Confirm risky worktree archive (#994)

This commit is contained in:
Mohamed Boudra
2026-05-13 23:27:49 +08:00
committed by GitHub
parent 512702fe46
commit f1e5640a26
8 changed files with 261 additions and 81 deletions
@@ -106,6 +106,7 @@ import {
requireWorkspaceExecutionDirectory,
resolveWorkspaceExecutionDirectory,
} from "@/utils/workspace-execution";
import { confirmRiskyWorktreeArchive } from "@/git/worktree-archive-warning";
import {
archiveWorkspaceOptimistically,
archiveWorkspacesOptimistically,
@@ -1474,92 +1475,93 @@ function WorkspaceRowWithMenu({
});
}, [activeWorkspaceSelection, workspace.serverId, workspace.workspaceId]);
const handleArchiveWorktree = useCallback(() => {
const archiveWorktreeAfterConfirmation = useCallback(async () => {
if (isArchiving) {
return;
}
void (async () => {
const confirmed = await confirmDialog({
title: "Archive worktree?",
message: `Archive "${workspace.name}"?\n\nThe worktree will be removed from disk, terminals will be stopped, and agents inside will be archived.\n\nYour branch is still accessible if you committed.`,
confirmLabel: "Archive",
cancelLabel: "Cancel",
destructive: true,
const confirmed = await confirmRiskyWorktreeArchive({
worktreeName: workspace.name,
isDirty: workspace.archiveHasUncommittedChanges,
aheadOfOrigin: workspace.archiveUnpushedCommitCount,
diffStat: workspace.diffStat,
});
if (!confirmed) {
return;
}
let archiveDirectory: string;
try {
archiveDirectory = requireWorkspaceExecutionDirectory({
workspaceId: workspace.workspaceId,
workspaceDirectory: workspace.workspaceDirectory,
});
} catch (error) {
toast.error(error instanceof Error ? error.message : "Workspace path not available");
return;
}
if (!confirmed) {
return;
}
let archiveDirectory: string;
try {
archiveDirectory = requireWorkspaceExecutionDirectory({
workspaceId: workspace.workspaceId,
workspaceDirectory: workspace.workspaceDirectory,
});
} catch (error) {
toast.error(error instanceof Error ? error.message : "Workspace path not available");
return;
}
if (!archiveDirectory) {
toast.error("Workspace path not available");
return;
}
if (!archiveDirectory) {
toast.error("Workspace path not available");
return;
}
redirectAfterArchive();
redirectAfterArchive();
void archiveWorktree({
serverId: workspace.serverId,
cwd: archiveDirectory,
worktreePath: archiveDirectory,
}).catch((error) => {
const message = error instanceof Error ? error.message : "Failed to archive worktree";
toast.error(message);
});
})();
void archiveWorktree({
serverId: workspace.serverId,
cwd: archiveDirectory,
worktreePath: archiveDirectory,
}).catch((error) => {
const message = error instanceof Error ? error.message : "Failed to archive worktree";
toast.error(message);
});
}, [archiveWorktree, isArchiving, redirectAfterArchive, toast, workspace]);
const handleArchiveWorkspace = useCallback(() => {
const handleArchiveWorktree = useCallback(() => {
void archiveWorktreeAfterConfirmation();
}, [archiveWorktreeAfterConfirmation]);
const hideWorkspaceAfterConfirmation = useCallback(async () => {
if (isArchivingWorkspace) {
return;
}
void (async () => {
const confirmed = await confirmDialog({
title: "Hide workspace?",
message: `Hide "${workspace.name}" from the sidebar?\n\nFiles on disk will not be changed.`,
confirmLabel: "Hide",
cancelLabel: "Cancel",
destructive: true,
const confirmed = await confirmDialog({
title: "Hide workspace?",
message: `Hide "${workspace.name}" from the sidebar?\n\nFiles on disk will not be changed.`,
confirmLabel: "Hide",
cancelLabel: "Cancel",
destructive: true,
});
if (!confirmed) {
return;
}
const client = getHostRuntimeStore().getClient(workspace.serverId);
if (!client) {
toast.error("Host is not connected");
return;
}
setIsArchivingWorkspace(true);
try {
await archiveWorkspaceOptimistically({
client,
workspace,
afterHide: redirectAfterArchive,
});
if (!confirmed) {
return;
}
const client = getHostRuntimeStore().getClient(workspace.serverId);
if (!client) {
toast.error("Host is not connected");
return;
}
setIsArchivingWorkspace(true);
void (async () => {
try {
await archiveWorkspaceOptimistically({
client,
workspace,
afterHide: redirectAfterArchive,
});
} catch (error) {
toast.error(error instanceof Error ? error.message : "Failed to hide workspace");
} finally {
setIsArchivingWorkspace(false);
}
})();
})();
} catch (error) {
toast.error(error instanceof Error ? error.message : "Failed to hide workspace");
} finally {
setIsArchivingWorkspace(false);
}
}, [isArchivingWorkspace, redirectAfterArchive, toast, workspace]);
const handleArchiveWorkspace = useCallback(() => {
void hideWorkspaceAfterConfirmation();
}, [hideWorkspaceAfterConfirmation]);
const handleCopyPath = useCallback(() => {
let copyTargetDirectory: string;
try {
@@ -1589,7 +1591,7 @@ function WorkspaceRowWithMenu({
priority: 0,
handle: () => {
if (isWorktree) {
handleArchiveWorktree();
void archiveWorktreeAfterConfirmation();
} else {
handleArchiveWorkspace();
}