feat(ui): duplicate workflow node
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import { memo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
CheckCircleOutlined as CheckCircleOutlinedIcon,
|
||||
CloseCircleOutlined as CloseCircleOutlinedIcon,
|
||||
@@ -17,8 +16,6 @@ export type ConditionNodeProps = SharedNodeProps & {
|
||||
};
|
||||
|
||||
const ExecuteResultNode = ({ node, disabled, branchId, branchIndex }: ConditionNodeProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { token: themeToken } = theme.useToken();
|
||||
|
||||
return (
|
||||
@@ -42,16 +39,15 @@ const ExecuteResultNode = ({ node, disabled, branchId, branchIndex }: ConditionN
|
||||
<div className="flex h-[48px] flex-col items-center justify-center truncate px-4 py-2">
|
||||
<div className="flex items-center space-x-2">
|
||||
{node.type === WorkflowNodeType.ExecuteSuccess ? (
|
||||
<>
|
||||
<CheckCircleOutlinedIcon style={{ color: themeToken.colorSuccess }} />
|
||||
<div>{t("workflow_node.execute_success.label")}</div>
|
||||
</>
|
||||
<CheckCircleOutlinedIcon style={{ color: themeToken.colorSuccess }} />
|
||||
) : (
|
||||
<>
|
||||
<CloseCircleOutlinedIcon style={{ color: themeToken.colorError }} />
|
||||
<div>{t("workflow_node.execute_failure.label")}</div>
|
||||
</>
|
||||
<CloseCircleOutlinedIcon style={{ color: themeToken.colorError }} />
|
||||
)}
|
||||
<SharedNode.Title
|
||||
className="focus:bg-background focus:text-foreground overflow-hidden outline-slate-200 focus:rounded-sm"
|
||||
node={node}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
@@ -14,7 +14,7 @@ const UnknownNode = ({ node, disabled }: MonitorNodeProps) => {
|
||||
const { removeNode } = useWorkflowStore(useZustandShallowSelector(["removeNode"]));
|
||||
|
||||
const handleClickRemove = () => {
|
||||
removeNode(node.id);
|
||||
removeNode(node);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
EllipsisOutlined as EllipsisOutlinedIcon,
|
||||
FormOutlined as FormOutlinedIcon,
|
||||
MoreOutlined as MoreOutlinedIcon,
|
||||
SnippetsOutlined as SnippetsOutlinedIcon,
|
||||
} from "@ant-design/icons";
|
||||
import { useControllableValue } from "ahooks";
|
||||
import { Button, Card, Drawer, Dropdown, Input, type InputRef, type MenuProps, Modal, Popover, Space } from "antd";
|
||||
@@ -82,14 +83,27 @@ const isNodeBranchLike = (node: WorkflowNode) => {
|
||||
);
|
||||
};
|
||||
|
||||
const isNodeReadOnly = (node: WorkflowNode) => {
|
||||
const isNodeUnduplicatable = (node: WorkflowNode) => {
|
||||
return (
|
||||
node.type === WorkflowNodeType.Start ||
|
||||
node.type === WorkflowNodeType.End ||
|
||||
node.type === WorkflowNodeType.Branch ||
|
||||
node.type === WorkflowNodeType.ExecuteResultBranch ||
|
||||
node.type === WorkflowNodeType.ExecuteSuccess ||
|
||||
node.type === WorkflowNodeType.ExecuteFailure
|
||||
);
|
||||
};
|
||||
|
||||
const isNodeUnremovable = (node: WorkflowNode) => {
|
||||
return node.type === WorkflowNodeType.Start || node.type === WorkflowNodeType.End;
|
||||
};
|
||||
|
||||
const SharedNodeMenu = ({ menus, trigger, node, disabled, branchId, branchIndex, afterUpdate, afterDelete }: SharedNodeMenuProps) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { updateNode, removeNode, removeBranch } = useWorkflowStore(useZustandShallowSelector(["updateNode", "removeNode", "removeBranch"]));
|
||||
const { duplicateNode, updateNode, removeNode, duplicateBranch, removeBranch } = useWorkflowStore(
|
||||
useZustandShallowSelector(["duplicateNode", "updateNode", "removeNode", "duplicateBranch", "removeBranch"])
|
||||
);
|
||||
|
||||
const [modalApi, ModelContextHolder] = Modal.useModal();
|
||||
|
||||
@@ -112,11 +126,19 @@ const SharedNodeMenu = ({ menus, trigger, node, disabled, branchId, branchIndex,
|
||||
afterUpdate?.();
|
||||
};
|
||||
|
||||
const handleDeleteClick = async () => {
|
||||
const handleDuplicateClick = async () => {
|
||||
if (isNodeBranchLike(node)) {
|
||||
await duplicateBranch(branchId!, branchIndex!);
|
||||
} else {
|
||||
await duplicateNode(node);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveClick = async () => {
|
||||
if (isNodeBranchLike(node)) {
|
||||
await removeBranch(branchId!, branchIndex!);
|
||||
} else {
|
||||
await removeNode(node.id);
|
||||
await removeNode(node);
|
||||
}
|
||||
|
||||
afterDelete?.();
|
||||
@@ -155,16 +177,23 @@ const SharedNodeMenu = ({ menus, trigger, node, disabled, branchId, branchIndex,
|
||||
setTimeout(() => nameInputRef.current?.focus(), 1);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "duplicate",
|
||||
disabled: disabled || isNodeUnduplicatable(node),
|
||||
label: isNodeBranchLike(node) ? t("workflow_node.action.duplicate_branch") : t("workflow_node.action.duplicate_node"),
|
||||
icon: <SnippetsOutlinedIcon />,
|
||||
onClick: handleDuplicateClick,
|
||||
},
|
||||
{
|
||||
type: "divider",
|
||||
},
|
||||
{
|
||||
key: "remove",
|
||||
disabled: disabled || isNodeReadOnly(node),
|
||||
disabled: disabled || isNodeUnremovable(node),
|
||||
label: isNodeBranchLike(node) ? t("workflow_node.action.remove_branch") : t("workflow_node.action.remove_node"),
|
||||
icon: <CloseCircleOutlinedIcon />,
|
||||
danger: true,
|
||||
onClick: handleDeleteClick,
|
||||
onClick: handleRemoveClick,
|
||||
},
|
||||
] satisfies MenuProps["items"];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user