fix: chain workflow with agent presets
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled

This commit is contained in:
Your Name 2026-03-17 18:04:30 +08:00
parent 0b6a794097
commit fbbc63f865
5 changed files with 66 additions and 21 deletions

View File

@ -61,6 +61,7 @@ import {
AgentWorkflowPanel,
type AgentWorkflowInputs,
} from "@/components/agents/AgentWorkflowPanel";
import { AgentPresetPanel } from "@/components/agents/AgentPresetPanel";
import { CanvasWorkspace } from "@/components/canvas";
import { CanvasChatPanel } from "@/components/canvas/CanvasChatPanel";
import { CanvasFileListPanel } from "@/components/canvas/CanvasFileListPanel";
@ -159,6 +160,7 @@ export default function CanvasEditorPage({ params }: PageProps) {
const [workflowSelections, setWorkflowSelections] = useState<
Partial<Record<AgentWorkflowStepKey, string>>
>({});
const [selectedAgentPresetId, setSelectedAgentPresetId] = useState<string | null>(null);
const [workflowHydrationSource, setWorkflowHydrationSource] = useState<
"pending" | "project" | "local" | "empty"
>("pending");
@ -261,6 +263,7 @@ export default function CanvasEditorPage({ params }: PageProps) {
store: "",
});
setWorkflowSelections({});
setSelectedAgentPresetId(null);
// 🆕 先清空当前画布状态,确保切换时不会显示旧数据
useCanvasStore.getState().clearCanvas();
@ -280,6 +283,9 @@ export default function CanvasEditorPage({ params }: PageProps) {
store: String(persistedWorkflow.inputs?.store || "").trim(),
});
setWorkflowSelections(persistedWorkflow.selections || {});
setSelectedAgentPresetId(
String(persistedWorkflow.selectedAgentPresetId || "").trim() || null
);
setWorkflowHydrationSource("project");
} else {
setWorkflowHydrationSource("empty");
@ -329,13 +335,14 @@ export default function CanvasEditorPage({ params }: PageProps) {
store: workflowInputs.store.trim(),
},
selections: workflowSelections,
selectedAgentPresetId: selectedAgentPresetId || null,
};
return {
...getCanvasState(),
workflowState,
};
}, [getCanvasState, workflowInputs, workflowSelections]);
}, [getCanvasState, workflowInputs, workflowSelections, selectedAgentPresetId]);
useEffect(() => {
if (typeof window === "undefined") return;
@ -356,6 +363,7 @@ export default function CanvasEditorPage({ params }: PageProps) {
store: String(parsed.inputs?.store || "").trim(),
});
setWorkflowSelections(parsed.selections || {});
setSelectedAgentPresetId(String(parsed.selectedAgentPresetId || "").trim() || null);
} catch (error) {
console.warn("[Canvas] Failed to hydrate workflow state from localStorage:", error);
} finally {
@ -372,12 +380,19 @@ export default function CanvasEditorPage({ params }: PageProps) {
JSON.stringify({
inputs: workflowInputs,
selections: workflowSelections,
selectedAgentPresetId,
})
);
} catch (error) {
console.warn("[Canvas] Failed to persist workflow state:", error);
}
}, [workflowHydrationSource, workflowInputs, workflowSelections, workflowStorageKey]);
}, [
workflowHydrationSource,
workflowInputs,
workflowSelections,
workflowStorageKey,
selectedAgentPresetId,
]);
const persistCanvasState = useCallback(
async (reason: "autosave" | "delete" | "beforeunload") => {
@ -868,22 +883,35 @@ export default function CanvasEditorPage({ params }: PageProps) {
<div className="absolute inset-0 flex pt-[72px]">
<div className="min-w-0 flex-1 border-r bg-white dark:bg-zinc-950">
<AgentWorkflowPanel
config={resolvedWorkflowUiConfig}
inputs={workflowInputs}
onInputsChange={setWorkflowInputs}
selections={workflowSelections}
onSelectionsChange={setWorkflowSelections}
onReset={() => {
setWorkflowInputs({
primarySku: "",
secondarySku: "",
brand: "",
store: "",
});
setWorkflowSelections({});
}}
/>
<div className="grid h-full grid-rows-[minmax(0,1fr)_minmax(0,1fr)]">
<div className="min-h-0 border-b">
<AgentWorkflowPanel
embedded
config={resolvedWorkflowUiConfig}
inputs={workflowInputs}
onInputsChange={setWorkflowInputs}
selections={workflowSelections}
onSelectionsChange={setWorkflowSelections}
onReset={() => {
setWorkflowInputs({
primarySku: "",
secondarySku: "",
brand: "",
store: "",
});
setWorkflowSelections({});
setSelectedAgentPresetId(null);
}}
/>
</div>
<div className="min-h-0">
<AgentPresetPanel
embedded
selectedPresetId={selectedAgentPresetId}
onSelectPreset={setSelectedAgentPresetId}
/>
</div>
</div>
</div>
<div
@ -894,7 +922,7 @@ export default function CanvasEditorPage({ params }: PageProps) {
<CanvasChatPanel
chatId={`canvas-${id}`}
onClose={() => {}}
selectedAgentPresetId={null}
selectedAgentPresetId={isAgentFeatureEnabled ? selectedAgentPresetId : null}
chatScope="agent"
workflowContext={workflowContext}
/>

View File

@ -5,6 +5,7 @@ import useSWR from "swr";
import { Loader2, Plus, Sparkles } from "lucide-react";
import { toast } from "sonner";
import { fetcher } from "@/lib/utils";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { ScrollArea } from "@/components/ui/scroll-area";
@ -23,11 +24,13 @@ import { AgentPresetDialog } from "@/components/agents/AgentPresetDialog";
interface AgentPresetPanelProps {
selectedPresetId?: string | null;
onSelectPreset: (presetId: string | null) => void;
embedded?: boolean;
}
export function AgentPresetPanel({
selectedPresetId,
onSelectPreset,
embedded = false,
}: AgentPresetPanelProps) {
const [keyword, setKeyword] = useState("");
const [categoryFilters, setCategoryFilters] = useState({
@ -149,7 +152,12 @@ export function AgentPresetPanel({
return (
<>
<div className="flex h-full flex-col border-r bg-white dark:bg-zinc-950">
<div
className={cn(
"flex h-full flex-col bg-white dark:bg-zinc-950",
embedded ? "" : "border-r"
)}
>
<div className="border-b p-4">
<div className="mb-3 flex items-center justify-between">
<div>

View File

@ -33,6 +33,7 @@ interface AgentWorkflowPanelProps {
selections: Partial<Record<AgentWorkflowStepKey, string>>;
onSelectionsChange: (next: Partial<Record<AgentWorkflowStepKey, string>>) => void;
onReset?: () => void;
embedded?: boolean;
}
function buildSelectionSummary(params: {
@ -67,6 +68,7 @@ export function AgentWorkflowPanel({
selections,
onSelectionsChange,
onReset,
embedded = false,
}: AgentWorkflowPanelProps) {
const resolvedConfig = useMemo(() => {
const source = config?.steps?.length ? config : defaultAgentWorkflowUiConfig;
@ -116,7 +118,12 @@ export function AgentWorkflowPanel({
};
return (
<div className="flex h-full flex-col border-r bg-white dark:bg-zinc-950">
<div
className={cn(
"flex h-full flex-col bg-white dark:bg-zinc-950",
embedded ? "" : "border-r"
)}
>
<div className="border-b p-4">
<div className="flex items-start justify-between gap-3">
<div>

View File

@ -609,6 +609,7 @@ export const canvasProject = pgTable("CanvasProject", {
store?: string;
};
selections?: Record<string, string>;
selectedAgentPresetId?: string | null;
};
}>(),
createdAt: timestamp("createdAt").notNull().defaultNow(),

View File

@ -69,6 +69,7 @@ export interface AgentWorkflowPersistedState {
store: string;
};
selections: Partial<Record<AgentWorkflowStepKey, string>>;
selectedAgentPresetId?: string | null;
}
export interface AgentCategoryTreeConfig {