From 7007a8aa664d69cdd6a5a2d3173b2408b076252b Mon Sep 17 00:00:00 2001 From: Kacper Date: Wed, 24 Dec 2025 01:53:40 +0100 Subject: [PATCH] feat: Add ConfirmDialog component and integrate into GitHubIssuesView - Introduced a new ConfirmDialog component for user confirmation prompts. - Integrated ConfirmDialog into GitHubIssuesView to confirm re-validation of issues, enhancing user interaction and decision-making. - Updated handleValidateIssue function to support re-validation options, improving flexibility in issue validation handling. --- apps/ui/src/components/ui/confirm-dialog.tsx | 83 +++++++++++++++++++ .../components/views/github-issues-view.tsx | 36 ++++++-- 2 files changed, 114 insertions(+), 5 deletions(-) create mode 100644 apps/ui/src/components/ui/confirm-dialog.tsx diff --git a/apps/ui/src/components/ui/confirm-dialog.tsx b/apps/ui/src/components/ui/confirm-dialog.tsx new file mode 100644 index 00000000..28570d1a --- /dev/null +++ b/apps/ui/src/components/ui/confirm-dialog.tsx @@ -0,0 +1,83 @@ +import type { ReactNode } from 'react'; +import { LucideIcon } from 'lucide-react'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; +import { Button } from '@/components/ui/button'; +import { HotkeyButton } from '@/components/ui/hotkey-button'; + +interface ConfirmDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; + onConfirm: () => void; + title: string; + description: string; + /** Optional icon to show in the title */ + icon?: LucideIcon; + /** Icon color class. Defaults to "text-primary" */ + iconClassName?: string; + /** Optional content to show between description and buttons */ + children?: ReactNode; + /** Text for the confirm button. Defaults to "Confirm" */ + confirmText?: string; + /** Text for the cancel button. Defaults to "Cancel" */ + cancelText?: string; + /** Variant for the confirm button. Defaults to "default" */ + confirmVariant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link'; +} + +export function ConfirmDialog({ + open, + onOpenChange, + onConfirm, + title, + description, + icon: Icon, + iconClassName = 'text-primary', + children, + confirmText = 'Confirm', + cancelText = 'Cancel', + confirmVariant = 'default', +}: ConfirmDialogProps) { + const handleConfirm = () => { + onConfirm(); + onOpenChange(false); + }; + + return ( + + + + + {Icon && } + {title} + + {description} + + + {children} + + + + + {Icon && } + {confirmText} + + + + + ); +} diff --git a/apps/ui/src/components/views/github-issues-view.tsx b/apps/ui/src/components/views/github-issues-view.tsx index 0ffbc10f..1da8dc3c 100644 --- a/apps/ui/src/components/views/github-issues-view.tsx +++ b/apps/ui/src/components/views/github-issues-view.tsx @@ -42,6 +42,7 @@ function getFeaturePriority(complexity: IssueComplexity | undefined): number { import { useAppStore } from '@/store/app-store'; import { Button } from '@/components/ui/button'; import { Markdown } from '@/components/ui/markdown'; +import { ConfirmDialog } from '@/components/ui/confirm-dialog'; import { cn } from '@/lib/utils'; import { toast } from 'sonner'; import { ValidationDialog } from './github-issues-view/validation-dialog'; @@ -60,6 +61,8 @@ export function GitHubIssuesView() { const [cachedValidations, setCachedValidations] = useState>( new Map() ); + // Track revalidation confirmation dialog + const [showRevalidateConfirm, setShowRevalidateConfirm] = useState(false); const audioRef = useRef(null); const { currentProject, validationModel, muteDoneSound } = useAppStore(); @@ -246,7 +249,12 @@ export function GitHubIssuesView() { }, []); const handleValidateIssue = useCallback( - async (issue: GitHubIssue, showDialog = true) => { + async ( + issue: GitHubIssue, + options: { showDialog?: boolean; forceRevalidate?: boolean } = {} + ) => { + const { showDialog = true, forceRevalidate = false } = options; + if (!currentProject?.path) { toast.error('No project selected'); return; @@ -258,9 +266,9 @@ export function GitHubIssuesView() { return; } - // Check for cached result - if fresh, show it directly + // Check for cached result - if fresh, show it directly (unless force revalidate) const cached = cachedValidations.get(issue.number); - if (cached && showDialog) { + if (cached && showDialog && !forceRevalidate) { // Check if validation is stale (older than 24 hours) const validatedAt = new Date(cached.validatedAt); const hoursSinceValidation = (Date.now() - validatedAt.getTime()) / (1000 * 60 * 60); @@ -568,7 +576,7 @@ export function GitHubIssuesView() {