Make worktree isolation prominent in UI (#1020)

* auto-claude: subtask-1-1 - Add i18n translation keys for worktree notice banner and merge tooltip

- Added wizard.worktreeNotice.title and wizard.worktreeNotice.description for task creation banner
- Added review.mergeTooltip for merge button explanation
- Translations added to both en/tasks.json and fr/tasks.json

* auto-claude: subtask-1-2 - Add visible info banner to TaskCreationWizard expl

* auto-claude: subtask-1-3 - Add tooltip to 'Merge with AI' button in WorkspaceStatus

- Import Tooltip components from ui/tooltip
- Wrap merge button with Tooltip, TooltipTrigger, TooltipContent
- Add contextual tooltip text explaining merge operation:
  * With AI: explains worktree merge, removal, and AI conflict resolution
  * Without AI: explains worktree merge and removal
- Follows Radix UI tooltip pattern from reference file

* fix: use i18n key for merge button tooltip in WorkspaceStatus

* fix: clarify merge tooltip - worktree removal is optional (qa-requested)

Fixes misleading tooltip text that implied worktree is automatically removed
during merge. In reality, after merge, users are shown a dialog where they can
choose to keep or remove the worktree. Updated tooltip to reflect this flow.

Changes:
- Updated en/tasks.json: Changed tooltip to clarify worktree removal is optional
- Updated fr/tasks.json: Updated French translation to match

QA Feedback: "Its currently saying on the tooltip that it will 'remove the worktree'
Please validate if this is the actual logic. As per my understanding, there will be
an extra button afterwards that will make sure that the user has access to the work
tree if they want to revert anything. The user has to manually accept to remove the
work tree."

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>

* fix: use theme-aware colors for worktree info banner

Replace hardcoded blue colors with semantic theme classes to support
dark mode properly. Uses the same pattern as other info banners in
the codebase (bg-info/10, border-info/30, text-info).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Andy
2026-01-13 18:56:54 +01:00
committed by AndyMik90
parent d48e5f68ca
commit 4dbb7ee4ee
4 changed files with 65 additions and 28 deletions
@@ -12,7 +12,7 @@
*/
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Loader2, ChevronDown, ChevronUp, RotateCcw, FolderTree, GitBranch } from 'lucide-react';
import { Loader2, ChevronDown, ChevronUp, RotateCcw, FolderTree, GitBranch, Info } from 'lucide-react';
import { Button } from './ui/button';
import { Label } from './ui/label';
import {
@@ -521,6 +521,19 @@ export function TaskCreationWizard({
}
>
<div className="space-y-6">
{/* Worktree isolation info banner */}
<div className="flex items-start gap-3 p-4 bg-info/10 border border-info/30 rounded-lg">
<Info className="h-5 w-5 text-info flex-shrink-0 mt-0.5" />
<div className="flex-1 min-w-0">
<h4 className="text-sm font-medium text-foreground mb-1">
{t('tasks:wizard.worktreeNotice.title')}
</h4>
<p className="text-sm text-muted-foreground">
{t('tasks:wizard.worktreeNotice.description')}
</p>
</div>
</div>
{/* Main form fields */}
<TaskFormFields
description={description}
@@ -18,6 +18,7 @@ import {
import { useTranslation } from 'react-i18next';
import { Button } from '../../ui/button';
import { Checkbox } from '../../ui/checkbox';
import { Tooltip, TooltipContent, TooltipTrigger } from '../../ui/tooltip';
import { cn } from '../../../lib/utils';
import type { WorktreeStatus, MergeConflict, MergeStats, GitConflictInfo, SupportedIDE, SupportedTerminal } from '../../../../shared/types';
import { useSettingsStore } from '../../../stores/settings-store';
@@ -100,7 +101,7 @@ export function WorkspaceStatus({
onSwitchToTerminals,
onOpenInbuiltTerminal
}: WorkspaceStatusProps) {
const { t } = useTranslation(['taskReview', 'common']);
const { t } = useTranslation(['taskReview', 'common', 'tasks']);
const { settings } = useSettingsStore();
const preferredIDE = settings.preferredIDE || 'vscode';
const preferredTerminal = settings.preferredTerminal || 'system';
@@ -418,32 +419,41 @@ export function WorkspaceStatus({
{/* State 3: Merge preview loaded - show appropriate merge/stage button */}
{mergePreview && !isLoadingPreview && (
<Button
variant={hasGitConflicts || isBranchBehind || hasPathMappedMerges ? "warning" : "success"}
onClick={onMerge}
disabled={isMerging || isDiscarding}
className="flex-1"
>
{isMerging ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
{hasGitConflicts || isBranchBehind || hasPathMappedMerges
? t('taskReview:merge.buttons.resolving')
: stageOnly
? t('taskReview:merge.buttons.staging')
: t('taskReview:merge.buttons.merging')}
</>
) : (
<>
<GitMerge className="mr-2 h-4 w-4" />
{hasGitConflicts || isBranchBehind || hasPathMappedMerges
? (stageOnly ? t('taskReview:merge.buttons.stageWithAIMerge') : t('taskReview:merge.buttons.mergeWithAI'))
: (stageOnly
? t('taskReview:merge.buttons.stageTo', { branch: worktreeStatus.currentProjectBranch || worktreeStatus.baseBranch || 'main' })
: t('taskReview:merge.buttons.mergeTo', { branch: worktreeStatus.currentProjectBranch || worktreeStatus.baseBranch || 'main' }))}
</>
)}
</Button>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant={hasGitConflicts || isBranchBehind || hasPathMappedMerges ? "warning" : "success"}
onClick={onMerge}
disabled={isMerging || isDiscarding}
className="flex-1"
>
{isMerging ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
{hasGitConflicts || isBranchBehind || hasPathMappedMerges
? t('taskReview:merge.buttons.resolving')
: stageOnly
? t('taskReview:merge.buttons.staging')
: t('taskReview:merge.buttons.merging')}
</>
) : (
<>
<GitMerge className="mr-2 h-4 w-4" />
{hasGitConflicts || isBranchBehind || hasPathMappedMerges
? (stageOnly ? t('taskReview:merge.buttons.stageWithAIMerge') : t('taskReview:merge.buttons.mergeWithAI'))
: (stageOnly
? t('taskReview:merge.buttons.stageTo', { branch: worktreeStatus.currentProjectBranch || worktreeStatus.baseBranch || 'main' })
: t('taskReview:merge.buttons.mergeTo', { branch: worktreeStatus.currentProjectBranch || worktreeStatus.baseBranch || 'main' }))}
</>
)}
</Button>
</TooltipTrigger>
<TooltipContent>
<p className="max-w-xs">
{t('tasks:review.mergeTooltip')}
</p>
</TooltipContent>
</Tooltip>
)}
{/* Create PR Button */}
@@ -145,6 +145,10 @@
"browseFiles": "Browse Files",
"creating": "Creating...",
"createTask": "Create Task",
"worktreeNotice": {
"title": "Isolated Workspace",
"description": "This task runs in an isolated git worktree. Your main branch stays safe until you choose to merge."
},
"gitOptions": {
"title": "Git Options (optional)",
"baseBranchLabel": "Base Branch (optional)",
@@ -158,6 +162,9 @@
"createFailed": "Failed to create task. Please try again."
}
},
"review": {
"mergeTooltip": "Merges changes from the task's worktree branch back to your base branch. AI will resolve any conflicts. You can then choose whether to keep or remove the worktree."
},
"edit": {
"title": "Edit Task",
"description": "Update task details including title, description, classification, images, and settings. Changes will be saved to the spec files.",
@@ -145,6 +145,10 @@
"browseFiles": "Parcourir les fichiers",
"creating": "Création...",
"createTask": "Créer la tâche",
"worktreeNotice": {
"title": "Espace de travail isolé",
"description": "Cette tâche s'exécute dans un worktree git isolé. Votre branche principale reste protégée jusqu'à ce que vous choisissiez de fusionner."
},
"gitOptions": {
"title": "Options Git (optionnel)",
"baseBranchLabel": "Branche de base (optionnel)",
@@ -158,6 +162,9 @@
"createFailed": "Échec de la création de la tâche. Veuillez réessayer."
}
},
"review": {
"mergeTooltip": "Fusionne les changements de la branche worktree de la tâche vers votre branche de base. L'IA résoudra les conflits éventuels. Vous pourrez ensuite choisir de conserver ou de supprimer le worktree."
},
"edit": {
"title": "Modifier la tâche",
"description": "Mettez à jour les détails de la tâche, y compris le titre, la description, la classification, les images et les paramètres. Les modifications seront enregistrées dans les fichiers de spécification.",