From ce91bcb53edf39e264d67862006eb37da4670627 Mon Sep 17 00:00:00 2001 From: rcourtman Date: Wed, 5 Aug 2026 13:17:06 +0100 Subject: [PATCH] fix(ui): prioritize responsive table columns Contract-Neutral: Responsive table layout only; no API or contract changes. --- frontend-modern/browser-verification.json | 70 +++++++--- .../features/docker/DockerNetworksTable.tsx | 85 +++++++++++- .../platformOverviewLayout.guardrails.test.ts | 12 ++ .../proxmox/ProxmoxReplicationTable.tsx | 131 ++++++++++++++++-- .../truenas/TrueNASVirtualMachinesTable.tsx | 16 ++- .../features/vmware/VsphereNetworksTable.tsx | 8 +- 6 files changed, 275 insertions(+), 47 deletions(-) diff --git a/frontend-modern/browser-verification.json b/frontend-modern/browser-verification.json index 36d50febd..b75338600 100644 --- a/frontend-modern/browser-verification.json +++ b/frontend-modern/browser-verification.json @@ -1,45 +1,77 @@ { "version": 1, - "base_sha": "58864f5ecc3abd351cf252b07995d605e3f7c498", - "verified_at": "2026-08-05T11:30:51Z", + "base_sha": "7d066f1d5c2f8921695cae5cf5bddf2e2b8e7151", + "verified_at": "2026-08-05T12:07:34Z", "result": "passed", "changed_paths": [ - "frontend-modern/src/components/shared/InlineDetailTableRow.tsx", - "frontend-modern/src/features/truenas/TrueNASAppsTable.tsx", - "frontend-modern/src/index.css" + "frontend-modern/src/features/docker/DockerNetworksTable.tsx", + "frontend-modern/src/features/proxmox/ProxmoxReplicationTable.tsx", + "frontend-modern/src/features/truenas/TrueNASVirtualMachinesTable.tsx", + "frontend-modern/src/features/vmware/VsphereNetworksTable.tsx" ], "content_sha256": { - "frontend-modern/src/components/shared/InlineDetailTableRow.tsx": "c614aee58b3953fdafb6e65035c73796dcc5ae3b6b8a55479632e61d95af1f12", - "frontend-modern/src/features/truenas/TrueNASAppsTable.tsx": "50374a199a49dcac90386a1b22cc45c38674225defba469bad3d1d263ae6b8df", - "frontend-modern/src/index.css": "817c3f407d83909e43bb771019f0b7b460b498d0333e9eb3cac2fe697b5d78be" + "frontend-modern/src/features/docker/DockerNetworksTable.tsx": "a5a10d77fc0f575d05fb5754d7b65840692c9fde7a726899f1a4814c2b5cd2b1", + "frontend-modern/src/features/proxmox/ProxmoxReplicationTable.tsx": "9571289310a518495c88860089cd0ba191c69cd4821c7ba90163e97a42217c12", + "frontend-modern/src/features/truenas/TrueNASVirtualMachinesTable.tsx": "1ec149f222086b4e9433d07b15699775cb6eca5a20ee968eaf817f030f4f3ac1", + "frontend-modern/src/features/vmware/VsphereNetworksTable.tsx": "7c2580565602b9e7927ea4a16548f104d0144ec37ec93f692cc882171b1f9b57" }, "routes": [ "/proxmox/overview", + "/proxmox/storage", + "/proxmox/replication", + "/proxmox/backups", + "/proxmox/ceph", + "/proxmox/mail", "/docker/overview", + "/docker/images", + "/docker/storage", + "/docker/networks", + "/docker/swarm", "/kubernetes/overview", + "/kubernetes/nodes", + "/kubernetes/workloads", + "/kubernetes/services", + "/kubernetes/storage", + "/kubernetes/configuration", + "/kubernetes/events", + "/truenas/overview", + "/truenas/storage", + "/truenas/services", "/truenas/apps", + "/truenas/vms", "/truenas/shares", - "/vmware/overview" + "/truenas/protection", + "/vmware/overview", + "/vmware/storage", + "/vmware/networks", + "/vmware/health", + "/vmware/activity", + "/standalone/machines", + "/standalone/availability" ], "viewports": [ { "width": 320, "height": 900 }, - { "width": 375, "height": 812 }, + { "width": 375, "height": 900 }, { "width": 768, "height": 900 }, { "width": 1024, "height": 900 }, { "width": 1280, "height": 900 }, { "width": 1600, "height": 900 } ], "states": [ - "Rendered TrueNAS Apps with App, CPU, Memory, and Updates using the complete phone-width table instead of reserving hidden desktop tracks", - "Kept expanded TrueNAS App and Share detail rows aligned as visible column counts changed from phone through desktop breakpoints", - "Kept expanded Kubernetes deployment, Docker host, vSphere host, Proxmox node, and Proxmox workload rows aligned to their visible summary columns", - "Measured visible header widths against table widths at 320, 375, 768, 1024, 1280, and 1600 pixels with no document overflow", - "Visually inspected the expanded Proxmox node and workload details at phone width with operational columns and drawer content remaining readable" + "Rendered every audited platform table at phone, tablet, laptop, desktop, and wide-desktop widths without document overflow", + "Kept Proxmox replication guest names readable by prioritizing Guest over Job, Fails, and Error while progressively revealing operational columns", + "Prioritized Docker network attachment summaries over the compact Attention field and retained useful network, subnet, driver, and host context as space increased", + "Displayed TrueNAS VM state, CPU, and memory at phone width while deferring secondary Flags metadata until tablet width", + "Displayed vSphere network VM impact at phone width alongside network name and type, with hosts and datacenter returning at wider layouts", + "Kept representative expanded detail rows aligned to the actual visible summary columns after resizing in both directions", + "Matched Proxmox, Docker, Kubernetes, TrueNAS, vSphere, and Machines page, tab, panel, and table bounds at 1280 pixels" ], "interactions": [ - "Expanded and collapsed representative resource rows using their disclosure controls across Proxmox, Docker, Kubernetes, TrueNAS, and vSphere", - "Resized the live browser repeatedly across every audited breakpoint while each representative detail row remained open", - "Sorted TrueNAS Apps by CPU through descending and ascending states, then restored the default order", - "Verified responsive detail colspans returned to compact values after resizing from desktop back to phone width" + "Expanded representative healthy, degraded, stopped, pending, warning, and failed rows across Proxmox, Docker, Kubernetes, TrueNAS, vSphere, and Machines", + "Resized each audited table repeatedly through 320, 375, 768, 1024, 1280, and 1600 pixel widths while representative details remained open", + "Switched Proxmox backup views and storage tabs to exercise their independent table layouts", + "Verified final TrueNAS VM detail colspans changed from 4 compact columns to 7 desktop columns", + "Verified final vSphere network detail colspans changed from 3 compact columns to 5 expanded columns", + "Measured every visible header allocation against its table width and checked for horizontal document overflow" ] } diff --git a/frontend-modern/src/features/docker/DockerNetworksTable.tsx b/frontend-modern/src/features/docker/DockerNetworksTable.tsx index 7b5fd93a0..ceb0523e2 100644 --- a/frontend-modern/src/features/docker/DockerNetworksTable.tsx +++ b/frontend-modern/src/features/docker/DockerNetworksTable.tsx @@ -12,6 +12,7 @@ import { getPlatformTableCellClassForKind, getPlatformTableContainerLayout, getPlatformTableHeadClassForKind, + type PlatformTableContainerLayout, PlatformTableShell, } from '@/features/platformPage/sharedPlatformPage'; import { useObservedElementWidth } from '@/hooks/useObservedElementWidth'; @@ -46,6 +47,54 @@ type AttachmentGroupKey = 'attention' | 'running' | 'other'; type AttachmentStatusFilter = 'all' | AttachmentGroupKey; +type DockerNetworkColumn = 'network' | 'attached' | 'attention' | 'subnet' | 'driver' | 'host'; + +const DOCKER_NETWORK_COLUMN_WIDTH_CLASS: Record< + PlatformTableContainerLayout, + Record +> = { + compact: { + network: 'w-[40%]', + attached: 'w-[40%]', + attention: 'w-[20%]', + subnet: 'w-0', + driver: 'w-0', + host: 'w-0', + }, + basic: { + network: 'w-[38%]', + attached: 'w-[42%]', + attention: 'w-[20%]', + subnet: 'w-0', + driver: 'w-0', + host: 'w-0', + }, + operational: { + network: 'w-[25%]', + attached: 'w-[35%]', + attention: 'w-[15%]', + subnet: 'w-[25%]', + driver: 'w-0', + host: 'w-0', + }, + expanded: { + network: 'w-[23%]', + attached: 'w-[32%]', + attention: 'w-[13%]', + subnet: 'w-[22%]', + driver: 'w-[10%]', + host: 'w-0', + }, + full: { + network: 'w-[20%]', + attached: 'w-[27%]', + attention: 'w-[13%]', + subnet: 'w-[18%]', + driver: 'w-[10%]', + host: 'w-[12%]', + }, +}; + type AttachmentGroup = { key: AttachmentGroupKey; label: string; @@ -369,6 +418,8 @@ export const DockerNetworksTable: Component = (props) const showSubnet = createMemo(() => !['compact', 'basic'].includes(layout())); const showDriver = createMemo(() => ['expanded', 'full'].includes(layout())); const showHost = createMemo(() => layout() === 'full'); + const columnWidthClass = (column: DockerNetworkColumn) => + DOCKER_NETWORK_COLUMN_WIDTH_CLASS[layout()][column]; const visibleColumnCount = createMemo( () => 3 + Number(showSubnet()) + Number(showDriver()) + Number(showHost()), ); @@ -414,19 +465,41 @@ export const DockerNetworksTable: Component = (props) tableClass="min-w-[0px] table-fixed text-xs" header={ <> - Network - + + Network + + - Attention + + Attention + - Subnets + + Subnets + - Driver + + Driver + - Host + + Host + } diff --git a/frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts b/frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts index 31c3793d4..e762e9c32 100644 --- a/frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts +++ b/frontend-modern/src/features/platformPage/__tests__/platformOverviewLayout.guardrails.test.ts @@ -301,6 +301,9 @@ describe('platform overview layout guardrails', () => { expect(dockerPageSurfaceSource).toContain(' { expect(truenasProtectionTableSource).toContain('md:min-w-[960px]'); expect(truenasStorageTopologyTableSource).toContain('md:min-w-[960px]'); expect(truenasVirtualMachinesTableSource).toContain('md:min-w-[960px]'); + expect(truenasVirtualMachinesTableSource).toMatch( + /class="hidden sm:table-cell md:w-\[19%\]"[\s\S]{0,120}?Flags/, + ); expect(vmwarePageSurfaceSource).toContain(' { expect(vmwarePageSurfaceSource).toContain('suppressTypeFilter'); expect(vmwarePageSurfaceSource).toContain(' +> = { + compact: { + status: 'w-[20%]', + job: 'w-0', + guest: 'w-[40%]', + route: 'w-[20%]', + schedule: 'w-0', + lastSync: 'w-[20%]', + nextSync: 'w-0', + duration: 'w-0', + fails: 'w-0', + error: 'w-0', + }, + basic: { + status: 'w-[14%]', + job: 'w-[11%]', + guest: 'w-[28%]', + route: 'w-[17%]', + schedule: 'w-0', + lastSync: 'w-[15%]', + nextSync: 'w-[15%]', + duration: 'w-0', + fails: 'w-0', + error: 'w-0', + }, + operational: { + status: 'w-[11%]', + job: 'w-[7%]', + guest: 'w-[21%]', + route: 'w-[12%]', + schedule: 'w-[9%]', + lastSync: 'w-[11%]', + nextSync: 'w-[13%]', + duration: 'w-[11%]', + fails: 'w-[5%]', + error: 'w-0', + }, + expanded: { + status: 'w-[10%]', + job: 'w-[7%]', + guest: 'w-[20%]', + route: 'w-[11%]', + schedule: 'w-[8%]', + lastSync: 'w-[10%]', + nextSync: 'w-[12%]', + duration: 'w-[10%]', + fails: 'w-[4%]', + error: 'w-[8%]', + }, + full: { + status: 'w-[10%]', + job: 'w-[7%]', + guest: 'w-[20%]', + route: 'w-[11%]', + schedule: 'w-[8%]', + lastSync: 'w-[10%]', + nextSync: 'w-[12%]', + duration: 'w-[10%]', + fails: 'w-[4%]', + error: 'w-[8%]', + }, +}; + const STATUS_FILTER_OPTIONS: PlatformTableFilterOption[] = [ { value: 'all', label: 'All' }, { @@ -193,6 +272,8 @@ export const ProxmoxReplicationTable: Component<{ const showNext = createMemo(() => layout() !== 'compact'); const showOperational = createMemo(() => ['operational', 'expanded', 'full'].includes(layout())); const showError = createMemo(() => ['expanded', 'full'].includes(layout())); + const columnWidthClass = (column: ReplicationColumn) => + REPLICATION_COLUMN_WIDTH_CLASS[layout()][column]; return ( - Status - - Job - - Guest + Status + + + + Job + + + + Guest + + Route - + Schedule - + Last sync - + Next sync - + Duration - + Fails - Error + + Error + } diff --git a/frontend-modern/src/features/truenas/TrueNASVirtualMachinesTable.tsx b/frontend-modern/src/features/truenas/TrueNASVirtualMachinesTable.tsx index 33e15d763..3271cdf20 100644 --- a/frontend-modern/src/features/truenas/TrueNASVirtualMachinesTable.tsx +++ b/frontend-modern/src/features/truenas/TrueNASVirtualMachinesTable.tsx @@ -219,7 +219,7 @@ export const TrueNASVirtualMachinesTable: Component<{ kind="numeric-value" sort={sort} sortKey="cpu" - class="hidden sm:table-cell md:w-[10%]" + class="md:w-[10%]" > CPU @@ -227,7 +227,7 @@ export const TrueNASVirtualMachinesTable: Component<{ kind="numeric-value" sort={sort} sortKey="memory" - class="hidden sm:table-cell md:w-[10%]" + class="md:w-[10%]" > Memory @@ -246,7 +246,11 @@ export const TrueNASVirtualMachinesTable: Component<{ > Devices - + @@ -312,12 +316,12 @@ export const TrueNASVirtualMachinesTable: Component<{ @@ -333,7 +337,7 @@ export const TrueNASVirtualMachinesTable: Component<{ {devices().label} @@ -181,7 +181,7 @@ export const VsphereNetworksTable: Component<{ kind="text" sort={sort} sortKey="type" - class="md:w-[13%]" + class="w-[35%] md:w-[13%]" > Type @@ -196,7 +196,7 @@ export const VsphereNetworksTable: Component<{ kind="numeric-value" sort={sort} sortKey="vms" - class="hidden sm:table-cell md:w-[7%]" + class="w-[20%] md:w-[7%]" > VMs @@ -280,7 +280,7 @@ export const VsphereNetworksTable: Component<{ {hosts().label}