diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md index 91e054936..5a2efdc11 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 da980c9eb..91072ee1a 100644 --- a/frontend-modern/browser-verification.json +++ b/frontend-modern/browser-verification.json @@ -1,34 +1,36 @@ { "version": 1, - "base_sha": "636367e96ee97ce56c7b1353635236a418a3922c", - "verified_at": "2026-08-27T19:10:47Z", + "base_sha": "b0c1eca4cdace3cb798a77b2fa0c01a220f76981", + "verified_at": "2026-08-27T19:35:10Z", "result": "passed", "changed_paths": [ - "frontend-modern/src/features/alerts/AlertEscalationSection.tsx", - "frontend-modern/src/features/alerts/helpers.ts", - "frontend-modern/src/features/alerts/useAlertScheduleState.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/features/alerts/AlertEscalationSection.tsx": "f80f94d529196fffb4e184288c5ce9369f673bc8cabc0eb2047ebc10b7dfe363", - "frontend-modern/src/features/alerts/helpers.ts": "27feef6ede9bdb6668af5c447c5b9256f019b8df5a291ae8b5d436d371363794", - "frontend-modern/src/features/alerts/useAlertScheduleState.ts": "84ec18253c926be70d941daf5b56bf045cf372ded5026033849d38f76c23e84f" + "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": ["/alerts/schedule"], + "routes": ["/standalone/availability", "/proxmox/backups/date", "/docker/overview"], "viewports": [ - { "width": 1280, "height": 720 }, + { "width": 1920, "height": 800 }, { "width": 390, "height": 844 } ], "states": [ - "alert escalation enabled with one level and selected disabled destinations visible", - "level delay normalized to the 5 minute lower bound", - "level delay normalized to the 180 minute upper bound", - "upper-bound level retained in the narrow layout without horizontal overflow" + "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": [ - "enabled alert escalation and added an escalation level", - "entered 0 minutes and blurred the field, confirming it normalized to 5", - "entered 999 minutes and blurred the field, confirming it normalized to 180", - "resized from desktop to 390px and confirmed zero document-level horizontal overflow", - "confirmed the browser console contained no warnings or errors" + "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')} - -
+