better conflict handling in the frontend app for merge contlicts (better UX)
This commit is contained in:
@@ -227,28 +227,26 @@ export function TaskReview({
|
||||
<Eye className="mr-2 h-4 w-4" />
|
||||
View Changes
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
console.log('[TaskReview] Check Conflicts button clicked');
|
||||
onLoadMergePreview();
|
||||
}}
|
||||
disabled={isLoadingPreview}
|
||||
className="flex-1"
|
||||
>
|
||||
{isLoadingPreview ? (
|
||||
<>
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
Checking...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Search className="mr-2 h-4 w-4" />
|
||||
Check Conflicts
|
||||
</>
|
||||
)}
|
||||
</Button>
|
||||
{/* Refresh conflicts button - conflicts are auto-loaded but user can refresh */}
|
||||
{mergePreview && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
console.log('[TaskReview] Refresh conflicts clicked');
|
||||
onLoadMergePreview();
|
||||
}}
|
||||
disabled={isLoadingPreview}
|
||||
className="flex-none"
|
||||
title="Refresh conflict check"
|
||||
>
|
||||
{isLoadingPreview ? (
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<RotateCcw className="h-4 w-4" />
|
||||
)}
|
||||
</Button>
|
||||
)}
|
||||
{worktreeStatus.worktreePath && (
|
||||
<Button
|
||||
variant="outline"
|
||||
@@ -260,12 +258,21 @@ export function TaskReview({
|
||||
});
|
||||
}}
|
||||
className="flex-none"
|
||||
title="Open worktree in terminal"
|
||||
>
|
||||
<ExternalLink className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Loading indicator while checking conflicts */}
|
||||
{isLoadingPreview && !mergePreview && (
|
||||
<div className="flex items-center gap-2 text-muted-foreground text-sm mb-3">
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
Checking for conflicts...
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Merge Preview Summary */}
|
||||
{mergePreview && (
|
||||
<div className={cn(
|
||||
@@ -643,10 +650,10 @@ export function TaskReview({
|
||||
onShowConflictDialog(false);
|
||||
onMerge();
|
||||
}}
|
||||
className="bg-primary"
|
||||
className="bg-warning text-warning-foreground hover:bg-warning/90"
|
||||
>
|
||||
<GitMerge className="mr-2 h-4 w-4" />
|
||||
{stageOnly ? 'Stage Anyway' : 'Merge Anyway'}
|
||||
{stageOnly ? 'Stage with AI Merge' : 'Merge with AI'}
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
|
||||
@@ -191,9 +191,7 @@ export function useTaskDetail({ task }: UseTaskDetailOptions) {
|
||||
const previewData = JSON.parse(stored);
|
||||
console.log('%c[useTaskDetail] Restored merge preview from sessionStorage:', 'color: magenta;', previewData);
|
||||
setMergePreview(previewData);
|
||||
if (previewData.conflicts?.length > 0) {
|
||||
setShowConflictDialog(true);
|
||||
}
|
||||
// Don't auto-popup - restored data stays silent
|
||||
} catch (e) {
|
||||
console.warn('[useTaskDetail] Failed to parse stored merge preview');
|
||||
sessionStorage.removeItem(storageKey);
|
||||
@@ -218,10 +216,7 @@ export function useTaskDetail({ task }: UseTaskDetailOptions) {
|
||||
setMergePreview(previewData);
|
||||
// Persist to sessionStorage to survive HMR reloads
|
||||
sessionStorage.setItem(`mergePreview-${task.id}`, JSON.stringify(previewData));
|
||||
// Show conflict dialog if there are conflicts that need attention
|
||||
if (previewData.conflicts.length > 0) {
|
||||
setShowConflictDialog(true);
|
||||
}
|
||||
// Don't auto-popup conflict dialog - let user click to see details if curious
|
||||
} else {
|
||||
console.warn('%c[useTaskDetail] Preview not successful or no preview data:', 'color: orange;', result);
|
||||
console.warn(' - success:', result.success);
|
||||
@@ -236,6 +231,20 @@ export function useTaskDetail({ task }: UseTaskDetailOptions) {
|
||||
}
|
||||
}, [task.id]);
|
||||
|
||||
// Auto-load merge preview when worktree is ready (eliminates need to click "Check Conflicts")
|
||||
// NOTE: This must be placed AFTER loadMergePreview definition since it depends on that callback
|
||||
useEffect(() => {
|
||||
// Only auto-load if:
|
||||
// 1. Task needs review
|
||||
// 2. Worktree exists
|
||||
// 3. We haven't already loaded the preview
|
||||
// 4. We're not currently loading
|
||||
if (needsReview && worktreeStatus?.exists && !mergePreview && !isLoadingPreview) {
|
||||
console.log('[useTaskDetail] Auto-loading merge preview for task:', task.id);
|
||||
loadMergePreview();
|
||||
}
|
||||
}, [needsReview, worktreeStatus?.exists, mergePreview, isLoadingPreview, task.id, loadMergePreview]);
|
||||
|
||||
return {
|
||||
// State
|
||||
feedback,
|
||||
|
||||
Reference in New Issue
Block a user