diff --git a/src/components/explorer.tsx b/src/components/explorer.tsx index 8c99f34..e73d3c8 100644 --- a/src/components/explorer.tsx +++ b/src/components/explorer.tsx @@ -105,8 +105,6 @@ const renameFile = (oldPath: string, newPath: string) => { return false; }; -const getSvgIcon = (path: string) => {}; - export const Explorer: FC = () => { const workspace = { close: useWorkspace((state) => state.close), @@ -116,6 +114,7 @@ export const Explorer: FC = () => { nodeDefs: useWorkspace((state) => state.nodeDefs), nodeTree: useWorkspace((state) => state.nodeTree), workdir: useWorkspace((state) => state.workdir), + onEditingNodeDef: useWorkspace((state) => state.onEditingNodeDef), open: useWorkspace((state) => state.open), }; const { t } = useTranslation(); @@ -798,6 +797,14 @@ export const Explorer: FC = () => { fieldNames={{ key: "title" }} treeData={workspace.nodeTree ? [workspace.nodeTree] : []} draggable={{ icon: false, nodeDraggable: (node) => !!node.isLeaf }} + onSelect={(_, info) => { + const node = info.node; + if (node && node.isLeaf) { + workspace.onEditingNodeDef({ + data: node.def!, + }); + } + }} onDragStart={(e) => { e.event.dataTransfer.setData("explore-node", e.node.def?.name ?? ""); }} diff --git a/src/components/inspector.tsx b/src/components/inspector.tsx index 13d6852..89fc64e 100644 --- a/src/components/inspector.tsx +++ b/src/components/inspector.tsx @@ -10,11 +10,60 @@ import Markdown from "react-markdown"; interface OptionType extends DefaultOptionType {} -export const Inspector: FC = () => { +const TreeInspector: FC = () => { const workspace = { editing: useWorkspace((state) => state.editing), - editingNode: useWorkspace((state) => state.editingNode), - editingTree: useWorkspace((state) => state.editingTree), + editingTree: useWorkspace((state) => state.editingTree)!, + }; + const { t } = useTranslation(); + const [form] = Form.useForm(); + + // set form values + useEffect(() => { + const data = workspace.editingTree.data; + form.resetFields(); + form.setFieldValue("name", data.name); + form.setFieldValue("desc", data.desc); + }, [workspace.editingTree]); + + const finish = (values: any) => { + const data = {} as TreeModel; + data.name = values.name; + data.desc = values.desc || undefined; + workspace.editing?.dispatch?.("updateTree", { + data: { + name: values.name, + desc: values.desc || undefined, + }, + } as EditTree); + }; + + return ( + <> +
+ {t("tree.overview")} +
+
+
+ + + + + + +
+
+ + ); +}; + +const NodeInspector: FC = () => { + const workspace = { + editing: useWorkspace((state) => state.editing), + editingNode: useWorkspace((state) => state.editingNode)!, getNodeDef: useWorkspace((state) => state.getNodeDef), nodeDefs: useWorkspace((state) => state.nodeDefs), onEditingNode: useWorkspace((state) => state.onEditingNode), @@ -26,31 +75,24 @@ export const Inspector: FC = () => { // set form values useEffect(() => { - if (workspace.editingTree) { - const data = workspace.editingTree.data; - form.resetFields(); - form.setFieldValue("name", data.name); - form.setFieldValue("desc", data.desc); - } else if (workspace.editingNode) { - const data = workspace.editingNode.data; - const def = workspace.getNodeDef(workspace.editingNode.data.name); - form.resetFields(); - form.setFieldValue("id", data.id); - form.setFieldValue("name", data.name); - form.setFieldValue("desc", data.desc); - form.setFieldValue("debug", data.debug); - form.setFieldValue("path", data.path); - def.args?.forEach((v) => { - form.setFieldValue(`args.${v.name}`, data.args?.[v.name]); - }); - def.input?.forEach((_, i) => { - form.setFieldValue(`input.${i}`, data.input?.[i]); - }); - def.output?.forEach((_, i) => { - form.setFieldValue(`output.${i}`, data.output?.[i]); - }); - } - }, [workspace.editingNode, workspace.editingTree]); + const data = workspace.editingNode.data; + const def = workspace.getNodeDef(workspace.editingNode.data.name); + form.resetFields(); + form.setFieldValue("id", data.id); + form.setFieldValue("name", data.name); + form.setFieldValue("desc", data.desc); + form.setFieldValue("debug", data.debug); + form.setFieldValue("path", data.path); + def.args?.forEach((v) => { + form.setFieldValue(`args.${v.name}`, data.args?.[v.name]); + }); + def.input?.forEach((_, i) => { + form.setFieldValue(`input.${i}`, data.input?.[i]); + }); + def.output?.forEach((_, i) => { + form.setFieldValue(`output.${i}`, data.output?.[i]); + }); + }, [workspace.editingNode]); // auto complete for node const nodeOptions = useMemo(() => { @@ -99,264 +141,279 @@ export const Inspector: FC = () => { return options; }, [workspace.allFiles, workspace.fileTree]); - if (workspace.editingTree) { - const finish = (values: any) => { - const data = {} as TreeModel; - data.name = values.name; - data.desc = values.desc || undefined; - workspace.editing?.dispatch?.("updateTree", { + const editingNode = workspace.editingNode; + const def = workspace.getNodeDef(editingNode.data.name); + const disabled = !editingNode.editable; + + // update value + const finish = (values: any) => { + const data = {} as NodeModel; + data.id = editingNode.data.id; + data.name = values.name; + data.debug = values.debug || undefined; + data.desc = values.desc || undefined; + data.path = values.path || undefined; + + def.args?.forEach((arg) => { + const v = values[`args.${arg.name}`]; + if (v !== null && v !== undefined && v !== "") { + data.args ||= {}; + data.args[arg.name] = v; + } + }); + + def.input?.forEach((_, i) => { + const v = values[`input.${i}`]; + data.input ||= []; + data.input.push(v ?? ""); + }); + + def.output?.forEach((_, i) => { + const v = values[`output.${i}`]; + data.output ||= []; + data.output.push(v ?? ""); + }); + workspace.editing?.dispatch?.("updateNode", { + data: data, + } as EditNode); + }; + + // change node def + const changeNodeDef = (newname: string) => { + if (editingNode.data.name !== newname) { + workspace.onEditingNode({ data: { - name: values.name, - desc: values.desc || undefined, + id: editingNode.data.id, + name: workspace.nodeDefs.get(newname)?.name ?? newname, + desc: editingNode.data.desc, + debug: editingNode.data.debug, }, - } as EditTree); - }; - return ( - -
- {t("tree.overview")} -
-
{ + if (form.getFieldValue("path") !== editingNode.data.path) { + finish(form.getFieldsValue()); + } else { + form.submit(); + } + }; + + return ( + <> +
+ {def.desc} +
+
+
- - - - - - - -
-
- - ); - } else if (workspace.editingNode) { - const editingNode = workspace.editingNode; - const def = workspace.getNodeDef(editingNode.data.name); - const disabled = !editingNode.editable; - - // update value - const finish = (values: any) => { - const data = {} as NodeModel; - data.id = editingNode.data.id; - data.name = values.name; - data.debug = values.debug || undefined; - data.desc = values.desc || undefined; - data.path = values.path || undefined; - - def.args?.forEach((arg) => { - const v = values[`args.${arg.name}`]; - if (v !== null && v !== undefined && v !== "") { - data.args ||= {}; - data.args[arg.name] = v; - } - }); - - def.input?.forEach((_, i) => { - const v = values[`input.${i}`]; - data.input ||= []; - data.input.push(v ?? ""); - }); - - def.output?.forEach((_, i) => { - const v = values[`output.${i}`]; - data.output ||= []; - data.output.push(v ?? ""); - }); - workspace.editing?.dispatch?.("updateNode", { - data: data, - } as EditNode); - }; - - // change node def - const changeNodeDef = (newname: string) => { - if (editingNode.data.name !== newname) { - workspace.onEditingNode({ - data: { - id: editingNode.data.id, - name: workspace.nodeDefs.get(newname)?.name ?? newname, - desc: editingNode.data.desc, - debug: editingNode.data.debug, - }, - editable: editingNode.editable, - }); - finish(form.getFieldsValue()); - } else { - form.submit(); - } - }; - - const changeSubtree = () => { - if (form.getFieldValue("path") !== editingNode.data.path) { - finish(form.getFieldsValue()); - } else { - form.submit(); - } - }; - - return ( - -
- {def.desc} -
-
-
{t("node.id")}
+ } > - {t("node.id")}
- } - > - - - - changeNodeDef(form.getFieldValue("name"))} - onSelect={changeNodeDef} - onInputKeyDown={(e) => e.code === Hotkey.Escape && e.preventDefault()} - filterOption={(inputValue: string, option?: OptionType) => { - const label = option!.label as string; - return label.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1; - }} - /> - - - - - - - - - e.code === Hotkey.Escape && e.preventDefault()} - filterOption={(inputValue: string, option?: OptionType) => { - const label = option!.label as string; - return label.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1; - }} - /> - - {def.doc} - {def.input && def.input.length > 0 && ( - <> - -

{t("node.inputVariable")}

-
- {def.input.map((v, i) => { - const required = v.indexOf("?") == -1; - const desc = v.replace("?", ""); - return ( - - e.code === Hotkey.Escape && e.preventDefault()} - filterOption={(inputValue: string, option?: OptionType) => { - const label = option!.label as string; - return label.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1; - }} - /> - - ); - })} - - )} - {def.args && def.args.length > 0 && ( - <> - -

{t("node.args")}

-
- {def.args.map((v) => { - const required = v.type.indexOf("?") == -1; - const type = v.type.replace("?", "") as NodeArgType; - return ( - - {type === "string" && } - {type === "int" && ( - - )} - {type === "float" && } - {type === "boolean" && } - {type === "code" && ( - - )} - {type === "enum" && ( - - )} - - ); - })} - - )} - {def.output && def.output.length > 0 && ( - <> - -

{t("node.outputVariable")}

-
- {def.output.map((v, i) => { - const required = v.indexOf("?") == -1; - const desc = v.replace("?", ""); - return ( - - e.code === Hotkey.Escape && e.preventDefault()} - filterOption={(inputValue: string, option?: OptionType) => { - const label = option!.label as string; - return label.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1; - }} - /> - - ); - })} - - )} - - -
- ); - } else { - return null; + + + + changeNodeDef(form.getFieldValue("name"))} + onSelect={changeNodeDef} + onInputKeyDown={(e) => e.code === Hotkey.Escape && e.preventDefault()} + filterOption={(inputValue: string, option?: OptionType) => { + const label = option!.label as string; + return label.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1; + }} + /> + + + + + + + + + e.code === Hotkey.Escape && e.preventDefault()} + filterOption={(inputValue: string, option?: OptionType) => { + const label = option!.label as string; + return label.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1; + }} + /> + + {def.doc} + {def.input && def.input.length > 0 && ( + <> + +

{t("node.inputVariable")}

+
+ {def.input.map((v, i) => { + const required = v.indexOf("?") == -1; + const desc = v.replace("?", ""); + return ( + + e.code === Hotkey.Escape && e.preventDefault()} + filterOption={(inputValue: string, option?: OptionType) => { + const label = option!.label as string; + return label.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1; + }} + /> + + ); + })} + + )} + {def.args && def.args.length > 0 && ( + <> + +

{t("node.args")}

+
+ {def.args.map((v) => { + const required = v.type.indexOf("?") == -1; + const type = v.type.replace("?", "") as NodeArgType; + return ( + + {type === "string" && } + {type === "int" && ( + + )} + {type === "float" && } + {type === "boolean" && } + {type === "code" && ( + + )} + {type === "enum" && ( + + )} + + ); + })} + + )} + {def.output && def.output.length > 0 && ( + <> + +

{t("node.outputVariable")}

+
+ {def.output.map((v, i) => { + const required = v.indexOf("?") == -1; + const desc = v.replace("?", ""); + return ( + + e.code === Hotkey.Escape && e.preventDefault()} + filterOption={(inputValue: string, option?: OptionType) => { + const label = option!.label as string; + return label.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1; + }} + /> + + ); + })} + + )} + + + + ); +}; + +const NodeDefInspector: FC = () => { + const [form] = Form.useForm(); + return ( + <> +
+ Node Definition +
+
+
+
+ + ); +}; + +export const Inspector: FC = () => { + const workspace = { + editingNode: useWorkspace((state) => state.editingNode), + editingTree: useWorkspace((state) => state.editingTree), + editingNodeDef: useWorkspace((state) => state.editingNodeDef), + }; + let isEditingNode = false; + let isEditingTree = false; + let isEditingNodeDef = false; + if (workspace.editingNodeDef) { + isEditingNodeDef = true; + } else if (workspace.editingTree) { + isEditingTree = true; + } else if (workspace.editingNode) { + isEditingNode = true; } + return ( + + {isEditingNodeDef && } + {isEditingTree && } + {isEditingNode && } + + ); }; diff --git a/src/components/workspace.tsx b/src/components/workspace.tsx index f1a0d85..e1c173f 100644 --- a/src/components/workspace.tsx +++ b/src/components/workspace.tsx @@ -409,18 +409,7 @@ export const Workspace: FC = () => { /> )} - {workspace.editors.length > 0 && ( - - - - )} + ); diff --git a/src/contexts/workspace-context.ts b/src/contexts/workspace-context.ts index f15c133..ed73e0d 100644 --- a/src/contexts/workspace-context.ts +++ b/src/contexts/workspace-context.ts @@ -93,6 +93,10 @@ export type EditNode = { editable: boolean; }; +export type EditNodeDef = { + data: NodeDef; +}; + export type EditTree = { data: TreeModel; }; @@ -133,6 +137,10 @@ export type WorkspaceStore = { editingNode?: EditNode | null; onEditingNode: (node: EditNode) => void; + // edit node def + editingNodeDef?: EditNodeDef | null; + onEditingNodeDef: (node: EditNodeDef) => void; + // edit tree editingTree?: EditTree | null; onEditingTree: (tree: EditTree | null) => void; @@ -373,7 +381,7 @@ export const useWorkspace = create((set, get) => ({ } if (editors.length === 0) { editting = undefined; - set({ editingNode: undefined }); + set({ editingNode: undefined, editingTree: undefined }); } set({ editing: editting, editors: editors }); }, @@ -479,12 +487,16 @@ export const useWorkspace = create((set, get) => ({ // node edit onEditingNode: (node) => { - set({ editingNode: node }); + set({ editingNode: node, editingNodeDef: null }); + }, + + onEditingNodeDef: (nodeDef) => { + set({ editingNodeDef: nodeDef }); }, // tree edit onEditingTree: (tree) => { - set({ editingTree: tree }); + set({ editingTree: tree, editingNodeDef: null }); }, // node def