diff --git a/docs/release-control/v6/internal/subsystems/frontend-primitives.md b/docs/release-control/v6/internal/subsystems/frontend-primitives.md index 64a29fb4c..249f4ee1f 100644 --- a/docs/release-control/v6/internal/subsystems/frontend-primitives.md +++ b/docs/release-control/v6/internal/subsystems/frontend-primitives.md @@ -523,6 +523,10 @@ not a replacement status card, CTA band, or page-local nested card. Shared error-boundary fallback actions are also command buttons: reset, reload, and retry controls must compose `Button` so emergency UI does not become a separate local button vocabulary. + Update confirmation and progress modal actions are part of the same command + boundary: cancel, start, retry, close, history, reload-now, and close-icon + controls must compose `Button` or `ActionIconButton` instead of carrying + modal-local blue, neutral, or icon-button class strings. Compact icon-only row, inline, and floating action controls belong to `ActionIconButton`. Feature surfaces may own the icon choice, click handler, label text, and layout slot, but icon-button size, tone, focus ring, @@ -1372,6 +1376,10 @@ not a replacement status card, CTA band, or page-local nested card. notices are part of the same settings callout boundary: the editor and credential slots own the source-specific lifecycle or API meaning, while `CalloutCard` owns the warning/success/danger shell and compact density. + Update confirmation and progress modal notices share that same primitive + boundary. The update flow owns version, prerequisite, root-access, restart, + and error copy; `CalloutCard` owns the info/warning/danger shell, spacing, + dark-mode tone, and icon layout. 8. Keep hosted settings-shell framing imports safe for bundle initialization. Self-hosted billing titles, descriptions, and referral copy used by `settingsHeaderMeta.ts`, `settingsNavCatalog.ts`, and adjacent settings @@ -1786,6 +1794,9 @@ primitive internals such as `Button`, `PulseDataGrid`, and `HistoryChartOverlay`, as well as Login, Settings, Patrol, and AI finding surfaces; local `animate-spin` spinner shells in those consumers are governed by the shared-template registry rather than page-local discretion. +Update progress status indicators are included in that loading boundary: +progress-stage loading must compose `LoadingSpinner` rather than local spinner +SVGs. `DiscoveryLoadingFallback` owns the discovery-tab Suspense fallback row for resource, workload, and Docker host drawers: centered row layout, status semantics, discovery loading copy, and canonical `LoadingSpinner` composition @@ -3398,6 +3409,10 @@ Shared error-boundary fallbacks use the same boundary: the fallback owns error copy and reset/reload handlers, while `CalloutCard` owns danger tone, spacing, dark-mode styling, and alert layout instead of inline red panels or raw SVG alert glyphs. +Update confirmation and progress modals use the same shared boundary: the +modal flow owns update state and copy, while `CalloutCard`, `Button`, +`ActionIconButton`, `LoadingSpinner`, and lucide icons own the colored notice, +command, icon-only close, and status indicator chrome. Settings loading placeholders must route through the shared `SettingsLoadingSkeleton` primitive instead of local `animate-pulse` blocks. diff --git a/frontend-modern/scripts/shared-template-registry.json b/frontend-modern/scripts/shared-template-registry.json index 0b4d8b578..e9bb6213e 100644 --- a/frontend-modern/scripts/shared-template-registry.json +++ b/frontend-modern/scripts/shared-template-registry.json @@ -415,6 +415,48 @@ "scripts/shared-template-audit.mjs" ] }, + { + "id": "update-modal-action-callout-shell", + "category": "callout", + "summary": "Update confirmation and progress modals must compose CalloutCard, Button, ActionIconButton, LoadingSpinner, and library icons for shared status, warning, restart, and command chrome instead of recreating local colored panels, raw SVG glyphs, or modal-local button classes.", + "canonical": { + "path": "src/components/shared/CalloutCard.tsx", + "export": "CalloutCard" + }, + "requiredConsumers": [ + { "path": "src/components/UpdateConfirmationModal.tsx" }, + { "path": "src/components/UpdateProgressModal.tsx" } + ], + "forbiddenPatterns": [ + { + "path": "src/components/UpdateConfirmationModal.tsx", + "patterns": [ + " (props.isMajorUpgrade ? 'warning' : 'info'); + const warningTitle = () => + props.isMajorUpgrade && props.isPrerelease + ? 'Major Version Pre-Release' + : props.isMajorUpgrade + ? 'Major Version Upgrade' + : 'Pre-Release Build'; return (

Confirm Update

- +
{/* Body */}
{/* Version Jump */} -
-
- Version Update -
-
+ +
{props.currentVersion} - - - +
-
+ {/* Major version / pre-release warning */} -
-
- - - -
-

- {props.isMajorUpgrade && props.isPrerelease - ? 'Major Version Pre-Release' - : props.isMajorUpgrade - ? 'Major Version Upgrade' - : 'Pre-Release Build'} -

-

- {props.warning} -

-
-
-
+
{/* Estimated Time */}
- - - +
@@ -175,19 +116,10 @@ export function UpdateConfirmationModal(props: UpdateConfirmationModalProps) { {(prerequisite) => (
  • - - - +
  • )} @@ -198,42 +130,24 @@ export function UpdateConfirmationModal(props: UpdateConfirmationModalProps) { {/* Root Required Warning */} -
    -
    - - - -
    -
    Root access required
    -
    - This update requires elevated privileges to modify system files. -
    -
    -
    -
    +
    {/* Rollback Support */}
    - - - +
    @@ -258,39 +172,25 @@ export function UpdateConfirmationModal(props: UpdateConfirmationModalProps) { {/* Footer */}
    - - +
    diff --git a/frontend-modern/src/components/UpdateProgressModal.tsx b/frontend-modern/src/components/UpdateProgressModal.tsx index 5c397c7d4..277a886bb 100644 --- a/frontend-modern/src/components/UpdateProgressModal.tsx +++ b/frontend-modern/src/components/UpdateProgressModal.tsx @@ -1,6 +1,12 @@ import { createSignal, Show, onCleanup, createEffect } from 'solid-js'; import { UpdatesAPI, type UpdateStatus } from '@/api/updates'; +import AlertTriangleIcon from 'lucide-solid/icons/alert-triangle'; +import CheckCircleIcon from 'lucide-solid/icons/check-circle'; +import InfoIcon from 'lucide-solid/icons/info'; import { Dialog } from '@/components/shared/Dialog'; +import { ActionIconButton, Button } from '@/components/shared/Button'; +import { CalloutCard } from '@/components/shared/CalloutCard'; +import { LoadingSpinner } from '@/components/shared/LoadingSpinner'; import { ProgressBar } from '@/components/shared/ProgressBar'; import { apiFetch } from '@/utils/apiClient'; import { logger } from '@/utils/logger'; @@ -310,48 +316,14 @@ export function UpdateProgressModal(props: UpdateProgressModalProps) { if (!currentStatus) return null; if (hasError()) { - return ( - - - - ); + return