源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
This commit is contained in:
+103
@@ -0,0 +1,103 @@
|
||||
import { ConfirmationDialog } from "@tutti-os/ui-system";
|
||||
import { useRef, useState } from "react";
|
||||
import type { AgentGUIConversationRailLabels } from "./agentGUIConversationRailLabels";
|
||||
import type { AgentGUIProjectActionDialog } from "./agentGUIConversationRailTypes";
|
||||
|
||||
const DIALOG_CLASS_NAME =
|
||||
"nodrag tsh-desktop-no-drag [-webkit-app-region:no-drag]";
|
||||
|
||||
export async function executeConfirmedProjectRemoval(input: {
|
||||
onRemoveProject: (path: string) => Promise<boolean>;
|
||||
path: string;
|
||||
}): Promise<boolean> {
|
||||
return input.onRemoveProject(input.path);
|
||||
}
|
||||
|
||||
export function AgentGUIProjectActionConfirmationDialog(props: {
|
||||
action: AgentGUIProjectActionDialog | null;
|
||||
isDeletingProjectConversations: boolean;
|
||||
isInteractionLocked: () => boolean;
|
||||
labels: AgentGUIConversationRailLabels;
|
||||
onConfirmDeleteConversations: (sessionIds: string[]) => Promise<boolean>;
|
||||
onRemoveProject: (path: string) => Promise<boolean>;
|
||||
setAction: (action: AgentGUIProjectActionDialog | null) => void;
|
||||
}): React.JSX.Element {
|
||||
const { action, labels } = props;
|
||||
const projectRemovalInFlightRef = useRef(false);
|
||||
const [projectRemovalInFlight, setProjectRemovalInFlight] = useState(false);
|
||||
return (
|
||||
<ConfirmationDialog
|
||||
cancelLabel={labels.cancel}
|
||||
className={DIALOG_CLASS_NAME}
|
||||
confirmBusy={
|
||||
(action?.kind === "batch-delete" ||
|
||||
action?.kind === "batch-delete-conversations" ||
|
||||
action?.kind === "remove") &&
|
||||
(props.isDeletingProjectConversations || projectRemovalInFlight)
|
||||
}
|
||||
confirmDisabled={props.isInteractionLocked()}
|
||||
confirmLabel={
|
||||
action?.kind === "batch-delete"
|
||||
? labels.batchDeleteProjectSessionsConfirm
|
||||
: action?.kind === "batch-delete-conversations"
|
||||
? labels.batchDeleteConversationsConfirm
|
||||
: labels.removeProject
|
||||
}
|
||||
description={
|
||||
action?.kind === "batch-delete"
|
||||
? labels.batchDeleteProjectSessionsBody(
|
||||
action.conversationCount,
|
||||
action.label
|
||||
)
|
||||
: action?.kind === "batch-delete-conversations"
|
||||
? labels.batchDeleteConversationsBody(action.conversationCount)
|
||||
: action
|
||||
? labels.removeProjectConfirmDescription(action.label)
|
||||
: undefined
|
||||
}
|
||||
onCancel={() => {
|
||||
if (!projectRemovalInFlightRef.current) props.setAction(null);
|
||||
}}
|
||||
onConfirm={() => {
|
||||
if (props.isInteractionLocked()) return;
|
||||
if (!action) return;
|
||||
if (
|
||||
action.kind === "batch-delete" ||
|
||||
action.kind === "batch-delete-conversations"
|
||||
) {
|
||||
props.setAction(null);
|
||||
void props.onConfirmDeleteConversations(action.sessionIds);
|
||||
return;
|
||||
}
|
||||
if (projectRemovalInFlightRef.current) return;
|
||||
projectRemovalInFlightRef.current = true;
|
||||
setProjectRemovalInFlight(true);
|
||||
void (async () => {
|
||||
try {
|
||||
const removed = await executeConfirmedProjectRemoval({
|
||||
onRemoveProject: props.onRemoveProject,
|
||||
path: action.path
|
||||
});
|
||||
if (removed) props.setAction(null);
|
||||
} finally {
|
||||
projectRemovalInFlightRef.current = false;
|
||||
setProjectRemovalInFlight(false);
|
||||
}
|
||||
})();
|
||||
}}
|
||||
onOpenChange={(open) => {
|
||||
if (!open && !projectRemovalInFlightRef.current) props.setAction(null);
|
||||
}}
|
||||
open={action !== null}
|
||||
overlayClassName={DIALOG_CLASS_NAME}
|
||||
title={
|
||||
action?.kind === "batch-delete"
|
||||
? labels.batchDeleteProjectSessionsTitle
|
||||
: action?.kind === "batch-delete-conversations"
|
||||
? labels.batchDeleteConversationsTitle
|
||||
: labels.removeProjectConfirmTitle
|
||||
}
|
||||
tone="destructive"
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user