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:
@@ -12,7 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
import { useState, useEffect, useCallback, useRef, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
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 { Button } from './ui/button';
|
||||||
import { Label } from './ui/label';
|
import { Label } from './ui/label';
|
||||||
import {
|
import {
|
||||||
@@ -521,6 +521,19 @@ export function TaskCreationWizard({
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="space-y-6">
|
<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 */}
|
{/* Main form fields */}
|
||||||
<TaskFormFields
|
<TaskFormFields
|
||||||
description={description}
|
description={description}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import {
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Button } from '../../ui/button';
|
import { Button } from '../../ui/button';
|
||||||
import { Checkbox } from '../../ui/checkbox';
|
import { Checkbox } from '../../ui/checkbox';
|
||||||
|
import { Tooltip, TooltipContent, TooltipTrigger } from '../../ui/tooltip';
|
||||||
import { cn } from '../../../lib/utils';
|
import { cn } from '../../../lib/utils';
|
||||||
import type { WorktreeStatus, MergeConflict, MergeStats, GitConflictInfo, SupportedIDE, SupportedTerminal } from '../../../../shared/types';
|
import type { WorktreeStatus, MergeConflict, MergeStats, GitConflictInfo, SupportedIDE, SupportedTerminal } from '../../../../shared/types';
|
||||||
import { useSettingsStore } from '../../../stores/settings-store';
|
import { useSettingsStore } from '../../../stores/settings-store';
|
||||||
@@ -100,7 +101,7 @@ export function WorkspaceStatus({
|
|||||||
onSwitchToTerminals,
|
onSwitchToTerminals,
|
||||||
onOpenInbuiltTerminal
|
onOpenInbuiltTerminal
|
||||||
}: WorkspaceStatusProps) {
|
}: WorkspaceStatusProps) {
|
||||||
const { t } = useTranslation(['taskReview', 'common']);
|
const { t } = useTranslation(['taskReview', 'common', 'tasks']);
|
||||||
const { settings } = useSettingsStore();
|
const { settings } = useSettingsStore();
|
||||||
const preferredIDE = settings.preferredIDE || 'vscode';
|
const preferredIDE = settings.preferredIDE || 'vscode';
|
||||||
const preferredTerminal = settings.preferredTerminal || 'system';
|
const preferredTerminal = settings.preferredTerminal || 'system';
|
||||||
@@ -418,32 +419,41 @@ export function WorkspaceStatus({
|
|||||||
|
|
||||||
{/* State 3: Merge preview loaded - show appropriate merge/stage button */}
|
{/* State 3: Merge preview loaded - show appropriate merge/stage button */}
|
||||||
{mergePreview && !isLoadingPreview && (
|
{mergePreview && !isLoadingPreview && (
|
||||||
<Button
|
<Tooltip>
|
||||||
variant={hasGitConflicts || isBranchBehind || hasPathMappedMerges ? "warning" : "success"}
|
<TooltipTrigger asChild>
|
||||||
onClick={onMerge}
|
<Button
|
||||||
disabled={isMerging || isDiscarding}
|
variant={hasGitConflicts || isBranchBehind || hasPathMappedMerges ? "warning" : "success"}
|
||||||
className="flex-1"
|
onClick={onMerge}
|
||||||
>
|
disabled={isMerging || isDiscarding}
|
||||||
{isMerging ? (
|
className="flex-1"
|
||||||
<>
|
>
|
||||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
{isMerging ? (
|
||||||
{hasGitConflicts || isBranchBehind || hasPathMappedMerges
|
<>
|
||||||
? t('taskReview:merge.buttons.resolving')
|
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||||
: stageOnly
|
{hasGitConflicts || isBranchBehind || hasPathMappedMerges
|
||||||
? t('taskReview:merge.buttons.staging')
|
? t('taskReview:merge.buttons.resolving')
|
||||||
: t('taskReview:merge.buttons.merging')}
|
: 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'))
|
<GitMerge className="mr-2 h-4 w-4" />
|
||||||
: (stageOnly
|
{hasGitConflicts || isBranchBehind || hasPathMappedMerges
|
||||||
? t('taskReview:merge.buttons.stageTo', { branch: worktreeStatus.currentProjectBranch || worktreeStatus.baseBranch || 'main' })
|
? (stageOnly ? t('taskReview:merge.buttons.stageWithAIMerge') : t('taskReview:merge.buttons.mergeWithAI'))
|
||||||
: t('taskReview:merge.buttons.mergeTo', { branch: worktreeStatus.currentProjectBranch || worktreeStatus.baseBranch || 'main' }))}
|
: (stageOnly
|
||||||
</>
|
? t('taskReview:merge.buttons.stageTo', { branch: worktreeStatus.currentProjectBranch || worktreeStatus.baseBranch || 'main' })
|
||||||
)}
|
: t('taskReview:merge.buttons.mergeTo', { branch: worktreeStatus.currentProjectBranch || worktreeStatus.baseBranch || 'main' }))}
|
||||||
</Button>
|
</>
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</TooltipTrigger>
|
||||||
|
<TooltipContent>
|
||||||
|
<p className="max-w-xs">
|
||||||
|
{t('tasks:review.mergeTooltip')}
|
||||||
|
</p>
|
||||||
|
</TooltipContent>
|
||||||
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Create PR Button */}
|
{/* Create PR Button */}
|
||||||
|
|||||||
@@ -145,6 +145,10 @@
|
|||||||
"browseFiles": "Browse Files",
|
"browseFiles": "Browse Files",
|
||||||
"creating": "Creating...",
|
"creating": "Creating...",
|
||||||
"createTask": "Create Task",
|
"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": {
|
"gitOptions": {
|
||||||
"title": "Git Options (optional)",
|
"title": "Git Options (optional)",
|
||||||
"baseBranchLabel": "Base Branch (optional)",
|
"baseBranchLabel": "Base Branch (optional)",
|
||||||
@@ -158,6 +162,9 @@
|
|||||||
"createFailed": "Failed to create task. Please try again."
|
"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": {
|
"edit": {
|
||||||
"title": "Edit Task",
|
"title": "Edit Task",
|
||||||
"description": "Update task details including title, description, classification, images, and settings. Changes will be saved to the spec files.",
|
"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",
|
"browseFiles": "Parcourir les fichiers",
|
||||||
"creating": "Création...",
|
"creating": "Création...",
|
||||||
"createTask": "Créer la tâche",
|
"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": {
|
"gitOptions": {
|
||||||
"title": "Options Git (optionnel)",
|
"title": "Options Git (optionnel)",
|
||||||
"baseBranchLabel": "Branche de base (optionnel)",
|
"baseBranchLabel": "Branche de base (optionnel)",
|
||||||
@@ -158,6 +162,9 @@
|
|||||||
"createFailed": "Échec de la création de la tâche. Veuillez réessayer."
|
"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": {
|
"edit": {
|
||||||
"title": "Modifier la tâche",
|
"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.",
|
"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.",
|
||||||
|
|||||||
Reference in New Issue
Block a user