From 7a514154abde3b0bf4eed7c2b25fdf3700895f3f Mon Sep 17 00:00:00 2001 From: rcourtman Date: Thu, 19 Mar 2026 05:55:28 +0000 Subject: [PATCH] Centralize dashboard guest identity helpers --- .../src/components/Dashboard/GuestDrawer.test.tsx | 13 +++++++++---- .../src/components/Dashboard/GuestDrawer.tsx | 6 ++---- .../src/components/Dashboard/GuestRow.tsx | 6 +----- .../frontendResourceTypeBoundaries.test.ts | 4 ++++ 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/frontend-modern/src/components/Dashboard/GuestDrawer.test.tsx b/frontend-modern/src/components/Dashboard/GuestDrawer.test.tsx index cdeae9014..7c2c7d837 100644 --- a/frontend-modern/src/components/Dashboard/GuestDrawer.test.tsx +++ b/frontend-modern/src/components/Dashboard/GuestDrawer.test.tsx @@ -2,6 +2,7 @@ import { describe, it, expect, vi, afterEach, beforeEach } from 'vitest'; import { render, screen, fireEvent, cleanup } from '@solidjs/testing-library'; import type { WorkloadGuest } from '@/types/workloads'; import type { Memory, Disk, GuestNetworkInterface } from '@/types/api'; +import { getCanonicalWorkloadId } from '@/utils/workloads'; // ── Mocks ────────────────────────────────────────────────────────────── @@ -507,19 +508,23 @@ describe('GuestDrawer', () => { // ── WebInterfaceUrlField ── describe('WebInterfaceUrlField', () => { - it('passes correct metadataId using guest.id', () => { + it('passes canonical metadataId using shared workload identity', () => { render(() => ); - expect(screen.getByTestId('url-id').textContent).toBe('my-guest-id'); + expect(screen.getByTestId('url-id').textContent).toBe( + getCanonicalWorkloadId(makeGuest({ id: 'my-guest-id' })), + ); }); - it('builds fallback id from instance:node:vmid when id is empty', () => { + it('builds canonical id from instance:node:vmid when id is empty', () => { render(() => ( )); - expect(screen.getByTestId('url-id').textContent).toBe('pve:n1:200'); + expect(screen.getByTestId('url-id').textContent).toBe( + getCanonicalWorkloadId(makeGuest({ id: '', instance: 'pve', node: 'n1', vmid: 200 })), + ); }); it('labels app-container guests as "container"', () => { diff --git a/frontend-modern/src/components/Dashboard/GuestDrawer.tsx b/frontend-modern/src/components/Dashboard/GuestDrawer.tsx index 095c65d66..1ed5f7e80 100644 --- a/frontend-modern/src/components/Dashboard/GuestDrawer.tsx +++ b/frontend-modern/src/components/Dashboard/GuestDrawer.tsx @@ -6,6 +6,7 @@ import { DiskList } from './DiskList'; import { DiscoveryTab } from '../Discovery/DiscoveryTab'; import { getDiscoveryResourceTypeForWorkload, + getCanonicalWorkloadId, getWebInterfaceTargetLabelForWorkload, resolveWorkloadType, } from '@/utils/workloads'; @@ -28,10 +29,7 @@ interface GuestDrawerProps { export const GuestDrawer: Component = (props) => { const navigate = useNavigate(); - const guestId = () => { - if (props.guest.id) return props.guest.id; - return `${props.guest.instance}:${props.guest.node}:${props.guest.vmid}`; - }; + const guestId = () => getCanonicalWorkloadId(props.guest); const infrastructureHref = () => buildInfrastructureHrefForWorkload(props.guest); const isVM = (guest: Guest): boolean => { diff --git a/frontend-modern/src/components/Dashboard/GuestRow.tsx b/frontend-modern/src/components/Dashboard/GuestRow.tsx index 13c142060..7d2f39ce8 100644 --- a/frontend-modern/src/components/Dashboard/GuestRow.tsx +++ b/frontend-modern/src/components/Dashboard/GuestRow.tsx @@ -110,10 +110,6 @@ const getOutlierEmphasis = (value: number, stats: IODistributionStats): IOEmphas const GROUPED_FIRST_CELL_INDENT = 'pl-3 sm:pl-5 lg:pl-8'; const DEFAULT_FIRST_CELL_INDENT = 'pl-2 sm:pl-3'; -const buildGuestId = (guest: Guest) => { - return getCanonicalWorkloadId(guest); -}; - // Type guard for VM vs Container const isVM = (guest: Guest): guest is VM => { return resolveWorkloadType(guest) === 'vm'; @@ -771,7 +767,7 @@ interface GuestRowProps { export function GuestRow(props: GuestRowProps) { const navigate = useNavigate(); - const guestId = createMemo(() => buildGuestId(props.guest)); + const guestId = createMemo(() => getCanonicalWorkloadId(props.guest)); const infrastructureHref = createMemo(() => buildInfrastructureHrefForWorkload(props.guest)); // Use breakpoint hook directly for responsive behavior diff --git a/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts b/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts index 4723b2075..47151cb97 100644 --- a/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts +++ b/frontend-modern/src/utils/__tests__/frontendResourceTypeBoundaries.test.ts @@ -316,6 +316,10 @@ describe('frontend resource type boundaries', () => { expect(dashboardSource).toContain('normalizeWorkloadViewModeParam'); expect(dashboardSource).not.toContain('function normalizeViewModeParam'); expect(dashboardSource).not.toContain('workloadSummaryGuestId'); + expect(guestRowSource).toContain('getCanonicalWorkloadId'); + expect(guestRowSource).not.toContain('buildGuestId'); + expect(guestDrawerSource).toContain('getCanonicalWorkloadId'); + expect(guestDrawerSource).not.toContain('const guestId = () => {'); expect(emptyStateSource).toContain('getEmptyStatePresentation'); expect(emptyStateSource).not.toContain('const iconBgClass: Record ='); expect(emptyStateSource).not.toContain(