diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md index 41a3ccf07..d7203b68f 100644 --- a/docs/release-control/v6/internal/subsystems/frontend-primitives.md +++ b/docs/release-control/v6/internal/subsystems/frontend-primitives.md @@ -215,6 +215,7 @@ overflow. 1a. `frontend-modern/src/components/Infrastructure/resourceDetailDrawerMetricsHistoryModel.ts` 1b. `frontend-modern/src/components/Workloads/nodeDrawerModel.ts` 1c. `frontend-modern/src/features/docker/dockerHostDrawerModel.ts` + 1d. `frontend-modern/src/components/Workloads/AvailabilityProbeSuggestionCard.tsx` 2. `frontend-modern/src/components/Settings/Settings.tsx` 3. `frontend-modern/src/components/Settings/SettingsDialogs.tsx` 4. `frontend-modern/src/components/Settings/SettingsPageShell.tsx` @@ -1226,6 +1227,12 @@ not a replacement status card, CTA band, or page-local nested card. otherwise the shared `lg` transition is canonical. Feature surfaces own the labels, values, wrapping, and selection behavior, but must not restore drawer-width `justify-between` rows on desktop. + This contract also covers secondary drawer facts in availability status and + suggestion cards, resource change-history entries, Docker/PBS/PMG service + support panels, and Docker container-update management cards. Headers, + status summaries, actions, disk capacity summaries, and RAID state pairs may + retain intentional endpoint alignment; ordinary label/value facts in those + surfaces may not. Read-only metadata chips belong to `MetadataBadge` and domain wrappers over it. Organization role and share-status chips must use `OrganizationRoleBadge` and `OrganizationShareStatusBadge`, so role/status @@ -6185,6 +6192,10 @@ Known platform resources use that same compact presentation when availability is attached. `AvailabilityProbeStatusCard` is the shared detail primitive for Workloads and Docker host drawers; it renders the complete target, protocol, latest result, latency when relevant, evidence freshness, and last observation. +Its fact rows, and the matching service/probe/target rows in +`AvailabilityProbeSuggestionCard`, compose `InfoCardKeyValueRow` so phone +layouts remain condensed while wide cards keep each value adjacent to its +label. Plural attached checks render as repeated bounded cards from `availabilityChecks`, while the row keeps one compatibility summary. Expired successful evidence must render an amber `Stale` state with no green diff --git a/docs/release-control/v6/internal/subsystems/registry.json b/docs/release-control/v6/internal/subsystems/registry.json index d90c300ae..b6bf1b1e1 100644 --- a/docs/release-control/v6/internal/subsystems/registry.json +++ b/docs/release-control/v6/internal/subsystems/registry.json @@ -4899,6 +4899,7 @@ "frontend-modern/src/components/SetupWizard/SetupCompletionPreview.tsx", "frontend-modern/src/components/SetupWizard/SetupWizard.tsx", "frontend-modern/src/components/Toast/Toast.tsx", + "frontend-modern/src/components/Workloads/AvailabilityProbeSuggestionCard.tsx", "frontend-modern/src/components/Workloads/nodeDrawerModel.ts", "frontend-modern/src/features/docker/dockerHostDrawerModel.ts", "frontend-modern/src/features/platformPage/platformEstateOverviewModel.ts", @@ -5185,8 +5186,21 @@ "frontend-modern/src/utils/__tests__/reportingResourceTypes.test.ts" ] }, - { - "id": "workload-presentation-helpers", + { + "id": "compact-info-card-consumers", + "label": "compact information card consumer proof", + "match_prefixes": [], + "match_files": [ + "frontend-modern/src/components/Workloads/AvailabilityProbeSuggestionCard.tsx" + ], + "allow_same_subsystem_tests": false, + "test_prefixes": [], + "exact_files": [ + "frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts" + ] + }, + { + "id": "workload-presentation-helpers", "label": "workload presentation helper proof", "match_prefixes": [], "match_files": [ diff --git a/docs/release-control/v6/internal/subsystems/unified-resources.md b/docs/release-control/v6/internal/subsystems/unified-resources.md index 00cff987b..c83bf6ee5 100644 --- a/docs/release-control/v6/internal/subsystems/unified-resources.md +++ b/docs/release-control/v6/internal/subsystems/unified-resources.md @@ -1329,6 +1329,11 @@ and temperature facts must also compose the frontend-primitives `InfoCardKeyValueRow`. Mobile rows retain their condensed endpoint layout; desktop rows use the shared fixed label track so labels and values remain visually adjacent instead of spanning the full drawer width. +The same boundary applies to availability facts, resource change-history +metadata, Docker/PBS/PMG service facts, nested PMG queue/mail breakdowns, and +Docker container-update management facts. Their headers, actions, and compact +status summaries remain feature-owned, while ordinary label/value rows compose +`InfoCardKeyValueRow` rather than restoring a drawer-width flex split. Curated technical inventory follows the shared compact-row contract instead of the secondary-card contract. Docker-host drawers must project system, runtime, memory, storage, and telemetry facts through diff --git a/frontend-modern/browser-verification.json b/frontend-modern/browser-verification.json index a79b4887d..c1766e9ba 100644 --- a/frontend-modern/browser-verification.json +++ b/frontend-modern/browser-verification.json @@ -1,43 +1,36 @@ { "version": 1, - "base_sha": "e0baecc418d15a6638ef80ed1e2b39d08aa9a5ad", - "verified_at": "2026-08-27T18:57:57Z", + "base_sha": "81b09d870fb39112cbcef70becf09d6f30d77393", + "verified_at": "2026-08-27T19:35:10Z", "result": "passed", "changed_paths": [ - "frontend-modern/src/components/Storage/StorageDetailKeyValueRow.tsx", - "frontend-modern/src/components/shared/InfoCardFrame.tsx", - "frontend-modern/src/components/shared/cards/DisksCard.tsx", - "frontend-modern/src/components/shared/cards/HardwareCard.tsx", - "frontend-modern/src/components/shared/cards/RootDiskCard.tsx", - "frontend-modern/src/components/shared/cards/SystemInfoCard.tsx", - "frontend-modern/src/components/shared/cards/TemperaturesCard.tsx", - "frontend-modern/src/features/storageBackups/detailPresentation.ts" + "frontend-modern/src/components/Infrastructure/AvailabilityProbeStatusCard.tsx", + "frontend-modern/src/components/Infrastructure/ResourceDetailDrawerOverviewTab.tsx", + "frontend-modern/src/components/Workloads/AvailabilityProbeSuggestionCard.tsx", + "frontend-modern/src/features/docker/DockerHostDrawerOverview.tsx" ], "content_sha256": { - "frontend-modern/src/components/Storage/StorageDetailKeyValueRow.tsx": "db827a709c0f018c24dd0821ae9845022a2ba15c7052b6471926957aafdf6270", - "frontend-modern/src/components/shared/InfoCardFrame.tsx": "0819bce063e2caf72ffbbd3beb398fd4776a7fe089da7eac5c899bd92fffe66c", - "frontend-modern/src/components/shared/cards/DisksCard.tsx": "f9721f90d6b1c1a7030bbc1767c90a4d353d8c4a82843e47ad37aae8f687c46d", - "frontend-modern/src/components/shared/cards/HardwareCard.tsx": "66df4609cc019cf5a7d0928abb82a2ad88f99683cd277ee1f0e38b9b48d281dc", - "frontend-modern/src/components/shared/cards/RootDiskCard.tsx": "48a1698a5781639a2fcb027837edc6c7b580e392b37041c89911f23c71d80fc6", - "frontend-modern/src/components/shared/cards/SystemInfoCard.tsx": "723fab36dbd6eeaf882f6eb89d2d0c7c276f5b930c17bfcbc44413a13f531880", - "frontend-modern/src/components/shared/cards/TemperaturesCard.tsx": "f91cecf1de23abec0b7b571b02516643206ba2b27f7cb37cd8b941f2588229dd", - "frontend-modern/src/features/storageBackups/detailPresentation.ts": "6dd2da6052aa37e6cfe2488356a296c578c26f7aed3ee8e49f6a5362135b34e7" + "frontend-modern/src/components/Infrastructure/AvailabilityProbeStatusCard.tsx": "2d991718c178866ba5bd7d1b89e7a1a9bec6fcd30133bc2fd549aa2fd3ccf4e5", + "frontend-modern/src/components/Infrastructure/ResourceDetailDrawerOverviewTab.tsx": "ac68e2e7f5d954ca5bd23b44f347817ce9a39414ab493d22ad52340ceb3296e2", + "frontend-modern/src/components/Workloads/AvailabilityProbeSuggestionCard.tsx": "a8c549b1284befee652c9ecc79c3c449602d1a102f3867acb81f4a5c9f5fd042", + "frontend-modern/src/features/docker/DockerHostDrawerOverview.tsx": "ab63fba8e1a06cb5951e0d3dc637d92ef371f2b5db5da2dfb80408cd477c0ea5" }, - "routes": ["/standalone/machines", "/proxmox/storage"], + "routes": ["/standalone/availability", "/proxmox/backups/date", "/docker/overview"], "viewports": [ { "width": 1920, "height": 800 }, { "width": 390, "height": 844 } ], "states": [ - "Apollo-114 expanded with Platform details and Machine details visible", - "west-f-service-pool expanded with Configuration and ZFS Pool cards visible" + "Solar inverter web panel expanded with availability facts visible", + "backup-vault expanded with Platform details and PBS service facts visible", + "auth-service-01 expanded on Manage with Container updates visible" ], "interactions": [ - "expanded the Apollo-114 row, opened Platform details, and revealed the nested Machine details", - "confirmed System, Hardware, Disks, and temperature facts use an adjacent fixed label track at 1920px", - "confirmed machine facts retain condensed right-aligned values and clean wrapping at 390px", - "expanded west-f-service-pool and confirmed Configuration values sit adjacent to their labels at 1920px", - "confirmed storage Configuration values retain condensed right alignment and clean wrapping at 390px", - "reloaded the phone machine route and repeated the complete disclosure interaction" + "expanded the Solar inverter web panel and confirmed desktop availability values use an adjacent fixed label track", + "confirmed availability facts retain condensed right-aligned values and clean wrapping at 390px", + "expanded backup-vault, opened Platform details, and revealed the PBS service section", + "confirmed PBS service facts use adjacent desktop values and retain compact mobile alignment", + "expanded auth-service-01, selected Manage, and confirmed Container updates facts use adjacent desktop values", + "confirmed Docker management facts retain condensed right alignment at 390px" ] } diff --git a/frontend-modern/scripts/shared-template-registry.json b/frontend-modern/scripts/shared-template-registry.json index a697ac9c0..13a0f3426 100644 --- a/frontend-modern/scripts/shared-template-registry.json +++ b/frontend-modern/scripts/shared-template-registry.json @@ -466,6 +466,7 @@ { "path": "src/components/shared/cards/RootDiskCard.tsx" }, { "path": "src/components/shared/cards/SystemInfoCard.tsx" }, { "path": "src/components/shared/cards/TemperaturesCard.tsx" }, + { "path": "src/components/Workloads/AvailabilityProbeSuggestionCard.tsx" }, { "path": "src/components/Workloads/DrawerDiskListCard.tsx" }, { "path": "src/features/docker/DockerHostDrawerOverview.tsx" }, { "path": "src/features/storageBackups/detailPresentation.ts" } diff --git a/frontend-modern/src/components/Infrastructure/AvailabilityProbeStatusCard.tsx b/frontend-modern/src/components/Infrastructure/AvailabilityProbeStatusCard.tsx index e4144e020..f16bffbfe 100644 --- a/frontend-modern/src/components/Infrastructure/AvailabilityProbeStatusCard.tsx +++ b/frontend-modern/src/components/Infrastructure/AvailabilityProbeStatusCard.tsx @@ -2,7 +2,7 @@ import { For, Show, createMemo } from 'solid-js'; import { Activity, AlertCircle, Check } from 'lucide-solid'; import type { ResourceAvailabilityMeta } from '@/types/resource'; -import { InfoCardFrame } from '@/components/shared/InfoCardFrame'; +import { InfoCardFrame, InfoCardKeyValueRow } from '@/components/shared/InfoCardFrame'; import { getAvailabilityProbeMethodLabel, getAvailabilityProbeEndpointLabel, @@ -129,130 +129,111 @@ export function AvailabilityProbeStatusCard(props: AvailabilityProbeStatusCardPr
-
- Latency - —} - > - } > - {latency()} - - -
-
- Method - - {method()} - -
-
- Target - - {targetAddr()} - -
+ + {latency()} + + + } + /> + + -
- Checked - {lastChecked()} -
+
-
- Freshness - - {presentation()?.freshnessLabel ?? 'freshness unknown'} - -
+ {(label) => ( -
- Resource - {label()} -
+ )}
{(cert) => (
-
- Certificate - - {certificateTrust().label} - -
+ -
- Subject - - {cert().subject} - -
+
{(expiry) => ( -
- Expires - - {expiry()} - -
+ )}
-
- Hostname - - {cert().hostnameValid ? 'Matches' : 'Mismatch'} - -
+ -
- Issuer - - {cert().issuer} - -
+
{(fingerprint) => ( -
- SHA-256 - - {fingerprint().slice(0, 16)}… - -
+ )}
diff --git a/frontend-modern/src/components/Infrastructure/ResourceDetailDrawerOverviewTab.tsx b/frontend-modern/src/components/Infrastructure/ResourceDetailDrawerOverviewTab.tsx index 814e3f640..9f84d2b00 100644 --- a/frontend-modern/src/components/Infrastructure/ResourceDetailDrawerOverviewTab.tsx +++ b/frontend-modern/src/components/Infrastructure/ResourceDetailDrawerOverviewTab.tsx @@ -18,7 +18,7 @@ import { RaidCard } from '@/components/shared/cards/RaidCard'; import { DiscoveryTab } from '@/components/Discovery/DiscoveryTab'; import { DiscoveryLoadingFallback } from '@/components/shared/DiscoveryLoadingFallback'; import { FormSelect } from '@/components/shared/FormSelect'; -import { InfoCardFrame } from '@/components/shared/InfoCardFrame'; +import { InfoCardFrame, InfoCardKeyValueRow } from '@/components/shared/InfoCardFrame'; import { WebInterfaceUrlField } from '@/components/shared/WebInterfaceUrlField'; import { WEB_INTERFACE_LINK_COLOR_CLASS, @@ -575,31 +575,27 @@ export const ResourceDetailDrawerOverviewTab: Component{sourceTypePresentation.label}
-
- Confidence - - {formatConfidenceLabel(change.confidence)} - -
-
- Adapter - - {sourceAdapterPresentation?.label || '—'} - -
+ + -
- Actor - {change.actor} -
+
-
- Transition - - {change.from || '—'} → {change.to || '—'} - -
+
@@ -726,27 +722,24 @@ export const ResourceDetailDrawerOverviewTab: Component
-
- Containers - - {formatInteger(drawer.dockerContainerCount())} - -
-
- Updates - 0 ? 'text-sky-700 dark:text-sky-300' : 'text-base-content'}`} - > - {formatInteger(drawer.dockerUpdatesAvailable())} - -
+ + 0 + ? 'text-sky-700 dark:text-sky-300' + : '' + } + /> -
- Checked - - {drawer.dockerUpdatesCheckedRelative()} - -
+
@@ -758,24 +751,24 @@ export const ResourceDetailDrawerOverviewTab: Component
-
- Action - - {formatIdentifierLabel(drawer.dockerHostCommand()?.type, { - fallback: 'command', - })} - -
-
- State - - {formatIdentifierLabel(drawer.dockerHostCommand()?.status, { - fallback: 'unknown', - })} - -
+ +
-
- State - - {connection.label} - -
+ -
- Version - {pbs().version} -
+
-
- Uptime - - {formatUptime(pbs().uptimeSeconds ?? resource.uptime ?? 0)} - -
+
0}> -
- Active tasks - - {formatInteger(drawer.pbsActiveTaskCount())} - -
+
@@ -1141,25 +1127,19 @@ export const ResourceDetailDrawerOverviewTab: Component
-
- State - - {connection.label} - -
+ -
- Version - {pmg().version} -
+
-
- Uptime - - {formatUptime(pmg().uptimeSeconds ?? resource.uptime ?? 0)} - -
+
@@ -1187,22 +1167,21 @@ export const ResourceDetailDrawerOverviewTab: Component -
- Nodes - - {formatInteger(pmg().nodeCount)} - -
+
-
- Updated - - {drawer.pmgUpdatedRelative()} - -
+
@@ -1213,14 +1192,13 @@ export const ResourceDetailDrawerOverviewTab: Component {(entry) => ( -
- {entry.label} - - {formatInteger(entry.value)} - -
+ )}
@@ -1232,12 +1210,10 @@ export const ResourceDetailDrawerOverviewTab: Component {(entry) => ( -
- {entry.label} - - {formatInteger(entry.value)} - -
+ )}
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 7ee1fd8ca..5753f8901 100644 --- a/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.history.test.tsx +++ b/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.history.test.tsx @@ -802,6 +802,12 @@ describe('ResourceDetailDrawer change history section', () => { expect(panel.getByText('Routine restart requested')).toBeInTheDocument(); expect(panel.getByText('Confidence')).toBeInTheDocument(); expect(panel.getByText('Adapter')).toBeInTheDocument(); + expect(panel.getByText('Confidence').parentElement).toHaveClass( + 'justify-between', + 'lg:grid', + 'lg:grid-cols-[7rem_minmax(0,1fr)]', + ); + expect(panel.getByText('High')).toHaveClass('text-right', 'lg:text-left'); expect(panel.getByText('Metadata')).toBeInTheDocument(); expect(panel.getByText(/"ticket": "INC-1234"/)).toBeInTheDocument(); expect(panel.queryByText('Capabilities')).toBeNull(); diff --git a/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.service-cards.test.tsx b/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.service-cards.test.tsx index e702469b1..5ef3e9ff4 100644 --- a/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.service-cards.test.tsx +++ b/frontend-modern/src/components/Infrastructure/__tests__/ResourceDetailDrawer.service-cards.test.tsx @@ -113,6 +113,12 @@ describe('ResourceDetailDrawer service cards', () => { expect(serviceDetails.queryByText('Connection')).toBeNull(); expect(serviceDetails.getAllByText('State').length).toBeGreaterThan(0); expect(serviceDetails.getAllByText('pbs-main.local').length).toBeGreaterThan(0); + expect(serviceDetails.getByText('State').parentElement).toHaveClass( + 'justify-between', + 'lg:grid', + 'lg:grid-cols-[7rem_minmax(0,1fr)]', + ); + expect(serviceDetails.getByText('Healthy')).toHaveClass('text-right', 'lg:text-left'); expect(queryByText('Backup summary')).toBeNull(); expect(queryByText('Job breakdown')).toBeNull(); expect(queryByText('Types')).toBeNull(); @@ -307,6 +313,12 @@ describe('ResourceDetailDrawer service cards', () => { expect(serviceDetails.queryByText('Connection')).toBeNull(); expect(serviceDetails.getAllByText('State').length).toBeGreaterThan(0); expect(serviceDetails.getAllByText('pmg-main.local').length).toBeGreaterThan(0); + expect(serviceDetails.getByText('State').parentElement).toHaveClass( + 'justify-between', + 'lg:grid', + 'lg:grid-cols-[7rem_minmax(0,1fr)]', + ); + expect(serviceDetails.getByText('Healthy')).toHaveClass('text-right', 'lg:text-left'); expect(queryByText('Mail flow summary')).toBeNull(); expect(queryByText('Queue breakdown')).toBeNull(); expect(queryByText('Mail processing')).toBeNull(); @@ -384,6 +396,11 @@ describe('ResourceDetailDrawer service cards', () => { expect(getByText('18 containers · 4 updates')).toBeInTheDocument(); fireEvent.click(getByRole('button', { name: 'Show service' })); expect(getByText('Docker runtime')).toBeInTheDocument(); + expect(getByText('Containers').parentElement).toHaveClass( + 'justify-between', + 'lg:grid', + 'lg:grid-cols-[7rem_minmax(0,1fr)]', + ); expect(queryByText('Container Updates')).toBeNull(); expect(queryByText('Check now')).toBeNull(); expect(queryByText('Show update controls')).toBeNull(); diff --git a/frontend-modern/src/components/Workloads/AvailabilityProbeSuggestionCard.tsx b/frontend-modern/src/components/Workloads/AvailabilityProbeSuggestionCard.tsx index c8d549c16..f2e3dedcb 100644 --- a/frontend-modern/src/components/Workloads/AvailabilityProbeSuggestionCard.tsx +++ b/frontend-modern/src/components/Workloads/AvailabilityProbeSuggestionCard.tsx @@ -7,7 +7,7 @@ import { type AvailabilityTarget, } from '@/api/availabilityTargets'; import type { AvailabilityProbeSuggestion } from '@/types/discovery'; -import { InfoCardFrame } from '@/components/shared/InfoCardFrame'; +import { InfoCardFrame, InfoCardKeyValueRow } from '@/components/shared/InfoCardFrame'; interface AvailabilityProbeSuggestionCardProps { suggestion: AvailabilityProbeSuggestion; @@ -64,28 +64,19 @@ export function AvailabilityProbeSuggestionCard(props: AvailabilityProbeSuggesti
-
- Service - - {props.suggestion.service_name} - -
-
- Probe - {protocolLabel()} -
-
- Target - - {props.suggestion.address} - -
+ + +
{error()}
diff --git a/frontend-modern/src/components/Workloads/__tests__/AvailabilityProbeStatusCard.test.tsx b/frontend-modern/src/components/Workloads/__tests__/AvailabilityProbeStatusCard.test.tsx index e9797623d..89c591e98 100644 --- a/frontend-modern/src/components/Workloads/__tests__/AvailabilityProbeStatusCard.test.tsx +++ b/frontend-modern/src/components/Workloads/__tests__/AvailabilityProbeStatusCard.test.tsx @@ -21,6 +21,12 @@ describe('AvailabilityProbeStatusCard', () => { expect(screen.getByText('Not checked')).toBeInTheDocument(); expect(screen.queryByText('Down')).not.toBeInTheDocument(); expect(screen.getByText('freshness unknown')).toBeInTheDocument(); + expect(screen.getByText('Latency').parentElement).toHaveClass( + 'justify-between', + 'lg:grid', + 'lg:grid-cols-[7rem_minmax(0,1fr)]', + ); + expect(screen.getByText('freshness unknown')).toHaveClass('text-right', 'lg:text-left'); }); it('shows stale evidence and an unresolved canonical resource link', () => { diff --git a/frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts b/frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts index a74750013..6364fec79 100644 --- a/frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts +++ b/frontend-modern/src/components/shared/SharedPrimitives.guardrails.test.ts @@ -1171,6 +1171,7 @@ describe('shared primitive guardrails', () => { 'src/components/shared/cards/RootDiskCard.tsx', 'src/components/shared/cards/SystemInfoCard.tsx', 'src/components/shared/cards/TemperaturesCard.tsx', + 'src/components/Workloads/AvailabilityProbeSuggestionCard.tsx', 'src/components/Workloads/DrawerDiskListCard.tsx', 'src/features/docker/DockerHostDrawerOverview.tsx', 'src/features/storageBackups/detailPresentation.ts', @@ -1233,6 +1234,19 @@ describe('shared primitive guardrails', () => { expect(source).toContain('InfoCardKeyValueRow'); expect(source).not.toContain('flex items-center justify-between'); } + + for (const consumerPath of [ + 'src/components/Infrastructure/AvailabilityProbeStatusCard.tsx', + 'src/components/Infrastructure/ResourceDetailDrawerOverviewTab.tsx', + 'src/components/Workloads/AvailabilityProbeSuggestionCard.tsx', + 'src/features/docker/DockerHostDrawerOverview.tsx', + ]) { + const source = readFrontendSource(consumerPath); + expect(source).toContain('InfoCardKeyValueRow'); + expect(source).not.toMatch( + /class="flex items-(?:center|start) justify-between gap-2">\s*/, + ); + } }); it('keeps shared subtabs as one primitive and leaves shell styling to owning surfaces', () => { diff --git a/frontend-modern/src/features/docker/DockerHostDrawerOverview.tsx b/frontend-modern/src/features/docker/DockerHostDrawerOverview.tsx index 9458063fb..44ec32a69 100644 --- a/frontend-modern/src/features/docker/DockerHostDrawerOverview.tsx +++ b/frontend-modern/src/features/docker/DockerHostDrawerOverview.tsx @@ -5,7 +5,7 @@ import { type DrawerDiskListItem, } from '@/components/Workloads/DrawerDiskListCard'; import { AvailabilityProbeStatusCards } from '@/components/Infrastructure/AvailabilityProbeStatusCard'; -import { InfoCardFrame } from '@/components/shared/InfoCardFrame'; +import { InfoCardFrame, InfoCardKeyValueRow } from '@/components/shared/InfoCardFrame'; import { TechnicalDetailsSection } from '@/components/shared/TechnicalDetailsDisclosure'; import { DrawerAttentionSection } from '@/components/shared/DrawerAttentionSection'; import { @@ -99,32 +99,19 @@ export function DockerHostDrawerManagement(props: DockerHostDrawerOverviewProps) Container updates
-
- Available - {updatesAvailable()} -
+ {(timestamp) => ( -
- Last checked - {formatRelativeTime(timestamp)} -
+ )}
-
- - {titleCase(cleanText(hostCommand()?.type).replace(/_/g, ' ') || 'Command')} - - - {titleCase(cleanText(hostCommand()?.status).replace(/_/g, ' ') || 'unknown')} - -
+