From 46b3d5327406c20294e77309d678c87c3cd76061 Mon Sep 17 00:00:00 2001 From: Anso Date: Mon, 4 May 2026 11:53:35 -0400 Subject: [PATCH] refactor(frontend): migrate diff dialogs to Modal chrome (D-5) (#909) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor(frontend): extend Modal size system with wide variant Adds 'wide' (max-w-5xl w-[95vw]) to ModalSize for dialogs that render Monaco DiffEditor side-by-side, which need ~1024px to display both panels clearly. The existing 'xl' cap at max-w-xl (576px) is too narrow for that use case. * refactor(frontend): migrate ComposeDiffPreviewDialog to Modal chrome (D-5) Replaces raw Dialog/DialogHeader/DialogFooter with Modal size="wide", ModalHeader, and ModalFooter. Kicker carries the stack name and file type context; title is the file name (accessible dialog name for tests). Footer hint reuses the existing "ON DISK → UNSAVED" label via the hint prop. * refactor(frontend): migrate GitSourceDiffDialog to Modal chrome (D-5) Replaces Dialog + nested AlertDialog with Modal size="wide", ModalHeader, ModalFooter, and ConfirmModal. Kicker is "GIT · PULL PREVIEW"; title is the stack name. Short SHA moves to the sr-only description. The "Deploy after apply" checkbox in the footer hint slot uses normal-case and tracking-normal on the Label to prevent KICKER_CLASS uppercase/tracking from being inherited. The overwrite confirmation uses ConfirmModal with variant="destructive" (rose rail) since it replaces local file content. --- .../components/ComposeDiffPreviewDialog.tsx | 120 ++++----- .../components/stack/GitSourceDiffDialog.tsx | 232 +++++++++--------- frontend/src/components/ui/modal.tsx | 3 +- 3 files changed, 167 insertions(+), 188 deletions(-) diff --git a/frontend/src/components/ComposeDiffPreviewDialog.tsx b/frontend/src/components/ComposeDiffPreviewDialog.tsx index 8e632ad6..b1cefbc5 100644 --- a/frontend/src/components/ComposeDiffPreviewDialog.tsx +++ b/frontend/src/components/ComposeDiffPreviewDialog.tsx @@ -1,14 +1,7 @@ import { Suspense } from 'react'; import { DiffEditor } from '@/lib/monacoLoader'; -import { FileDiff, Loader2 } from 'lucide-react'; -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogDescription, - DialogFooter, -} from '@/components/ui/dialog'; +import { Loader2 } from 'lucide-react'; +import { Modal, ModalHeader, ModalFooter } from '@/components/ui/modal'; import { Button } from '@/components/ui/button'; export interface ComposeDiffPreviewDialogProps { @@ -39,65 +32,60 @@ export function ComposeDiffPreviewDialog({ onConfirm, }: ComposeDiffPreviewDialogProps) { return ( - - - - - - Review changes to {stackName} - {fileName} - - - Review the diff between on-disk content and unsaved editor changes before saving. - - + + -
-
- }> - - -
+
+
+ }> + +
+
- - ON DISK → UNSAVED -
- - -
-
- -
+ onOpenChange(false)} + disabled={confirming} + > + Cancel + + } + primary={ + + } + /> + ); } diff --git a/frontend/src/components/stack/GitSourceDiffDialog.tsx b/frontend/src/components/stack/GitSourceDiffDialog.tsx index 5188c462..935b3095 100644 --- a/frontend/src/components/stack/GitSourceDiffDialog.tsx +++ b/frontend/src/components/stack/GitSourceDiffDialog.tsx @@ -1,8 +1,7 @@ import { useState, Suspense } from 'react'; import { DiffEditor } from '@/lib/monacoLoader'; -import { AlertTriangle, GitBranch, Loader2 } from 'lucide-react'; -import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from '@/components/ui/dialog'; -import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle } from '@/components/ui/alert-dialog'; +import { AlertTriangle, Loader2 } from 'lucide-react'; +import { Modal, ModalHeader, ModalFooter, ConfirmModal } from '@/components/ui/modal'; import { Tabs, TabsList, TabsTrigger, TabsHighlight, TabsHighlightItem } from '@/components/ui/tabs'; import { Button } from '@/components/ui/button'; import { Checkbox } from '@/components/ui/checkbox'; @@ -72,79 +71,73 @@ export function GitSourceDiffDialog({ return ( <> - - - - - - Review update for - {stackName} - @{shortSha} - - - Review the diff between the current on-disk stack files and the incoming Git commit. - - + + -
- {!pull.validation.ok && ( -
- -
-

Incoming compose failed validation

-
{pull.validation.error}
-
+
+ {!pull.validation.ok && ( +
+ +
+

Incoming compose failed validation

+
{pull.validation.error}
- )} - {pull.hasLocalChanges && ( -
- -
-

Local edits detected on disk

-

Applying will overwrite changes that differ from the last applied commit.

-
-
- )} - - {envAvailable && ( - setDiffTab(v as 'compose' | 'env')}> - - - - compose.yaml - - - .env - - - - - )} -
- -
-
- }> - -
-
+ )} + {pull.hasLocalChanges && ( +
+ +
+

Local edits detected on disk

+

Applying will overwrite changes that differ from the last applied commit.

+
+
+ )} - + {envAvailable && ( + setDiffTab(v as 'compose' | 'env')}> + + + + compose.yaml + + + .env + + + + + )} +
+ +
+
+ }> + + +
+
+ + setDeployAfter(checked === true)} disabled={applying || !pull.validation.ok} /> -
-
- - -
- - -
- - - - - Overwrite local edits? - - The on-disk stack files differ from the last applied commit. Applying this pull will replace them with the incoming content. - - - - Cancel - { - setConfirmOpen(false); - await apply(); - }} + } + secondary={ + + } + primary={ + + } + /> + + + { + setConfirmOpen(false); + await apply(); + }} + /> ); } diff --git a/frontend/src/components/ui/modal.tsx b/frontend/src/components/ui/modal.tsx index 6ccce8ac..566b791c 100644 --- a/frontend/src/components/ui/modal.tsx +++ b/frontend/src/components/ui/modal.tsx @@ -18,13 +18,14 @@ import { const KICKER_CLASS = 'font-mono text-[10px] uppercase tracking-[0.22em]'; -type ModalSize = 'sm' | 'md' | 'lg' | 'xl'; +type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'wide'; const SIZE_CLASS: Record = { sm: 'max-w-sm', md: 'max-w-md', lg: 'max-w-lg', xl: 'max-w-xl w-[95vw]', + wide: 'max-w-5xl w-[95vw]', }; interface ModalProps {