From da96ad865bd9cf2e890cb1aad58dc5e13d13264d Mon Sep 17 00:00:00 2001 From: codetypes Date: Thu, 20 Mar 2025 00:45:25 +0800 Subject: [PATCH] show variable using count --- public/locales/en.json | 1 + public/locales/zh.json | 1 + sample/vars/test-vars.json | 17 +- src/behavior3 | 2 +- src/components/editor.tsx | 96 +++--- src/components/inspector.tsx | 493 ++++++++++++++++++------------ src/components/register-node.ts | 8 +- src/contexts/workspace-context.ts | 37 ++- 8 files changed, 375 insertions(+), 280 deletions(-) diff --git a/public/locales/en.json b/public/locales/en.json index 58766b3..8527cfd 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -110,6 +110,7 @@ "node.invalidVariableName": "Invalid variable name, should start with a letter or underscore", "node.name": "Node name", "node.noNodeSelected": "No node selected", + "node.notFound": "Node '{{name}}' not found", "node.oneof.error": "Only one is allowed between input '{{input}}' and argument '{{arg}}({{desc}})'", "node.oneof.inputNotfound": "Input '{{input}}' not found", "node.outputVariable": "Output variables", diff --git a/public/locales/zh.json b/public/locales/zh.json index f067f7b..8f8c130 100644 --- a/public/locales/zh.json +++ b/public/locales/zh.json @@ -110,6 +110,7 @@ "node.invalidVariableName": "变量名必须以字母或下划线开头", "node.name": "节点名称", "node.noNodeSelected": "未选择任务节点", + "node.notFound": "节点 “{{name}}” 不存在", "node.oneof.error": "输入项 “{{input}}” 和参数 “{{arg}}({{desc}})” 之中,只能选择设置其中之一", "node.oneof.inputNotfound": "输入项“{{input}}”不存在", "node.outputVariable": "输出变量", diff --git a/sample/vars/test-vars.json b/sample/vars/test-vars.json index 6e0028e..bc0dc91 100644 --- a/sample/vars/test-vars.json +++ b/sample/vars/test-vars.json @@ -63,16 +63,10 @@ "name": "Clear", "output": [ "test" - ], - "children": [ - { - "id": 9, - "name": "Idle" - } ] }, { - "id": 10, + "id": 9, "name": "TestB3", "args": { "time": 1, @@ -83,7 +77,7 @@ } }, { - "id": 11, + "id": 10, "name": "TestB3", "args": { "time": 1, @@ -92,6 +86,13 @@ "name": "1", "status": "RUNNING" } + }, + { + "id": 11, + "name": "Clear", + "output": [ + "context" + ] } ] }, diff --git a/src/behavior3 b/src/behavior3 index ca44652..13ebbcd 160000 --- a/src/behavior3 +++ b/src/behavior3 @@ -1 +1 @@ -Subproject commit ca446528bd715eb250a6f32d94bcf8af0d4d5c12 +Subproject commit 13ebbcde9ea69535b94e615e1fde286e15573daa diff --git a/src/components/editor.tsx b/src/components/editor.tsx index 4019cd1..d4b0921 100644 --- a/src/components/editor.tsx +++ b/src/components/editor.tsx @@ -70,34 +70,34 @@ const refreshTreeData = (data: TreeGraphData) => { const isTreeUpdated = (editor: EditorStore, editTree: EditTree) => { if ( - editor.data.firstid !== editTree.data.firstid || - editor.data.export !== editTree.data.export || - editor.data.name !== editTree.data.name || - editor.data.desc !== editTree.data.desc + editor.data.firstid !== editTree.firstid || + editor.data.export !== editTree.export || + editor.data.name !== editTree.name || + editor.data.desc !== editTree.desc ) { return true; } - let max = Math.max(editor.declare.declvar.length, editTree.data.declvar.length); + let max = Math.max(editor.declare.declvar.length, editTree.declvar.length); for (let i = 0; i < max; i++) { const v1: VarDef | undefined = editor.declare.declvar[i]; - const v2: VarDef | undefined = editTree.data.declvar[i]; + const v2: VarDef | undefined = editTree.declvar[i]; if (v1?.name !== v2?.name || v1?.desc !== v2?.desc) { return true; } } - max = Math.max(editor.data.group.length, editTree.data.group.length); + max = Math.max(editor.data.group.length, editTree.group.length); for (let i = 0; i < max; i++) { - if (editor.data.group[i] !== editTree.data.group[i]) { + if (editor.data.group[i] !== editTree.group[i]) { return true; } } - max = Math.max(editor.declare.import.length, editTree.data.import.length); + max = Math.max(editor.declare.import.length, editTree.import.length); for (let i = 0; i < max; i++) { const v1: ImportDef | undefined = editor.declare.import[i]; - const v2: ImportDef | undefined = editTree.data.import[i]; + const v2: ImportDef | undefined = editTree.import[i]; if (v1?.path !== v2?.path) { return true; } @@ -551,12 +551,12 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . const updateTree = (editTree: EditTree) => { if (isTreeUpdated(editor, editTree)) { - editor.data.desc = editTree.data.desc || ""; - editor.data.export = editTree.data.export !== false; - editor.data.group = editTree.data.group; - editor.data.firstid = editTree.data.firstid ?? 1; - editor.declare.declvar = editTree.data.declvar || []; - editor.declare.import = editTree.data.import || []; + editor.data.desc = editTree.desc || ""; + editor.data.export = editTree.export !== false; + editor.data.group = editTree.group; + editor.data.firstid = editTree.firstid ?? 1; + editor.declare.declvar = editTree.declvar || []; + editor.declare.import = editTree.import || []; editor.data.import = editor.declare.import.map((v) => v.path).sort(); editor.data.declvar = editor.declare.declvar .map((v) => ({ ...v })) @@ -568,6 +568,32 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . } }; + const clickVar = (...names: string[]) => { + const changed = findHightlight(editor.root, names); + if (changed.length > 0) { + const refreshHighlight = (node: TreeGraphData) => { + const item = editor.graph.findById(node.id); + if (names.length > 0) { + node.highlightGray = !(node.highlightInput || node.highlightOutput || node.highlightArgs); + } else { + node.highlightGray = false; + } + item.draw(); + if (node.children) { + node.children.forEach(refreshHighlight); + } + }; + refreshHighlight(editor.root); + } + if (names.length === 0 && editor.searchingText) { + onSearchChange({ + ...filterOption, + filterType: "content", + filterStr: editor.searchingText, + }); + } + }; + const selectNode = (id: string | null) => { if (editor.selectedId) { setItemState(editor.selectedId, "selected", false); @@ -953,41 +979,15 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . }); editor.graph.on("node:click", (e: G6GraphEvent) => { - const highlight: string[] = []; + const names: string[] = []; if (e.shape.cfg.name === "input-text") { const data = findDataById(e.item.getID()); - data.input?.forEach((v) => v && highlight.push(v)); + data.input?.forEach((v) => v && names.push(v)); } else if (e.shape.cfg.name === "output-text") { const data = findDataById(e.item.getID()); - data.output?.forEach((v) => v && highlight.push(v)); - } - const changed = findHightlight(editor.root, highlight); - if (changed.length > 0) { - const refreshHighlight = (node: TreeGraphData) => { - const item = editor.graph.findById(node.id); - if (highlight.length > 0) { - node.highlightGray = !( - node.highlightInput || - node.highlightOutput || - node.highlightArgs - ); - } else { - node.highlightGray = false; - } - item.draw(); - if (node.children) { - node.children.forEach(refreshHighlight); - } - }; - refreshHighlight(editor.root); - } - if (highlight.length === 0 && editor.searchingText) { - onSearchChange({ - ...filterOption, - filterType: "content", - filterStr: editor.searchingText, - }); + data.output?.forEach((v) => v && names.push(v)); } + clickVar(...names); }); editor.graph.on("node:contextmenu", (e: G6GraphEvent) => { @@ -1253,6 +1253,10 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . saveAsSubtree(); break; } + case "clickVar": { + clickVar(data as string); + break; + } } }; diff --git a/src/components/inspector.tsx b/src/components/inspector.tsx index 361fbac..afef19e 100644 --- a/src/components/inspector.tsx +++ b/src/components/inspector.tsx @@ -57,12 +57,13 @@ interface OptionType extends DefaultOptionType { const TreeInspector: FC = () => { const workspace = useWorkspace( useShallow((state) => ({ + allFiles: state.allFiles, editing: state.editing, editingTree: state.editingTree!, - allFiles: state.allFiles, - relative: state.relative, fileTree: state.fileTree, groupDefs: state.groupDefs, + nodeDefs: state.nodeDefs, + relative: state.relative, })) ); const { t } = useTranslation(); @@ -72,10 +73,50 @@ const TreeInspector: FC = () => { const groupDefs: GroupDef[] = useMemo(() => { return workspace.groupDefs.map((v) => ({ name: v, - value: workspace.editingTree.data.group.includes(v), + value: workspace.editingTree.group.includes(v), })); }, [workspace.groupDefs, workspace.editingTree]); + // using count + const usingCount: Record = useMemo(() => { + const count: Record = {}; + const collect = (node: TreeGraphData) => { + const def = workspace.nodeDefs.get(node.name); + if (def.input) { + node.input?.forEach((v) => { + count[v] = (count[v] ?? 0) + 1; + }); + } + if (def.output) { + node.output?.forEach((v) => { + count[v] = (count[v] ?? 0) + 1; + }); + } + if (def.args) { + def.args.forEach((arg) => { + const expr = node.args?.[arg.name] as string | string[] | undefined; + if (!isExprType(arg.type) || !expr) { + return; + } + if (Array.isArray(expr)) { + expr.forEach((str) => { + parseExpr(str).forEach((v) => { + count[v] = (count[v] ?? 0) + 1; + }); + }); + } else { + parseExpr(expr).forEach((v) => { + count[v] = (count[v] ?? 0) + 1; + }); + } + }); + } + node.children?.forEach(collect); + }; + collect(workspace.editingTree.root); + return count; + }, [workspace.editingTree, workspace.nodeDefs]); + // auto complete for subtree const subtreeOptions = useMemo(() => { const options: OptionType[] = []; @@ -93,42 +134,39 @@ const TreeInspector: FC = () => { // set form values useEffect(() => { - const data = workspace.editingTree.data; - loadVarDef(data.import); + loadVarDef(workspace.editingTree.import); form.resetFields(); - form.setFieldValue("name", data.name); - form.setFieldValue("desc", data.desc); - form.setFieldValue("export", data.export !== false); - form.setFieldValue("firstid", data.firstid); + form.setFieldValue("name", workspace.editingTree.name); + form.setFieldValue("desc", workspace.editingTree.desc); + form.setFieldValue("export", workspace.editingTree.export !== false); + form.setFieldValue("firstid", workspace.editingTree.firstid); form.setFieldValue("group", groupDefs); - form.setFieldValue("declvar", data.declvar); - form.setFieldValue("import", data.import); - form.setFieldValue("subtree", data.subtree); + form.setFieldValue("declvar", workspace.editingTree.declvar); + form.setFieldValue("import", workspace.editingTree.import); + form.setFieldValue("subtree", workspace.editingTree.subtree); }, [workspace.editingTree, groupDefs]); // eslint-disable-next-line @typescript-eslint/no-explicit-any const finish = (values: any) => { workspace.editing?.dispatch("updateTree", { - data: { - name: values.name, - desc: values.desc, - export: values.export, - firstid: Number(values.firstid), - group: (values.group as GroupDef[]) - .map((v) => (v.value ? v.name : "")) - .filter((v) => v) - .sort((a, b) => a.localeCompare(b)), - declvar: (values.declvar as VarDef[]) - .filter((v) => v && v.name) - .sort((a, b) => a.name.localeCompare(b.name)), - import: (values.import as ImportDef[]) - .filter((v) => v && v.path) - .sort((a, b) => a.path.localeCompare(b.path)) - .map((v) => ({ - path: v.path, - vars: v.vars ?? [], - })), - }, + name: values.name, + desc: values.desc, + export: values.export, + firstid: Number(values.firstid), + group: (values.group as GroupDef[]) + .map((v) => (v.value ? v.name : "")) + .filter((v) => v) + .sort((a, b) => a.localeCompare(b)), + declvar: (values.declvar as VarDef[]) + .filter((v) => v && v.name) + .sort((a, b) => a.name.localeCompare(b.name)), + import: (values.import as ImportDef[]) + .filter((v) => v && v.path) + .sort((a, b) => a.path.localeCompare(b.path)) + .map((v) => ({ + path: v.path, + vars: v.vars ?? [], + })), } as EditTree); }; @@ -200,70 +238,85 @@ const TreeInspector: FC = () => {

{t("tree.vars")}

- {(items, { add, remove }, { errors }) => ( + {(fields, { add, remove }, { errors }) => (
- {items.map((item) => ( - - - { + const vardef = workspace.editingTree.declvar[item.name]; + return ( + + + - - - 0 -
- } - placeholder={t("tree.vars.name")} - onBlur={form.submit} - /> - - - - - - { - remove(item.name); - form.submit(); - }} - /> - - ))} + ]} + > + + workspace.editing?.dispatch("clickVar", vardef.name) + } + > + + + {usingCount[vardef.name] ?? 0} + + + } + placeholder={t("tree.vars.name")} + onBlur={form.submit} + /> + + + + + + { + remove(item.name); + form.submit(); + }} + /> + + ); + })} { )}
- {workspace.editingTree.data.subtree.length > 0 && ( + {workspace.editingTree.subtree.length > 0 && ( <>

{t("tree.vars.subtree")}

- {(vars) => ( + {(fields) => (
- {vars.map((v, idx, arr) => ( - - - -
- - 0 -
-
- - - - - - -
-
- ))} + {fields.map((item, idx) => { + const vardef = workspace.editingTree.subtree[item.name]; + return ( + + + +
workspace.editing?.dispatch("clickVar", vardef.name)} + > + + + {usingCount[vardef.name] ?? 0} + +
+
+ + + + + + +
+
+ ); + })}
)}
@@ -390,61 +453,72 @@ const TreeInspector: FC = () => { {(vars) => (
- {vars.map((v, idx, arr) => ( - - - -
- - 0 -
-
- - - - - - -
-
- ))} + {vars.map((v, idx) => { + const vardef = workspace.editingTree.import[item.name].vars[v.name]; + return ( + + + +
+ workspace.editing?.dispatch("clickVar", vardef.name) + } + > + + + {usingCount[vardef.name] ?? 0} + +
+
+ + + + + + +
+
+ ); + })}
)}
@@ -793,7 +867,22 @@ const NodeInspector: FC = () => { > - + 0) { + if (args && Object.keys(args).length > 0) { const { str, line } = toBreakWord(`${i18n.t("regnode.args")}${JSON.stringify(args)}`, 200); if (data.highlightArgs) { addShape("rect", { @@ -420,7 +420,7 @@ G6.registerNode( } const input = data.input ?? []; - if (nodeDef.input && input.length > 0) { + if (input.length > 0) { const { str, line } = toBreakWord( `${i18n.t("regnode.input")}${JSON.stringify(input)}`, 200 @@ -458,7 +458,7 @@ G6.registerNode( } const output = data.output ?? []; - if (nodeDef.output && output.length > 0) { + if (output.length > 0) { const { str, line } = toBreakWord( `${i18n.t("regnode.output")}${JSON.stringify(output)}`, 200 diff --git a/src/contexts/workspace-context.ts b/src/contexts/workspace-context.ts index 61f11bf..b759ff2 100644 --- a/src/contexts/workspace-context.ts +++ b/src/contexts/workspace-context.ts @@ -46,7 +46,8 @@ export type EditEvent = | "updateNode" | "searchNode" | "editSubtree" - | "saveAsSubtree"; + | "saveAsSubtree" + | "clickVar"; export class EditorStore { path: string; @@ -123,16 +124,15 @@ export type EditNodeDef = { }; export type EditTree = { - data: { - name: string; - desc?: string; - export?: boolean; - firstid?: number; - group: string[]; - import: ImportDef[]; - declvar: VarDef[]; - subtree: VarDef[]; - }; + name: string; + desc?: string; + export?: boolean; + firstid?: number; + group: string[]; + import: ImportDef[]; + declvar: VarDef[]; + subtree: VarDef[]; + root: TreeGraphData; }; export type FileMeta = { @@ -692,14 +692,13 @@ export const useWorkspace = create((set, get) => ({ workspace.refresh(editor.path); set({ editingTree: { - data: { - ...editor.data, - import: editor.declare.import, - declvar: editor.declare.declvar, - subtree: editor.declare.subtree - .map((def) => def.vars) - .reduce((acc, v) => [...acc, ...v], []), - }, + ...editor.data, + root: editor.root, + import: editor.declare.import, + declvar: editor.declare.declvar, + subtree: editor.declare.subtree + .map((def) => def.vars) + .reduce((acc, v) => [...acc, ...v], []), }, editingNodeDef: null, editingNode: null,