From 6da67acf8cb329d676a7fe916d3ef7dcc7b41d2e Mon Sep 17 00:00:00 2001 From: rcourtman Date: Mon, 23 Mar 2026 11:48:25 +0000 Subject: [PATCH] Simplify drawer service detail summaries --- .../internal/subsystems/unified-resources.md | 3 ++ .../ResourceDetailDrawer.history.test.tsx | 2 ++ .../resourceDetailDrawerServiceModel.test.ts | 32 ++++++++++++++++++- .../resourceDetailDrawerServiceModel.ts | 18 +++++++---- 4 files changed, 48 insertions(+), 7 deletions(-) diff --git a/docs/release-control/v6/internal/subsystems/unified-resources.md b/docs/release-control/v6/internal/subsystems/unified-resources.md index ac6311336..6815b330d 100644 --- a/docs/release-control/v6/internal/subsystems/unified-resources.md +++ b/docs/release-control/v6/internal/subsystems/unified-resources.md @@ -511,6 +511,9 @@ inside PBS or PMG cards, and the service-local reveal labels stay terse also use shorter section labels (`Types`, `Queue detail`, `Mail detail`) and count-only summary badges so opened cards read like current state instead of descriptive chrome. +That collapsed `Service details` summary now also uses resource-facing count +phrasing (`1 datastore`, `7 containers`, `16 delayed messages`) instead of +implementation wording like `queue total`. Within that same PMG opened state, queue and backlog remain the primary metric tiles while node count moves into quieter support context beneath them, so the first read stays on mail-flow state instead of cluster metadata. diff --git a/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.history.test.tsx b/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.history.test.tsx index 8b4743834..f547dcd6a 100644 --- a/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.history.test.tsx +++ b/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.history.test.tsx @@ -173,6 +173,8 @@ describe('ResourceDetailDrawer change history section', () => { expect(resourceDetailDrawerServiceModelSource).toContain( 'export const buildPmgVisibleMailBreakdown', ); + expect(resourceDetailDrawerServiceModelSource).toContain("formatCount(pmg.queueTotal || 0, 'queued message')"); + expect(resourceDetailDrawerServiceModelSource).toContain("'delayed message'"); expect(resourceDetailDrawerOverviewSource).not.toContain('MonitoringAPI.'); expect(resourceDetailDrawerOverviewSource).toContain('drawer.queueDockerUpdateCheck'); expect(resourceDetailDrawerOverviewSource).toContain('drawer.queueDockerUpdateAll'); diff --git a/frontend-modern/src/components/Infrastructure/__tests__/resourceDetailDrawerServiceModel.test.ts b/frontend-modern/src/components/Infrastructure/__tests__/resourceDetailDrawerServiceModel.test.ts index 62ebbba67..3365a53e4 100644 --- a/frontend-modern/src/components/Infrastructure/__tests__/resourceDetailDrawerServiceModel.test.ts +++ b/frontend-modern/src/components/Infrastructure/__tests__/resourceDetailDrawerServiceModel.test.ts @@ -65,7 +65,7 @@ describe('resourceDetailDrawerServiceModel', () => { pbs: undefined, pmg, }), - ).toBe('519 queue total · 16 backlog'); + ).toBe('519 queued messages · 16 delayed messages'); }); it('keeps docker service summary on container and update counts', () => { @@ -81,4 +81,34 @@ describe('resourceDetailDrawerServiceModel', () => { }), ).toBe('7 containers · 3 updates'); }); + + it('pluralizes singular service summary counts cleanly', () => { + expect( + getServiceDetailsSummary({ + resourceType: 'docker-host', + docker: { + containerCount: 1, + updatesAvailableCount: 1, + }, + pbs: undefined, + pmg: undefined, + }), + ).toBe('1 container · 1 update'); + + expect( + getServiceDetailsSummary({ + resourceType: 'pbs', + docker: undefined, + pbs: { + datastoreCount: 1, + backupJobCount: 1, + syncJobCount: 0, + verifyJobCount: 0, + pruneJobCount: 0, + garbageJobCount: 0, + }, + pmg: undefined, + }), + ).toBe('1 datastore · 1 job'); + }); }); diff --git a/frontend-modern/src/components/Infrastructure/resourceDetailDrawerServiceModel.ts b/frontend-modern/src/components/Infrastructure/resourceDetailDrawerServiceModel.ts index c4f2641c3..1e8a15b9a 100644 --- a/frontend-modern/src/components/Infrastructure/resourceDetailDrawerServiceModel.ts +++ b/frontend-modern/src/components/Infrastructure/resourceDetailDrawerServiceModel.ts @@ -34,6 +34,9 @@ const filterVisibleBreakdown = ( return nonZero.length > 0 ? nonZero : entries; }; +const formatCount = (value: number, singular: string, plural = `${singular}s`): string => + `${formatInteger(value)} ${value === 1 ? singular : plural}`; + export const getPbsJobTotal = (pbs: PbsPlatformDataLike | undefined): number => { if (!pbs) return 0; return ( @@ -96,21 +99,24 @@ export const getServiceDetailsSummary = (args: { const { resourceType, docker, pbs, pmg } = args; if (resourceType === 'docker-host') { - return `${formatInteger(docker?.containerCount ?? 0)} containers · ${formatInteger( + return `${formatCount(docker?.containerCount ?? 0, 'container')} · ${formatCount( docker?.updatesAvailableCount ?? 0, - )} updates`; + 'update', + )}`; } if (pbs) { - return `${formatInteger(pbs.datastoreCount || 0)} datastores · ${formatInteger( + return `${formatCount(pbs.datastoreCount || 0, 'datastore')} · ${formatCount( getPbsJobTotal(pbs), - )} jobs`; + 'job', + )}`; } if (pmg) { - return `${formatInteger(pmg.queueTotal || 0)} queue total · ${formatInteger( + return `${formatCount(pmg.queueTotal || 0, 'queued message')} · ${formatCount( getPmgQueueBacklog(pmg), - )} backlog`; + 'delayed message', + )}`; } return null;