Retire platform table frame allowlist

This commit is contained in:
rcourtman
2026-06-12 11:36:18 +01:00
parent 6dc931aac6
commit d221640086
51 changed files with 2543 additions and 2888 deletions
@@ -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,
@@ -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",
@@ -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
@@ -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
@@ -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"
@@ -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}');
@@ -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
<DetailField label="Signal" value={props.incident.label} />
<DetailField label="Severity" value={severityLabel(props.incident.severity)} />
<DetailField label="Resource" value={props.incident.resourceName} />
<DetailField
label="Type"
value={formatResourceType(props.incident.resourceType)}
/>
<DetailField label="Type" value={formatResourceType(props.incident.resourceType)} />
<DetailField label="Host" value={docker()?.hostname} />
<DetailField label="Runtime" value={docker()?.runtime} />
<DetailField label="Swarm cluster" value={docker()?.swarm?.clusterName} />
@@ -251,38 +237,39 @@ export const DockerAlertsTable: Component<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title="Active Alerts" />
<Table class="min-w-full table-fixed text-xs md:min-w-[960px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[22%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[10%]`}>
Severity
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[34%]`}>
Alert
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Host
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[10%]`}
>
Started
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden xl:table-cell md:w-[10%]`}
>
Action
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title="Active Alerts"
tableClass="min-w-full table-fixed text-xs md:min-w-[960px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[22%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[10%]`}>
Severity
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[34%]`}>
Alert
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Host
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[10%]`}
>
Started
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden xl:table-cell md:w-[10%]`}
>
Action
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(incident) => {
const docker = () => incident.resource.docker;
@@ -316,7 +303,6 @@ export const DockerAlertsTable: Component<{
<div class="truncate text-[10px] text-muted">
{formatResourceType(incident.resourceType)}
<Show when={incident.resource.parentName}>
{' '}
on {incident.resource.parentName}
</Show>
</div>
@@ -392,9 +378,9 @@ export const DockerAlertsTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<DockerNativeTableProps> = (props) =>
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Swarm Configs'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[1040px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[28%]`}>
Config
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[16%]`}>
Template
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[16%]`}
>
Created
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[24%]`}
>
Labels
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[16%]`}>
Host
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'Swarm Configs'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1040px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[28%]`}>
Config
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[16%]`}>
Template
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[16%]`}
>
Created
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[24%]`}
>
Labels
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[16%]`}>
Host
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(resource) => (
<TableRow class="text-[11px] sm:text-xs" data-docker-config-row={resource.id}>
@@ -136,9 +126,9 @@ export const DockerConfigsTable: Component<DockerNativeTableProps> = (props) =>
</TableRow>
)}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<DockerNativeTableProps> = (props)
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Containers'} />
<Table class={`${getDockerContainerTableMinWidthClass()} table-fixed text-xs`}>
<PlatformTableShell
title={props.title ?? 'Containers'}
tableClass={`${getDockerContainerTableMinWidthClass()} table-fixed text-xs`}
colgroup={
<colgroup>
<For each={visibleColumns()}>
{(column) => (
@@ -332,21 +322,23 @@ export const DockerContainersTable: Component<DockerNativeTableProps> = (props)
)}
</For>
</colgroup>
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<For each={visibleColumns()}>
{(column) => (
<TableHead class={getPlatformTableHeadClassForKind(column.kind)}>
<Show when={column.id === 'memory'} fallback={<>{column.label}</>}>
<span class="md:hidden">Mem</span>
<span class="hidden md:inline">Memory</span>
</Show>
</TableHead>
)}
</For>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
}
header={
<>
<For each={visibleColumns()}>
{(column) => (
<TableHead class={getPlatformTableHeadClassForKind(column.kind)}>
<Show when={column.id === 'memory'} fallback={<>{column.label}</>}>
<span class="md:hidden">Mem</span>
<span class="hidden md:inline">Memory</span>
</Show>
</TableHead>
)}
</For>
</>
}
body={
<>
<For each={sortedRows()}>
{(resource) => {
const indicator = mapDockerContainerStatus(resource);
@@ -555,9 +547,9 @@ export const DockerContainersTable: Component<DockerNativeTableProps> = (props)
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<DockerNativeTableProps> = (props) => {
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Images'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[1120px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[24%]`}>
Image
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[22%]`}>
Tags
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[24%]`}
>
Digests
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[10%]`}
>
Size
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[8%]`}
>
In Use
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[12%]`}
>
Host
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'Images'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1120px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[24%]`}>
Image
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[22%]`}>
Tags
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[24%]`}
>
Digests
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[10%]`}
>
Size
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[8%]`}>
In Use
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[12%]`}
>
Host
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(resource) => {
const detailRowId = () => drawer.detailRowId(resource);
@@ -179,9 +167,9 @@ export const DockerImagesTable: Component<DockerNativeTableProps> = (props) => {
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<DockerNetworkAttachmentRow, AttachmentStatusFilter>({
const tableState = createPlatformTableFilterState<
DockerNetworkAttachmentRow,
AttachmentStatusFilter
>({
resources: () => [...props.rows],
initialStatus: 'all',
filter: filterAttachmentRows,
@@ -401,38 +393,39 @@ export const DockerNetworksTable: Component<DockerNetworksTableProps> = (props)
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Networks'} />
<Table class="min-w-[850px] table-fixed text-xs md:min-w-[1320px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} w-[220px]`}>
Network
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} w-[360px]`}>
Attached workloads
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} w-[150px]`}>
Attention
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[300px]`}
>
Subnets
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[140px]`}
>
Driver
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[140px]`}
>
Host
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'Networks'}
tableClass="min-w-[850px] table-fixed text-xs md:min-w-[1320px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} w-[220px]`}>
Network
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} w-[360px]`}>
Attached workloads
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} w-[150px]`}>
Attention
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[300px]`}
>
Subnets
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[140px]`}
>
Driver
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[140px]`}
>
Host
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(resource) => {
const detailRowId = () => drawer.detailRowId(resource);
@@ -517,9 +510,9 @@ export const DockerNetworksTable: Component<DockerNetworksTableProps> = (props)
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<DockerNativeTableProps> = (props) =>
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Swarm Secrets'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[1080px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[24%]`}>
Secret
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[14%]`}>
Driver
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Template
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Created
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[18%]`}
>
Labels
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[16%]`}>
Host
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'Swarm Secrets'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1080px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[24%]`}>
Secret
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[14%]`}>
Driver
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Template
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Created
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[18%]`}
>
Labels
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[16%]`}>
Host
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(resource) => (
<TableRow class="text-[11px] sm:text-xs" data-docker-secret-row={resource.id}>
@@ -146,9 +136,9 @@ export const DockerSecretsTable: Component<DockerNativeTableProps> = (props) =>
</TableRow>
)}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Swarm Services'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[1320px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
{/*
<PlatformTableShell
title={props.title ?? 'Swarm Services'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1320px]"
header={
<>
{/*
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.
*/}
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[16%]`}>
Service
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[9%]`}
>
Stack
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[19%]`}
>
Image
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[8%]`}>
Mode
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[8%]`}
>
Desired
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[8%]`}
>
Running
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[12%]`}
>
Update
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Ports
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Host
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[16%]`}>
Service
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[9%]`}
>
Stack
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[19%]`}
>
Image
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[8%]`}>
Mode
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[8%]`}
>
Desired
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[8%]`}>
Running
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[12%]`}
>
Update
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Ports
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Host
</TableHead>
</>
}
body={
<>
<For each={sortedRows()}>
{(service) => {
const name = () => asTrimmedString(service.name) || service.id;
@@ -275,9 +263,9 @@ export const DockerServicesTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title="Engine Storage Usage" />
<Table class="min-w-full table-fixed text-xs md:min-w-[1080px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[22%]`}>
Host
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[19%]`}
>
Images
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[19%]`}
>
Containers
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[20%]`}
>
Volumes
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[20%]`}
>
Build Cache
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title="Engine Storage Usage"
tableClass="min-w-full table-fixed text-xs md:min-w-[1080px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[22%]`}>
Host
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[19%]`}
>
Images
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[19%]`}
>
Containers
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[20%]`}
>
Volumes
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[20%]`}
>
Build Cache
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(host) => {
const name = () => asTrimmedString(host.name) || host.id;
@@ -184,9 +174,9 @@ export const DockerStorageUsageTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<DockerNativeTableProps> = (props)
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Swarm Nodes'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[1120px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[20%]`}>
Node
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[10%]`}>
Role
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[12%]`}>
Availability
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Reachability
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[16%]`}
>
Engine
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[8%]`}
>
CPUs
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[10%]`}
>
Memory
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Address
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'Swarm Nodes'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1120px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[20%]`}>
Node
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[10%]`}>
Role
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[12%]`}>
Availability
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Reachability
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[16%]`}
>
Engine
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[8%]`}
>
CPUs
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[10%]`}
>
Memory
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Address
</TableHead>
</>
}
body={
<>
<For each={sortedRows()}>
{(resource) => {
const managerReachability = () =>
@@ -179,9 +169,9 @@ export const DockerSwarmNodesTable: Component<DockerNativeTableProps> = (props)
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<DockerNativeTableProps> = (props) => {
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Swarm Tasks'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[1160px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[18%]`}>
Task
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[18%]`}
>
Service
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[8%]`}
>
Slot
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[12%]`}>
Desired
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[16%]`}>
Current
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[16%]`}
>
Node
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[12%]`}
>
Started
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'Swarm Tasks'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1160px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[18%]`}>
Task
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[18%]`}
>
Service
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[8%]`}
>
Slot
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[12%]`}>
Desired
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[16%]`}>
Current
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[16%]`}
>
Node
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[12%]`}
>
Started
</TableHead>
</>
}
body={
<>
<For each={sortedRows()}>
{(resource) => (
<TableRow class="text-[11px] sm:text-xs" data-docker-task-row={resource.id}>
@@ -168,9 +158,9 @@ export const DockerTasksTable: Component<DockerNativeTableProps> = (props) => {
</TableRow>
)}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<DockerNativeTableProps> = (props) =>
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Volumes'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[1120px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[22%]`}>
Volume
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[12%]`}>
Driver
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Scope
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[10%]`}
>
Size
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[8%]`}
>
Refs
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Created
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[24%]`}
>
Mountpoint
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'Volumes'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1120px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[22%]`}>
Volume
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[12%]`}>
Driver
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Scope
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[10%]`}
>
Size
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[8%]`}
>
Refs
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Created
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[24%]`}
>
Mountpoint
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(resource) => {
const detailRowId = () => drawer.detailRowId(resource);
@@ -209,9 +199,9 @@ export const DockerVolumesTable: Component<DockerNativeTableProps> = (props) =>
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title="Active Alerts" />
<Table class="min-w-full table-fixed text-xs md:min-w-[960px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[22%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[10%]`}>
Severity
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[34%]`}>
Alert
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Scope
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[10%]`}
>
Started
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden xl:table-cell md:w-[10%]`}
>
Action
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title="Active Alerts"
tableClass="min-w-full table-fixed text-xs md:min-w-[960px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[22%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[10%]`}>
Severity
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[34%]`}>
Alert
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Scope
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[10%]`}
>
Started
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden xl:table-cell md:w-[10%]`}
>
Action
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(incident) => {
const k = () => incident.resource.kubernetes;
@@ -342,7 +332,6 @@ export const KubernetesAlertsTable: Component<{
<div class="truncate text-[10px] text-muted">
{formatResourceType(incident.resourceType)}
<Show when={k()?.ownerKind && k()?.ownerName}>
{' '}
· {k()?.ownerKind}/{k()?.ownerName}
</Show>
</div>
@@ -369,10 +358,7 @@ export const KubernetesAlertsTable: Component<{
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden md:table-cell`}
>
<span
class="block truncate text-base-content"
title={scopeText()}
>
<span class="block truncate text-base-content" title={scopeText()}>
{scopeText()}
</span>
<span class="block truncate text-[10px] text-muted">
@@ -418,9 +404,9 @@ export const KubernetesAlertsTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'HorizontalPodAutoscalers'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[1080px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[20%]`}>
Autoscaler
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[16%]`}
>
Scope
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[18%]`}>
Scale target
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[10%]`}>
Bounds
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[9%]`}
>
Current
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[9%]`}
>
Desired
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[11%]`}>
Metrics
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[7%]`}
>
Labels
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'HorizontalPodAutoscalers'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1080px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[20%]`}>
Autoscaler
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[16%]`}
>
Scope
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[18%]`}>
Scale target
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[10%]`}>
Bounds
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[9%]`}>
Current
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[9%]`}>
Desired
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[11%]`}>
Metrics
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[7%]`}
>
Labels
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(resource) => {
const indicator = () => getSimpleStatusIndicator(resource.status);
@@ -185,87 +171,90 @@ export const KubernetesAutoscalingTable: Component<{
return (
<>
<TableRow
class={`${getPlatformResourceDetailRowClass(isExpanded())} text-[11px] sm:text-xs`}
aria-controls={isExpanded() ? detailRowId() : undefined}
aria-expanded={isExpanded() ? 'true' : 'false'}
data-kubernetes-autoscaling-row={resource.id}
onClick={() => drawer.toggle(resource)}
onKeyDown={drawer.handleActivationKey(resource)}
tabIndex={0}
>
<TableCell class={getPlatformTableCellClassForKind('name')}>
<div class="flex min-w-0 items-center gap-2">
<StatusDot
size="sm"
variant={indicator().variant}
title={resource.status || 'unknown'}
ariaHidden
/>
<span class="truncate font-semibold text-base-content" title={name()}>
{name()}
<TableRow
class={`${getPlatformResourceDetailRowClass(isExpanded())} text-[11px] sm:text-xs`}
aria-controls={isExpanded() ? detailRowId() : undefined}
aria-expanded={isExpanded() ? 'true' : 'false'}
data-kubernetes-autoscaling-row={resource.id}
onClick={() => drawer.toggle(resource)}
onKeyDown={drawer.handleActivationKey(resource)}
tabIndex={0}
>
<TableCell class={getPlatformTableCellClassForKind('name')}>
<div class="flex min-w-0 items-center gap-2">
<StatusDot
size="sm"
variant={indicator().variant}
title={resource.status || 'unknown'}
ariaHidden
/>
<span class="truncate font-semibold text-base-content" title={name()}>
{name()}
</span>
</div>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[12rem] truncate" title={scope()}>
{scope()}
</span>
</div>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[12rem] truncate" title={scope()}>
{scope()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span class="inline-block max-w-[14rem] truncate" title={target()}>
{target()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
{bounds(resource)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{numberValue(resource.kubernetes?.currentReplicas)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{numberValue(resource.kubernetes?.desiredReplicas)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span class="inline-block max-w-[10rem] truncate" title={metrics().title}>
{metrics().label}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[8rem] truncate" title={labels().title}>
{labels().label}
</span>
</TableCell>
</TableRow>
<PlatformResourceDetailTableRow
resource={resource}
open={isExpanded()}
detailRowId={detailRowId()}
colSpan={8}
resolveResourceLabel={resolveResourceLabel}
onClose={() => drawer.close(resource)}
/>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span class="inline-block max-w-[14rem] truncate" title={target()}>
{target()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
{bounds(resource)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{numberValue(resource.kubernetes?.currentReplicas)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{numberValue(resource.kubernetes?.desiredReplicas)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span
class="inline-block max-w-[10rem] truncate"
title={metrics().title}
>
{metrics().label}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[8rem] truncate" title={labels().title}>
{labels().label}
</span>
</TableCell>
</TableRow>
<PlatformResourceDetailTableRow
resource={resource}
open={isExpanded()}
detailRowId={detailRowId()}
colSpan={8}
resolveResourceLabel={resolveResourceLabel}
onClose={() => drawer.close(resource)}
/>
</>
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Clusters'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[1040px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[17%]`}>
Cluster
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[15%]`}>
Context
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}>
Version
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[8%]`}>
Nodes
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[8%]`}>
Pods
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[12%]`}>
Deployments
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[15%]`}>
CPU
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[15%]`}>
Memory
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'Clusters'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1040px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[17%]`}>
Cluster
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[15%]`}
>
Context
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Version
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[8%]`}>
Nodes
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[8%]`}
>
Pods
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[12%]`}
>
Deployments
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[15%]`}>
CPU
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[15%]`}>
Memory
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(cluster) => {
const name = () =>
@@ -283,9 +281,9 @@ export const KubernetesClustersTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader
title={props.title ?? 'Namespaces, ConfigMaps, Secrets, ServiceAccounts, RBAC'}
/>
<Table class="min-w-full table-fixed text-xs md:min-w-[1160px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[18%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[13%]`}>
Kind
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[16%]`}
>
Scope
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[16%]`}>
Lifecycle / trust
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[14%]`}>
Data shape
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Token refs
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Labels
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'Namespaces, ConfigMaps, Secrets, ServiceAccounts, RBAC'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1160px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[18%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[13%]`}>
Kind
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[16%]`}
>
Scope
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[16%]`}>
Lifecycle / trust
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[14%]`}>
Data shape
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Token refs
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Labels
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(resource) => {
const indicator = () => getSimpleStatusIndicator(resource.status);
@@ -286,82 +274,82 @@ export const KubernetesConfigTable: Component<{
return (
<>
<TableRow
class={`${getPlatformResourceDetailRowClass(isExpanded())} text-[11px] sm:text-xs`}
aria-controls={isExpanded() ? detailRowId() : undefined}
aria-expanded={isExpanded() ? 'true' : 'false'}
data-kubernetes-config-row={resource.id}
onClick={() => drawer.toggle(resource)}
onKeyDown={drawer.handleActivationKey(resource)}
tabIndex={0}
>
<TableCell class={getPlatformTableCellClassForKind('name')}>
<div class="flex min-w-0 items-center gap-2">
<StatusDot
size="sm"
variant={indicator().variant}
title={resource.status || 'unknown'}
ariaHidden
/>
<span class="truncate font-semibold text-base-content" title={name()}>
{name()}
<TableRow
class={`${getPlatformResourceDetailRowClass(isExpanded())} text-[11px] sm:text-xs`}
aria-controls={isExpanded() ? detailRowId() : undefined}
aria-expanded={isExpanded() ? 'true' : 'false'}
data-kubernetes-config-row={resource.id}
onClick={() => drawer.toggle(resource)}
onKeyDown={drawer.handleActivationKey(resource)}
tabIndex={0}
>
<TableCell class={getPlatformTableCellClassForKind('name')}>
<div class="flex min-w-0 items-center gap-2">
<StatusDot
size="sm"
variant={indicator().variant}
title={resource.status || 'unknown'}
ariaHidden
/>
<span class="truncate font-semibold text-base-content" title={name()}>
{name()}
</span>
</div>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
{kind()}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[13rem] truncate" title={scope()}>
{scope()}
</span>
</div>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
{kind()}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[13rem] truncate" title={scope()}>
{scope()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
{state()}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span class="inline-block max-w-[13rem] truncate" title={data().title}>
{data().label}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[13rem] truncate" title={refs().title}>
{refs().label}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[9rem] truncate" title={labels().title}>
{labels().label}
</span>
</TableCell>
</TableRow>
<PlatformResourceDetailTableRow
resource={resource}
open={isExpanded()}
detailRowId={detailRowId()}
colSpan={7}
resolveResourceLabel={resolveResourceLabel}
onClose={() => drawer.close(resource)}
/>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
{state()}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span class="inline-block max-w-[13rem] truncate" title={data().title}>
{data().label}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[13rem] truncate" title={refs().title}>
{refs().label}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[9rem] truncate" title={labels().title}>
{labels().label}
</span>
</TableCell>
</TableRow>
<PlatformResourceDetailTableRow
resource={resource}
open={isExpanded()}
detailRowId={detailRowId()}
colSpan={7}
resolveResourceLabel={resolveResourceLabel}
onClose={() => drawer.close(resource)}
/>
</>
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Workload Controllers'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[1120px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[18%]`}>
Controller
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[9%]`}>
Kind
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Scope
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[12%]`}>
Target
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[8%]`}
>
Current
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[10%]`}
>
Ready/Done
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[9%]`}
>
Available
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[11%]`}>
Exceptions
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[9%]`}
>
Detail
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'Workload Controllers'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1120px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[18%]`}>
Controller
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[9%]`}>
Kind
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Scope
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[12%]`}>
Target
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[8%]`}>
Current
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[10%]`}
>
Ready/Done
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[9%]`}
>
Available
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[11%]`}>
Exceptions
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[9%]`}
>
Detail
</TableHead>
</>
}
body={
<>
<For each={sortedRows()}>
{(resource) => {
const indicator = () => mapKubernetesControllerStatus(resource);
@@ -279,92 +267,92 @@ export const KubernetesControllersTable: Component<{
return (
<>
<TableRow
class={`${getPlatformResourceDetailRowClass(isExpanded())} text-[11px] sm:text-xs`}
aria-controls={isExpanded() ? detailRowId() : undefined}
aria-expanded={isExpanded() ? 'true' : 'false'}
data-kubernetes-controller-row={resource.id}
onClick={() => drawer.toggle(resource)}
onKeyDown={drawer.handleActivationKey(resource)}
tabIndex={0}
>
<TableCell class={getPlatformTableCellClassForKind('name')}>
<div class="flex min-w-0 items-center gap-2">
<StatusDot
size="sm"
variant={indicator().variant}
title={indicator().label}
ariaHidden
/>
<span class="truncate font-semibold text-base-content" title={name()}>
{name()}
<TableRow
class={`${getPlatformResourceDetailRowClass(isExpanded())} text-[11px] sm:text-xs`}
aria-controls={isExpanded() ? detailRowId() : undefined}
aria-expanded={isExpanded() ? 'true' : 'false'}
data-kubernetes-controller-row={resource.id}
onClick={() => drawer.toggle(resource)}
onKeyDown={drawer.handleActivationKey(resource)}
tabIndex={0}
>
<TableCell class={getPlatformTableCellClassForKind('name')}>
<div class="flex min-w-0 items-center gap-2">
<StatusDot
size="sm"
variant={indicator().variant}
title={indicator().label}
ariaHidden
/>
<span class="truncate font-semibold text-base-content" title={name()}>
{name()}
</span>
</div>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
{kind()}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[12rem] truncate" title={scope()}>
{scope()}
</span>
</div>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
{kind()}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[12rem] truncate" title={scope()}>
{scope()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span class="inline-block max-w-[12rem] truncate" title={target()}>
{target()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{numberValue(currentValue(resource))}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{numberValue(readyOrDoneValue(resource))}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} hidden text-base-content md:table-cell`}
>
{numberValue(availableValue(resource))}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span class="inline-block max-w-[13rem] truncate" title={exceptions()}>
{exceptions()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[14rem] truncate" title={detail()}>
{detail()}
</span>
</TableCell>
</TableRow>
<PlatformResourceDetailTableRow
resource={resource}
open={isExpanded()}
detailRowId={detailRowId()}
colSpan={9}
resolveResourceLabel={resolveResourceLabel}
onClose={() => drawer.close(resource)}
/>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span class="inline-block max-w-[12rem] truncate" title={target()}>
{target()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{numberValue(currentValue(resource))}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{numberValue(readyOrDoneValue(resource))}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} hidden text-base-content md:table-cell`}
>
{numberValue(availableValue(resource))}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span class="inline-block max-w-[13rem] truncate" title={exceptions()}>
{exceptions()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[14rem] truncate" title={detail()}>
{detail()}
</span>
</TableCell>
</TableRow>
<PlatformResourceDetailTableRow
resource={resource}
open={isExpanded()}
detailRowId={detailRowId()}
colSpan={9}
resolveResourceLabel={resolveResourceLabel}
onClose={() => drawer.close(resource)}
/>
</>
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Deployments'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[1320px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
{/*
<PlatformTableShell
title={props.title ?? 'Deployments'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1320px]"
header={
<>
{/*
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.
*/}
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[25%]`}>
Deployment
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[20%]`}
>
Namespace
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[17%]`}
>
Cluster
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[8%]`}
>
Desired
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[8%]`}
>
Updated
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[7%]`}
>
Ready
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[9%]`}
>
Available
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[6%]`}
>
Age
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[25%]`}>
Deployment
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[20%]`}
>
Namespace
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[17%]`}
>
Cluster
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[8%]`}
>
Desired
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[8%]`}
>
Updated
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[7%]`}>
Ready
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[9%]`}>
Available
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[6%]`}>
Age
</TableHead>
</>
}
body={
<>
<For each={sortedRows()}>
{(deployment) => {
const name = () => asTrimmedString(deployment.name) || deployment.id;
@@ -178,81 +162,84 @@ export const KubernetesDeploymentsTable: Component<{
const isExpanded = () => drawer.isExpanded(deployment);
return (
<>
<TableRow
class={`${getPlatformResourceDetailRowClass(isExpanded())} text-[11px] sm:text-xs`}
aria-controls={isExpanded() ? detailRowId() : undefined}
aria-expanded={isExpanded() ? 'true' : 'false'}
data-kubernetes-deployment-row={deployment.id}
onClick={() => drawer.toggle(deployment)}
onKeyDown={drawer.handleActivationKey(deployment)}
tabIndex={0}
>
<TableCell class={getPlatformTableCellClassForKind('name')}>
<div class="flex min-w-0 items-center gap-2">
<StatusDot
size="sm"
variant={indicator().variant}
title={indicator().label}
ariaHidden
/>
<span class="truncate font-semibold text-base-content" title={name()}>
{name()}
<TableRow
class={`${getPlatformResourceDetailRowClass(isExpanded())} text-[11px] sm:text-xs`}
aria-controls={isExpanded() ? detailRowId() : undefined}
aria-expanded={isExpanded() ? 'true' : 'false'}
data-kubernetes-deployment-row={deployment.id}
onClick={() => drawer.toggle(deployment)}
onKeyDown={drawer.handleActivationKey(deployment)}
tabIndex={0}
>
<TableCell class={getPlatformTableCellClassForKind('name')}>
<div class="flex min-w-0 items-center gap-2">
<StatusDot
size="sm"
variant={indicator().variant}
title={indicator().label}
ariaHidden
/>
<span class="truncate font-semibold text-base-content" title={name()}>
{name()}
</span>
</div>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
{ns()}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
{cluster()}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} hidden text-base-content md:table-cell`}
>
{replicaCount(deployment.kubernetes?.desiredReplicas)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} hidden text-base-content md:table-cell`}
>
{replicaCount(deployment.kubernetes?.updatedReplicas)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{replicaCount(deployment.kubernetes?.readyReplicas)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{replicaCount(deployment.kubernetes?.availableReplicas)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
<span
class="tabular-nums"
title={deployment.kubernetes?.createdAt || ''}
>
{age()}
</span>
</div>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
{ns()}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
{cluster()}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} hidden text-base-content md:table-cell`}
>
{replicaCount(deployment.kubernetes?.desiredReplicas)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} hidden text-base-content md:table-cell`}
>
{replicaCount(deployment.kubernetes?.updatedReplicas)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{replicaCount(deployment.kubernetes?.readyReplicas)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{replicaCount(deployment.kubernetes?.availableReplicas)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
<span class="tabular-nums" title={deployment.kubernetes?.createdAt || ''}>
{age()}
</span>
</TableCell>
</TableRow>
<PlatformResourceDetailTableRow
resource={deployment}
open={isExpanded()}
detailRowId={detailRowId()}
colSpan={8}
resolveResourceLabel={resolveResourceLabel}
onClose={() => drawer.close(deployment)}
/>
</TableCell>
</TableRow>
<PlatformResourceDetailTableRow
resource={deployment}
open={isExpanded()}
detailRowId={detailRowId()}
colSpan={8}
resolveResourceLabel={resolveResourceLabel}
onClose={() => drawer.close(deployment)}
/>
</>
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Events'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[1180px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[16%]`}>
Event
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[15%]`}
>
Scope
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[10%]`}>
Type
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[14%]`}>
Reason
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[15%]`}>
Object
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[7%]`}
>
Count
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Observed
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[10%]`}>
Message
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'Events'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1180px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[16%]`}>
Event
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[15%]`}
>
Scope
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[10%]`}>
Type
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[14%]`}>
Reason
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[15%]`}>
Object
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[7%]`}>
Count
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Observed
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[10%]`}>
Message
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(resource) => {
const indicator = () =>
@@ -168,98 +156,98 @@ export const KubernetesEventsTable: Component<{
return (
<>
<TableRow
class={`${getPlatformResourceDetailRowClass(isExpanded())} text-[11px] sm:text-xs`}
aria-controls={isExpanded() ? detailRowId() : undefined}
aria-expanded={isExpanded() ? 'true' : 'false'}
data-kubernetes-event-row={resource.id}
onClick={() => drawer.toggle(resource)}
onKeyDown={drawer.handleActivationKey(resource)}
tabIndex={0}
>
<TableCell class={getPlatformTableCellClassForKind('name')}>
<div class="flex min-w-0 items-center gap-2">
<StatusDot
size="sm"
variant={indicator().variant}
title={indicator().label}
ariaHidden
/>
<span class="truncate font-semibold text-base-content" title={name()}>
{name()}
<TableRow
class={`${getPlatformResourceDetailRowClass(isExpanded())} text-[11px] sm:text-xs`}
aria-controls={isExpanded() ? detailRowId() : undefined}
aria-expanded={isExpanded() ? 'true' : 'false'}
data-kubernetes-event-row={resource.id}
onClick={() => drawer.toggle(resource)}
onKeyDown={drawer.handleActivationKey(resource)}
tabIndex={0}
>
<TableCell class={getPlatformTableCellClassForKind('name')}>
<div class="flex min-w-0 items-center gap-2">
<StatusDot
size="sm"
variant={indicator().variant}
title={indicator().label}
ariaHidden
/>
<span class="truncate font-semibold text-base-content" title={name()}>
{name()}
</span>
</div>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[12rem] truncate" title={scope()}>
{scope()}
</span>
</div>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[12rem] truncate" title={scope()}>
{scope()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
{textValue(resource.kubernetes?.eventType)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span
class="inline-block max-w-[12rem] truncate"
title={textValue(resource.kubernetes?.reason)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
{textValue(resource.kubernetes?.reason)}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span
class="inline-block max-w-[13rem] truncate"
title={involvedObject(resource)}
{textValue(resource.kubernetes?.eventType)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
{involvedObject(resource)}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{numberValue(resource.kubernetes?.count)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span
class="inline-block max-w-[12rem] truncate"
title={observedTimestamp(resource) || observed()}
<span
class="inline-block max-w-[12rem] truncate"
title={textValue(resource.kubernetes?.reason)}
>
{textValue(resource.kubernetes?.reason)}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
{observed()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span class="inline-block max-w-[16rem] truncate" title={message()}>
{message()}
</span>
</TableCell>
</TableRow>
<PlatformResourceDetailTableRow
resource={resource}
open={isExpanded()}
detailRowId={detailRowId()}
colSpan={8}
resolveResourceLabel={resolveResourceLabel}
onClose={() => drawer.close(resource)}
/>
<span
class="inline-block max-w-[13rem] truncate"
title={involvedObject(resource)}
>
{involvedObject(resource)}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{numberValue(resource.kubernetes?.count)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span
class="inline-block max-w-[12rem] truncate"
title={observedTimestamp(resource) || observed()}
>
{observed()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span class="inline-block max-w-[16rem] truncate" title={message()}>
{message()}
</span>
</TableCell>
</TableRow>
<PlatformResourceDetailTableRow
resource={resource}
open={isExpanded()}
detailRowId={detailRowId()}
colSpan={8}
resolveResourceLabel={resolveResourceLabel}
onClose={() => drawer.close(resource)}
/>
</>
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Ingresses and EndpointSlices'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[1180px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[19%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[12%]`}>
Kind
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Scope
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[12%]`}>
Type / class
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[18%]`}
>
Address / hosts
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[12%]`}>
Ports
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Targets
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'Ingresses and EndpointSlices'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1180px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[19%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[12%]`}>
Kind
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Scope
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[12%]`}>
Type / class
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[18%]`}
>
Address / hosts
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[12%]`}>
Ports
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Targets
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(resource) => {
const indicator = () => getSimpleStatusIndicator(resource.status);
@@ -306,9 +296,9 @@ export const KubernetesNetworkingTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Pods'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[1240px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[20%]`}>
Pod
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Scope
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Node
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[8%]`}>
Status
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[7%]`}
>
Ready
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[8%]`}
>
Restarts
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Owner
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Image
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[4%]`}
>
Age
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'Pods'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1240px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[20%]`}>
Pod
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Scope
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Node
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[8%]`}>
Status
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[7%]`}>
Ready
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[8%]`}>
Restarts
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Owner
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Image
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[4%]`}
>
Age
</TableHead>
</>
}
body={
<>
<For each={sortedRows()}>
{(resource) => {
const indicator = () => mapKubernetesPodStatus(resource);
@@ -204,97 +190,97 @@ export const KubernetesPodsTable: Component<{
return (
<>
<TableRow
class={`${getPlatformResourceDetailRowClass(isExpanded())} text-[11px] sm:text-xs`}
aria-controls={isExpanded() ? detailRowId() : undefined}
aria-expanded={isExpanded() ? 'true' : 'false'}
data-kubernetes-pod-row={resource.id}
onClick={() => drawer.toggle(resource)}
onKeyDown={drawer.handleActivationKey(resource)}
tabIndex={0}
>
<TableCell class={getPlatformTableCellClassForKind('name')}>
<div class="flex min-w-0 items-center gap-2">
<StatusDot
size="sm"
variant={indicator().variant}
title={indicator().label}
ariaHidden
/>
<span class="truncate font-semibold text-base-content" title={name()}>
{name()}
<TableRow
class={`${getPlatformResourceDetailRowClass(isExpanded())} text-[11px] sm:text-xs`}
aria-controls={isExpanded() ? detailRowId() : undefined}
aria-expanded={isExpanded() ? 'true' : 'false'}
data-kubernetes-pod-row={resource.id}
onClick={() => drawer.toggle(resource)}
onKeyDown={drawer.handleActivationKey(resource)}
tabIndex={0}
>
<TableCell class={getPlatformTableCellClassForKind('name')}>
<div class="flex min-w-0 items-center gap-2">
<StatusDot
size="sm"
variant={indicator().variant}
title={indicator().label}
ariaHidden
/>
<span class="truncate font-semibold text-base-content" title={name()}>
{name()}
</span>
</div>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="block max-w-full truncate" title={scope()}>
{scope()}
</span>
</div>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="block max-w-full truncate" title={scope()}>
{scope()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="block max-w-full truncate" title={node()}>
{node()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
{/* The mapped label carries the container failure reason
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="block max-w-full truncate" title={node()}>
{node()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
{/* The mapped label carries the container failure reason
(CrashLoopBackOff, ImagePullBackOff, ...) where the raw
phase would still read "Running". */}
<span class="block max-w-full truncate" title={indicator().label}>
{indicator().label}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{readySummary(resource)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{numericValue(restartCount(resource))}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="block max-w-full truncate" title={owner()}>
{owner()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="block max-w-full truncate" title={image()}>
{image()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
{age()}
</TableCell>
</TableRow>
<PlatformResourceDetailTableRow
resource={resource}
open={isExpanded()}
detailRowId={detailRowId()}
colSpan={9}
resolveResourceLabel={resolveResourceLabel}
onClose={() => drawer.close(resource)}
/>
<span class="block max-w-full truncate" title={indicator().label}>
{indicator().label}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{readySummary(resource)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('numeric-value')} text-base-content`}
>
{numericValue(restartCount(resource))}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="block max-w-full truncate" title={owner()}>
{owner()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="block max-w-full truncate" title={image()}>
{image()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
{age()}
</TableCell>
</TableRow>
<PlatformResourceDetailTableRow
resource={resource}
open={isExpanded()}
detailRowId={detailRowId()}
colSpan={9}
resolveResourceLabel={resolveResourceLabel}
onClose={() => drawer.close(resource)}
/>
</>
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader
title={
props.title ??
'NetworkPolicies, PodDisruptionBudgets, ResourceQuotas, and LimitRanges'
}
/>
<Table class="min-w-full table-fixed text-xs md:min-w-[1180px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[17%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[14%]`}>
Kind
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[15%]`}
>
Scope
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[15%]`}>
Policy shape
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[16%]`}>
Spec / limits
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Observed state
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[9%]`}
>
Labels
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={
props.title ??
'NetworkPolicies, PodDisruptionBudgets, ResourceQuotas, and LimitRanges'
}
tableClass="min-w-full table-fixed text-xs md:min-w-[1180px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[17%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[14%]`}>
Kind
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[15%]`}
>
Scope
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[15%]`}>
Policy shape
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[16%]`}>
Spec / limits
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Observed state
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[9%]`}
>
Labels
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(resource) => {
const indicator = () => getSimpleStatusIndicator(resource.status);
@@ -309,84 +297,84 @@ export const KubernetesPolicyTable: Component<{
return (
<>
<TableRow
class={`${getPlatformResourceDetailRowClass(isExpanded())} text-[11px] sm:text-xs`}
aria-controls={isExpanded() ? detailRowId() : undefined}
aria-expanded={isExpanded() ? 'true' : 'false'}
data-kubernetes-policy-row={resource.id}
onClick={() => drawer.toggle(resource)}
onKeyDown={drawer.handleActivationKey(resource)}
tabIndex={0}
>
<TableCell class={getPlatformTableCellClassForKind('name')}>
<div class="flex min-w-0 items-center gap-2">
<StatusDot
size="sm"
variant={indicator().variant}
title={resource.status || 'unknown'}
ariaHidden
/>
<span class="truncate font-semibold text-base-content" title={name()}>
{name()}
<TableRow
class={`${getPlatformResourceDetailRowClass(isExpanded())} text-[11px] sm:text-xs`}
aria-controls={isExpanded() ? detailRowId() : undefined}
aria-expanded={isExpanded() ? 'true' : 'false'}
data-kubernetes-policy-row={resource.id}
onClick={() => drawer.toggle(resource)}
onKeyDown={drawer.handleActivationKey(resource)}
tabIndex={0}
>
<TableCell class={getPlatformTableCellClassForKind('name')}>
<div class="flex min-w-0 items-center gap-2">
<StatusDot
size="sm"
variant={indicator().variant}
title={resource.status || 'unknown'}
ariaHidden
/>
<span class="truncate font-semibold text-base-content" title={name()}>
{name()}
</span>
</div>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
{policyKind(resource)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[13rem] truncate" title={scope()}>
{scope()}
</span>
</div>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
{policyKind(resource)}
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[13rem] truncate" title={scope()}>
{scope()}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span class="inline-block max-w-[13rem] truncate" title={shape().title}>
{shape().label}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span class="inline-block max-w-[16rem] truncate" title={spec().title}>
{spec().label}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[14rem] truncate" title={state().title}>
{state().label}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[8rem] truncate" title={labels().title}>
{labels().label}
</span>
</TableCell>
</TableRow>
<PlatformResourceDetailTableRow
resource={resource}
open={isExpanded()}
detailRowId={detailRowId()}
colSpan={7}
resolveResourceLabel={resolveResourceLabel}
onClose={() => drawer.close(resource)}
/>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span class="inline-block max-w-[13rem] truncate" title={shape().title}>
{shape().label}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} text-base-content`}
>
<span class="inline-block max-w-[16rem] truncate" title={spec().title}>
{spec().label}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[14rem] truncate" title={state().title}>
{state().label}
</span>
</TableCell>
<TableCell
class={`${getPlatformTableCellClassForKind('text')} hidden text-base-content md:table-cell`}
>
<span class="inline-block max-w-[8rem] truncate" title={labels().title}>
{labels().label}
</span>
</TableCell>
</TableRow>
<PlatformResourceDetailTableRow
resource={resource}
open={isExpanded()}
detailRowId={detailRowId()}
colSpan={7}
resolveResourceLabel={resolveResourceLabel}
onClose={() => drawer.close(resource)}
/>
</>
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Services'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[1120px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[19%]`}>
Service
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[15%]`}
>
Scope
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[11%]`}>
Type
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[13%]`}>
Cluster IP
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
External IPs
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[16%]`}>
Ports
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Selector
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'Services'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1120px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[19%]`}>
Service
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[15%]`}
>
Scope
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[11%]`}>
Type
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[13%]`}>
Cluster IP
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
External IPs
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[16%]`}>
Ports
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Selector
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(resource) => {
const indicator = () => getSimpleStatusIndicator(resource.status);
@@ -267,9 +257,9 @@ export const KubernetesServicesTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Storage Classes, Volumes, and Claims'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[1120px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[19%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[10%]`}>
Kind
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Scope
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[14%]`}>
Binding / phase
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Class
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[8%]`}
>
Size
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[12%]`}
>
Access / policy
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Provider / binding
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'Storage Classes, Volumes, and Claims'}
tableClass="min-w-full table-fixed text-xs md:min-w-[1120px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[19%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[10%]`}>
Kind
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Scope
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[14%]`}>
Binding / phase
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Class
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[8%]`}>
Size
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[12%]`}
>
Access / policy
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Provider / binding
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(resource) => {
const indicator = () => getSimpleStatusIndicator(resource.status);
@@ -339,9 +327,9 @@ export const KubernetesStorageTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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');
}
@@ -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 (
<Show when={rows().length > 0}>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<Table class="min-w-[1020px] table-fixed text-xs">
<PlatformTableShell
tableClass="min-w-[1020px] table-fixed text-xs"
colgroup={
<colgroup>
<col style={{ width: '16%' }} />
<col style={{ width: '10%' }} />
@@ -167,27 +158,23 @@ export function ProxmoxBackupServersTable(props: {
<col style={{ width: '7%' }} />
<col style={{ width: '7%' }} />
</colgroup>
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={getPlatformTableHeadClassForKind('name')}>Backup server</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Status</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Version</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>CPU</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Memory
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Uptime
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Datastore</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>Used</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Backups
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>Dedup</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
}
header={
<>
<TableHead class={getPlatformTableHeadClassForKind('name')}>Backup server</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Status</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Version</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>CPU</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>Memory</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>Uptime</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Datastore</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>Used</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>Backups</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>Dedup</TableHead>
</>
}
body={
<>
<For each={rows()}>
{(row) => {
const pct = () => (row.datastore ? usagePercent(row.datastore) : undefined);
@@ -309,9 +296,9 @@ export function ProxmoxBackupServersTable(props: {
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
);
}
@@ -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<{
</Card>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<Table class="min-w-[1100px] text-xs">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={getPlatformTableHeadClassForKind('name')}>Cluster</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Health</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>FSID</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Quorum
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
OSDs
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
PGs
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Pools
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Capacity
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Services</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Detail</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
tableClass="min-w-[1100px] text-xs"
header={
<>
<TableHead class={getPlatformTableHeadClassForKind('name')}>Cluster</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Health</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>FSID</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Quorum
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
OSDs
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>PGs</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Pools
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Capacity
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Services</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Detail</TableHead>
</>
}
body={
<>
<For each={filtered()}>
{(cluster) => {
const ind = indicatorFor(classify(cluster));
@@ -389,9 +378,9 @@ export const ProxmoxCephTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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: {
</Card>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<Table class="min-w-[1000px] table-fixed text-xs">
<PlatformTableShell
tableClass="min-w-[1000px] table-fixed text-xs"
colgroup={
<colgroup>
<For each={visibleColumns()}>
{(column) => (
@@ -129,82 +127,84 @@ export function ProxmoxCoverageTable(props: {
)}
</For>
</colgroup>
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
}
header={
<>
<SortableHead
label="Workload"
sortKey="workload"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('name')}
/>
<SortableHead
label="Posture"
sortKey="posture"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('text')}
/>
<SortableHead
label="Restore"
sortKey="latest"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="right"
headClass={getPlatformTableHeadClassForKind('numeric-value')}
/>
<Show when={props.showPbsColumn}>
<SortableHead
label="Workload"
sortKey="workload"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('name')}
/>
<SortableHead
label="Posture"
sortKey="posture"
label="PBS snapshot"
sortKey="pbs"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('text')}
/>
</Show>
<Show when={props.showArchiveColumn}>
<SortableHead
label="Restore"
sortKey="latest"
label="PVE file"
sortKey="archive"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="right"
headClass={getPlatformTableHeadClassForKind('numeric-value')}
align="left"
headClass={getPlatformTableHeadClassForKind('text')}
/>
<Show when={props.showPbsColumn}>
<SortableHead
label="PBS snapshot"
sortKey="pbs"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('text')}
/>
</Show>
<Show when={props.showArchiveColumn}>
<SortableHead
label="PVE file"
sortKey="archive"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('text')}
/>
</Show>
<Show when={props.showSnapshotColumn}>
<SortableHead
label="Guest snapshot"
sortKey="snapshot"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('text')}
/>
</Show>
<Show when={props.showTaskColumn}>
<SortableHead
label="Task"
sortKey="task"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('text')}
/>
</Show>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
</Show>
<Show when={props.showSnapshotColumn}>
<SortableHead
label="Guest snapshot"
sortKey="snapshot"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('text')}
/>
</Show>
<Show when={props.showTaskColumn}>
<SortableHead
label="Task"
sortKey="task"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('text')}
/>
</Show>
</>
}
body={
<>
<For each={props.rows}>
{(row) => {
const isExpanded = () => props.expandedKeys.has(row.key);
@@ -449,9 +449,9 @@ export function ProxmoxCoverageTable(props: {
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
);
}
@@ -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<{
</Card>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<Table class="min-w-[1080px] text-xs">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={getPlatformTableHeadClassForKind('name')}>Instance</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Version</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Nodes
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Uptime
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Mail in
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Spam
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Virus
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Quarantine
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Queue
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Deferred
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
tableClass="min-w-[1080px] text-xs"
header={
<>
<TableHead class={getPlatformTableHeadClassForKind('name')}>Instance</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Version</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Nodes
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Uptime
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Mail in
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Spam
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Virus
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Quarantine
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Queue
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Deferred
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(instance) => {
const pmg = () => instance.pmg;
@@ -222,9 +213,9 @@ export const ProxmoxMailGatewayTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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: {
</Card>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<Table class="min-w-[1080px] table-fixed text-xs">
{/* Keep column widths stable; long locations/details truncate with title text. */}
<colgroup>
<col style={{ width: '17%' }} />
<col style={{ width: '7%' }} />
<col style={{ width: '8%' }} />
<col style={{ width: '8%' }} />
<col style={{ width: '14%' }} />
<col style={{ width: '11%' }} />
<col style={{ width: '13%' }} />
<col style={{ width: '8%' }} />
<col style={{ width: '14%' }} />
</colgroup>
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<SortableHead
label="Workload"
sortKey="workload"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('name')}
/>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Type</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>
{PROXMOX_BACKUP_COLUMN_LABELS.targetId}
</TableHead>
<SortableHead
label="Source"
sortKey="source"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('text')}
/>
<SortableHead
label="Location"
sortKey="location"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('text')}
/>
<SortableHead
label={PROXMOX_BACKUP_COLUMN_LABELS.created}
sortKey="created"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="right"
headClass={getPlatformTableHeadClassForKind('numeric-value')}
/>
<SortableHead
label="Size"
sortKey="size"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="center"
headClass={getPlatformTableHeadClassForKind('metric-bar')}
/>
<SortableHead
label="State"
sortKey="state"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('text')}
/>
<TableHead class={getPlatformTableHeadClassForKind('text')}>
{PROXMOX_BACKUP_COLUMN_LABELS.details}
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
tableClass="min-w-[1080px] table-fixed text-xs"
header={
<>
<SortableHead
label="Workload"
sortKey="workload"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('name')}
/>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Type</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>
{PROXMOX_BACKUP_COLUMN_LABELS.targetId}
</TableHead>
<SortableHead
label="Source"
sortKey="source"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('text')}
/>
<SortableHead
label="Location"
sortKey="location"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('text')}
/>
<SortableHead
label={PROXMOX_BACKUP_COLUMN_LABELS.created}
sortKey="created"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="right"
headClass={getPlatformTableHeadClassForKind('numeric-value')}
/>
<SortableHead
label="Size"
sortKey="size"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="center"
headClass={getPlatformTableHeadClassForKind('metric-bar')}
/>
<SortableHead
label="State"
sortKey="state"
currentSort={props.sortKey}
direction={props.sortDirection}
onSort={props.onSort}
align="left"
headClass={getPlatformTableHeadClassForKind('text')}
/>
<TableHead class={getPlatformTableHeadClassForKind('text')}>
{PROXMOX_BACKUP_COLUMN_LABELS.details}
</TableHead>
</>
}
body={
<>
<Show
when={showDayGroups()}
fallback={<For each={props.artifacts}>{(artifact) => renderRow(artifact)}</For>}
@@ -267,9 +246,9 @@ export function ProxmoxRecoverableTable(props: {
)}
</For>
</Show>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
);
}
@@ -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<{
</Card>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<Table class="min-w-[1200px] text-xs">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Status</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Job</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('name')}>Guest</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>
Source Target
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>
Schedule
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Last sync
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Next sync
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Duration
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Fail count
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Error</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
tableClass="min-w-[1200px] text-xs"
header={
<>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Status</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Job</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('name')}>Guest</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>
Source Target
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Schedule</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Last sync
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Next sync
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Duration
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('numeric-value')}>
Fail count
</TableHead>
<TableHead class={getPlatformTableHeadClassForKind('text')}>Error</TableHead>
</>
}
body={
<>
<For each={filtered()}>
{(job) => {
const classification = classifyJob(job);
@@ -385,9 +374,9 @@ export const ProxmoxReplicationTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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(() => (
<ProxmoxBackupsTable emptyIcon={<span />} workloads={[workloadResource]} />
<ProxmoxBackupsTable
emptyIcon={<span />}
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');
});
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title="Machines" />
<Table class="min-w-full table-fixed text-xs md:min-w-[1210px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<For each={visibleColumns()}>
{(column) => (
<AgentMachineSortableHead
column={column}
activeSort={sortKey()}
direction={sortDirection()}
onSort={handleSort}
/>
)}
</For>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title="Machines"
tableClass="min-w-full table-fixed text-xs md:min-w-[1210px]"
header={
<>
<For each={visibleColumns()}>
{(column) => (
<AgentMachineSortableHead
column={column}
activeSort={sortKey()}
direction={sortDirection()}
onSort={handleSort}
/>
)}
</For>
</>
}
body={
<>
<For each={sortedMachines()}>
{(machine) => {
const name = () => asTrimmedString(machine.name) || machine.id;
@@ -1755,9 +1745,9 @@ export const AgentsMachinesTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader
title="Availability checks"
actions={
<div class="flex flex-wrap items-center justify-end gap-2">
<A href={buildAvailabilityTargetAddPath('service')} class={settingsLinkClass}>
<PlusIcon class="h-3.5 w-3.5" />
Add service/device check
</A>
<A href={buildAvailabilitySettingsPath()} class={settingsLinkClass}>
<SettingsIcon class="h-3.5 w-3.5" />
Manage
</A>
</div>
}
/>
<Table class="min-w-full table-fixed text-xs md:min-w-[900px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead
class={`${getPlatformTableHeadClassForKind('name')} w-[42%] md:w-[22%]`}
>
Check
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[12%]`}
>
Method
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[28%]`}
>
Target
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} w-[28%] md:w-[12%]`}
>
Result
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[10%]`}
>
Checked
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden lg:table-cell lg:w-[8%]`}
>
Failures
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden lg:table-cell lg:w-[8%]`}
>
Interval
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title="Availability checks"
actions={
<div class="flex flex-wrap items-center justify-end gap-2">
<A href={buildAvailabilityTargetAddPath('service')} class={settingsLinkClass}>
<PlusIcon class="h-3.5 w-3.5" />
Add service/device check
</A>
<A href={buildAvailabilitySettingsPath()} class={settingsLinkClass}>
<SettingsIcon class="h-3.5 w-3.5" />
Manage
</A>
</div>
}
tableClass="min-w-full table-fixed text-xs md:min-w-[900px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} w-[42%] md:w-[22%]`}>
Check
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[12%]`}
>
Method
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[28%]`}
>
Target
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} w-[28%] md:w-[12%]`}
>
Result
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[10%]`}
>
Checked
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden lg:table-cell lg:w-[8%]`}
>
Failures
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden lg:table-cell lg:w-[8%]`}
>
Interval
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(check) => {
const availability = () => availabilityFor(check);
@@ -260,9 +246,9 @@ export const AvailabilityChecksTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title="Health Alerts" />
<Table class="min-w-full table-fixed text-xs md:min-w-[960px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[20%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[10%]`}>
Severity
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[32%]`}>
Alert
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Source
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[10%]`}
>
Started
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden xl:table-cell md:w-[15%]`}
>
Action
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title="Health Alerts"
tableClass="min-w-full table-fixed text-xs md:min-w-[960px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[20%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[10%]`}>
Severity
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[32%]`}>
Alert
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[13%]`}
>
Source
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[10%]`}
>
Started
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden xl:table-cell md:w-[15%]`}
>
Action
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(incident) => {
const detailRowId = () => drawer.detailRowId(incident);
@@ -318,7 +308,6 @@ export const TrueNASAlertsTable: Component<{
<div class="truncate text-[10px] text-muted">
{formatResourceType(incident.resourceType)}
<Show when={incident.resource.parentName}>
{' '}
on {incident.resource.parentName}
</Show>
</div>
@@ -391,9 +380,9 @@ export const TrueNASAlertsTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title="Apps" />
<Table class="min-w-full table-fixed text-xs md:min-w-[960px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[17%]`}>
App
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Version
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[9%]`}>
CPU
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[12%]`}>
Memory
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden sm:table-cell md:w-[12%]`}
>
Containers
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[18%]`}
>
Ports
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[12%]`}
>
Images
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[10%]`}>
Updates
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title="Apps"
tableClass="min-w-full table-fixed text-xs md:min-w-[960px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[17%]`}>
App
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Version
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[9%]`}>
CPU
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[12%]`}>
Memory
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden sm:table-cell md:w-[12%]`}
>
Containers
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[18%]`}
>
Ports
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[12%]`}
>
Images
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[10%]`}>
Updates
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(resource) => {
const app = () => appMeta(resource);
@@ -354,9 +344,9 @@ export const TrueNASAppsTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title="Network Shares" />
<Table class="min-w-full table-fixed text-xs md:min-w-[960px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[23%]`}>
Share
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[11%]`}>
Protocol
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[27%]`}
>
Path
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[19%]`}>
Access
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[13%]`}
>
Clients
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[7%]`}>
State
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title="Network Shares"
tableClass="min-w-full table-fixed text-xs md:min-w-[960px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[23%]`}>
Share
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[11%]`}>
Protocol
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[27%]`}
>
Path
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[19%]`}>
Access
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[13%]`}
>
Clients
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[7%]`}>
State
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(resource) => {
const share = () => shareMeta(resource);
@@ -291,9 +281,9 @@ export const TrueNASNetworkSharesTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader
title="Snapshots & Replication"
actions={
<span class="text-[10px] font-medium text-muted">
{tableState.total()} event{tableState.total() === 1 ? '' : 's'}
</span>
}
/>
<Table class="min-w-full table-fixed text-xs md:min-w-[960px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[22%]`}>
Dataset
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[25%]`}>
Artifact
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[23%]`}
>
Target
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[12%]`}
>
Completed
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden lg:table-cell md:w-[8%]`}
>
Size
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[9%]`}>
Outcome
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title="Snapshots & Replication"
actions={
<span class="text-[10px] font-medium text-muted">
{tableState.total()} event{tableState.total() === 1 ? '' : 's'}
</span>
}
tableClass="min-w-full table-fixed text-xs md:min-w-[960px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[22%]`}>
Dataset
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[25%]`}>
Artifact
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[23%]`}
>
Target
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} md:w-[12%]`}
>
Completed
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden lg:table-cell md:w-[8%]`}
>
Size
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[9%]`}>
Outcome
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(point) => {
const outcome = () => normalizeRecoveryOutcome(point.outcome);
@@ -520,9 +508,9 @@ export const TrueNASProtectionTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title="Services" />
<Table class="min-w-full table-fixed text-xs md:min-w-[900px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[24%]`}>
Service
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[14%]`}>
State
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[14%]`}>
Boot
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden sm:table-cell md:w-[20%]`}
>
PIDs
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[28%]`}>
System
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title="Services"
tableClass="min-w-full table-fixed text-xs md:min-w-[900px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[24%]`}>
Service
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[14%]`}>
State
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[14%]`}>
Boot
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden sm:table-cell md:w-[20%]`}
>
PIDs
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[28%]`}>
System
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(row) => {
const status = () => mapTrueNASServiceStatus(row);
@@ -321,9 +311,9 @@ export const TrueNASServicesTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title="Storage" />
<Table class="min-w-full table-fixed text-xs md:min-w-[960px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[32%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[10%]`}>
Kind
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[28%]`}>
Usage / Size
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[8%]`}
>
Disks
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden lg:table-cell md:w-[8%]`}
>
Temp
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[14%]`}>
Health
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title="Storage"
tableClass="min-w-full table-fixed text-xs md:min-w-[960px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[32%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[10%]`}>
Kind
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[28%]`}>
Usage / Size
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[8%]`}
>
Disks
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden lg:table-cell md:w-[8%]`}
>
Temp
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[14%]`}>
Health
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(row) => {
const resource = () => row.resource;
@@ -354,9 +344,9 @@ export const TrueNASStorageTopologyTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title={props.title ?? 'Systems'} />
<Table class="min-w-full table-fixed text-xs md:min-w-[960px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[17%]`}>
System
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[10%]`}>
CPU
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[10%]`}>
Memory
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[13%]`}>
Capacity
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[6%]`}
>
Temp
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell lg:w-[15%]`}
>
Inventory
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden lg:table-cell lg:w-[8%]`}
>
Shares
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell lg:w-[10%]`}
>
VMs / Apps
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden lg:table-cell lg:w-[10%]`}
>
Services
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title={props.title ?? 'Systems'}
tableClass="min-w-full table-fixed text-xs md:min-w-[960px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[17%]`}>
System
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[10%]`}>
CPU
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[10%]`}>
Memory
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[13%]`}>
Capacity
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[6%]`}
>
Temp
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell lg:w-[15%]`}
>
Inventory
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden lg:table-cell lg:w-[8%]`}
>
Shares
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell lg:w-[10%]`}
>
VMs / Apps
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden lg:table-cell lg:w-[10%]`}
>
Services
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(system) => {
const name = () => asTrimmedString(system.name) || system.id;
@@ -384,9 +374,9 @@ export const TrueNASSystemsTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title="Virtual Machines" />
<Table class="min-w-full table-fixed text-xs md:min-w-[960px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[22%]`}>
VM
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[10%]`}>
State
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden sm:table-cell md:w-[10%]`}
>
CPU
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden sm:table-cell md:w-[10%]`}
>
Memory
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[11%]`}
>
Boot
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[18%]`}
>
Devices
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[19%]`}>
Flags
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title="Virtual Machines"
tableClass="min-w-full table-fixed text-xs md:min-w-[960px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[22%]`}>
VM
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[10%]`}>
State
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden sm:table-cell md:w-[10%]`}
>
CPU
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden sm:table-cell md:w-[10%]`}
>
Memory
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[11%]`}
>
Boot
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[18%]`}
>
Devices
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[19%]`}>
Flags
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(resource) => {
const vm = () => vmMeta(resource);
@@ -298,9 +288,9 @@ export const TrueNASVirtualMachinesTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title="Recent Activity" />
<Table class="min-w-full table-fixed text-xs md:min-w-[1120px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[20%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[8%]`}>
Type
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[34%]`}>
Activity
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[10%]`}>
State
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Actor
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[10%]`}
>
vCenter
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden xl:table-cell md:w-[8%]`}
>
When
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title="Recent Activity"
tableClass="min-w-full table-fixed text-xs md:min-w-[1120px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[20%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[8%]`}>
Type
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[34%]`}>
Activity
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[10%]`}>
State
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Actor
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[10%]`}
>
vCenter
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden xl:table-cell md:w-[8%]`}
>
When
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(activity) => {
const meta = () => activity.resource.vmware;
@@ -312,7 +302,6 @@ export const VsphereActivityTable: Component<{
<div class="truncate text-[10px] text-muted">
{formatResourceType(activity.resourceType)}
<Show when={activity.resource.parentName}>
{' '}
on {activity.resource.parentName}
</Show>
</div>
@@ -389,9 +378,9 @@ export const VsphereActivityTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title="Health Signals" />
<Table class="min-w-full table-fixed text-xs md:min-w-[1040px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[20%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[10%]`}>
Severity
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[34%]`}>
Signal
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
vCenter
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[12%]`}
>
Entity
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden xl:table-cell md:w-[10%]`}
>
Started
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title="Health Signals"
tableClass="min-w-full table-fixed text-xs md:min-w-[1040px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[20%]`}>
Resource
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('badge')} md:w-[10%]`}>
Severity
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[34%]`}>
Signal
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
vCenter
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[12%]`}
>
Entity
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden xl:table-cell md:w-[10%]`}
>
Started
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(incident) => {
const meta = () => incident.resource.vmware;
@@ -308,7 +298,6 @@ export const VsphereAlertsTable: Component<{
<div class="truncate text-[10px] text-muted">
{formatResourceType(incident.resourceType)}
<Show when={incident.resource.parentName}>
{' '}
on {incident.resource.parentName}
</Show>
</div>
@@ -387,9 +376,9 @@ export const VsphereAlertsTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title="Datastores" />
<Table class="min-w-full table-fixed text-xs md:min-w-[1080px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[21%]`}>
Datastore
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[9%]`}>
Type
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[18%]`}>
Capacity
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Hosts
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[7%]`}
>
VMs
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[13%]`}
>
Consumers
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Datacenter
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title="Datastores"
tableClass="min-w-full table-fixed text-xs md:min-w-[1080px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[21%]`}>
Datastore
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[9%]`}>
Type
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('metric-bar')} md:w-[18%]`}>
Capacity
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[14%]`}
>
Hosts
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[7%]`}
>
VMs
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[13%]`}
>
Consumers
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[10%]`}
>
Datacenter
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(datastore) => {
const hosts = createMemo(() => hostSummary(datastore));
@@ -314,9 +304,9 @@ export const VsphereDatastoresTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>
@@ -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<{
/>
}
>
<TableCard class={PLATFORM_TABLE_CARD_CLASS}>
<TableCardHeader title="Networks" />
<Table class="min-w-full table-fixed text-xs md:min-w-[1040px]">
<TableHeader>
<TableRow class={PLATFORM_TABLE_HEADER_ROW_CLASS}>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[24%]`}>
Network
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[13%]`}>
Type
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[18%]`}
>
Hosts
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[7%]`}
>
VMs
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[18%]`}
>
Connected VMs
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[12%]`}
>
Datacenter
</TableHead>
</TableRow>
</TableHeader>
<TableBody class={PLATFORM_TABLE_BODY_CLASS}>
<PlatformTableShell
title="Networks"
tableClass="min-w-full table-fixed text-xs md:min-w-[1040px]"
header={
<>
<TableHead class={`${getPlatformTableHeadClassForKind('name')} md:w-[24%]`}>
Network
</TableHead>
<TableHead class={`${getPlatformTableHeadClassForKind('text')} md:w-[13%]`}>
Type
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[18%]`}
>
Hosts
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('numeric-value')} hidden md:table-cell md:w-[7%]`}
>
VMs
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden lg:table-cell md:w-[18%]`}
>
Connected VMs
</TableHead>
<TableHead
class={`${getPlatformTableHeadClassForKind('text')} hidden md:table-cell md:w-[12%]`}
>
Datacenter
</TableHead>
</>
}
body={
<>
<For each={tableState.filtered()}>
{(network) => {
const hosts = createMemo(() => hostSummary(network));
@@ -268,9 +258,9 @@ export const VsphereNetworksTable: Component<{
);
}}
</For>
</TableBody>
</Table>
</TableCard>
</>
}
/>
</Show>
</div>
</Show>