feat(session): enhance delete dialog for worktrees
This commit is contained in:
@@ -10,7 +10,7 @@ import {
|
|||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from '@/components/ui/dialog';
|
} from '@/components/ui/dialog';
|
||||||
import { RiCheckboxBlankLine, RiCheckboxLine } from '@remixicon/react';
|
import { RiCheckboxBlankLine, RiCheckboxLine, RiDeleteBinLine, RiGitBranchLine } from '@remixicon/react';
|
||||||
import { MobileOverlayPanel } from '@/components/ui/MobileOverlayPanel';
|
import { MobileOverlayPanel } from '@/components/ui/MobileOverlayPanel';
|
||||||
import { DirectoryExplorerDialog } from './DirectoryExplorerDialog';
|
import { DirectoryExplorerDialog } from './DirectoryExplorerDialog';
|
||||||
import { cn, formatPathForDisplay } from '@/lib/utils';
|
import { cn, formatPathForDisplay } from '@/lib/utils';
|
||||||
@@ -379,22 +379,45 @@ export const SessionDialogs: React.FC = () => {
|
|||||||
: '';
|
: '';
|
||||||
|
|
||||||
const deleteDialogBody = deleteDialog ? (
|
const deleteDialogBody = deleteDialog ? (
|
||||||
<div className="space-y-2">
|
<div className={cn(isWorktreeDelete ? 'space-y-3' : 'space-y-2')}>
|
||||||
{deleteDialog.sessions.length > 0 && (
|
{deleteDialog.sessions.length > 0 && (
|
||||||
<div className="space-y-1.5 rounded-xl border border-border/40 bg-sidebar/60 p-3">
|
<div className={cn(
|
||||||
|
isWorktreeDelete ? 'rounded-lg bg-muted/30 p-3' : 'space-y-1.5 rounded-xl border border-border/40 bg-sidebar/60 p-3'
|
||||||
|
)}>
|
||||||
{isWorktreeDelete && (
|
{isWorktreeDelete && (
|
||||||
<span className="typography-meta font-medium text-foreground">
|
<div className="flex items-center gap-2">
|
||||||
{deleteDialog.sessions.length === 1 ? 'Linked session' : 'Linked sessions'}
|
<span className="typography-meta font-medium text-foreground">
|
||||||
</span>
|
{deleteDialog.sessions.length === 1 ? 'Linked session' : 'Linked sessions'}
|
||||||
|
</span>
|
||||||
|
<span className="typography-micro text-muted-foreground/70">
|
||||||
|
{deleteDialog.sessions.length}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
<ul className="space-y-0.5">
|
<ul className={cn(isWorktreeDelete ? 'mt-2 space-y-1' : 'space-y-0.5')}>
|
||||||
{deleteDialog.sessions.slice(0, 5).map((session) => (
|
{deleteDialog.sessions.slice(0, 5).map((session) => (
|
||||||
<li key={session.id} className="typography-micro text-muted-foreground/80">
|
<li
|
||||||
{session.title || 'Untitled Session'}
|
key={session.id}
|
||||||
|
className={cn(
|
||||||
|
isWorktreeDelete
|
||||||
|
? 'flex items-center gap-2 rounded-md px-2.5 py-1.5 text-sm text-muted-foreground'
|
||||||
|
: 'typography-micro text-muted-foreground/80'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span className={cn(!isWorktreeDelete && 'hidden')}>
|
||||||
|
•
|
||||||
|
</span>
|
||||||
|
<span className="truncate">
|
||||||
|
{session.title || 'Untitled Session'}
|
||||||
|
</span>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
{deleteDialog.sessions.length > 5 && (
|
{deleteDialog.sessions.length > 5 && (
|
||||||
<li className="typography-micro text-muted-foreground/70">
|
<li className={cn(
|
||||||
|
isWorktreeDelete
|
||||||
|
? 'px-2.5 py-1 text-xs text-muted-foreground/70'
|
||||||
|
: 'typography-micro text-muted-foreground/70'
|
||||||
|
)}>
|
||||||
+{deleteDialog.sessions.length - 5} more
|
+{deleteDialog.sessions.length - 5} more
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
@@ -403,8 +426,9 @@ export const SessionDialogs: React.FC = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{isWorktreeDelete ? (
|
{isWorktreeDelete ? (
|
||||||
<div className="space-y-2 rounded-xl border border-border/40 bg-sidebar/60 p-3">
|
<div className="space-y-2 rounded-lg bg-muted/30 p-3">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
<RiGitBranchLine className="h-4 w-4 text-muted-foreground" />
|
||||||
<span className="typography-meta font-medium text-foreground">Worktree</span>
|
<span className="typography-meta font-medium text-foreground">Worktree</span>
|
||||||
{targetWorktree?.label ? (
|
{targetWorktree?.label ? (
|
||||||
<span className="typography-micro text-muted-foreground/70">{targetWorktree.label}</span>
|
<span className="typography-micro text-muted-foreground/70">{targetWorktree.label}</span>
|
||||||
@@ -417,44 +441,6 @@ export const SessionDialogs: React.FC = () => {
|
|||||||
<p className="typography-micro text-warning">Uncommitted changes will be discarded.</p>
|
<p className="typography-micro text-warning">Uncommitted changes will be discarded.</p>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{canRemoveRemoteBranches ? (
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => {
|
|
||||||
if (removeRemoteOptionDisabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setDeleteDialogShouldRemoveRemote((prev) => !prev);
|
|
||||||
}}
|
|
||||||
disabled={removeRemoteOptionDisabled}
|
|
||||||
className={cn(
|
|
||||||
'flex w-full items-start gap-3 rounded-xl border border-border/40 bg-sidebar/70 px-3 py-2 text-left',
|
|
||||||
removeRemoteOptionDisabled
|
|
||||||
? 'cursor-not-allowed opacity-60'
|
|
||||||
: 'hover:bg-sidebar/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary'
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<span className="mt-0.5 flex size-5 items-center justify-center text-muted-foreground">
|
|
||||||
{deleteDialogShouldRemoveRemote ? (
|
|
||||||
<RiCheckboxLine className="size-4 text-primary" />
|
|
||||||
) : (
|
|
||||||
<RiCheckboxBlankLine className="size-4" />
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
<div className="flex-1 space-y-1">
|
|
||||||
<span className="typography-meta font-medium text-foreground">Delete remote branch</span>
|
|
||||||
<p className="typography-micro text-muted-foreground/70">
|
|
||||||
{deleteDialogShouldRemoveRemote
|
|
||||||
? 'Remote branch on origin will also be removed.'
|
|
||||||
: 'Keep the remote branch intact.'}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
) : (
|
|
||||||
<p className="typography-micro text-muted-foreground/70">
|
|
||||||
Remote branch information unavailable for this worktree.
|
|
||||||
</p>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="rounded-xl border border-border/40 bg-sidebar/60 p-3">
|
<div className="rounded-xl border border-border/40 bg-sidebar/60 p-3">
|
||||||
@@ -466,7 +452,49 @@ export const SessionDialogs: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
const deleteDialogActions = (
|
const deleteRemoteBranchAction = isWorktreeDelete ? (
|
||||||
|
canRemoveRemoteBranches ? (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
if (removeRemoteOptionDisabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setDeleteDialogShouldRemoveRemote((prev) => !prev);
|
||||||
|
}}
|
||||||
|
disabled={removeRemoteOptionDisabled}
|
||||||
|
className={cn(
|
||||||
|
'flex items-center gap-2 rounded-md px-2 py-1 text-sm text-muted-foreground transition-colors',
|
||||||
|
removeRemoteOptionDisabled
|
||||||
|
? 'cursor-not-allowed opacity-60'
|
||||||
|
: 'hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{deleteDialogShouldRemoveRemote ? (
|
||||||
|
<RiCheckboxLine className="size-4 text-primary" />
|
||||||
|
) : (
|
||||||
|
<RiCheckboxBlankLine className="size-4" />
|
||||||
|
)}
|
||||||
|
Delete remote branch
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<span className="text-xs text-muted-foreground/70">Remote branch info unavailable</span>
|
||||||
|
)
|
||||||
|
) : null;
|
||||||
|
|
||||||
|
const deleteDialogActions = isWorktreeDelete ? (
|
||||||
|
<div className="flex w-full items-center justify-between gap-3">
|
||||||
|
{deleteRemoteBranchAction}
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Button variant="ghost" onClick={closeDeleteDialog} disabled={isProcessingDelete}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button variant="destructive" onClick={handleConfirmDelete} disabled={isProcessingDelete}>
|
||||||
|
{isProcessingDelete ? 'Deleting…' : 'Delete worktree'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
<>
|
<>
|
||||||
<Button variant="ghost" onClick={closeDeleteDialog} disabled={isProcessingDelete}>
|
<Button variant="ghost" onClick={closeDeleteDialog} disabled={isProcessingDelete}>
|
||||||
Cancel
|
Cancel
|
||||||
@@ -474,11 +502,9 @@ export const SessionDialogs: React.FC = () => {
|
|||||||
<Button variant="destructive" onClick={handleConfirmDelete} disabled={isProcessingDelete}>
|
<Button variant="destructive" onClick={handleConfirmDelete} disabled={isProcessingDelete}>
|
||||||
{isProcessingDelete
|
{isProcessingDelete
|
||||||
? 'Deleting…'
|
? 'Deleting…'
|
||||||
: isWorktreeDelete
|
: deleteDialog?.sessions.length === 1
|
||||||
? 'Delete worktree'
|
? 'Delete session'
|
||||||
: deleteDialog?.sessions.length === 1
|
: 'Delete sessions'}
|
||||||
? 'Delete session'
|
|
||||||
: 'Delete sessions'}
|
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
@@ -522,12 +548,23 @@ export const SessionDialogs: React.FC = () => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<DialogContent className="max-w-[min(520px,100vw-2rem)] space-y-2 pb-2">
|
<DialogContent
|
||||||
|
className={cn(
|
||||||
|
isWorktreeDelete
|
||||||
|
? 'max-w-xl max-h-[70vh] flex flex-col overflow-hidden gap-3'
|
||||||
|
: 'max-w-[min(520px,100vw-2rem)] space-y-2 pb-2'
|
||||||
|
)}
|
||||||
|
>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
<DialogTitle>{deleteDialogTitle}</DialogTitle>
|
<DialogTitle className={cn(isWorktreeDelete && 'flex items-center gap-2')}>
|
||||||
|
{isWorktreeDelete && <RiDeleteBinLine className="h-5 w-5" />}
|
||||||
|
{deleteDialogTitle}
|
||||||
|
</DialogTitle>
|
||||||
{deleteDialogDescription && <DialogDescription>{deleteDialogDescription}</DialogDescription>}
|
{deleteDialogDescription && <DialogDescription>{deleteDialogDescription}</DialogDescription>}
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
{deleteDialogBody}
|
<div className={cn(isWorktreeDelete && 'flex-1 min-h-0 overflow-y-auto space-y-2')}>
|
||||||
|
{deleteDialogBody}
|
||||||
|
</div>
|
||||||
<DialogFooter className="mt-2 gap-2 pt-1 pb-1">{deleteDialogActions}</DialogFooter>
|
<DialogFooter className="mt-2 gap-2 pt-1 pb-1">{deleteDialogActions}</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
|
|||||||
Reference in New Issue
Block a user