feat(frontend): add assistant delete menu to prompt editor topbar
Place a more-actions dropdown beside the assistant ID with confirmed delete that returns to the assistant list after removal. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -18,8 +18,10 @@ import {
|
|||||||
Database,
|
Database,
|
||||||
Loader2,
|
Loader2,
|
||||||
MessageSquareText,
|
MessageSquareText,
|
||||||
|
MoreHorizontal,
|
||||||
Save,
|
Save,
|
||||||
Sparkles,
|
Sparkles,
|
||||||
|
Trash2,
|
||||||
Webhook,
|
Webhook,
|
||||||
Wrench,
|
Wrench,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
@@ -45,6 +47,12 @@ import { SectionCard } from "@/components/editor/section-card";
|
|||||||
import { VisionConfigSection } from "@/components/editor/vision-config-section";
|
import { VisionConfigSection } from "@/components/editor/vision-config-section";
|
||||||
import { TurnConfigEditor } from "@/components/turn-config-editor";
|
import { TurnConfigEditor } from "@/components/turn-config-editor";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
DropdownMenu,
|
||||||
|
DropdownMenuContent,
|
||||||
|
DropdownMenuItem,
|
||||||
|
DropdownMenuTrigger,
|
||||||
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { TopbarPortal } from "@/components/layout/topbar-portal";
|
import { TopbarPortal } from "@/components/layout/topbar-portal";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import {
|
import {
|
||||||
@@ -118,6 +126,7 @@ type PromptEditorProps = {
|
|||||||
tools: Tool[];
|
tools: Tool[];
|
||||||
onBack: () => void;
|
onBack: () => void;
|
||||||
onSave: () => void;
|
onSave: () => void;
|
||||||
|
onDelete?: () => void | Promise<void>;
|
||||||
updateForm: <K extends keyof AssistantForm>(
|
updateForm: <K extends keyof AssistantForm>(
|
||||||
key: K,
|
key: K,
|
||||||
value: AssistantForm[K],
|
value: AssistantForm[K],
|
||||||
@@ -142,6 +151,7 @@ export function PromptEditor({
|
|||||||
tools,
|
tools,
|
||||||
onBack,
|
onBack,
|
||||||
onSave,
|
onSave,
|
||||||
|
onDelete,
|
||||||
updateForm,
|
updateForm,
|
||||||
handlePromptVisionEnabledChange,
|
handlePromptVisionEnabledChange,
|
||||||
handlePromptModelChange,
|
handlePromptModelChange,
|
||||||
@@ -171,6 +181,7 @@ export function PromptEditor({
|
|||||||
const [activeSection, setActiveSection] =
|
const [activeSection, setActiveSection] =
|
||||||
useState<PromptSectionId>("conversation");
|
useState<PromptSectionId>("conversation");
|
||||||
const [debugOpen, setDebugOpen] = useState(true);
|
const [debugOpen, setDebugOpen] = useState(true);
|
||||||
|
const [deleting, setDeleting] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const container = scrollContainerRef.current;
|
const container = scrollContainerRef.current;
|
||||||
@@ -283,6 +294,16 @@ export function PromptEditor({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleDeleteSelect() {
|
||||||
|
if (!onDelete || deleting) return;
|
||||||
|
setDeleting(true);
|
||||||
|
try {
|
||||||
|
await onDelete();
|
||||||
|
} finally {
|
||||||
|
setDeleting(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TopbarPortal>
|
<TopbarPortal>
|
||||||
@@ -294,6 +315,42 @@ export function PromptEditor({
|
|||||||
onChange={(value) => updateForm("name", value)}
|
onChange={(value) => updateForm("name", value)}
|
||||||
/>
|
/>
|
||||||
<AssistantIdentity assistantId={assistantId} />
|
<AssistantIdentity assistantId={assistantId} />
|
||||||
|
{onDelete && (
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
size="icon-sm"
|
||||||
|
className="border-hairline-strong text-muted-foreground hover:text-foreground"
|
||||||
|
disabled={!assistantId || deleting}
|
||||||
|
aria-label="更多操作"
|
||||||
|
>
|
||||||
|
{deleting ? (
|
||||||
|
<Loader2 size={15} className="animate-spin" />
|
||||||
|
) : (
|
||||||
|
<MoreHorizontal size={15} />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent
|
||||||
|
align="start"
|
||||||
|
className="w-32 min-w-32 rounded-xl border border-hairline bg-popover p-1"
|
||||||
|
>
|
||||||
|
<DropdownMenuItem
|
||||||
|
variant="destructive"
|
||||||
|
className="rounded-lg"
|
||||||
|
disabled={deleting}
|
||||||
|
onSelect={(event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
window.setTimeout(() => void handleDeleteSelect(), 0);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Trash2 size={14} />
|
||||||
|
删除
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex shrink-0 items-center gap-2">
|
<div className="flex shrink-0 items-center gap-2">
|
||||||
|
|||||||
@@ -639,6 +639,19 @@ export function AssistantPage(props: AssistantPageProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleDeleteCurrentAssistant() {
|
||||||
|
if (!editingId) return;
|
||||||
|
const assistantName = form.name.trim() || "未命名助手";
|
||||||
|
if (!window.confirm(`确认删除助手“${assistantName}”?`)) return;
|
||||||
|
setSaveError(null);
|
||||||
|
try {
|
||||||
|
await assistantsApi.remove(editingId);
|
||||||
|
router.push("/assistants");
|
||||||
|
} catch (error) {
|
||||||
|
setSaveError(error instanceof Error ? error.message : "删除失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ---- 外部智能体平台(Dify / FastGPT)----
|
// ---- 外部智能体平台(Dify / FastGPT)----
|
||||||
function fillAgentPlatformForm(a: Assistant): AgentPlatformForm {
|
function fillAgentPlatformForm(a: Assistant): AgentPlatformForm {
|
||||||
const next: AgentPlatformForm = {
|
const next: AgentPlatformForm = {
|
||||||
@@ -1611,6 +1624,7 @@ export function AssistantPage(props: AssistantPageProps) {
|
|||||||
tools={tools}
|
tools={tools}
|
||||||
onBack={() => router.push("/assistants")}
|
onBack={() => router.push("/assistants")}
|
||||||
onSave={() => void handleSavePrompt()}
|
onSave={() => void handleSavePrompt()}
|
||||||
|
onDelete={() => void handleDeleteCurrentAssistant()}
|
||||||
updateForm={updateForm}
|
updateForm={updateForm}
|
||||||
handlePromptVisionEnabledChange={handlePromptVisionEnabledChange}
|
handlePromptVisionEnabledChange={handlePromptVisionEnabledChange}
|
||||||
handlePromptModelChange={handlePromptModelChange}
|
handlePromptModelChange={handlePromptModelChange}
|
||||||
|
|||||||
Reference in New Issue
Block a user