feat(ui): disable nodes during workflow running

This commit is contained in:
Fu Diwei 2025-01-04 12:58:45 +08:00
parent 52dfa5e8c3
commit 2213399f5e
8 changed files with 38 additions and 26 deletions

View File

@ -44,8 +44,6 @@ var sslProviderUrls = map[string]string{
sslProviderGts: gtsUrl, sslProviderGts: gtsUrl,
} }
const defaultEmail = "536464346@qq.com"
type Certificate struct { type Certificate struct {
CertUrl string `json:"certUrl"` CertUrl string `json:"certUrl"`
CertStableUrl string `json:"certStableUrl"` CertStableUrl string `json:"certStableUrl"`

View File

@ -16,9 +16,10 @@ import AddNode from "./node/AddNode";
export type NodeProps = { export type NodeProps = {
node: WorkflowNode; node: WorkflowNode;
disabled?: boolean;
}; };
const WorkflowElement = ({ node }: NodeProps) => { const WorkflowElement = ({ node, disabled }: NodeProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { updateNode, removeNode } = useWorkflowStore(useZustandShallowSelector(["updateNode", "removeNode"])); const { updateNode, removeNode } = useWorkflowStore(useZustandShallowSelector(["updateNode", "removeNode"]));
@ -94,6 +95,8 @@ const WorkflowElement = ({ node }: NodeProps) => {
}; };
const handleNodeClick = () => { const handleNodeClick = () => {
if (disabled) return;
showPanel({ showPanel({
name: node.name, name: node.name,
children: <PanelBody data={node} />, children: <PanelBody data={node} />,
@ -111,10 +114,13 @@ const WorkflowElement = ({ node }: NodeProps) => {
items: [ items: [
{ {
key: "delete", key: "delete",
disabled: disabled,
label: t("workflow_node.action.delete_node"), label: t("workflow_node.action.delete_node"),
icon: <CloseCircleOutlinedIcon />, icon: <CloseCircleOutlinedIcon />,
danger: true, danger: true,
onClick: () => { onClick: () => {
if (disabled) return;
removeNode(node.id); removeNode(node.id);
}, },
}, },
@ -150,7 +156,7 @@ const WorkflowElement = ({ node }: NodeProps) => {
</Card> </Card>
</Popover> </Popover>
<AddNode node={node} /> <AddNode node={node} disabled={disabled} />
</> </>
); );
}; };

View File

@ -10,9 +10,10 @@ import { useWorkflowStore } from "@/stores/workflow";
export type WorkflowElementsProps = { export type WorkflowElementsProps = {
className?: string; className?: string;
style?: React.CSSProperties; style?: React.CSSProperties;
disabled?: boolean;
}; };
const WorkflowElements = ({ className, style }: WorkflowElementsProps) => { const WorkflowElements = ({ className, style, disabled }: WorkflowElementsProps) => {
const { workflow } = useWorkflowStore(useZustandShallowSelector(["workflow"])); const { workflow } = useWorkflowStore(useZustandShallowSelector(["workflow"]));
const elements = useMemo(() => { const elements = useMemo(() => {
@ -20,7 +21,7 @@ const WorkflowElements = ({ className, style }: WorkflowElementsProps) => {
let current = workflow.draft as WorkflowNode; let current = workflow.draft as WorkflowNode;
while (current) { while (current) {
nodes.push(<NodeRender node={current} key={current.id} />); nodes.push(<NodeRender key={current.id} node={current} disabled={disabled} />);
current = current.next as WorkflowNode; current = current.next as WorkflowNode;
} }

View File

@ -15,9 +15,10 @@ import { useWorkflowStore } from "@/stores/workflow";
export type AddNodeProps = { export type AddNodeProps = {
node: WorkflowNode; node: WorkflowNode;
disabled?: boolean;
}; };
const AddNode = ({ node }: AddNodeProps) => { const AddNode = ({ node, disabled }: AddNodeProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { addNode } = useWorkflowStore(useZustandShallowSelector(["addNode"])); const { addNode } = useWorkflowStore(useZustandShallowSelector(["addNode"]));
@ -31,20 +32,19 @@ const AddNode = ({ node }: AddNodeProps) => {
].map(([type, label, icon]) => { ].map(([type, label, icon]) => {
return { return {
key: type as string, key: type as string,
disabled: true,
label: t(label as string), label: t(label as string),
icon: icon, icon: icon,
onClick: () => { onClick: () => {
handleNodeTypeSelect(type as WorkflowNodeType); if (disabled) return;
const nextNode = newNode(type as WorkflowNodeType);
addNode(nextNode, node.id);
}, },
}; };
}); });
}, []); }, []);
const handleNodeTypeSelect = (type: WorkflowNodeType) => {
const nextNode = newNode(type);
addNode(nextNode, node.id);
};
return ( return (
<div className="relative py-6 before:absolute before:left-1/2 before:top-0 before:h-full before:w-[2px] before:-translate-x-1/2 before:bg-stone-200 before:content-['']"> <div className="relative py-6 before:absolute before:left-1/2 before:top-0 before:h-full before:w-[2px] before:-translate-x-1/2 before:bg-stone-200 before:content-['']">
<Dropdown menu={{ items: dropdownMenus }} trigger={["click"]}> <Dropdown menu={{ items: dropdownMenus }} trigger={["click"]}>

View File

@ -11,9 +11,10 @@ import NodeRender from "./NodeRender";
export type BrandNodeProps = { export type BrandNodeProps = {
node: WorkflowNode; node: WorkflowNode;
disabled?: boolean;
}; };
const BranchNode = ({ node }: BrandNodeProps) => { const BranchNode = ({ node, disabled }: BrandNodeProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { addBranch } = useWorkflowStore(useZustandShallowSelector(["addBranch"])); const { addBranch } = useWorkflowStore(useZustandShallowSelector(["addBranch"]));
@ -23,7 +24,7 @@ const BranchNode = ({ node }: BrandNodeProps) => {
let current = node as WorkflowNode | undefined; let current = node as WorkflowNode | undefined;
while (current) { while (current) {
elements.push(<NodeRender key={current.id} node={current} branchId={branchNodeId} branchIndex={branchIndex} />); elements.push(<NodeRender key={current.id} node={current} branchId={branchNodeId} branchIndex={branchIndex} disabled={disabled} />);
current = current.next; current = current.next;
} }
@ -35,6 +36,7 @@ const BranchNode = ({ node }: BrandNodeProps) => {
<div className="relative flex gap-x-16 before:absolute before:inset-x-[128px] before:top-0 before:h-[2px] before:bg-stone-200 before:content-[''] after:absolute after:inset-x-[128px] after:bottom-0 after:h-[2px] after:bg-stone-200 after:content-['']"> <div className="relative flex gap-x-16 before:absolute before:inset-x-[128px] before:top-0 before:h-[2px] before:bg-stone-200 before:content-[''] after:absolute after:inset-x-[128px] after:bottom-0 after:h-[2px] after:bg-stone-200 after:content-['']">
<Button <Button
className="absolute left-1/2 z-[1] -translate-x-1/2 -translate-y-1/2 text-xs" className="absolute left-1/2 z-[1] -translate-x-1/2 -translate-y-1/2 text-xs"
disabled={disabled}
size="small" size="small"
shape="round" shape="round"
variant="outlined" variant="outlined"
@ -55,7 +57,7 @@ const BranchNode = ({ node }: BrandNodeProps) => {
))} ))}
</div> </div>
<AddNode node={node} /> <AddNode node={node} disabled={disabled} />
</> </>
); );
}; };

View File

@ -11,11 +11,12 @@ import AddNode from "./AddNode";
export type ConditionNodeProps = { export type ConditionNodeProps = {
node: WorkflowNode; node: WorkflowNode;
branchId?: string; branchId: string;
branchIndex?: number; branchIndex: number;
disabled?: boolean;
}; };
const ConditionNode = ({ node, branchId, branchIndex }: ConditionNodeProps) => { const ConditionNode = ({ node, branchId, branchIndex, disabled }: ConditionNodeProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const { updateNode, removeBranch } = useWorkflowStore(useZustandShallowSelector(["updateNode", "removeBranch"])); const { updateNode, removeBranch } = useWorkflowStore(useZustandShallowSelector(["updateNode", "removeBranch"]));
@ -44,11 +45,14 @@ const ConditionNode = ({ node, branchId, branchIndex }: ConditionNodeProps) => {
items: [ items: [
{ {
key: "delete", key: "delete",
disabled: disabled,
label: t("workflow_node.action.delete_branch"), label: t("workflow_node.action.delete_branch"),
icon: <CloseCircleOutlinedIcon />, icon: <CloseCircleOutlinedIcon />,
danger: true, danger: true,
onClick: () => { onClick: () => {
removeBranch(branchId ?? "", branchIndex ?? 0); if (disabled) return;
removeBranch(branchId!, branchIndex!);
}, },
}, },
], ],
@ -76,7 +80,7 @@ const ConditionNode = ({ node, branchId, branchIndex }: ConditionNodeProps) => {
</Card> </Card>
</Popover> </Popover>
<AddNode node={node} /> <AddNode node={node} disabled={disabled} />
</> </>
); );
}; };

View File

@ -11,22 +11,23 @@ export type NodeRenderProps = {
node: WorkflowNode; node: WorkflowNode;
branchId?: string; branchId?: string;
branchIndex?: number; branchIndex?: number;
disabled?: boolean;
}; };
const NodeRender = ({ node: data, branchId, branchIndex }: NodeRenderProps) => { const NodeRender = ({ node: data, branchId, branchIndex, disabled }: NodeRenderProps) => {
const render = () => { const render = () => {
switch (data.type) { switch (data.type) {
case WorkflowNodeType.Start: case WorkflowNodeType.Start:
case WorkflowNodeType.Apply: case WorkflowNodeType.Apply:
case WorkflowNodeType.Deploy: case WorkflowNodeType.Deploy:
case WorkflowNodeType.Notify: case WorkflowNodeType.Notify:
return <WorkflowElement node={data} />; return <WorkflowElement node={data} disabled={disabled} />;
case WorkflowNodeType.End: case WorkflowNodeType.End:
return <EndNode />; return <EndNode />;
case WorkflowNodeType.Branch: case WorkflowNodeType.Branch:
return <BranchNode node={data} />; return <BranchNode node={data} disabled={disabled} />;
case WorkflowNodeType.Condition: case WorkflowNodeType.Condition:
return <ConditionNode node={data as WorkflowNode} branchId={branchId} branchIndex={branchIndex} />; return <ConditionNode node={data as WorkflowNode} branchId={branchId!} branchIndex={branchIndex!} disabled={disabled} />;
} }
}; };

View File

@ -248,7 +248,7 @@ const WorkflowDetail = () => {
<Show when={tabValue === "orchestration"}> <Show when={tabValue === "orchestration"}>
<div className="relative"> <div className="relative">
<div className="py-12 lg:pr-36 xl:pr-48"> <div className="py-12 lg:pr-36 xl:pr-48">
<WorkflowElements /> <WorkflowElements disabled={isRunning} />
</div> </div>
<div className="absolute right-0 top-0 z-[1]"> <div className="absolute right-0 top-0 z-[1]">
<Space> <Space>