From d22164008673d6429a04c610fc731d2653ef899d Mon Sep 17 00:00:00 2001 From: rcourtman Date: Fri, 12 Jun 2026 11:36:18 +0100 Subject: [PATCH] Retire platform table frame allowlist --- .../subsystems/frontend-primitives.md | 14 +- .../v6/internal/subsystems/registry.json | 81 +++++ .../internal/subsystems/storage-recovery.md | 6 +- .../internal/subsystems/unified-resources.md | 46 ++- .../scripts/shared-template-registry.json | 48 +-- .../SharedPrimitives.guardrails.test.ts | 2 +- .../src/features/docker/DockerAlertsTable.tsx | 92 +++--- .../features/docker/DockerConfigsTable.tsx | 76 +++-- .../features/docker/DockerContainersTable.tsx | 60 ++-- .../src/features/docker/DockerImagesTable.tsx | 88 +++--- .../features/docker/DockerNetworksTable.tsx | 91 +++--- .../features/docker/DockerSecretsTable.tsx | 86 +++--- .../features/docker/DockerServicesTable.tsx | 120 ++++---- .../docker/DockerStorageUsageTable.tsx | 84 +++--- .../features/docker/DockerSwarmNodesTable.tsx | 106 +++---- .../src/features/docker/DockerTasksTable.tsx | 96 +++--- .../features/docker/DockerVolumesTable.tsx | 100 +++---- .../kubernetes/KubernetesAlertsTable.tsx | 92 +++--- .../kubernetes/KubernetesAutoscalingTable.tsx | 247 ++++++++-------- .../kubernetes/KubernetesClustersTable.tsx | 94 +++--- .../kubernetes/KubernetesConfigTable.tsx | 230 +++++++-------- .../kubernetes/KubernetesControllersTable.tsx | 266 ++++++++--------- .../kubernetes/KubernetesDeploymentsTable.tsx | 247 ++++++++-------- .../kubernetes/KubernetesEventsTable.tsx | 258 ++++++++-------- .../kubernetes/KubernetesNetworkingTable.tsx | 92 +++--- .../kubernetes/KubernetesPodsTable.tsx | 278 +++++++++--------- .../kubernetes/KubernetesPolicyTable.tsx | 240 +++++++-------- .../kubernetes/KubernetesServicesTable.tsx | 92 +++--- .../kubernetes/KubernetesStorageTable.tsx | 104 +++---- .../platformOverviewLayout.guardrails.test.ts | 41 +-- .../proxmox/ProxmoxBackupServersTable.tsx | 63 ++-- .../src/features/proxmox/ProxmoxCephTable.tsx | 73 ++--- .../features/proxmox/ProxmoxCoverageTable.tsx | 148 +++++----- .../proxmox/ProxmoxMailGatewayTable.tsx | 87 +++--- .../proxmox/ProxmoxRecoverableTable.tsx | 169 +++++------ .../proxmox/ProxmoxReplicationTable.tsx | 77 +++-- .../__tests__/ProxmoxBackupsTable.test.tsx | 50 +++- .../standalone/AgentsMachinesTable.tsx | 58 ++-- .../standalone/AvailabilityChecksTable.tsx | 132 ++++----- .../features/truenas/TrueNASAlertsTable.tsx | 87 +++--- .../src/features/truenas/TrueNASAppsTable.tsx | 102 +++---- .../truenas/TrueNASNetworkSharesTable.tsx | 82 +++--- .../truenas/TrueNASProtectionTable.tsx | 98 +++--- .../features/truenas/TrueNASServicesTable.tsx | 72 ++--- .../truenas/TrueNASStorageTopologyTable.tsx | 82 +++--- .../features/truenas/TrueNASSystemsTable.tsx | 112 ++++--- .../truenas/TrueNASVirtualMachinesTable.tsx | 96 +++--- .../features/vmware/VsphereActivityTable.tsx | 93 +++--- .../features/vmware/VsphereAlertsTable.tsx | 87 +++--- .../vmware/VsphereDatastoresTable.tsx | 96 +++--- .../features/vmware/VsphereNetworksTable.tsx | 90 +++--- 51 files changed, 2543 insertions(+), 2888 deletions(-) diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md index a071de532..305c6f2c5 100644 --- a/docs/release-control/v6/internal/subsystems/frontend-primitives.md +++ b/docs/release-control/v6/internal/subsystems/frontend-primitives.md @@ -2375,15 +2375,13 @@ primitive. Platform table frames are one of those registry-backed templates. `frontend-modern/src/features/platformPage/sharedPlatformPage.tsx` owns `PlatformTableShell`, including the canonical table card, header row, and body -divide styling. New platform tables must start from `PlatformTableShell`; the -legacy table-frame allowlist in `shared-template-registry.json` is migration -debt, not precedent, and must shrink as existing tables are moved onto the -shared shell. -Host overview tables for Docker, Kubernetes, Proxmox, and vSphere now compose -that shared shell directly. Future host overview tables must preserve the split: +divide styling. Platform table frames now have no local-frame exceptions in +`shared-template-registry.json`: new and existing platform tables must compose +`PlatformTableShell` instead of recreating the `TableCard`, header row, or body +divide frame locally. Platform table consumers must preserve the owner split: frontend-primitives owns the repeated `PlatformTableShell` frame and guardrail -registry, while unified-resource consumers own the platform-specific row fields, -drawers, and resource semantics. +registry, while platform and unified-resource consumers own the source-specific +row fields, drawers, and resource semantics. The shared help icon now follows that same owner split. `frontend-modern/src/components/shared/HelpIcon.tsx` stays the render shell, `frontend-modern/src/components/shared/useHelpIconState.ts` owns open state, diff --git a/docs/release-control/v6/internal/subsystems/registry.json b/docs/release-control/v6/internal/subsystems/registry.json index 2601f2301..bcf02e78c 100644 --- a/docs/release-control/v6/internal/subsystems/registry.json +++ b/docs/release-control/v6/internal/subsystems/registry.json @@ -353,6 +353,22 @@ "security-privacy" ] }, + { + "path": "frontend-modern/src/features/proxmox/ProxmoxBackupServersTable.tsx", + "subsystems": [ + "storage-recovery", + "unified-resources" + ], + "rationale": "Proxmox backup server table rows are both a storage/recovery backup-health surface and a unified-resource platform-table consumer boundary" + }, + { + "path": "frontend-modern/src/features/proxmox/ProxmoxRecoverableTable.tsx", + "subsystems": [ + "storage-recovery", + "unified-resources" + ], + "rationale": "Proxmox recoverable workload table rows are both a storage/recovery coverage surface and a unified-resource platform-table consumer boundary" + }, { "path": "frontend-modern/src/routing/routePreload.ts", "rationale": "the app-shell route preload registry is both a canonical frontend shell boundary and an authenticated hot-path performance boundary", @@ -5148,6 +5164,7 @@ "frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts", "frontend-modern/src/components/Kubernetes/K8sDeploymentsDrawer.tsx", "frontend-modern/src/components/Kubernetes/K8sNamespacesDrawer.tsx", + "frontend-modern/src/features/docker/DockerAlertsTable.tsx", "frontend-modern/src/features/docker/DockerConfigsTable.tsx", "frontend-modern/src/features/docker/DockerContainersTable.tsx", "frontend-modern/src/features/docker/DockerHostsTable.tsx", @@ -5157,9 +5174,12 @@ "frontend-modern/src/features/docker/dockerPageModel.ts", "frontend-modern/src/features/docker/DockerPageSurface.tsx", "frontend-modern/src/features/docker/DockerSecretsTable.tsx", + "frontend-modern/src/features/docker/DockerServicesTable.tsx", + "frontend-modern/src/features/docker/DockerStorageUsageTable.tsx", "frontend-modern/src/features/docker/DockerSwarmNodesTable.tsx", "frontend-modern/src/features/docker/DockerTasksTable.tsx", "frontend-modern/src/features/docker/DockerVolumesTable.tsx", + "frontend-modern/src/features/kubernetes/KubernetesAlertsTable.tsx", "frontend-modern/src/features/kubernetes/KubernetesAutoscalingTable.tsx", "frontend-modern/src/features/kubernetes/KubernetesClustersTable.tsx", "frontend-modern/src/features/kubernetes/KubernetesConfigTable.tsx", @@ -5174,8 +5194,28 @@ "frontend-modern/src/features/kubernetes/KubernetesPolicyTable.tsx", "frontend-modern/src/features/kubernetes/KubernetesServicesTable.tsx", "frontend-modern/src/features/kubernetes/KubernetesStorageTable.tsx", + "frontend-modern/src/features/proxmox/ProxmoxBackupServersTable.tsx", + "frontend-modern/src/features/proxmox/ProxmoxCephTable.tsx", + "frontend-modern/src/features/proxmox/ProxmoxCoverageTable.tsx", + "frontend-modern/src/features/proxmox/ProxmoxMailGatewayTable.tsx", "frontend-modern/src/features/proxmox/ProxmoxNodesTable.tsx", + "frontend-modern/src/features/proxmox/ProxmoxRecoverableTable.tsx", + "frontend-modern/src/features/proxmox/ProxmoxReplicationTable.tsx", + "frontend-modern/src/features/standalone/AgentsMachinesTable.tsx", + "frontend-modern/src/features/standalone/AvailabilityChecksTable.tsx", + "frontend-modern/src/features/truenas/TrueNASAlertsTable.tsx", + "frontend-modern/src/features/truenas/TrueNASAppsTable.tsx", + "frontend-modern/src/features/truenas/TrueNASNetworkSharesTable.tsx", + "frontend-modern/src/features/truenas/TrueNASProtectionTable.tsx", + "frontend-modern/src/features/truenas/TrueNASServicesTable.tsx", + "frontend-modern/src/features/truenas/TrueNASStorageTopologyTable.tsx", + "frontend-modern/src/features/truenas/TrueNASSystemsTable.tsx", + "frontend-modern/src/features/truenas/TrueNASVirtualMachinesTable.tsx", + "frontend-modern/src/features/vmware/VsphereActivityTable.tsx", + "frontend-modern/src/features/vmware/VsphereAlertsTable.tsx", + "frontend-modern/src/features/vmware/VsphereDatastoresTable.tsx", "frontend-modern/src/features/vmware/VsphereHostsTable.tsx", + "frontend-modern/src/features/vmware/VsphereNetworksTable.tsx", "frontend-modern/src/hooks/useUnifiedResources.ts", "frontend-modern/src/routing/resourceLinks.ts", "frontend-modern/src/types/resource.ts", @@ -5290,6 +5330,7 @@ "frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts", "frontend-modern/src/components/Kubernetes/K8sDeploymentsDrawer.tsx", "frontend-modern/src/components/Kubernetes/K8sNamespacesDrawer.tsx", + "frontend-modern/src/features/docker/DockerAlertsTable.tsx", "frontend-modern/src/features/docker/DockerConfigsTable.tsx", "frontend-modern/src/features/docker/DockerContainersTable.tsx", "frontend-modern/src/features/docker/DockerHostsTable.tsx", @@ -5299,9 +5340,12 @@ "frontend-modern/src/features/docker/dockerPageModel.ts", "frontend-modern/src/features/docker/DockerPageSurface.tsx", "frontend-modern/src/features/docker/DockerSecretsTable.tsx", + "frontend-modern/src/features/docker/DockerServicesTable.tsx", + "frontend-modern/src/features/docker/DockerStorageUsageTable.tsx", "frontend-modern/src/features/docker/DockerSwarmNodesTable.tsx", "frontend-modern/src/features/docker/DockerTasksTable.tsx", "frontend-modern/src/features/docker/DockerVolumesTable.tsx", + "frontend-modern/src/features/kubernetes/KubernetesAlertsTable.tsx", "frontend-modern/src/features/kubernetes/KubernetesAutoscalingTable.tsx", "frontend-modern/src/features/kubernetes/KubernetesClustersTable.tsx", "frontend-modern/src/features/kubernetes/KubernetesConfigTable.tsx", @@ -5316,8 +5360,28 @@ "frontend-modern/src/features/kubernetes/KubernetesPolicyTable.tsx", "frontend-modern/src/features/kubernetes/KubernetesServicesTable.tsx", "frontend-modern/src/features/kubernetes/KubernetesStorageTable.tsx", + "frontend-modern/src/features/proxmox/ProxmoxBackupServersTable.tsx", + "frontend-modern/src/features/proxmox/ProxmoxCephTable.tsx", + "frontend-modern/src/features/proxmox/ProxmoxCoverageTable.tsx", + "frontend-modern/src/features/proxmox/ProxmoxMailGatewayTable.tsx", "frontend-modern/src/features/proxmox/ProxmoxNodesTable.tsx", + "frontend-modern/src/features/proxmox/ProxmoxRecoverableTable.tsx", + "frontend-modern/src/features/proxmox/ProxmoxReplicationTable.tsx", + "frontend-modern/src/features/standalone/AgentsMachinesTable.tsx", + "frontend-modern/src/features/standalone/AvailabilityChecksTable.tsx", + "frontend-modern/src/features/truenas/TrueNASAlertsTable.tsx", + "frontend-modern/src/features/truenas/TrueNASAppsTable.tsx", + "frontend-modern/src/features/truenas/TrueNASNetworkSharesTable.tsx", + "frontend-modern/src/features/truenas/TrueNASProtectionTable.tsx", + "frontend-modern/src/features/truenas/TrueNASServicesTable.tsx", + "frontend-modern/src/features/truenas/TrueNASStorageTopologyTable.tsx", + "frontend-modern/src/features/truenas/TrueNASSystemsTable.tsx", + "frontend-modern/src/features/truenas/TrueNASVirtualMachinesTable.tsx", + "frontend-modern/src/features/vmware/VsphereActivityTable.tsx", + "frontend-modern/src/features/vmware/VsphereAlertsTable.tsx", + "frontend-modern/src/features/vmware/VsphereDatastoresTable.tsx", "frontend-modern/src/features/vmware/VsphereHostsTable.tsx", + "frontend-modern/src/features/vmware/VsphereNetworksTable.tsx", "frontend-modern/src/hooks/useUnifiedResources.ts", "frontend-modern/src/routing/resourceLinks.ts", "frontend-modern/src/types/resource.ts", @@ -5340,6 +5404,7 @@ "frontend-modern/src/components/Infrastructure/__tests__/UnifiedResourceTable.workloads-link.test.tsx", "frontend-modern/src/components/Infrastructure/__tests__/unifiedResourceTableStateModel.test.ts", "frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts", + "frontend-modern/src/features/docker/__tests__/DockerAlertsTable.test.tsx", "frontend-modern/src/features/docker/__tests__/DockerHostsTable.test.tsx", "frontend-modern/src/features/docker/__tests__/DockerNativeTables.test.tsx", "frontend-modern/src/features/docker/__tests__/dockerPageModel.test.ts", @@ -5356,8 +5421,24 @@ "frontend-modern/src/features/kubernetes/__tests__/KubernetesPolicyTable.test.tsx", "frontend-modern/src/features/kubernetes/__tests__/KubernetesServicesTable.test.tsx", "frontend-modern/src/features/kubernetes/__tests__/KubernetesStorageTable.test.tsx", + "frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts", + "frontend-modern/src/features/proxmox/__tests__/ProxmoxBackupServersTable.test.ts", + "frontend-modern/src/features/proxmox/__tests__/ProxmoxCoverageTable.test.tsx", "frontend-modern/src/features/proxmox/__tests__/ProxmoxNodesTable.test.tsx", + "frontend-modern/src/features/proxmox/__tests__/ProxmoxPageSurface.contract.test.tsx", + "frontend-modern/src/features/standalone/__tests__/AgentsMachinesTable.test.tsx", + "frontend-modern/src/features/standalone/__tests__/AvailabilityChecksTable.test.tsx", + "frontend-modern/src/features/truenas/__tests__/TrueNASAlertsTable.test.tsx", + "frontend-modern/src/features/truenas/__tests__/TrueNASPageSurface.contract.test.tsx", + "frontend-modern/src/features/truenas/__tests__/TrueNASProtectionTable.test.tsx", + "frontend-modern/src/features/truenas/__tests__/TrueNASServicesTable.test.tsx", + "frontend-modern/src/features/truenas/__tests__/TrueNASStorageTopologyTable.test.tsx", + "frontend-modern/src/features/truenas/__tests__/TrueNASSystemsTable.test.tsx", + "frontend-modern/src/features/vmware/__tests__/VsphereActivityTable.test.tsx", + "frontend-modern/src/features/vmware/__tests__/VsphereAlertsTable.test.tsx", + "frontend-modern/src/features/vmware/__tests__/VsphereDatastoresTable.test.tsx", "frontend-modern/src/features/vmware/__tests__/VsphereHostsTable.test.tsx", + "frontend-modern/src/features/vmware/__tests__/VsphereNetworksTable.test.tsx", "frontend-modern/src/hooks/__tests__/useUnifiedResources.test.ts", "frontend-modern/src/routing/__tests__/resourceLinks.test.ts", "frontend-modern/src/stores/__tests__/websocket-unified.test.ts", diff --git a/docs/release-control/v6/internal/subsystems/storage-recovery.md b/docs/release-control/v6/internal/subsystems/storage-recovery.md index 4c2edbc06..4da971b83 100644 --- a/docs/release-control/v6/internal/subsystems/storage-recovery.md +++ b/docs/release-control/v6/internal/subsystems/storage-recovery.md @@ -54,8 +54,10 @@ state. ## Shared Boundaries -1. `internal/api/setup_script_render.go` shared with `agent-lifecycle`, `api-contracts`: the generated Proxmox setup-script is a shared boundary across agent lifecycle (forced-command keys, install/uninstall edits), API contracts (rendered token shape and encoded rerun URL), and storage/recovery (backup visibility grants, Pulse-managed temperature SSH keys, and SMART disk-temperature collection). -2. `internal/proxmoxidentity/backup_identity.go` shared with `alerts`, `monitoring`: Proxmox PBS backup subject identity is a shared runtime boundary for monitoring backup freshness, backup-age alert attribution, and recovery-point guest mapping. +1. `frontend-modern/src/features/proxmox/ProxmoxBackupServersTable.tsx` shared with `unified-resources`: Proxmox backup server table rows are both a storage/recovery backup-health surface and a unified-resource platform-table consumer boundary. +2. `frontend-modern/src/features/proxmox/ProxmoxRecoverableTable.tsx` shared with `unified-resources`: Proxmox recoverable workload table rows are both a storage/recovery coverage surface and a unified-resource platform-table consumer boundary. +3. `internal/api/setup_script_render.go` shared with `agent-lifecycle`, `api-contracts`: the generated Proxmox setup-script is a shared boundary across agent lifecycle (forced-command keys, install/uninstall edits), API contracts (rendered token shape and encoded rerun URL), and storage/recovery (backup visibility grants, Pulse-managed temperature SSH keys, and SMART disk-temperature collection). +4. `internal/proxmoxidentity/backup_identity.go` shared with `alerts`, `monitoring`: Proxmox PBS backup subject identity is a shared runtime boundary for monitoring backup freshness, backup-age alert attribution, and recovery-point guest mapping. ## Extension Points diff --git a/docs/release-control/v6/internal/subsystems/unified-resources.md b/docs/release-control/v6/internal/subsystems/unified-resources.md index 076c28248..3b441c9a6 100644 --- a/docs/release-control/v6/internal/subsystems/unified-resources.md +++ b/docs/release-control/v6/internal/subsystems/unified-resources.md @@ -132,6 +132,28 @@ cross-source deduplication. 110. `frontend-modern/src/features/kubernetes/KubernetesPolicyTable.tsx` 111. `frontend-modern/src/features/kubernetes/KubernetesAutoscalingTable.tsx` 112. `frontend-modern/src/features/kubernetes/KubernetesEventsTable.tsx` +113. `frontend-modern/src/features/docker/DockerAlertsTable.tsx` +114. `frontend-modern/src/features/docker/DockerServicesTable.tsx` +115. `frontend-modern/src/features/docker/DockerStorageUsageTable.tsx` +116. `frontend-modern/src/features/kubernetes/KubernetesAlertsTable.tsx` +117. `frontend-modern/src/features/proxmox/ProxmoxBackupServersTable.tsx` +118. `frontend-modern/src/features/proxmox/ProxmoxCephTable.tsx` +119. `frontend-modern/src/features/proxmox/ProxmoxCoverageTable.tsx` +120. `frontend-modern/src/features/proxmox/ProxmoxMailGatewayTable.tsx` +121. `frontend-modern/src/features/proxmox/ProxmoxRecoverableTable.tsx` +122. `frontend-modern/src/features/proxmox/ProxmoxReplicationTable.tsx` +123. `frontend-modern/src/features/truenas/TrueNASAlertsTable.tsx` +124. `frontend-modern/src/features/truenas/TrueNASAppsTable.tsx` +125. `frontend-modern/src/features/truenas/TrueNASNetworkSharesTable.tsx` +126. `frontend-modern/src/features/truenas/TrueNASProtectionTable.tsx` +127. `frontend-modern/src/features/truenas/TrueNASServicesTable.tsx` +128. `frontend-modern/src/features/truenas/TrueNASStorageTopologyTable.tsx` +129. `frontend-modern/src/features/truenas/TrueNASSystemsTable.tsx` +130. `frontend-modern/src/features/truenas/TrueNASVirtualMachinesTable.tsx` +131. `frontend-modern/src/features/vmware/VsphereActivityTable.tsx` +132. `frontend-modern/src/features/vmware/VsphereAlertsTable.tsx` +133. `frontend-modern/src/features/vmware/VsphereDatastoresTable.tsx` +134. `frontend-modern/src/features/vmware/VsphereNetworksTable.tsx` ## Shared Boundaries @@ -184,14 +206,14 @@ workload, service, storage, configuration, policy, and event object rows belong in their workflow tabs. If a future Overview repeats a detailed table, the owning workflow must be retired or the Overview content must be reduced to aggregate signal. -Platform host overview tables are unified-resource consumers even when their -visual table frame is frontend-primitives-owned. `DockerHostsTable.tsx`, -`KubernetesNodesTable.tsx`, `ProxmoxNodesTable.tsx`, and -`VsphereHostsTable.tsx` own source-specific row fields over canonical -`Resource` projections, while `PlatformTableShell` owns the shared table card, -header row, and body frame. Future host overview tables must keep that split: -row data and platform semantics stay in the unified-resource consumer, and the -repeated table shell stays in the shared frontend primitive. +Platform native tables are unified-resource consumers even when their visual +table frame is frontend-primitives-owned. Docker / Podman, Kubernetes, Proxmox, +Standalone, TrueNAS, and vSphere platform tables own source-specific row fields, +filter semantics, drawer handoffs, and resource projections, while +`PlatformTableShell` owns the shared table card, header row, and body frame. +Future platform tables must keep that split: row data and platform semantics +stay in the unified-resource consumer, and the repeated table shell stays in the +shared frontend primitive. Product-originated resource references may arrive as registered unified resource IDs, source-specific IDs, or canonical identity aliases. The unified-resource registry owns resolving those references through @@ -290,11 +312,13 @@ container inventory table. 9. `frontend-modern/src/components/Infrastructure/unifiedResourceTableStateModel.ts` shared with `performance-and-scalability`: unified resource table state derivation, sort-cycle policy, service sorting, and responsive column layout are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary. 10. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableState.ts` shared with `performance-and-scalability`: unified resource table state, grouping, and windowing are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary. 11. `frontend-modern/src/components/Infrastructure/useUnifiedResourceTableViewportSync.ts` shared with `performance-and-scalability`: unified resource table viewport sync and selected-row reveal are both a canonical unified-resource consumer surface and a fleet-scale performance hot-path boundary. -15. `frontend-modern/src/utils/platformSupportManifest.generated.ts` shared with `frontend-primitives`: the generated platform support projection is both a canonical unified-resource platform union boundary and a shared frontend source/platform vocabulary boundary. +12. `frontend-modern/src/features/proxmox/ProxmoxBackupServersTable.tsx` shared with `storage-recovery`: Proxmox backup server table rows are both a storage/recovery backup-health surface and a unified-resource platform-table consumer boundary. +13. `frontend-modern/src/features/proxmox/ProxmoxRecoverableTable.tsx` shared with `storage-recovery`: Proxmox recoverable workload table rows are both a storage/recovery coverage surface and a unified-resource platform-table consumer boundary. +14. `frontend-modern/src/utils/platformSupportManifest.generated.ts` shared with `frontend-primitives`: the generated platform support projection is both a canonical unified-resource platform union boundary and a shared frontend source/platform vocabulary boundary. It must carry the manifest `surface_kind` distinction so `docker` remains machine-readable as a `runtime-lens` while owning infrastructure sources remain `platform` entries. -16. `frontend-modern/src/utils/sourcePlatforms.ts` shared with `frontend-primitives`: the source platform normalizer is both a canonical unified-resource source adapter boundary and a shared frontend source/platform vocabulary boundary. +15. `frontend-modern/src/utils/sourcePlatforms.ts` shared with `frontend-primitives`: the source platform normalizer is both a canonical unified-resource source adapter boundary and a shared frontend source/platform vocabulary boundary. That shared vocabulary boundary owns the generic `docker` platform label: selectors, badges, and filter options render it as "Docker / Podman" so v5 Docker users can still find the runtime surface while Podman-backed @@ -316,7 +340,7 @@ container inventory table. display/source family; `platformScopes` is the overlap set used when a runtime workload belongs to both Docker and an owning infrastructure platform. -17. `internal/api/resources.go` shared with `api-contracts`: the unified resource endpoint is both a backend payload contract surface and a unified-resource runtime boundary. +16. `internal/api/resources.go` shared with `api-contracts`: the unified resource endpoint is both a backend payload contract surface and a unified-resource runtime boundary. App-container Discovery targets are part of that shared payload contract. Backend resources must expose frontend-facing `resourceType=app-container` with the reporting Docker/Podman agent id and the stable container name as diff --git a/frontend-modern/scripts/shared-template-registry.json b/frontend-modern/scripts/shared-template-registry.json index 648031713..c6eb22a71 100644 --- a/frontend-modern/scripts/shared-template-registry.json +++ b/frontend-modern/scripts/shared-template-registry.json @@ -59,52 +59,8 @@ "TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}", "TableBody class={PLATFORM_TABLE_BODY_CLASS}" ], - "legacyReason": "Existing platform tables predate PlatformTableShell and are registered legacy migration debt. New tables must use the canonical shell.", - "allowedPaths": [ - "src/features/docker/DockerAlertsTable.tsx", - "src/features/docker/DockerConfigsTable.tsx", - "src/features/docker/DockerContainersTable.tsx", - "src/features/docker/DockerImagesTable.tsx", - "src/features/docker/DockerNetworksTable.tsx", - "src/features/docker/DockerSecretsTable.tsx", - "src/features/docker/DockerServicesTable.tsx", - "src/features/docker/DockerStorageUsageTable.tsx", - "src/features/docker/DockerSwarmNodesTable.tsx", - "src/features/docker/DockerTasksTable.tsx", - "src/features/docker/DockerVolumesTable.tsx", - "src/features/kubernetes/KubernetesAlertsTable.tsx", - "src/features/kubernetes/KubernetesAutoscalingTable.tsx", - "src/features/kubernetes/KubernetesClustersTable.tsx", - "src/features/kubernetes/KubernetesConfigTable.tsx", - "src/features/kubernetes/KubernetesControllersTable.tsx", - "src/features/kubernetes/KubernetesDeploymentsTable.tsx", - "src/features/kubernetes/KubernetesEventsTable.tsx", - "src/features/kubernetes/KubernetesNetworkingTable.tsx", - "src/features/kubernetes/KubernetesPodsTable.tsx", - "src/features/kubernetes/KubernetesPolicyTable.tsx", - "src/features/kubernetes/KubernetesServicesTable.tsx", - "src/features/kubernetes/KubernetesStorageTable.tsx", - "src/features/proxmox/ProxmoxBackupServersTable.tsx", - "src/features/proxmox/ProxmoxCephTable.tsx", - "src/features/proxmox/ProxmoxCoverageTable.tsx", - "src/features/proxmox/ProxmoxMailGatewayTable.tsx", - "src/features/proxmox/ProxmoxRecoverableTable.tsx", - "src/features/proxmox/ProxmoxReplicationTable.tsx", - "src/features/standalone/AgentsMachinesTable.tsx", - "src/features/standalone/AvailabilityChecksTable.tsx", - "src/features/truenas/TrueNASAlertsTable.tsx", - "src/features/truenas/TrueNASAppsTable.tsx", - "src/features/truenas/TrueNASNetworkSharesTable.tsx", - "src/features/truenas/TrueNASProtectionTable.tsx", - "src/features/truenas/TrueNASServicesTable.tsx", - "src/features/truenas/TrueNASStorageTopologyTable.tsx", - "src/features/truenas/TrueNASSystemsTable.tsx", - "src/features/truenas/TrueNASVirtualMachinesTable.tsx", - "src/features/vmware/VsphereActivityTable.tsx", - "src/features/vmware/VsphereAlertsTable.tsx", - "src/features/vmware/VsphereDatastoresTable.tsx", - "src/features/vmware/VsphereNetworksTable.tsx" - ], + "legacyReason": "Retired migration debt. Platform table frames must use PlatformTableShell; no local-frame exceptions are currently allowed.", + "allowedPaths": [], "proof": [ "src/components/shared/SharedPrimitives.guardrails.test.ts", "scripts/shared-template-audit.mjs" diff --git a/frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts b/frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts index 6139de79e..288c89b3e 100644 --- a/frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts +++ b/frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts @@ -961,7 +961,7 @@ describe('shared primitive guardrails', () => { 'src/features/platformPage/sharedPlatformPage.tsx', ); expect(registeredGuard?.canonical?.export).toBe('PlatformTableShell'); - expect(registeredGuard?.allowedPaths?.length).toBeGreaterThan(0); + expect(registeredGuard?.allowedPaths ?? []).toHaveLength(0); expect(sharedPlatformPageSource).toContain('export function PlatformTableShell'); expect(sharedPlatformPageSource).toContain('TableCard class={props.cardClass'); expect(sharedPlatformPageSource).toContain('TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}'); diff --git a/frontend-modern/src/features/docker/DockerAlertsTable.tsx b/frontend-modern/src/features/docker/DockerAlertsTable.tsx index cbc756cdd..d7d9964a0 100644 --- a/frontend-modern/src/features/docker/DockerAlertsTable.tsx +++ b/frontend-modern/src/features/docker/DockerAlertsTable.tsx @@ -1,20 +1,8 @@ import { For, Show, type Component, type JSX } from 'solid-js'; import XIcon from 'lucide-solid/icons/x'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; -import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, @@ -22,6 +10,7 @@ import { getPlatformTableHeadClassForKind, platformChipStatusDot, type PlatformTableFilterOption, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { createPlatformResourceDetailState, @@ -185,10 +174,7 @@ const AlertDetail: Component<{ incident: DockerIncidentRow; onClose: () => void - + @@ -251,38 +237,39 @@ export const DockerAlertsTable: Component<{ /> } > - - - - - - - Resource - - - Severity - - - Alert - - - - - - - + + + Resource + + + Severity + + + Alert + + + + + + } + body={ + <> {(incident) => { const docker = () => incident.resource.docker; @@ -316,7 +303,6 @@ export const DockerAlertsTable: Component<{
{formatResourceType(incident.resourceType)} - {' '} on {incident.resource.parentName}
@@ -392,9 +378,9 @@ export const DockerAlertsTable: Component<{ ); }}
-
-
-
+ + } + /> diff --git a/frontend-modern/src/features/docker/DockerConfigsTable.tsx b/frontend-modern/src/features/docker/DockerConfigsTable.tsx index da66e3f57..fc88f227b 100644 --- a/frontend-modern/src/features/docker/DockerConfigsTable.tsx +++ b/frontend-modern/src/features/docker/DockerConfigsTable.tsx @@ -1,24 +1,13 @@ import { For, Show, type Component } from 'solid-js'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { DockerResourceNameCell, @@ -72,33 +61,34 @@ export const DockerConfigsTable: Component = (props) => /> } > - - - - - - - Config - - - Template - - - - - Host - - - - + + + Config + + + Template + + + + + Host + + + } + body={ + <> {(resource) => ( @@ -136,9 +126,9 @@ export const DockerConfigsTable: Component = (props) => )} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/docker/DockerContainersTable.tsx b/frontend-modern/src/features/docker/DockerContainersTable.tsx index 85a2f23b5..6e6fb098f 100644 --- a/frontend-modern/src/features/docker/DockerContainersTable.tsx +++ b/frontend-modern/src/features/docker/DockerContainersTable.tsx @@ -5,29 +5,18 @@ import { UpdateButton } from '@/components/shared/ContainerUpdateBadge'; import { ResponsiveMetricCell } from '@/components/shared/responsive'; import { StackedMemoryBar } from '@/components/Workloads/StackedMemoryBar'; import { getWorkloadTableLayoutMode } from '@/components/Workloads/guestRowModel'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; import { useBreakpoint } from '@/hooks/useBreakpoint'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { asTrimmedString } from '@/utils/stringUtils'; import { buildMetricKeyForUnifiedResource } from '@/utils/metricsKeys'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -316,9 +305,10 @@ export const DockerContainersTable: Component = (props) /> } > - - - + {(column) => ( @@ -332,21 +322,23 @@ export const DockerContainersTable: Component = (props) )} - - - - {(column) => ( - - {column.label}}> - Mem - - - - )} - - - - + } + header={ + <> + + {(column) => ( + + {column.label}}> + Mem + + + + )} + + + } + body={ + <> {(resource) => { const indicator = mapDockerContainerStatus(resource); @@ -555,9 +547,9 @@ export const DockerContainersTable: Component = (props) ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/docker/DockerImagesTable.tsx b/frontend-modern/src/features/docker/DockerImagesTable.tsx index def6f55f9..bd53745bf 100644 --- a/frontend-modern/src/features/docker/DockerImagesTable.tsx +++ b/frontend-modern/src/features/docker/DockerImagesTable.tsx @@ -1,24 +1,13 @@ import { For, Show, type Component } from 'solid-js'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -81,40 +70,39 @@ export const DockerImagesTable: Component = (props) => { /> } > - - - - - - - Image - - - Tags - - - - Size - - - In Use - - - - - + + + Image + + + Tags + + + + Size + + + In Use + + + + } + body={ + <> {(resource) => { const detailRowId = () => drawer.detailRowId(resource); @@ -179,9 +167,9 @@ export const DockerImagesTable: Component = (props) => { ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/docker/DockerNetworksTable.tsx b/frontend-modern/src/features/docker/DockerNetworksTable.tsx index 31f23bbf9..f02c47a5f 100644 --- a/frontend-modern/src/features/docker/DockerNetworksTable.tsx +++ b/frontend-modern/src/features/docker/DockerNetworksTable.tsx @@ -1,26 +1,15 @@ import { For, Show, createMemo, createSignal, type Component } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, type PlatformTableFilterOption, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { createPlatformResourceDetailState, @@ -200,7 +189,10 @@ const AttachmentRowCard: Component<{ row: DockerNetworkAttachmentRow }> = (props const AttachmentDetail: Component<{ rows: readonly DockerNetworkAttachmentRow[] }> = (props) => { const [showAll, setShowAll] = createSignal(false); - const tableState = createPlatformTableFilterState({ + const tableState = createPlatformTableFilterState< + DockerNetworkAttachmentRow, + AttachmentStatusFilter + >({ resources: () => [...props.rows], initialStatus: 'all', filter: filterAttachmentRows, @@ -401,38 +393,39 @@ export const DockerNetworksTable: Component = (props) /> } > - - - - - - - Network - - - Attached workloads - - - Attention - - - - - - - + + + Network + + + Attached workloads + + + Attention + + + + + + } + body={ + <> {(resource) => { const detailRowId = () => drawer.detailRowId(resource); @@ -517,9 +510,9 @@ export const DockerNetworksTable: Component = (props) ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/docker/DockerSecretsTable.tsx b/frontend-modern/src/features/docker/DockerSecretsTable.tsx index 2dff3d478..7d83f2f0b 100644 --- a/frontend-modern/src/features/docker/DockerSecretsTable.tsx +++ b/frontend-modern/src/features/docker/DockerSecretsTable.tsx @@ -1,24 +1,13 @@ import { For, Show, type Component } from 'solid-js'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { DockerResourceNameCell, @@ -72,38 +61,39 @@ export const DockerSecretsTable: Component = (props) => /> } > - - - - - - - Secret - - - Driver - - - - - - Host - - - - + + + Secret + + + Driver + + + + + + Host + + + } + body={ + <> {(resource) => ( @@ -146,9 +136,9 @@ export const DockerSecretsTable: Component = (props) => )} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/docker/DockerServicesTable.tsx b/frontend-modern/src/features/docker/DockerServicesTable.tsx index 7c12b7fd6..4add5d4cc 100644 --- a/frontend-modern/src/features/docker/DockerServicesTable.tsx +++ b/frontend-modern/src/features/docker/DockerServicesTable.tsx @@ -1,26 +1,15 @@ import { For, Show, createMemo, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { asTrimmedString } from '@/utils/stringUtils'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PLATFORM_HEALTH_FILTER_OPTIONS, PlatformTableToolbar, PlatformTableEmptyState, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import type { Resource } from '@/types/resource'; import { @@ -142,12 +131,12 @@ export const DockerServicesTable: Component<{ /> } > - - - - - - {/* + + {/* Desktop widths: Service and Image take the lion's share because their content is long (registry refs, fully qualified service names). Mode / Desired / Running trim @@ -155,50 +144,49 @@ export const DockerServicesTable: Component<{ Host get middle slices for rollout state, port lists, and hostnames. Mobile widths are unchanged. */} - - Service - - - - - Mode - - - - Running - - - - - - - + + Service + + + + + Mode + + + + Running + + + + + + } + body={ + <> {(service) => { const name = () => asTrimmedString(service.name) || service.id; @@ -275,9 +263,9 @@ export const DockerServicesTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/docker/DockerStorageUsageTable.tsx b/frontend-modern/src/features/docker/DockerStorageUsageTable.tsx index e6bce29e9..6b9f6cbc2 100644 --- a/frontend-modern/src/features/docker/DockerStorageUsageTable.tsx +++ b/frontend-modern/src/features/docker/DockerStorageUsageTable.tsx @@ -1,28 +1,17 @@ import { For, Show, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { formatBytes } from '@/utils/format'; import { getSimpleStatusIndicator } from '@/utils/status'; import { asTrimmedString } from '@/utils/stringUtils'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import type { DockerStorageUsageMeta, Resource } from '@/types/resource'; import { @@ -110,37 +99,38 @@ export const DockerStorageUsageTable: Component<{ /> } > - - - - - - - Host - - - Images - - - Containers - - - - - - + + + Host + + + Images + + + Containers + + + + + } + body={ + <> {(host) => { const name = () => asTrimmedString(host.name) || host.id; @@ -184,9 +174,9 @@ export const DockerStorageUsageTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/docker/DockerSwarmNodesTable.tsx b/frontend-modern/src/features/docker/DockerSwarmNodesTable.tsx index cc9a22580..31074543a 100644 --- a/frontend-modern/src/features/docker/DockerSwarmNodesTable.tsx +++ b/frontend-modern/src/features/docker/DockerSwarmNodesTable.tsx @@ -1,24 +1,13 @@ import { For, Show, createMemo, type Component } from 'solid-js'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { DockerResourceNameCell, @@ -78,48 +67,49 @@ export const DockerSwarmNodesTable: Component = (props) /> } > - - - - - - - Node - - - Role - - - Availability - - - - - - Memory - - - - - + + + Node + + + Role + + + Availability + + + + + + Memory + + + + } + body={ + <> {(resource) => { const managerReachability = () => @@ -179,9 +169,9 @@ export const DockerSwarmNodesTable: Component = (props) ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/docker/DockerTasksTable.tsx b/frontend-modern/src/features/docker/DockerTasksTable.tsx index 466d13086..782a1d496 100644 --- a/frontend-modern/src/features/docker/DockerTasksTable.tsx +++ b/frontend-modern/src/features/docker/DockerTasksTable.tsx @@ -1,24 +1,13 @@ import { For, Show, createMemo, type Component } from 'solid-js'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { DockerResourceNameCell, @@ -77,43 +66,44 @@ export const DockerTasksTable: Component = (props) => { /> } > - - - - - - - Task - - - - - Desired - - - Current - - - - - - + + + Task + + + + + Desired + + + Current + + + + + } + body={ + <> {(resource) => ( @@ -168,9 +158,9 @@ export const DockerTasksTable: Component = (props) => { )} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/docker/DockerVolumesTable.tsx b/frontend-modern/src/features/docker/DockerVolumesTable.tsx index 9216c17de..59e1bad59 100644 --- a/frontend-modern/src/features/docker/DockerVolumesTable.tsx +++ b/frontend-modern/src/features/docker/DockerVolumesTable.tsx @@ -1,24 +1,13 @@ import { For, Show, type Component } from 'solid-js'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -101,45 +90,46 @@ export const DockerVolumesTable: Component = (props) => /> } > - - - - - - - Volume - - - Driver - - - - Size - - - - - - - + + + Volume + + + Driver + + + + Size + + + + + + } + body={ + <> {(resource) => { const detailRowId = () => drawer.detailRowId(resource); @@ -209,9 +199,9 @@ export const DockerVolumesTable: Component = (props) => ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/kubernetes/KubernetesAlertsTable.tsx b/frontend-modern/src/features/kubernetes/KubernetesAlertsTable.tsx index 53bdb71a9..35223d75d 100644 --- a/frontend-modern/src/features/kubernetes/KubernetesAlertsTable.tsx +++ b/frontend-modern/src/features/kubernetes/KubernetesAlertsTable.tsx @@ -1,20 +1,8 @@ import { For, Show, type Component, type JSX } from 'solid-js'; import XIcon from 'lucide-solid/icons/x'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; -import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, @@ -22,6 +10,7 @@ import { getPlatformTableHeadClassForKind, platformChipStatusDot, type PlatformTableFilterOption, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { createPlatformResourceDetailState, @@ -271,38 +260,39 @@ export const KubernetesAlertsTable: Component<{ /> } > - - - - - - - Resource - - - Severity - - - Alert - - - - - - - + + + Resource + + + Severity + + + Alert + + + + + + } + body={ + <> {(incident) => { const k = () => incident.resource.kubernetes; @@ -342,7 +332,6 @@ export const KubernetesAlertsTable: Component<{
{formatResourceType(incident.resourceType)} - {' '} · {k()?.ownerKind}/{k()?.ownerName}
@@ -369,10 +358,7 @@ export const KubernetesAlertsTable: Component<{
-
-
-
+ + } + /> diff --git a/frontend-modern/src/features/kubernetes/KubernetesAutoscalingTable.tsx b/frontend-modern/src/features/kubernetes/KubernetesAutoscalingTable.tsx index 91256b45a..a670f709f 100644 --- a/frontend-modern/src/features/kubernetes/KubernetesAutoscalingTable.tsx +++ b/frontend-modern/src/features/kubernetes/KubernetesAutoscalingTable.tsx @@ -1,27 +1,16 @@ import { For, Show, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { getSimpleStatusIndicator } from '@/utils/status'; import { asTrimmedString } from '@/utils/stringUtils'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -132,46 +121,43 @@ export const KubernetesAutoscalingTable: Component<{ /> } > - - - - - - - Autoscaler - - - - Scale target - - - Bounds - - - Current - - - Desired - - - Metrics - - - - - + + + Autoscaler + + + + Scale target + + + Bounds + + + Current + + + Desired + + + Metrics + + + + } + body={ + <> {(resource) => { const indicator = () => getSimpleStatusIndicator(resource.status); @@ -185,87 +171,90 @@ export const KubernetesAutoscalingTable: Component<{ return ( <> - drawer.toggle(resource)} - onKeyDown={drawer.handleActivationKey(resource)} - tabIndex={0} - > - -
- - - {name()} + drawer.toggle(resource)} + onKeyDown={drawer.handleActivationKey(resource)} + tabIndex={0} + > + +
+ + + {name()} + +
+
+
-
- - - - {target()} - - - - {bounds(resource)} - - - {numberValue(resource.kubernetes?.currentReplicas)} - - - {numberValue(resource.kubernetes?.desiredReplicas)} - - - - {metrics().label} - - - -
- drawer.close(resource)} - /> + + + + {target()} + + + + {bounds(resource)} + + + {numberValue(resource.kubernetes?.currentReplicas)} + + + {numberValue(resource.kubernetes?.desiredReplicas)} + + + + {metrics().label} + + + + + drawer.close(resource)} + /> ); }}
-
-
-
+ + } + /> diff --git a/frontend-modern/src/features/kubernetes/KubernetesClustersTable.tsx b/frontend-modern/src/features/kubernetes/KubernetesClustersTable.tsx index e3f9eb3df..d8aeb8b05 100644 --- a/frontend-modern/src/features/kubernetes/KubernetesClustersTable.tsx +++ b/frontend-modern/src/features/kubernetes/KubernetesClustersTable.tsx @@ -1,30 +1,19 @@ import { For, Show, createMemo, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; import { ResponsiveMetricCell } from '@/components/shared/responsive'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; import { StackedMemoryBar } from '@/components/Workloads/StackedMemoryBar'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { buildMetricKeyForUnifiedResource } from '@/utils/metricsKeys'; import { getSimpleStatusIndicator } from '@/utils/status'; import { asTrimmedString } from '@/utils/stringUtils'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PLATFORM_HEALTH_FILTER_OPTIONS, PlatformTableToolbar, PlatformTableEmptyState, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -134,38 +123,47 @@ export const KubernetesClustersTable: Component<{ /> } > - - - - - - - Cluster - - - - - Nodes - - - - - CPU - - - Memory - - - - + + + Cluster + + + + + Nodes + + + + + CPU + + + Memory + + + } + body={ + <> {(cluster) => { const name = () => @@ -283,9 +281,9 @@ export const KubernetesClustersTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/kubernetes/KubernetesConfigTable.tsx b/frontend-modern/src/features/kubernetes/KubernetesConfigTable.tsx index c928319b5..b9aec2d22 100644 --- a/frontend-modern/src/features/kubernetes/KubernetesConfigTable.tsx +++ b/frontend-modern/src/features/kubernetes/KubernetesConfigTable.tsx @@ -1,27 +1,16 @@ import { For, Show, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { getSimpleStatusIndicator } from '@/utils/status'; import { asTrimmedString } from '@/utils/stringUtils'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -234,43 +223,42 @@ export const KubernetesConfigTable: Component<{ /> } > - - - - - - - Resource - - - Kind - - - - Lifecycle / trust - - - Data shape - - - - - - + + + Resource + + + Kind + + + + Lifecycle / trust + + + Data shape + + + + + } + body={ + <> {(resource) => { const indicator = () => getSimpleStatusIndicator(resource.status); @@ -286,82 +274,82 @@ export const KubernetesConfigTable: Component<{ return ( <> - drawer.toggle(resource)} - onKeyDown={drawer.handleActivationKey(resource)} - tabIndex={0} - > - -
- - - {name()} + drawer.toggle(resource)} + onKeyDown={drawer.handleActivationKey(resource)} + tabIndex={0} + > + +
+ + + {name()} + +
+
+ + {kind()} + +
-
- - {kind()} - - - - {state()} - - - - {data().label} - - - - -
- drawer.close(resource)} - /> + + + {state()} + + + + {data().label} + + + + + + drawer.close(resource)} + /> ); }}
-
-
-
+ + } + /> diff --git a/frontend-modern/src/features/kubernetes/KubernetesControllersTable.tsx b/frontend-modern/src/features/kubernetes/KubernetesControllersTable.tsx index 1cf52d4f2..be3eeb75a 100644 --- a/frontend-modern/src/features/kubernetes/KubernetesControllersTable.tsx +++ b/frontend-modern/src/features/kubernetes/KubernetesControllersTable.tsx @@ -1,27 +1,16 @@ import { For, Show, createMemo, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { getResourceTypeLabel } from '@/utils/resourceTypePresentation'; import { asTrimmedString } from '@/utils/stringUtils'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -220,51 +209,50 @@ export const KubernetesControllersTable: Component<{ /> } > - - - - - - - Controller - - - Kind - - - - Target - - - Current - - - Ready/Done - - - - Exceptions - - - - - + + + Controller + + + Kind + + + + Target + + + Current + + + Ready/Done + + + + Exceptions + + + + } + body={ + <> {(resource) => { const indicator = () => mapKubernetesControllerStatus(resource); @@ -279,92 +267,92 @@ export const KubernetesControllersTable: Component<{ return ( <> - drawer.toggle(resource)} - onKeyDown={drawer.handleActivationKey(resource)} - tabIndex={0} - > - -
- - - {name()} + drawer.toggle(resource)} + onKeyDown={drawer.handleActivationKey(resource)} + tabIndex={0} + > + +
+ + + {name()} + +
+
+ + {kind()} + +
-
- - {kind()} - - - - - {target()} - - - - {numberValue(currentValue(resource))} - - - {numberValue(readyOrDoneValue(resource))} - - - - - {exceptions()} - - - -
- drawer.close(resource)} - /> + + + + {target()} + + + + {numberValue(currentValue(resource))} + + + {numberValue(readyOrDoneValue(resource))} + + + + + {exceptions()} + + + + + drawer.close(resource)} + /> ); }}
-
-
-
+ + } + /> diff --git a/frontend-modern/src/features/kubernetes/KubernetesDeploymentsTable.tsx b/frontend-modern/src/features/kubernetes/KubernetesDeploymentsTable.tsx index 151b3d742..fd636a689 100644 --- a/frontend-modern/src/features/kubernetes/KubernetesDeploymentsTable.tsx +++ b/frontend-modern/src/features/kubernetes/KubernetesDeploymentsTable.tsx @@ -1,27 +1,16 @@ import { For, Show, createMemo, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { asTrimmedString } from '@/utils/stringUtils'; import { formatRelativeTime } from '@/utils/format'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PLATFORM_HEALTH_FILTER_OPTIONS, PlatformTableToolbar, PlatformTableEmptyState, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -114,59 +103,54 @@ export const KubernetesDeploymentsTable: Component<{ /> } > - - - - - - {/* + + {/* Desktop widths: Deployment, Namespace, and Cluster take the biggest shares because their content can be long. The integer-count columns (Desired / Updated / Ready / Available) trim to what their headers plus 1-2 digit values need. Mobile widths are unchanged. */} - - Deployment - - - - - - - Ready - - - Available - - - Age - - - - + + Deployment + + + + + + + Ready + + + Available + + + Age + + + } + body={ + <> {(deployment) => { const name = () => asTrimmedString(deployment.name) || deployment.id; @@ -178,81 +162,84 @@ export const KubernetesDeploymentsTable: Component<{ const isExpanded = () => drawer.isExpanded(deployment); return ( <> - drawer.toggle(deployment)} - onKeyDown={drawer.handleActivationKey(deployment)} - tabIndex={0} - > - -
- - - {name()} + drawer.toggle(deployment)} + onKeyDown={drawer.handleActivationKey(deployment)} + tabIndex={0} + > + +
+ + + {name()} + +
+
+ + + + + + {replicaCount(deployment.kubernetes?.readyReplicas)} + + + {replicaCount(deployment.kubernetes?.availableReplicas)} + + + + {age()} -
-
- - - - - - {replicaCount(deployment.kubernetes?.readyReplicas)} - - - {replicaCount(deployment.kubernetes?.availableReplicas)} - - - - {age()} - - -
- drawer.close(deployment)} - /> + + + drawer.close(deployment)} + /> ); }}
-
-
-
+ + } + /> diff --git a/frontend-modern/src/features/kubernetes/KubernetesEventsTable.tsx b/frontend-modern/src/features/kubernetes/KubernetesEventsTable.tsx index 50845d980..ed25b46a2 100644 --- a/frontend-modern/src/features/kubernetes/KubernetesEventsTable.tsx +++ b/frontend-modern/src/features/kubernetes/KubernetesEventsTable.tsx @@ -1,27 +1,16 @@ import { For, Show, createMemo, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { asTrimmedString } from '@/utils/stringUtils'; import { formatRelativeTime } from '@/utils/format'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -117,44 +106,43 @@ export const KubernetesEventsTable: Component<{ /> } > - - - - - - - Event - - - - Type - - - Reason - - - Object - - - Count - - - - Message - - - - + + + Event + + + + Type + + + Reason + + + Object + + + Count + + + + Message + + + } + body={ + <> {(resource) => { const indicator = () => @@ -168,98 +156,98 @@ export const KubernetesEventsTable: Component<{ return ( <> - drawer.toggle(resource)} - onKeyDown={drawer.handleActivationKey(resource)} - tabIndex={0} - > - -
- - - {name()} + drawer.toggle(resource)} + onKeyDown={drawer.handleActivationKey(resource)} + tabIndex={0} + > + +
+ + + {name()} + +
+
+
-
- - - {textValue(resource.kubernetes?.eventType)} - - - + - {textValue(resource.kubernetes?.reason)} - - - - + - {involvedObject(resource)} - - - - {numberValue(resource.kubernetes?.count)} - - + - {observed()} - - - - - {message()} - - -
- drawer.close(resource)} - /> + + {involvedObject(resource)} + + + + {numberValue(resource.kubernetes?.count)} + + + + + {message()} + + + + drawer.close(resource)} + /> ); }}
-
-
-
+ + } + /> diff --git a/frontend-modern/src/features/kubernetes/KubernetesNetworkingTable.tsx b/frontend-modern/src/features/kubernetes/KubernetesNetworkingTable.tsx index 532aadcaa..7a09c5ca4 100644 --- a/frontend-modern/src/features/kubernetes/KubernetesNetworkingTable.tsx +++ b/frontend-modern/src/features/kubernetes/KubernetesNetworkingTable.tsx @@ -1,27 +1,16 @@ import { For, Show, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { getSimpleStatusIndicator } from '@/utils/status'; import { asTrimmedString } from '@/utils/stringUtils'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -179,41 +168,42 @@ export const KubernetesNetworkingTable: Component<{ /> } > - - - - - - - Resource - - - Kind - - - - Type / class - - - - Ports - - - - - + + + Resource + + + Kind + + + + Type / class + + + + Ports + + + + } + body={ + <> {(resource) => { const indicator = () => getSimpleStatusIndicator(resource.status); @@ -306,9 +296,9 @@ export const KubernetesNetworkingTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/kubernetes/KubernetesPodsTable.tsx b/frontend-modern/src/features/kubernetes/KubernetesPodsTable.tsx index e804b247a..3e3198698 100644 --- a/frontend-modern/src/features/kubernetes/KubernetesPodsTable.tsx +++ b/frontend-modern/src/features/kubernetes/KubernetesPodsTable.tsx @@ -1,26 +1,15 @@ import { For, Show, createMemo, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { asTrimmedString } from '@/utils/stringUtils'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -141,55 +130,52 @@ export const KubernetesPodsTable: Component<{ /> } > - - - - - - - Pod - - - - - Status - - - Ready - - - Restarts - - - - - - - + + + Pod + + + + + Status + + + Ready + + + Restarts + + + + + + } + body={ + <> {(resource) => { const indicator = () => mapKubernetesPodStatus(resource); @@ -204,97 +190,97 @@ export const KubernetesPodsTable: Component<{ return ( <> - drawer.toggle(resource)} - onKeyDown={drawer.handleActivationKey(resource)} - tabIndex={0} - > - -
- - - {name()} + drawer.toggle(resource)} + onKeyDown={drawer.handleActivationKey(resource)} + tabIndex={0} + > + +
+ + + {name()} + +
+
+
-
- - - - {/* The mapped label carries the container failure reason + + + + {/* The mapped label carries the container failure reason (CrashLoopBackOff, ImagePullBackOff, ...) where the raw phase would still read "Running". */} - - {indicator().label} - - - - {readySummary(resource)} - - - {numericValue(restartCount(resource))} - - - - -
- drawer.close(resource)} - /> + + {indicator().label} + + + + {readySummary(resource)} + + + {numericValue(restartCount(resource))} + + + + + + drawer.close(resource)} + /> ); }}
-
-
-
+ + } + /> diff --git a/frontend-modern/src/features/kubernetes/KubernetesPolicyTable.tsx b/frontend-modern/src/features/kubernetes/KubernetesPolicyTable.tsx index 17f622314..8db054840 100644 --- a/frontend-modern/src/features/kubernetes/KubernetesPolicyTable.tsx +++ b/frontend-modern/src/features/kubernetes/KubernetesPolicyTable.tsx @@ -1,27 +1,16 @@ import { For, Show, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { getSimpleStatusIndicator } from '@/utils/status'; import { asTrimmedString } from '@/utils/stringUtils'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -255,46 +244,45 @@ export const KubernetesPolicyTable: Component<{ /> } > - - - - - - - Resource - - - Kind - - - - Policy shape - - - Spec / limits - - - - - - + + + Resource + + + Kind + + + + Policy shape + + + Spec / limits + + + + + } + body={ + <> {(resource) => { const indicator = () => getSimpleStatusIndicator(resource.status); @@ -309,84 +297,84 @@ export const KubernetesPolicyTable: Component<{ return ( <> - drawer.toggle(resource)} - onKeyDown={drawer.handleActivationKey(resource)} - tabIndex={0} - > - -
- - - {name()} + drawer.toggle(resource)} + onKeyDown={drawer.handleActivationKey(resource)} + tabIndex={0} + > + +
+ + + {name()} + +
+
+ + {policyKind(resource)} + +
-
- - {policyKind(resource)} - - - - - {shape().label} - - - - - {spec().label} - - - - -
- drawer.close(resource)} - /> + + + + {shape().label} + + + + + {spec().label} + + + + + + drawer.close(resource)} + /> ); }}
-
-
-
+ + } + /> diff --git a/frontend-modern/src/features/kubernetes/KubernetesServicesTable.tsx b/frontend-modern/src/features/kubernetes/KubernetesServicesTable.tsx index cb658e9eb..e92fc1e64 100644 --- a/frontend-modern/src/features/kubernetes/KubernetesServicesTable.tsx +++ b/frontend-modern/src/features/kubernetes/KubernetesServicesTable.tsx @@ -1,27 +1,16 @@ import { For, Show, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { getSimpleStatusIndicator } from '@/utils/status'; import { asTrimmedString } from '@/utils/stringUtils'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -138,41 +127,42 @@ export const KubernetesServicesTable: Component<{ /> } > - - - - - - - Service - - - - Type - - - Cluster IP - - - - Ports - - - - - + + + Service + + + + Type + + + Cluster IP + + + + Ports + + + + } + body={ + <> {(resource) => { const indicator = () => getSimpleStatusIndicator(resource.status); @@ -267,9 +257,9 @@ export const KubernetesServicesTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/kubernetes/KubernetesStorageTable.tsx b/frontend-modern/src/features/kubernetes/KubernetesStorageTable.tsx index 5d920a62a..0c620ee4a 100644 --- a/frontend-modern/src/features/kubernetes/KubernetesStorageTable.tsx +++ b/frontend-modern/src/features/kubernetes/KubernetesStorageTable.tsx @@ -1,28 +1,17 @@ import { For, Show, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { formatBytes } from '@/utils/format'; import { getSimpleStatusIndicator } from '@/utils/status'; import { asTrimmedString } from '@/utils/stringUtils'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -202,48 +191,47 @@ export const KubernetesStorageTable: Component<{ /> } > - - - - - - - Resource - - - Kind - - - - Binding / phase - - - - Size - - - - - - + + + Resource + + + Kind + + + + Binding / phase + + + + Size + + + + + } + body={ + <> {(resource) => { const indicator = () => getSimpleStatusIndicator(resource.status); @@ -339,9 +327,9 @@ export const KubernetesStorageTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts b/frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts index 828fb3d4c..5d3fa7357 100644 --- a/frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts +++ b/frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts @@ -3,6 +3,7 @@ import agentsMachinesTableSource from '@/features/standalone/AgentsMachinesTable import agentMachineTableModelSource from '@/features/standalone/agentMachineTableModel.ts?raw'; import standalonePageModelSource from '@/features/standalone/standalonePageModel.ts?raw'; import standalonePageSurfaceSource from '@/features/standalone/StandalonePageSurface.tsx?raw'; +import dockerAlertsTableSource from '@/features/docker/DockerAlertsTable.tsx?raw'; import dockerConfigsTableSource from '@/features/docker/DockerConfigsTable.tsx?raw'; import dockerContainersTableSource from '@/features/docker/DockerContainersTable.tsx?raw'; import dockerHostsTableSource from '@/features/docker/DockerHostsTable.tsx?raw'; @@ -11,9 +12,11 @@ import dockerNetworksTableSource from '@/features/docker/DockerNetworksTable.tsx import dockerPageSurfaceSource from '@/features/docker/DockerPageSurface.tsx?raw'; import dockerSecretsTableSource from '@/features/docker/DockerSecretsTable.tsx?raw'; import dockerServicesTableSource from '@/features/docker/DockerServicesTable.tsx?raw'; +import dockerStorageUsageTableSource from '@/features/docker/DockerStorageUsageTable.tsx?raw'; import dockerSwarmNodesTableSource from '@/features/docker/DockerSwarmNodesTable.tsx?raw'; import dockerTasksTableSource from '@/features/docker/DockerTasksTable.tsx?raw'; import dockerVolumesTableSource from '@/features/docker/DockerVolumesTable.tsx?raw'; +import kubernetesAlertsTableSource from '@/features/kubernetes/KubernetesAlertsTable.tsx?raw'; import kubernetesAutoscalingTableSource from '@/features/kubernetes/KubernetesAutoscalingTable.tsx?raw'; import kubernetesClustersTableSource from '@/features/kubernetes/KubernetesClustersTable.tsx?raw'; import kubernetesConfigTableSource from '@/features/kubernetes/KubernetesConfigTable.tsx?raw'; @@ -46,6 +49,7 @@ import truenasAppsTableSource from '@/features/truenas/TrueNASAppsTable.tsx?raw' import truenasNetworkSharesTableSource from '@/features/truenas/TrueNASNetworkSharesTable.tsx?raw'; import truenasPageSurfaceSource from '@/features/truenas/TrueNASPageSurface.tsx?raw'; import truenasProtectionTableSource from '@/features/truenas/TrueNASProtectionTable.tsx?raw'; +import truenasServicesTableSource from '@/features/truenas/TrueNASServicesTable.tsx?raw'; import truenasStorageTopologyTableSource from '@/features/truenas/TrueNASStorageTopologyTable.tsx?raw'; import truenasSystemsTableSource from '@/features/truenas/TrueNASSystemsTable.tsx?raw'; import truenasVirtualMachinesTableSource from '@/features/truenas/TrueNASVirtualMachinesTable.tsx?raw'; @@ -54,22 +58,28 @@ import vsphereActivityTableSource from '@/features/vmware/VsphereActivityTable.t import vsphereAlertsTableSource from '@/features/vmware/VsphereAlertsTable.tsx?raw'; import vsphereDatastoresTableSource from '@/features/vmware/VsphereDatastoresTable.tsx?raw'; import vsphereHostsTableSource from '@/features/vmware/VsphereHostsTable.tsx?raw'; +import vsphereNetworksTableSource from '@/features/vmware/VsphereNetworksTable.tsx?raw'; const platformTableSources = [ agentsMachinesTableSource, + dockerAlertsTableSource, dockerContainersTableSource, + dockerHostsTableSource, dockerImagesTableSource, dockerVolumesTableSource, dockerNetworksTableSource, + dockerStorageUsageTableSource, dockerSwarmNodesTableSource, dockerServicesTableSource, dockerTasksTableSource, dockerSecretsTableSource, dockerConfigsTableSource, + kubernetesAlertsTableSource, kubernetesAutoscalingTableSource, kubernetesClustersTableSource, kubernetesConfigTableSource, kubernetesControllersTableSource, + kubernetesNodesTableSource, kubernetesPodsTableSource, kubernetesDeploymentsTableSource, kubernetesEventsTableSource, @@ -81,19 +91,26 @@ const platformTableSources = [ truenasAppsTableSource, truenasNetworkSharesTableSource, truenasProtectionTableSource, + truenasServicesTableSource, truenasStorageTopologyTableSource, truenasSystemsTableSource, truenasVirtualMachinesTableSource, vsphereActivityTableSource, vsphereAlertsTableSource, vsphereDatastoresTableSource, + vsphereHostsTableSource, + vsphereNetworksTableSource, ]; const platformShellTableSources = [ + ...platformTableSources, proxmoxNodesTableSource, - dockerHostsTableSource, - kubernetesNodesTableSource, - vsphereHostsTableSource, + proxmoxBackupServersTableSource, + proxmoxCoverageTableSource, + proxmoxRecoverableTableSource, + proxmoxCephTableSource, + proxmoxMailGatewayTableSource, + proxmoxReplicationTableSource, ]; const platformToolbarTableSources = [ @@ -166,16 +183,6 @@ describe('platform overview layout guardrails', () => { expect(sharedPlatformPageSource).toContain('createPlatformTableFilterState'); expect(sharedPlatformPageSource).toContain('PLATFORM_HEALTH_FILTER_OPTIONS'); - for (const source of platformTableSources) { - expect(source).toContain('TableCard'); - expect(source).toContain('TableCardHeader'); - expect(source).toContain('PLATFORM_TABLE_CARD_CLASS'); - expect(source).toContain('PLATFORM_TABLE_HEADER_ROW_CLASS'); - expect(source).toContain('PLATFORM_TABLE_BODY_CLASS'); - expect(source).toContain('getPlatformTableHeadClass'); - expect(source).toContain('getPlatformTableCellClass'); - } - for (const source of platformShellTableSources) { expect(source).toContain('PlatformTableShell'); expect(source).toContain('getPlatformTableHeadClass'); @@ -202,12 +209,12 @@ describe('platform overview layout guardrails', () => { it('keeps Proxmox detail tables on the shared platform table primitives', () => { for (const source of proxmoxBespokeTableSources) { - expect(source).toContain('TableCard'); - expect(source).toContain('PLATFORM_TABLE_CARD_CLASS'); - expect(source).toContain('PLATFORM_TABLE_HEADER_ROW_CLASS'); - expect(source).toContain('PLATFORM_TABLE_BODY_CLASS'); + expect(source).toContain('PlatformTableShell'); expect(source).toContain('getPlatformTableHeadClassForKind'); expect(source).toContain('getPlatformTableCellClassForKind'); + expect(source).not.toContain('TableCard class={PLATFORM_TABLE_CARD_CLASS}'); + expect(source).not.toContain('TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}'); + expect(source).not.toContain('TableBody class={PLATFORM_TABLE_BODY_CLASS}'); expect(source).not.toContain('border-collapse text-xs'); expect(source).not.toContain('bg-surface-alt text-muted border-b border-border'); } diff --git a/frontend-modern/src/features/proxmox/ProxmoxBackupServersTable.tsx b/frontend-modern/src/features/proxmox/ProxmoxBackupServersTable.tsx index 728544fc9..e06ac4e40 100644 --- a/frontend-modern/src/features/proxmox/ProxmoxBackupServersTable.tsx +++ b/frontend-modern/src/features/proxmox/ProxmoxBackupServersTable.tsx @@ -1,22 +1,12 @@ import { For, Show, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; -import { TableCard } from '@/components/shared/TableCard'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { formatBytes, formatUptime } from '@/utils/format'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import type { PBSBackup } from '@/types/api'; import type { Resource, ResourcePBSDatastore } from '@/types/resource'; @@ -153,8 +143,9 @@ export function ProxmoxBackupServersTable(props: { return ( 0}> - - + @@ -167,27 +158,23 @@ export function ProxmoxBackupServersTable(props: { - - - Backup server - Status - Version - CPU - - Memory - - - Uptime - - Datastore - Used - - Backups - - Dedup - - - + } + header={ + <> + Backup server + Status + Version + CPU + Memory + Uptime + Datastore + Used + Backups + Dedup + + } + body={ + <> {(row) => { const pct = () => (row.datastore ? usagePercent(row.datastore) : undefined); @@ -309,9 +296,9 @@ export function ProxmoxBackupServersTable(props: { ); }} - -
-
+ + } + />
); } diff --git a/frontend-modern/src/features/proxmox/ProxmoxCephTable.tsx b/frontend-modern/src/features/proxmox/ProxmoxCephTable.tsx index 69ff8e08d..47b521448 100644 --- a/frontend-modern/src/features/proxmox/ProxmoxCephTable.tsx +++ b/frontend-modern/src/features/proxmox/ProxmoxCephTable.tsx @@ -11,25 +11,15 @@ import { Card } from '@/components/shared/Card'; import { EmptyState } from '@/components/shared/EmptyState'; import { StatusDot } from '@/components/shared/StatusDot'; import type { StatusIndicatorVariant } from '@/utils/status'; -import { TableCard } from '@/components/shared/TableCard'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { formatBytes } from '@/utils/format'; import { asTrimmedString } from '@/utils/stringUtils'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableToolbar, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, type PlatformTableFilterOption, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import type { Resource, ResourceCephServiceMeta } from '@/types/resource'; import { ProxmoxCephClusterDrawer } from './ProxmoxCephClusterDrawer'; @@ -249,33 +239,32 @@ export const ProxmoxCephTable: Component<{ } > - - - - - Cluster - Health - FSID - - Quorum - - - OSDs - - - PGs - - - Pools - - - Capacity - - Services - Detail - - - + + Cluster + Health + FSID + + Quorum + + + OSDs + + PGs + + Pools + + + Capacity + + Services + Detail + + } + body={ + <> {(cluster) => { const ind = indicatorFor(classify(cluster)); @@ -389,9 +378,9 @@ export const ProxmoxCephTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/proxmox/ProxmoxCoverageTable.tsx b/frontend-modern/src/features/proxmox/ProxmoxCoverageTable.tsx index 0f9b191ef..e96ad1bf8 100644 --- a/frontend-modern/src/features/proxmox/ProxmoxCoverageTable.tsx +++ b/frontend-modern/src/features/proxmox/ProxmoxCoverageTable.tsx @@ -4,15 +4,12 @@ import ChevronRightIcon from 'lucide-solid/icons/chevron-right'; import { Card } from '@/components/shared/Card'; import { EmptyState } from '@/components/shared/EmptyState'; import { StatusDot } from '@/components/shared/StatusDot'; -import { Table, TableBody, TableCell, TableHeader, TableRow } from '@/components/shared/Table'; -import { TableCard } from '@/components/shared/TableCard'; +import { TableCell, TableRow } from '@/components/shared/Table'; import { formatBytes } from '@/utils/format'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import type { StatusIndicatorVariant } from '@/utils/status'; @@ -120,8 +117,9 @@ export function ProxmoxCoverageTable(props: { } > - - + {(column) => ( @@ -129,82 +127,84 @@ export function ProxmoxCoverageTable(props: { )} - - + } + header={ + <> + + + + - + + - - - - - - - - - - - - - - - + + + + + + + + + } + body={ + <> {(row) => { const isExpanded = () => props.expandedKeys.has(row.key); @@ -449,9 +449,9 @@ export function ProxmoxCoverageTable(props: { ); }} - -
-
+ + } + /> ); } diff --git a/frontend-modern/src/features/proxmox/ProxmoxMailGatewayTable.tsx b/frontend-modern/src/features/proxmox/ProxmoxMailGatewayTable.tsx index a91f62937..c925a2cbd 100644 --- a/frontend-modern/src/features/proxmox/ProxmoxMailGatewayTable.tsx +++ b/frontend-modern/src/features/proxmox/ProxmoxMailGatewayTable.tsx @@ -2,21 +2,10 @@ import { For, Show, createSignal, type Component, type JSX } from 'solid-js'; import { Card } from '@/components/shared/Card'; import { EmptyState } from '@/components/shared/EmptyState'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { getSimpleStatusIndicator } from '@/utils/status'; import { asTrimmedString } from '@/utils/stringUtils'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PLATFORM_HEALTH_FILTER_OPTIONS, PlatformTableToolbar, createPlatformTableFilterState, @@ -24,6 +13,7 @@ import { getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, type PlatformResourceStatusFilter, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import type { Resource } from '@/types/resource'; import { ProxmoxMailGatewayDrawer } from './ProxmoxMailGatewayDrawer'; @@ -95,39 +85,40 @@ export const ProxmoxMailGatewayTable: Component<{ } > - - - - - Instance - Version - - Nodes - - - Uptime - - - Mail in - - - Spam - - - Virus - - - Quarantine - - - Queue - - - Deferred - - - - + + Instance + Version + + Nodes + + + Uptime + + + Mail in + + + Spam + + + Virus + + + Quarantine + + + Queue + + + Deferred + + + } + body={ + <> {(instance) => { const pmg = () => instance.pmg; @@ -222,9 +213,9 @@ export const ProxmoxMailGatewayTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/proxmox/ProxmoxRecoverableTable.tsx b/frontend-modern/src/features/proxmox/ProxmoxRecoverableTable.tsx index 19498f8ce..e776dd168 100644 --- a/frontend-modern/src/features/proxmox/ProxmoxRecoverableTable.tsx +++ b/frontend-modern/src/features/proxmox/ProxmoxRecoverableTable.tsx @@ -2,26 +2,16 @@ import { For, Show, type Accessor, type JSX } from 'solid-js'; import { Card } from '@/components/shared/Card'; import { EmptyState } from '@/components/shared/EmptyState'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; -import { TableCard } from '@/components/shared/TableCard'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { formatBytes } from '@/utils/format'; import { getRecoveryFullDateLabel, recoveryDateKeyFromTimestamp, } from '@/utils/recoveryDatePresentation'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import type { RecoverableArtifact } from './proxmoxBackupRecoveryModel'; @@ -163,86 +153,75 @@ export function ProxmoxRecoverableTable(props: { } > - - - {/* Keep column widths stable; long locations/details truncate with title text. */} - - - - - - - - - - - - - - - Type - - {PROXMOX_BACKUP_COLUMN_LABELS.targetId} - - - - - - - - {PROXMOX_BACKUP_COLUMN_LABELS.details} - - - - + + + Type + + {PROXMOX_BACKUP_COLUMN_LABELS.targetId} + + + + + + + + {PROXMOX_BACKUP_COLUMN_LABELS.details} + + + } + body={ + <> {(artifact) => renderRow(artifact)}} @@ -267,9 +246,9 @@ export function ProxmoxRecoverableTable(props: { )} - -
-
+ + } + /> ); } diff --git a/frontend-modern/src/features/proxmox/ProxmoxReplicationTable.tsx b/frontend-modern/src/features/proxmox/ProxmoxReplicationTable.tsx index b7fc93767..967346b9c 100644 --- a/frontend-modern/src/features/proxmox/ProxmoxReplicationTable.tsx +++ b/frontend-modern/src/features/proxmox/ProxmoxReplicationTable.tsx @@ -3,26 +3,16 @@ import ArrowRightIcon from 'lucide-solid/icons/arrow-right'; import { Card } from '@/components/shared/Card'; import { EmptyState } from '@/components/shared/EmptyState'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; import type { StatusIndicatorVariant } from '@/utils/status'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { apiFetch } from '@/utils/apiClient'; import { formatRelativeTime } from '@/utils/format'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableToolbar, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, type PlatformTableFilterOption, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import type { ReplicationJob, ReplicationJobsResponse } from '@/types/api'; @@ -261,35 +251,34 @@ export const ProxmoxReplicationTable: Component<{ } > - - - - - Status - Job - Guest - - Source → Target - - - Schedule - - - Last sync - - - Next sync - - - Duration - - - Fail count - - Error - - - + + Status + Job + Guest + + Source → Target + + Schedule + + Last sync + + + Next sync + + + Duration + + + Fail count + + Error + + } + body={ + <> {(job) => { const classification = classifyJob(job); @@ -385,9 +374,9 @@ export const ProxmoxReplicationTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/proxmox/__tests__/ProxmoxBackupsTable.test.tsx b/frontend-modern/src/features/proxmox/__tests__/ProxmoxBackupsTable.test.tsx index 81f0ee82c..ef97cf3f1 100644 --- a/frontend-modern/src/features/proxmox/__tests__/ProxmoxBackupsTable.test.tsx +++ b/frontend-modern/src/features/proxmox/__tests__/ProxmoxBackupsTable.test.tsx @@ -4,6 +4,10 @@ import type { JSX } from 'solid-js'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { ProxmoxBackupsTable } from '../ProxmoxBackupsTable'; +import { + PLATFORM_TABLE_BODY_CLASS, + PLATFORM_TABLE_HEADER_ROW_CLASS, +} from '@/features/platformPage/sharedPlatformPage'; import type { Resource } from '@/types/resource'; import { getRecoveryFullDateLabel } from '@/utils/recoveryDatePresentation'; @@ -123,6 +127,41 @@ const workloadResource = { proxmox: { vmid: 112, node: 'pve-a', instance: 'pve-a' }, } as Resource; +const pbsServerResource = { + id: 'pbs-main', + type: 'pbs', + name: 'pbs-main', + displayName: 'pbs-main', + platformId: 'pbs-main', + platformType: 'proxmox-pbs', + sourceType: 'api', + status: 'online', + lastSeen: Date.parse('2026-05-25T00:00:00Z'), + cpu: { current: 12 }, + memory: { current: 40, total: 8_000, used: 3_200, free: 4_800 }, + uptime: 86_400, + pbs: { + instanceId: 'pbs-main', + version: '3.2.1', + connectionHealth: 'healthy', + datastores: [ + { name: 'main', total: 10_000, used: 4_000, available: 6_000, usagePercent: 40 }, + ], + }, +} as Resource; + +const expectClassTokens = (element: Element | null, className: string): void => { + expect(element).not.toBeNull(); + for (const token of className.split(/\s+/).filter(Boolean)) { + expect(element).toHaveClass(token); + } +}; + +const expectCanonicalPlatformTableShell = (table: HTMLElement): void => { + expectClassTokens(table.querySelector('thead tr'), PLATFORM_TABLE_HEADER_ROW_CLASS); + expectClassTokens(table.querySelector('tbody'), PLATFORM_TABLE_BODY_CLASS); +}; + afterEach(() => { cleanup(); apiFetchMock.mockReset(); @@ -133,7 +172,11 @@ describe('ProxmoxBackupsTable', () => { mockBackupAPIs(); renderInRouter(() => ( - } workloads={[workloadResource]} /> + } + workloads={[workloadResource]} + servers={[pbsServerResource]} + /> )); // Default view is the v5-parity backup feed: one row PER backup, so the @@ -157,6 +200,11 @@ describe('ProxmoxBackupsTable', () => { name: `${getRecoveryFullDateLabel('2026-05-25')} 3 backups`, }), ).toBeInTheDocument(); + const tables = screen.getAllByRole('table'); + expect(tables).toHaveLength(2); + for (const table of tables) { + expectCanonicalPlatformTableShell(table); + } expect(apiFetchMock).toHaveBeenCalledWith('/api/backups/pbs'); expect(apiFetchMock).toHaveBeenCalledWith('/api/backups/pve'); }); diff --git a/frontend-modern/src/features/standalone/AgentsMachinesTable.tsx b/frontend-modern/src/features/standalone/AgentsMachinesTable.tsx index 8467bcf83..3119e96dc 100644 --- a/frontend-modern/src/features/standalone/AgentsMachinesTable.tsx +++ b/frontend-modern/src/features/standalone/AgentsMachinesTable.tsx @@ -22,16 +22,7 @@ import { ColumnPicker } from '@/components/shared/ColumnPicker'; import { StatusDot } from '@/components/shared/StatusDot'; import { TemperatureGauge } from '@/components/shared/TemperatureGauge'; import { WebInterfaceNameLink } from '@/components/shared/WebInterfaceNameLink'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { TooltipPortal } from '@/components/shared/TooltipPortal'; import { hostOverrideIdCandidates } from '@/features/alerts/alertOverridesModel'; import { @@ -46,9 +37,6 @@ import { } from '@/features/platformPage/PlatformResourceDetailTableRow'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableResetFiltersButton, PlatformTableToolbar, @@ -57,6 +45,7 @@ import { getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, type PlatformResourceStatusFilter, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { useColumnVisibility } from '@/hooks/useColumnVisibility'; import type { Disk } from '@/types/api'; @@ -1407,24 +1396,25 @@ export const AgentsMachinesTable: Component<{ /> } > - - - - - - - {(column) => ( - - )} - - - - + + + {(column) => ( + + )} + + + } + body={ + <> {(machine) => { const name = () => asTrimmedString(machine.name) || machine.id; @@ -1755,9 +1745,9 @@ export const AgentsMachinesTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/standalone/AvailabilityChecksTable.tsx b/frontend-modern/src/features/standalone/AvailabilityChecksTable.tsx index 38bf00593..01e29540e 100644 --- a/frontend-modern/src/features/standalone/AvailabilityChecksTable.tsx +++ b/frontend-modern/src/features/standalone/AvailabilityChecksTable.tsx @@ -3,21 +3,9 @@ import { For, Show, type Component, type JSX } from 'solid-js'; import PlusIcon from 'lucide-solid/icons/plus'; import SettingsIcon from 'lucide-solid/icons/settings'; import { StatusDot } from '@/components/shared/StatusDot'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { PLATFORM_HEALTH_FILTER_OPTIONS, - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, @@ -25,6 +13,7 @@ import { getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, type PlatformResourceStatusFilter, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import type { Resource, ResourceAvailabilityMeta } from '@/types/resource'; import { formatRelativeTime } from '@/utils/format'; @@ -131,63 +120,60 @@ export const AvailabilityChecksTable: Component<{ /> } > - - - - - Add service/device check - - - - Manage - - - } - /> - - - - - Check - - - - - Result - - - - - - - + + + + Add service/device check + + + + Manage + + + } + tableClass="min-w-full table-fixed text-xs md:min-w-[900px]" + header={ + <> + + Check + + + + + Result + + + + + + } + body={ + <> {(check) => { const availability = () => availabilityFor(check); @@ -260,9 +246,9 @@ export const AvailabilityChecksTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/truenas/TrueNASAlertsTable.tsx b/frontend-modern/src/features/truenas/TrueNASAlertsTable.tsx index 803002928..f59657180 100644 --- a/frontend-modern/src/features/truenas/TrueNASAlertsTable.tsx +++ b/frontend-modern/src/features/truenas/TrueNASAlertsTable.tsx @@ -1,25 +1,14 @@ import { For, Show, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; -import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, type PlatformTableFilterOption, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { createPlatformResourceDetailState, @@ -254,38 +243,39 @@ export const TrueNASAlertsTable: Component<{ /> } > - - - - - - - Resource - - - Severity - - - Alert - - - - - - - + + + Resource + + + Severity + + + Alert + + + + + + } + body={ + <> {(incident) => { const detailRowId = () => drawer.detailRowId(incident); @@ -318,7 +308,6 @@ export const TrueNASAlertsTable: Component<{
{formatResourceType(incident.resourceType)} - {' '} on {incident.resource.parentName}
@@ -391,9 +380,9 @@ export const TrueNASAlertsTable: Component<{ ); }}
-
-
-
+ + } + /> diff --git a/frontend-modern/src/features/truenas/TrueNASAppsTable.tsx b/frontend-modern/src/features/truenas/TrueNASAppsTable.tsx index d90b52c88..bf5287803 100644 --- a/frontend-modern/src/features/truenas/TrueNASAppsTable.tsx +++ b/frontend-modern/src/features/truenas/TrueNASAppsTable.tsx @@ -1,31 +1,20 @@ import { For, Show, createMemo, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; import { ResponsiveMetricCell } from '@/components/shared/responsive'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; import { StackedMemoryBar } from '@/components/Workloads/StackedMemoryBar'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { getShortImageName } from '@/utils/format'; import { getSimpleStatusIndicator } from '@/utils/status'; import { asTrimmedString } from '@/utils/stringUtils'; import { buildMetricKeyForUnifiedResource } from '@/utils/metricsKeys'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, type PlatformTableFilterOption, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -197,46 +186,47 @@ export const TrueNASAppsTable: Component<{ /> } > - - - - - - - App - - - - CPU - - - Memory - - - - - - Updates - - - - + + + App + + + + CPU + + + Memory + + + + + + Updates + + + } + body={ + <> {(resource) => { const app = () => appMeta(resource); @@ -354,9 +344,9 @@ export const TrueNASAppsTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/truenas/TrueNASNetworkSharesTable.tsx b/frontend-modern/src/features/truenas/TrueNASNetworkSharesTable.tsx index 39e4fb956..687f52f00 100644 --- a/frontend-modern/src/features/truenas/TrueNASNetworkSharesTable.tsx +++ b/frontend-modern/src/features/truenas/TrueNASNetworkSharesTable.tsx @@ -1,27 +1,16 @@ import { For, Show, createMemo, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { getSimpleStatusIndicator } from '@/utils/status'; import { asTrimmedString } from '@/utils/stringUtils'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, type PlatformTableFilterOption, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -168,36 +157,37 @@ export const TrueNASNetworkSharesTable: Component<{ /> } > - - - - - - - Share - - - Protocol - - - - Access - - - - State - - - - + + + Share + + + Protocol + + + + Access + + + + State + + + } + body={ + <> {(resource) => { const share = () => shareMeta(resource); @@ -291,9 +281,9 @@ export const TrueNASNetworkSharesTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/truenas/TrueNASProtectionTable.tsx b/frontend-modern/src/features/truenas/TrueNASProtectionTable.tsx index 91c3b82ba..6e4c538fd 100644 --- a/frontend-modern/src/features/truenas/TrueNASProtectionTable.tsx +++ b/frontend-modern/src/features/truenas/TrueNASProtectionTable.tsx @@ -1,15 +1,6 @@ import { For, Show, createMemo, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { formatBytes } from '@/utils/format'; import { getRecoveryOutcomeBadgeClass, @@ -19,9 +10,6 @@ import { import { asTrimmedString } from '@/utils/stringUtils'; import type { StatusIndicatorVariant } from '@/utils/status'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformErrorState, PlatformTableEmptyState, PlatformTableLoadingState, @@ -30,6 +18,7 @@ import { getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, type PlatformTableFilterOption, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { createPlatformResourceDetailState, @@ -386,45 +375,44 @@ export const TrueNASProtectionTable: Component<{ /> } > - - - {tableState.total()} event{tableState.total() === 1 ? '' : 's'} - - } - /> - - - - - Dataset - - - Artifact - - - - Completed - - - - Outcome - - - - + + {tableState.total()} event{tableState.total() === 1 ? '' : 's'} + + } + tableClass="min-w-full table-fixed text-xs md:min-w-[960px]" + header={ + <> + + Dataset + + + Artifact + + + + Completed + + + + Outcome + + + } + body={ + <> {(point) => { const outcome = () => normalizeRecoveryOutcome(point.outcome); @@ -520,9 +508,9 @@ export const TrueNASProtectionTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/truenas/TrueNASServicesTable.tsx b/frontend-modern/src/features/truenas/TrueNASServicesTable.tsx index 9dd0affee..eb54e48d4 100644 --- a/frontend-modern/src/features/truenas/TrueNASServicesTable.tsx +++ b/frontend-modern/src/features/truenas/TrueNASServicesTable.tsx @@ -1,26 +1,15 @@ import { For, Show, createMemo, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { asTrimmedString } from '@/utils/stringUtils'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, type PlatformTableFilterOption, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { createPlatformResourceDetailState, @@ -217,31 +206,32 @@ export const TrueNASServicesTable: Component<{ /> } > - - - - - - - Service - - - State - - - Boot - - - - System - - - - + + + Service + + + State + + + Boot + + + + System + + + } + body={ + <> {(row) => { const status = () => mapTrueNASServiceStatus(row); @@ -321,9 +311,9 @@ export const TrueNASServicesTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/truenas/TrueNASStorageTopologyTable.tsx b/frontend-modern/src/features/truenas/TrueNASStorageTopologyTable.tsx index 8ea596dc1..ce5527f66 100644 --- a/frontend-modern/src/features/truenas/TrueNASStorageTopologyTable.tsx +++ b/frontend-modern/src/features/truenas/TrueNASStorageTopologyTable.tsx @@ -1,24 +1,12 @@ import { For, Show, createMemo, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; import { ResponsiveMetricCell } from '@/components/shared/responsive'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { formatBytes } from '@/utils/format'; import { getSimpleStatusIndicator } from '@/utils/status'; import { asTrimmedString } from '@/utils/stringUtils'; import { buildMetricKeyForUnifiedResource } from '@/utils/metricsKeys'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, @@ -26,6 +14,7 @@ import { getPlatformTableHeadClassForKind, platformChipStatusDot, type PlatformTableFilterOption, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -270,36 +259,37 @@ export const TrueNASStorageTopologyTable: Component<{ /> } > - - - - - - - Resource - - - Kind - - - Usage / Size - - - - - Health - - - - + + + Resource + + + Kind + + + Usage / Size + + + + + Health + + + } + body={ + <> {(row) => { const resource = () => row.resource; @@ -354,9 +344,9 @@ export const TrueNASStorageTopologyTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/truenas/TrueNASSystemsTable.tsx b/frontend-modern/src/features/truenas/TrueNASSystemsTable.tsx index a41f54522..5d77263fc 100644 --- a/frontend-modern/src/features/truenas/TrueNASSystemsTable.tsx +++ b/frontend-modern/src/features/truenas/TrueNASSystemsTable.tsx @@ -1,24 +1,12 @@ import { For, Show, createMemo, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; import { ResponsiveMetricCell } from '@/components/shared/responsive'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; import { StackedMemoryBar } from '@/components/Workloads/StackedMemoryBar'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { getSimpleStatusIndicator } from '@/utils/status'; import { asTrimmedString } from '@/utils/stringUtils'; import { buildMetricKeyForUnifiedResource } from '@/utils/metricsKeys'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PLATFORM_HEALTH_FILTER_OPTIONS, PlatformTableToolbar, PlatformTableEmptyState, @@ -27,6 +15,7 @@ import { getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, type PlatformResourceStatusFilter, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -181,51 +170,52 @@ export const TrueNASSystemsTable: Component<{ /> } > - - - - - - - System - - - CPU - - - Memory - - - Capacity - - - - - - - - - + + + System + + + CPU + + + Memory + + + Capacity + + + + + + + + } + body={ + <> {(system) => { const name = () => asTrimmedString(system.name) || system.id; @@ -384,9 +374,9 @@ export const TrueNASSystemsTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/truenas/TrueNASVirtualMachinesTable.tsx b/frontend-modern/src/features/truenas/TrueNASVirtualMachinesTable.tsx index ee678ab14..ade5c0f45 100644 --- a/frontend-modern/src/features/truenas/TrueNASVirtualMachinesTable.tsx +++ b/frontend-modern/src/features/truenas/TrueNASVirtualMachinesTable.tsx @@ -1,27 +1,16 @@ import { For, Show, createMemo, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { getSimpleStatusIndicator } from '@/utils/status'; import { asTrimmedString } from '@/utils/stringUtils'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, getPlatformTableCellClassForKind, getPlatformTableHeadClassForKind, type PlatformTableFilterOption, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -165,43 +154,44 @@ export const TrueNASVirtualMachinesTable: Component<{ /> } > - - - - - - - VM - - - State - - - - - - - Flags - - - - + + + VM + + + State + + + + + + + Flags + + + } + body={ + <> {(resource) => { const vm = () => vmMeta(resource); @@ -298,9 +288,9 @@ export const TrueNASVirtualMachinesTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/vmware/VsphereActivityTable.tsx b/frontend-modern/src/features/vmware/VsphereActivityTable.tsx index aad912ad7..c6b945946 100644 --- a/frontend-modern/src/features/vmware/VsphereActivityTable.tsx +++ b/frontend-modern/src/features/vmware/VsphereActivityTable.tsx @@ -1,20 +1,8 @@ import { For, Show, type Component, type JSX } from 'solid-js'; import XIcon from 'lucide-solid/icons/x'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; -import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, @@ -22,6 +10,7 @@ import { getPlatformTableHeadClassForKind, platformChipStatusDot, type PlatformTableFilterOption, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { createPlatformResourceDetailState, @@ -244,41 +233,42 @@ export const VsphereActivityTable: Component<{ /> } > - - - - - - - Resource - - - Type - - - Activity - - - State - - - - - - - + + + Resource + + + Type + + + Activity + + + State + + + + + + } + body={ + <> {(activity) => { const meta = () => activity.resource.vmware; @@ -312,7 +302,6 @@ export const VsphereActivityTable: Component<{
{formatResourceType(activity.resourceType)} - {' '} on {activity.resource.parentName}
@@ -389,9 +378,9 @@ export const VsphereActivityTable: Component<{ ); }}
-
-
-
+ + } + /> diff --git a/frontend-modern/src/features/vmware/VsphereAlertsTable.tsx b/frontend-modern/src/features/vmware/VsphereAlertsTable.tsx index 5b30a15e1..3bc2159a9 100644 --- a/frontend-modern/src/features/vmware/VsphereAlertsTable.tsx +++ b/frontend-modern/src/features/vmware/VsphereAlertsTable.tsx @@ -1,20 +1,8 @@ import { For, Show, type Component, type JSX } from 'solid-js'; import XIcon from 'lucide-solid/icons/x'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; -import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, @@ -22,6 +10,7 @@ import { getPlatformTableHeadClassForKind, platformChipStatusDot, type PlatformTableFilterOption, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { createPlatformResourceDetailState, @@ -243,38 +232,39 @@ export const VsphereAlertsTable: Component<{ /> } > - - - - - - - Resource - - - Severity - - - Signal - - - - - - - + + + Resource + + + Severity + + + Signal + + + + + + } + body={ + <> {(incident) => { const meta = () => incident.resource.vmware; @@ -308,7 +298,6 @@ export const VsphereAlertsTable: Component<{
{formatResourceType(incident.resourceType)} - {' '} on {incident.resource.parentName}
@@ -387,9 +376,9 @@ export const VsphereAlertsTable: Component<{ ); }}
-
-
-
+ + } + /> diff --git a/frontend-modern/src/features/vmware/VsphereDatastoresTable.tsx b/frontend-modern/src/features/vmware/VsphereDatastoresTable.tsx index c8bcd45b3..73b43edb3 100644 --- a/frontend-modern/src/features/vmware/VsphereDatastoresTable.tsx +++ b/frontend-modern/src/features/vmware/VsphereDatastoresTable.tsx @@ -1,22 +1,10 @@ import { For, Show, createMemo, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; import { StackedDiskBar } from '@/components/Workloads/StackedDiskBar'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { getSimpleStatusIndicator } from '@/utils/status'; import { asTrimmedString } from '@/utils/stringUtils'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, @@ -24,6 +12,7 @@ import { getPlatformTableHeadClassForKind, platformChipStatusDot, type PlatformTableFilterOption, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -176,43 +165,44 @@ export const VsphereDatastoresTable: Component<{ /> } > - - - - - - - Datastore - - - Type - - - Capacity - - - - - - - - + + + Datastore + + + Type + + + Capacity + + + + + + + } + body={ + <> {(datastore) => { const hosts = createMemo(() => hostSummary(datastore)); @@ -314,9 +304,9 @@ export const VsphereDatastoresTable: Component<{ ); }} - -
-
+ + } + /> diff --git a/frontend-modern/src/features/vmware/VsphereNetworksTable.tsx b/frontend-modern/src/features/vmware/VsphereNetworksTable.tsx index d4a3c53a5..b6d6e5ee3 100644 --- a/frontend-modern/src/features/vmware/VsphereNetworksTable.tsx +++ b/frontend-modern/src/features/vmware/VsphereNetworksTable.tsx @@ -1,21 +1,9 @@ import { For, Show, createMemo, type Component, type JSX } from 'solid-js'; import { StatusDot } from '@/components/shared/StatusDot'; -import { TableCard } from '@/components/shared/TableCard'; -import { TableCardHeader } from '@/components/shared/TableCardHeader'; -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from '@/components/shared/Table'; +import { TableCell, TableHead, TableRow } from '@/components/shared/Table'; import { getSimpleStatusIndicator } from '@/utils/status'; import { asTrimmedString } from '@/utils/stringUtils'; import { - PLATFORM_TABLE_BODY_CLASS, - PLATFORM_TABLE_CARD_CLASS, - PLATFORM_TABLE_HEADER_ROW_CLASS, PlatformTableEmptyState, PlatformTableToolbar, createPlatformTableFilterState, @@ -23,6 +11,7 @@ import { getPlatformTableHeadClassForKind, platformChipStatusDot, type PlatformTableFilterOption, + PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { PlatformResourceDetailTableRow, @@ -150,40 +139,41 @@ export const VsphereNetworksTable: Component<{ /> } > - - - - - - - Network - - - Type - - - - - - - - + + + Network + + + Type + + + + + + + } + body={ + <> {(network) => { const hosts = createMemo(() => hostSummary(network)); @@ -268,9 +258,9 @@ export const VsphereNetworksTable: Component<{ ); }} - -
-
+ + } + />