better conflict handling in the frontend app for merge contlicts (better UX)

This commit is contained in:
AndyMik90
2025-12-16 13:12:04 +01:00
parent b94eb6589b
commit 65937e198f
2 changed files with 47 additions and 31 deletions
@@ -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,