From 7378b09302a700477488db0b4a06a043b8e03791 Mon Sep 17 00:00:00 2001 From: robbond Date: Fri, 6 Mar 2026 06:48:44 +0000 Subject: [PATCH] feat(ui): add collapsible plesk instances panel with summary view --- components/dashboard/dashboard-controls.tsx | 860 +++++++++++--------- 1 file changed, 497 insertions(+), 363 deletions(-) diff --git a/components/dashboard/dashboard-controls.tsx b/components/dashboard/dashboard-controls.tsx index b1a0888..9c2c104 100644 --- a/components/dashboard/dashboard-controls.tsx +++ b/components/dashboard/dashboard-controls.tsx @@ -160,6 +160,23 @@ function getDomainHref(domainName: string) { return `https://${normalized}`; } +function getLatestTimestamp(values: Array) { + let latest: string | null = null; + let latestMs = Number.NEGATIVE_INFINITY; + + for (const value of values) { + if (!value) continue; + const ms = new Date(value).getTime(); + if (Number.isNaN(ms)) continue; + if (ms > latestMs) { + latestMs = ms; + latest = value; + } + } + + return latest; +} + export function DashboardControls({ instances, subscriptions, @@ -184,6 +201,7 @@ export function DashboardControls({ const [message, setMessage] = useState(null); const [loading, setLoading] = useState(false); const [isConnectPanelOpen, setIsConnectPanelOpen] = useState(!hasInstances); + const [isInstancesPanelOpen, setIsInstancesPanelOpen] = useState(true); useEffect(() => { if (!hasInstances) { @@ -217,6 +235,38 @@ export function DashboardControls({ ); }, [hasInstances, isConnectPanelOpen]); + useEffect(() => { + if (!hasInstances) { + setIsInstancesPanelOpen(true); + return; + } + + const savedState = window.localStorage.getItem( + "dashboard_instances_panel_open", + ); + + if (savedState === "true") { + setIsInstancesPanelOpen(true); + return; + } + + if (savedState === "false") { + setIsInstancesPanelOpen(false); + return; + } + + setIsInstancesPanelOpen(true); + }, [hasInstances]); + + useEffect(() => { + if (!hasInstances) return; + + window.localStorage.setItem( + "dashboard_instances_panel_open", + isInstancesPanelOpen ? "true" : "false", + ); + }, [hasInstances, isInstancesPanelOpen]); + const healthCounts = instances.reduce( (acc, instance) => { if (instance.status === "connected") acc.connected += 1; @@ -245,6 +295,30 @@ export function DashboardControls({ return statusMatches && searchMatches; }); + const instanceHealthSummary = instances.reduce( + (acc, instance) => { + const status = (instance.health_status ?? "unknown").toLowerCase(); + if (status === "ok") acc.ok += 1; + else if (status === "degraded") acc.degraded += 1; + else if (status === "down") acc.down += 1; + else acc.unknown += 1; + return acc; + }, + { ok: 0, degraded: 0, down: 0, unknown: 0 }, + ); + + const autoSyncEnabledCount = instances.filter( + (instance) => instance.auto_sync_enabled, + ).length; + + const latestInstanceSyncAt = getLatestTimestamp( + instances.map((instance) => instance.last_sync_at), + ); + + const latestInstanceHealthCheckAt = getLatestTimestamp( + instances.map((instance) => instance.health_last_checked_at), + ); + async function runRequest(url: string, body?: unknown) { const response = await fetch(url, { method: "POST", @@ -548,380 +622,440 @@ export function DashboardControls({
-

Plesk Instances

+
+

Plesk Instances

+ {hasInstances ? ( + + ) : null} +
-
- {instances.length === 0 ? ( -

- No Plesk instances connected yet. + {!isInstancesPanelOpen && hasInstances ? ( +

+

+ {instances.length} instance{instances.length === 1 ? "" : "s"}

- ) : ( - instances.map((instance) => ( -
- {(() => { - const health = getHealthBadge(instance.health_status); +

+ Health — OK: {instanceHealthSummary.ok}, Degraded:{" "} + {instanceHealthSummary.degraded}, Down:{" "} + {instanceHealthSummary.down}, Unknown:{" "} + {instanceHealthSummary.unknown} +

+

+ Auto-sync enabled on {autoSyncEnabledCount} instance + {autoSyncEnabledCount === 1 ? "" : "s"} +

+

+ Last sync: {formatDateTime(latestInstanceSyncAt)} +

+

+ Last health check: {formatDateTime(latestInstanceHealthCheckAt)} +

+
+ ) : null} - return ( -
-
- {autoSyncByInstance[instance.id] ? ( - - Auto-sync {autoSyncByInstance[instance.id].status} - - ) : null} -

- {instance.name} -

-

- {instance.base_url} -

-

- Status:{" "} - - {instance.status} - -

-

- Health:{" "} - - {health.label} - -

-

- Health last checked:{" "} - {formatDateTime(instance.health_last_checked_at)} -

-

- Health latency:{" "} - {instance.health_last_latency_ms != null - ? `${instance.health_last_latency_ms} ms` - : "—"} -

-

- Subscriptions:{" "} - {instance.last_sync_subscriptions ?? 0} -

-

- Domains: {instance.last_sync_domains ?? 0} -

-

- Last sync status:{" "} - - {instance.last_sync_status ?? "unknown"} - -

-

- Last sync time:{" "} - {formatDateTime(instance.last_sync_at)} -

-

- Last connected:{" "} - {instance.last_connected_at - ? formatDateTime(instance.last_connected_at) - : "never"} -

-

- Auto-sync:{" "} - {instance.auto_sync_enabled - ? "Enabled" - : "Disabled"} -

-

- Auto-sync frequency:{" "} - {instance.auto_sync_frequency_minutes ?? 60} min -

-

- Last auto-sync:{" "} - {formatDateTime(instance.last_auto_sync_at)} -

-

- Next auto-sync:{" "} - {formatDateTime(instance.next_auto_sync_at)} -

-

- Lock status:{" "} - {instance.auto_sync_lock_until && - new Date(instance.auto_sync_lock_until).getTime() > - Date.now() - ? "Sync in progress" - : "Idle"} -

- {autoSyncByInstance[instance.id] ? ( -

- Last auto-sync:{" "} - {formatDateTime( - autoSyncByInstance[instance.id].created_at, - )} -

- ) : null} - {instance.error_message ? ( -

- {instance.error_message} -

- ) : null} - {instance.last_sync_error ? ( -

- Last sync error: {instance.last_sync_error} -

- ) : null} - {autoSyncByInstance[instance.id]?.error_message ? ( -

- Auto-sync error:{" "} - {autoSyncByInstance[instance.id].error_message} -

- ) : null} - {instance.health_last_error ? ( -

- Health error: {instance.health_last_error} -

- ) : null} -
-
-
- - ) => - onUpdateAutoSync(instance.id, { - auto_sync_enabled: e.target.checked, - auto_sync_frequency_minutes: - instance.auto_sync_frequency_minutes ?? 60, - }) - } - disabled={loading} - /> -
- - - - -
-
- ); - })()} + {isInstancesPanelOpen ? ( + <> +
+ {instances.length === 0 ? ( +

+ No Plesk instances connected yet. +

+ ) : ( + instances.map((instance) => ( +
+ {(() => { + const health = getHealthBadge(instance.health_status); -
-

- Health Panel -

-
-

- Current Status:{" "} - - {getHealthBadge(instance.health_status).label} - -

-

- Last Checked:{" "} - - {formatDateTime(instance.health_last_checked_at)} - -

-

- Last Successful Check:{" "} - - {formatDateTime(instance.health_last_ok_at)} - -

-

- Latency:{" "} - - {instance.health_last_latency_ms != null - ? `${instance.health_last_latency_ms} ms` - : "—"} - -

-

- Last Error:{" "} - - {instance.health_last_error ?? "—"} - -

-
- -
- - - - - - - - - - - {(healthEventsByInstance[instance.id] ?? []) - .length === 0 ? ( - - - - ) : ( - (healthEventsByInstance[instance.id] ?? []).map( - (event) => ( - +
+ {autoSyncByInstance[instance.id] ? ( + -
- - - + + + + + + ), + ) + )} + +
TimeEventResultMessage
- No health events yet. -
- {formatDateTime(event.created_at)} - {event.action} - {mapHealthResult(event.action)} - - {event.error_message ?? "—"} - {event.metadata ? ( -
- - metadata - -
-                                          {JSON.stringify(
-                                            event.metadata,
-                                            null,
-                                            2,
-                                          )}
-                                        
-
- ) : null} + Auto-sync{" "} + {autoSyncByInstance[instance.id].status} + + ) : null} +

+ {instance.name} +

+

+ {instance.base_url} +

+

+ Status:{" "} + + {instance.status} + +

+

+ Health:{" "} + + {health.label} + +

+

+ Health last checked:{" "} + {formatDateTime( + instance.health_last_checked_at, + )} +

+

+ Health latency:{" "} + {instance.health_last_latency_ms != null + ? `${instance.health_last_latency_ms} ms` + : "—"} +

+

+ Subscriptions:{" "} + {instance.last_sync_subscriptions ?? 0} +

+

+ Domains: {instance.last_sync_domains ?? 0} +

+

+ Last sync status:{" "} + + {instance.last_sync_status ?? "unknown"} + +

+

+ Last sync time:{" "} + {formatDateTime(instance.last_sync_at)} +

+

+ Last connected:{" "} + {instance.last_connected_at + ? formatDateTime(instance.last_connected_at) + : "never"} +

+

+ Auto-sync:{" "} + {instance.auto_sync_enabled + ? "Enabled" + : "Disabled"} +

+

+ Auto-sync frequency:{" "} + {instance.auto_sync_frequency_minutes ?? 60} min +

+

+ Last auto-sync:{" "} + {formatDateTime(instance.last_auto_sync_at)} +

+

+ Next auto-sync:{" "} + {formatDateTime(instance.next_auto_sync_at)} +

+

+ Lock status:{" "} + {instance.auto_sync_lock_until && + new Date( + instance.auto_sync_lock_until, + ).getTime() > Date.now() + ? "Sync in progress" + : "Idle"} +

+ {autoSyncByInstance[instance.id] ? ( +

+ Last auto-sync:{" "} + {formatDateTime( + autoSyncByInstance[instance.id].created_at, + )} +

+ ) : null} + {instance.error_message ? ( +

+ {instance.error_message} +

+ ) : null} + {instance.last_sync_error ? ( +

+ Last sync error: {instance.last_sync_error} +

+ ) : null} + {autoSyncByInstance[instance.id] + ?.error_message ? ( +

+ Auto-sync error:{" "} + { + autoSyncByInstance[instance.id] + .error_message + } +

+ ) : null} + {instance.health_last_error ? ( +

+ Health error: {instance.health_last_error} +

+ ) : null} + +
+
+ + , + ) => + onUpdateAutoSync(instance.id, { + auto_sync_enabled: e.target.checked, + auto_sync_frequency_minutes: + instance.auto_sync_frequency_minutes ?? + 60, + }) + } + disabled={loading} + /> +
+ + + + +
+ + ); + })()} + +
+

+ Health Panel +

+
+

+ Current Status:{" "} + + {getHealthBadge(instance.health_status).label} + +

+

+ Last Checked:{" "} + + {formatDateTime(instance.health_last_checked_at)} + +

+

+ Last Successful Check:{" "} + + {formatDateTime(instance.health_last_ok_at)} + +

+

+ Latency:{" "} + + {instance.health_last_latency_ms != null + ? `${instance.health_last_latency_ms} ms` + : "—"} + +

+

+ Last Error:{" "} + + {instance.health_last_error ?? "—"} + +

+
+ +
+ + + + + + + + + + + {(healthEventsByInstance[instance.id] ?? []) + .length === 0 ? ( + + - ), - ) - )} - -
TimeEventResultMessage
+ No health events yet.
+ ) : ( + (healthEventsByInstance[instance.id] ?? []).map( + (event) => ( +
+ {formatDateTime(event.created_at)} + + {event.action} + + {mapHealthResult(event.action)} + + {event.error_message ?? "—"} + {event.metadata ? ( +
+ + metadata + +
+                                              {JSON.stringify(
+                                                event.metadata,
+                                                null,
+                                                2,
+                                              )}
+                                            
+
+ ) : null} +
+
+
-
-
- )) - )} -
+ )) + )} +
-
- - - - -
+
+ + + + +
-
- - -
+
+ + +
- {message ?

{message}

: null} + {message ? ( +

{message}

+ ) : null} + + ) : null}