support check children limit

This commit is contained in:
codetypes committed 2024-07-19 00:06:29 +08:00
1 parent b4021e487c
commit e4f0686f2f
7 files changed
+84 -47

No files matched your search

+2
View File
@@ -82,6 +82,8 @@
"regnode.subtree": "Subtree: ", "regnode.subtree": "Subtree: ",
"node.args": "Const arguments", "node.args": "Const arguments",
"node.children": "Subnode limit",
"node.children.unlimited": "Unlimited",
"node.debug": "Debug", "node.debug": "Debug",
"node.disabled": "Disabled", "node.disabled": "Disabled",
"node.deleteRootNodeDenied": "Unable to delete the root node", "node.deleteRootNodeDenied": "Unable to delete the root node",
+2
View File
@@ -82,6 +82,8 @@
"regnode.subtree": "子树:", "regnode.subtree": "子树:",
"node.args": "常量参数", "node.args": "常量参数",
"node.children": "子节点数量",
"node.children.unlimited": "无限制",
"node.debug": "调试", "node.debug": "调试",
"node.disabled": "禁用", "node.disabled": "禁用",
"node.deleteRootNodeDenied": "不能删除根节点", "node.deleteRootNodeDenied": "不能删除根节点",
+14
View File
@@ -403,6 +403,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
workspace.onEditingNode({ workspace.onEditingNode({
data: b3util.createNode(data, false), data: b3util.createNode(data, false),
editable: !isSubtreeNode(data), editable: !isSubtreeNode(data),
limit_error: !b3util.checkChildrenLimit(data),
}); });
setItemState(editor.selectedId, "selected", true); setItemState(editor.selectedId, "selected", true);
} else { } else {
@@ -453,6 +454,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
selectNode(null); selectNode(null);
curNodeData.children ||= []; curNodeData.children ||= [];
curNodeData.children.push(data); curNodeData.children.push(data);
refreshItem(curNodeData);
updateGrahp(); updateGrahp();
pushHistory(); pushHistory();
onChange(); onChange();
@@ -485,6 +487,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
const data = b3util.createTreeData(JSON.parse(str), editor.selectedId); const data = b3util.createTreeData(JSON.parse(str), editor.selectedId);
editor.autoId = b3util.refreshTreeDataId(data, editor.autoId); editor.autoId = b3util.refreshTreeDataId(data, editor.autoId);
parentData.children![idx] = data; parentData.children![idx] = data;
refreshItem(parentData);
updateGrahp(); updateGrahp();
} else { } else {
editor.data = b3util.createTreeData(JSON.parse(str), editor.selectedId); editor.data = b3util.createTreeData(JSON.parse(str), editor.selectedId);
@@ -520,6 +523,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
}; };
curNodeData.children ||= []; curNodeData.children ||= [];
curNodeData.children.push(b3util.createTreeData(newNodeData, editor.selectedId)); curNodeData.children.push(b3util.createTreeData(newNodeData, editor.selectedId));
refreshItem(curNodeData);
updateGrahp(); updateGrahp();
pushHistory(); pushHistory();
onChange(); onChange();
@@ -544,12 +548,17 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
const parentData = findParent(data)!; const parentData = findParent(data)!;
parentData.children = parentData.children!.filter((e) => e.id != editor.selectedId); parentData.children = parentData.children!.filter((e) => e.id != editor.selectedId);
refreshItem(parentData);
selectNode(null); selectNode(null);
updateGrahp(); updateGrahp();
pushHistory(); pushHistory();
onChange(); onChange();
}; };
const refreshItem = (data: TreeGraphData) => {
editor.graph.findById(data.id)?.draw();
};
const useStackData = (data: NodeModel) => { const useStackData = (data: NodeModel) => {
editor.data = b3util.createTreeData(data); editor.data = b3util.createTreeData(data);
editor.autoId = b3util.refreshTreeDataId(editor.data); editor.autoId = b3util.refreshTreeDataId(editor.data);
@@ -844,6 +853,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
); );
dstData.children ||= []; dstData.children ||= [];
dstData.children.push(newTreeData); dstData.children.push(newTreeData);
refreshItem(dstData);
srcNodeId = newTreeData.id; srcNodeId = newTreeData.id;
} else if (exploreFile && exploreFile !== editor.path) { } else if (exploreFile && exploreFile !== editor.path) {
const newTreeData: TreeGraphData = b3util.createTreeData( const newTreeData: TreeGraphData = b3util.createTreeData(
@@ -856,6 +866,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
); );
dstData.children ||= []; dstData.children ||= [];
dstData.children.push(newTreeData); dstData.children.push(newTreeData);
refreshItem(dstData);
srcNodeId = newTreeData.id; srcNodeId = newTreeData.id;
editor.autoId = b3util.refreshTreeDataId(newTreeData, Number(srcNodeId)); editor.autoId = b3util.refreshTreeDataId(newTreeData, Number(srcNodeId));
} }
@@ -916,6 +927,9 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
return; return;
} }
refreshItem(srcParent);
refreshItem(dstData);
updateGrahp(); updateGrahp();
pushHistory(); pushHistory();
onChange(); onChange();
+40 -47
View File
@@ -1,7 +1,6 @@
import { EditNode, EditTree, useWorkspace } from "@/contexts/workspace-context"; import { EditNode, EditTree, useWorkspace } from "@/contexts/workspace-context";
import { NodeArgType, NodeModel, TreeGraphData, TreeModel } from "@/misc/b3type"; import { NodeArgType, NodeModel, TreeGraphData } from "@/misc/b3type";
import { Hotkey, isMacos } from "@/misc/keys"; import { Hotkey, isMacos } from "@/misc/keys";
import Path from "@/misc/path";
import { EditOutlined } from "@ant-design/icons"; import { EditOutlined } from "@ant-design/icons";
import { import {
AutoComplete, AutoComplete,
@@ -102,6 +101,11 @@ const NodeInspector: FC = () => {
form.setFieldValue("debug", data.debug); form.setFieldValue("debug", data.debug);
form.setFieldValue("disabled", data.disabled); form.setFieldValue("disabled", data.disabled);
form.setFieldValue("path", data.path); form.setFieldValue("path", data.path);
if (def.children === undefined || def.children === -1) {
form.setFieldValue("children", t("node.children.unlimited"));
} else {
form.setFieldValue("children", def.children);
}
def.args?.forEach((v) => { def.args?.forEach((v) => {
form.setFieldValue(`args.${v.name}`, data.args?.[v.name] ?? v.default); form.setFieldValue(`args.${v.name}`, data.args?.[v.name] ?? v.default);
}); });
@@ -241,22 +245,18 @@ const NodeInspector: FC = () => {
labelCol={{ span: "auto" }} labelCol={{ span: "auto" }}
onFinish={finish} onFinish={finish}
> >
<Form.Item <Form.Item name="id" label={t("node.id")}>
name="id"
label={
<div style={{ minWidth: "80px", justifyContent: "flex-end" }}>{t("node.id")}</div>
}
>
<Input disabled={true} /> <Input disabled={true} />
</Form.Item> </Form.Item>
<Form.Item <Form.Item name="type" label={t("node.type")}>
name="type"
label={
<div style={{ minWidth: "80px", justifyContent: "flex-end" }}>{t("node.type")}</div>
}
>
<Input disabled={true} /> <Input disabled={true} />
</Form.Item> </Form.Item>
<Form.Item name="children" label={t("node.children")}>
<Input
style={{ borderColor: editingNode.limit_error ? "red" : undefined }}
disabled={true}
/>
</Form.Item>
<Form.Item label={t("node.name")} name="name"> <Form.Item label={t("node.name")} name="name">
<AutoComplete <AutoComplete
disabled={disabled} disabled={disabled}
@@ -418,22 +418,27 @@ const NodeDefInspector: FC = () => {
}; };
const { t } = useTranslation(); const { t } = useTranslation();
const [form] = Form.useForm(); const [form] = Form.useForm();
const data = workspace.editingNodeDef.data; const def = workspace.editingNodeDef.data;
// set form values // set form values
useEffect(() => { useEffect(() => {
form.resetFields(); form.resetFields();
form.setFieldValue("name", data.name); form.setFieldValue("name", def.name);
form.setFieldValue("type", data.type); form.setFieldValue("type", def.type);
form.setFieldValue("desc", data.desc); form.setFieldValue("desc", def.desc);
form.setFieldValue("doc", data.doc); form.setFieldValue("doc", def.doc);
data.input?.forEach((v, i) => { if (def.children === undefined || def.children === -1) {
form.setFieldValue("children", t("node.children.unlimited"));
} else {
form.setFieldValue("children", def.children);
}
def.input?.forEach((v, i) => {
form.setFieldValue(`input.${i}.name`, v.replaceAll("?", "")); form.setFieldValue(`input.${i}.name`, v.replaceAll("?", ""));
}); });
data.output?.forEach((v, i) => { def.output?.forEach((v, i) => {
form.setFieldValue(`output.${i}.name`, v.replaceAll("?", "")); form.setFieldValue(`output.${i}.name`, v.replaceAll("?", ""));
}); });
data.args?.forEach((v, i) => { def.args?.forEach((v, i) => {
form.setFieldValue(`args.${i}.type`, v.type.replaceAll("?", "")); form.setFieldValue(`args.${i}.type`, v.type.replaceAll("?", ""));
}); });
}, [workspace.editingNodeDef]); }, [workspace.editingNodeDef]);
@@ -452,37 +457,25 @@ const NodeDefInspector: FC = () => {
labelCol={{ span: "auto" }} labelCol={{ span: "auto" }}
// onFinish={finish} // onFinish={finish}
> >
<Form.Item <Form.Item name="name" label={t("node.name")}>
name="name"
label={
<div style={{ minWidth: "80px", justifyContent: "flex-end" }}>{t("node.name")}</div>
}
>
<Input disabled={true} /> <Input disabled={true} />
</Form.Item> </Form.Item>
<Form.Item <Form.Item name="type" label={t("node.type")}>
name="type"
label={
<div style={{ minWidth: "80px", justifyContent: "flex-end" }}>{t("node.type")}</div>
}
>
<Input disabled={true} /> <Input disabled={true} />
</Form.Item> </Form.Item>
<Form.Item <Form.Item name="children" label={t("node.children")}>
name="desc" <Input disabled={true} />
label={ </Form.Item>
<div style={{ minWidth: "80px", justifyContent: "flex-end" }}>{t("node.desc")}</div> <Form.Item name="desc" label={t("node.desc")}>
}
>
<TextArea autoSize disabled={true} /> <TextArea autoSize disabled={true} />
</Form.Item> </Form.Item>
<Markdown className="b3-markdown">{data.doc}</Markdown> <Markdown className="b3-markdown">{def.doc}</Markdown>
{data.input && data.input.length > 0 && ( {def.input && def.input.length > 0 && (
<> <>
<Divider orientation="left"> <Divider orientation="left">
<h4>{t("node.inputVariable")}</h4> <h4>{t("node.inputVariable")}</h4>
</Divider> </Divider>
{data.input.map((v, i) => { {def.input.map((v, i) => {
const required = v.indexOf("?") == -1; const required = v.indexOf("?") == -1;
return ( return (
<Form.Item <Form.Item
@@ -497,12 +490,12 @@ const NodeDefInspector: FC = () => {
})} })}
</> </>
)} )}
{data.args && data.args.length > 0 && ( {def.args && def.args.length > 0 && (
<> <>
<Divider orientation="left"> <Divider orientation="left">
<h4>{t("node.args")}</h4> <h4>{t("node.args")}</h4>
</Divider> </Divider>
{data.args.map((v, i) => { {def.args.map((v, i) => {
const required = v.type.indexOf("?") == -1; const required = v.type.indexOf("?") == -1;
return ( return (
<Form.Item <Form.Item
@@ -525,12 +518,12 @@ const NodeDefInspector: FC = () => {
})} })}
</> </>
)} )}
{data.output && data.output.length > 0 && ( {def.output && def.output.length > 0 && (
<> <>
<Divider orientation="left"> <Divider orientation="left">
<h4>{t("node.outputVariable")}</h4> <h4>{t("node.outputVariable")}</h4>
</Divider> </Divider>
{data.output.map((v, i) => { {def.output.map((v, i) => {
const required = v.indexOf("?") == -1; const required = v.indexOf("?") == -1;
return ( return (
<Form.Item <Form.Item
+1
View File
@@ -90,6 +90,7 @@ export type FileTreeType = {
export type EditNode = { export type EditNode = {
data: NodeModel; data: NodeModel;
editable: boolean; editable: boolean;
limit_error?: boolean;
}; };
export type EditNodeDef = { export type EditNodeDef = {
+1
View File
@@ -32,6 +32,7 @@ export interface NodeDef {
`${Status}` | `!${Status}` | `|${Status}` | `&${Status}`, `${Status}` | `!${Status}` | `|${Status}` | `&${Status}`,
"!running" | "&running" "!running" | "&running"
>[]; >[];
children?: -1 | 0 | 1;
} }
export interface NodeModel { export interface NodeModel {
+24
View File
@@ -73,6 +73,15 @@ export const checkNodeData = (data: NodeModel | null | undefined) => {
} }
let hasError = false; let hasError = false;
const conf = useWorkspace.getState().getNodeDef(data.name); const conf = useWorkspace.getState().getNodeDef(data.name);
if (conf.children !== undefined) {
if (conf.children == 0 && data.children?.length) {
hasError = true;
console.error(`check ${data.id}|${data.name}: no children is required`);
} else if (conf.children == 1 && data.children?.length !== 1) {
hasError = true;
console.error(`check ${data.id}|${data.name}: only one child is required`);
}
}
if (conf.input) { if (conf.input) {
for (let i = 0; i < conf.input.length; i++) { for (let i = 0; i < conf.input.length; i++) {
if (!data.input) { if (!data.input) {
@@ -330,6 +339,18 @@ export const calcTreeDataSize = (data: TreeGraphData) => {
return [220, height]; return [220, height];
}; };
export const checkChildrenLimit = (data: TreeGraphData) => {
const conf = data.def;
if (conf.children !== undefined) {
if (conf.children == 0 && data.children?.length) {
return false;
} else if (conf.children == 1 && data.children?.length !== 1) {
return false;
}
}
return true;
};
export const checkTreeData = (data: TreeGraphData) => { export const checkTreeData = (data: TreeGraphData) => {
const conf = data.def; const conf = data.def;
if (conf.input) { if (conf.input) {
@@ -346,6 +367,9 @@ export const checkTreeData = (data: TreeGraphData) => {
} }
} }
} }
if (!checkChildrenLimit(data)) {
return false;
}
if (conf.args) { if (conf.args) {
for (let i = 0; i < conf.args.length; i++) { for (let i = 0; i < conf.args.length; i++) {
const arg = conf.args[i]; const arg = conf.args[i];