add clone alert

This commit is contained in:
Yoan.liu 2025-05-22 22:32:22 +08:00
parent 19bbe1f069
commit c713d4705e
4 changed files with 96 additions and 4 deletions

View File

@ -6,7 +6,7 @@ export type UploadNodeProps = SharedNodeProps;
const CloneNode = ({ node, disabled }: SharedNodeProps) => {
return (
<>
<Card className="relative z-[1] mt-10 w-[256px] shadow-md" styles={{ body: { padding: 0 } }} hoverable>
<Card className="relative z-[1] w-[256px] shadow-md" styles={{ body: { padding: 0 } }} hoverable>
<div className="flex h-[64px] flex-col items-center justify-center truncate px-4 py-2"></div>
</Card>
<AddNode node={node} disabled={disabled} />

View File

@ -507,3 +507,45 @@ export const isAllNodesValidated = (node: WorkflowNode): boolean => {
return true;
};
export const hasCloneNode = (node: WorkflowNode): boolean => {
let current = node as typeof node | undefined;
while (current) {
if (current.type === WorkflowNodeType.Clone) {
return true;
}
if (isBranchLike(current)) {
for (const branch of current.branches!) {
if (hasCloneNode(branch)) {
return true;
}
}
}
current = current.next;
}
return false;
};
export const removeCloneNode = (node: WorkflowNode): WorkflowNode => {
return produce(node, (draft) => {
let current = draft as typeof draft | undefined;
while (current) {
if (current.next?.type === WorkflowNodeType.Clone) {
current.next = current.next.next;
break;
}
if (isBranchLike(current) && current.branches) {
current.branches = current.branches.map((branch) => removeCloneNode(branch));
}
current = current.next;
}
return draft;
});
};

View File

@ -21,7 +21,7 @@ import ModalForm from "@/components/ModalForm";
import Show from "@/components/Show";
import WorkflowElementsContainer from "@/components/workflow/WorkflowElementsContainer";
import WorkflowRuns from "@/components/workflow/WorkflowRuns";
import { isAllNodesValidated } from "@/domain/workflow";
import { hasCloneNode, isAllNodesValidated } from "@/domain/workflow";
import { WORKFLOW_RUN_STATUSES } from "@/domain/workflowRun";
import { useAntdForm, useZustandShallowSelector } from "@/hooks";
import { remove as removeWorkflow, subscribe as subscribeWorkflow, unsubscribe as unsubscribeWorkflow } from "@/repository/workflow";
@ -38,9 +38,12 @@ const WorkflowDetail = () => {
const [notificationApi, NotificationContextHolder] = notification.useNotification();
const { id: workflowId } = useParams();
const { workflow, initialized, ...workflowState } = useWorkflowStore(
useZustandShallowSelector(["workflow", "initialized", "init", "destroy", "setEnabled", "release", "discard"])
const { workflow, initialized, cancelClone, ...workflowState } = useWorkflowStore(
useZustandShallowSelector(["workflow", "initialized", "cancelClone", "init", "destroy", "setEnabled", "release", "discard"])
);
const cloning = hasCloneNode(workflow.draft!);
useEffect(() => {
workflowState.init(workflowId!);
@ -308,6 +311,28 @@ const WorkflowDetail = () => {
</div>
</div>
<Show when={cloning}>
<div className="absolute top-4 left-0 right-0 z-[10] flex justify-center">
<Alert
className="shadow-lg animate-fadeIn"
showIcon
message="选择要复制的节点,复制到目标位置"
type="info"
action={
<Button
size="small"
type="text"
onClick={() => {
cancelClone();
}}
>
</Button>
}
/>
</div>
</Show>
<WorkflowElementsContainer className="pt-16" />
</Card>
</div>
@ -395,3 +420,4 @@ const WorkflowBaseInfoModal = ({ trigger }: { trigger?: React.ReactNode }) => {
};
export default WorkflowDetail;

View File

@ -9,6 +9,7 @@ import {
addNode,
getOutputBeforeNodeId,
removeBranch,
removeCloneNode,
removeNode,
updateNode,
} from "@/domain/workflow";
@ -28,6 +29,7 @@ export type WorkflowState = {
addNode: (node: WorkflowNode, previousNodeId: string) => void;
updateNode: (node: WorkflowNode) => void;
removeNode: (nodeId: string) => void;
cancelClone: () => void;
addBranch: (branchId: string) => void;
removeBranch: (branchId: string, index: number) => void;
@ -203,6 +205,27 @@ export const useWorkflowStore = create<WorkflowState>((set, get) => ({
});
},
cancelClone: async () => {
if (!get().initialized) throw "Workflow not initialized yet";
const root = removeCloneNode(get().workflow.draft!);
const resp = await saveWorkflow({
id: get().workflow.id!,
draft: root,
hasDraft: true,
});
set((state: WorkflowState) => {
return {
workflow: produce(state.workflow, (draft) => {
draft.draft = resp.draft;
draft.hasDraft = resp.hasDraft;
}),
};
});
},
addBranch: async (branchId: string) => {
if (!get().initialized) throw "Workflow not initialized yet";
@ -247,3 +270,4 @@ export const useWorkflowStore = create<WorkflowState>((set, get) => ({
return getOutputBeforeNodeId(get().workflow.draft as WorkflowNode, nodeId, type);
},
}));