search node def in title bar
This commit is contained in:
1 parent
27bf5b98cc
commit
d582fadf6a
5 files changed
+86
-30
No files matched your search
+40
-13
@@ -35,6 +35,7 @@ type MenuEvent =
|
|||||||
|
|
||||||
export type NodeTreeType = {
|
export type NodeTreeType = {
|
||||||
title: string;
|
title: string;
|
||||||
|
path: string;
|
||||||
def?: NodeDef;
|
def?: NodeDef;
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
isLeaf?: boolean;
|
isLeaf?: boolean;
|
||||||
@@ -72,7 +73,7 @@ const findParent = (node: FileTreeType, parent?: FileTreeType): FileTreeType | u
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const resolveKeys = (path: string, node: FileTreeType, keys: React.Key[]) => {
|
const resolveKeys = (path: string, node: FileTreeType | NodeTreeType, keys: React.Key[]) => {
|
||||||
if (node.path === path) {
|
if (node.path === path) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -274,6 +275,7 @@ export const Explorer: FC = () => {
|
|||||||
const workspace = {
|
const workspace = {
|
||||||
close: useWorkspace((state) => state.close),
|
close: useWorkspace((state) => state.close),
|
||||||
editing: useWorkspace((state) => state.editing),
|
editing: useWorkspace((state) => state.editing),
|
||||||
|
editingNodeDef: useWorkspace((state) => state.editingNodeDef),
|
||||||
editors: useWorkspace((state) => state.editors),
|
editors: useWorkspace((state) => state.editors),
|
||||||
fileTree: useWorkspace((state) => state.fileTree),
|
fileTree: useWorkspace((state) => state.fileTree),
|
||||||
nodeDefs: useWorkspace((state) => state.nodeDefs),
|
nodeDefs: useWorkspace((state) => state.nodeDefs),
|
||||||
@@ -290,6 +292,10 @@ export const Explorer: FC = () => {
|
|||||||
const [newName, setNewName] = useState<string | null>(null);
|
const [newName, setNewName] = useState<string | null>(null);
|
||||||
const [contextMenu, setContextMenu] = useState<ItemType[]>([]);
|
const [contextMenu, setContextMenu] = useState<ItemType[]>([]);
|
||||||
|
|
||||||
|
const rootNodedefName = "nodeTree.root";
|
||||||
|
const [selectedNodedefKeys, setSelectedNodedefKeys] = useState<string[]>([]);
|
||||||
|
const [expandedNodedefKeys, setExpandedNodedefKeys] = useState<React.Key[]>([rootNodedefName]);
|
||||||
|
|
||||||
if (workspace.fileTree) {
|
if (workspace.fileTree) {
|
||||||
workspace.fileTree.icon = (
|
workspace.fileTree.icon = (
|
||||||
<Flex justify="center" align="center" style={{ height: "100%" }}>
|
<Flex justify="center" align="center" style={{ height: "100%" }}>
|
||||||
@@ -301,6 +307,7 @@ export const Explorer: FC = () => {
|
|||||||
const nodeTree = useMemo(() => {
|
const nodeTree = useMemo(() => {
|
||||||
const data: NodeTreeType = {
|
const data: NodeTreeType = {
|
||||||
title: t("nodeDefinition"),
|
title: t("nodeDefinition"),
|
||||||
|
path: rootNodedefName,
|
||||||
icon: (
|
icon: (
|
||||||
<Flex justify="center" align="center" style={{ height: "100%" }}>
|
<Flex justify="center" align="center" style={{ height: "100%" }}>
|
||||||
<PiTreeStructureFill size={19} />
|
<PiTreeStructureFill size={19} />
|
||||||
@@ -318,6 +325,7 @@ export const Explorer: FC = () => {
|
|||||||
const type = getNodeType(nodeDef);
|
const type = getNodeType(nodeDef);
|
||||||
catalog = {
|
catalog = {
|
||||||
title: nodeDef.type,
|
title: nodeDef.type,
|
||||||
|
path: `nodeTree.catalog.${nodeDef.type}`,
|
||||||
children: [],
|
children: [],
|
||||||
icon: (
|
icon: (
|
||||||
<Flex justify="center" align="center" style={{ height: "100%" }}>
|
<Flex justify="center" align="center" style={{ height: "100%" }}>
|
||||||
@@ -335,17 +343,14 @@ export const Explorer: FC = () => {
|
|||||||
title: `${nodeDef.name}(${nodeDef.desc})`,
|
title: `${nodeDef.name}(${nodeDef.desc})`,
|
||||||
isLeaf: true,
|
isLeaf: true,
|
||||||
def: nodeDef,
|
def: nodeDef,
|
||||||
|
path: `${nodeDef.name}`,
|
||||||
icon: nodeDef.icon ? (
|
icon: nodeDef.icon ? (
|
||||||
<Flex justify="center" align="center" style={{ height: "100%" }}>
|
<Flex justify="center" align="center" style={{ height: "100%" }}>
|
||||||
<img
|
<img
|
||||||
className="b3-node-icon"
|
className="b3-node-icon"
|
||||||
key={catalog.title}
|
key={catalog.title}
|
||||||
style={{ width: "13px", height: "13px", color: "white" }}
|
style={{ width: "13px", height: "13px", color: "white" }}
|
||||||
src={
|
src={`file:///${workspace.workdir}/${nodeDef.icon}`}
|
||||||
process.env.VITE_DEV_SERVER_URL && isMacos
|
|
||||||
? `${Path.basename(workspace.workdir)}/${nodeDef.icon}`
|
|
||||||
: `${workspace.workdir}/${nodeDef.icon}`
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
) : (
|
) : (
|
||||||
@@ -362,6 +367,7 @@ export const Explorer: FC = () => {
|
|||||||
return data;
|
return data;
|
||||||
}, [t, workspace.nodeDefs]);
|
}, [t, workspace.nodeDefs]);
|
||||||
|
|
||||||
|
// expand the selected tree
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (workspace.editing) {
|
if (workspace.editing) {
|
||||||
const keys: React.Key[] = [];
|
const keys: React.Key[] = [];
|
||||||
@@ -376,6 +382,21 @@ export const Explorer: FC = () => {
|
|||||||
}
|
}
|
||||||
}, [workspace.editing]);
|
}, [workspace.editing]);
|
||||||
|
|
||||||
|
// expand the selected node def
|
||||||
|
useEffect(() => {
|
||||||
|
if (workspace.editingNodeDef) {
|
||||||
|
const keys: React.Key[] = [];
|
||||||
|
resolveKeys(workspace.editingNodeDef.data.name, nodeTree, keys);
|
||||||
|
for (const k of expandedNodedefKeys) {
|
||||||
|
if (keys.indexOf(k) === -1) {
|
||||||
|
keys.push(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setExpandedNodedefKeys(keys);
|
||||||
|
setSelectedNodedefKeys([workspace.editingNodeDef.data.name]);
|
||||||
|
}
|
||||||
|
}, [t, workspace.editingNodeDef]);
|
||||||
|
|
||||||
const keysRef = useHotkeys<HTMLDivElement>(
|
const keysRef = useHotkeys<HTMLDivElement>(
|
||||||
[
|
[
|
||||||
Hotkey.F2,
|
Hotkey.F2,
|
||||||
@@ -763,6 +784,8 @@ export const Explorer: FC = () => {
|
|||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
treeData={workspace.fileTree ? [workspace.fileTree] : []}
|
treeData={workspace.fileTree ? [workspace.fileTree] : []}
|
||||||
fieldNames={{ key: "path" }}
|
fieldNames={{ key: "path" }}
|
||||||
|
expandedKeys={expandedKeys}
|
||||||
|
selectedKeys={selectedKeys}
|
||||||
onExpand={(keys) => {
|
onExpand={(keys) => {
|
||||||
setExpandedKeys(keys);
|
setExpandedKeys(keys);
|
||||||
}}
|
}}
|
||||||
@@ -840,7 +863,6 @@ export const Explorer: FC = () => {
|
|||||||
onDragStart={(e) => {
|
onDragStart={(e) => {
|
||||||
e.event.dataTransfer.setData("explore-file", e.node.path);
|
e.event.dataTransfer.setData("explore-file", e.node.path);
|
||||||
}}
|
}}
|
||||||
defaultExpandedKeys={[workspace.fileTree.path]}
|
|
||||||
draggable={
|
draggable={
|
||||||
newName !== null
|
newName !== null
|
||||||
? false
|
? false
|
||||||
@@ -852,17 +874,19 @@ export const Explorer: FC = () => {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
expandedKeys={expandedKeys}
|
|
||||||
switcherIcon={<DownOutlined />}
|
switcherIcon={<DownOutlined />}
|
||||||
selectedKeys={selectedKeys}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
<DirectoryTree
|
<DirectoryTree
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
fieldNames={{ key: "title" }}
|
fieldNames={{ key: "path" }}
|
||||||
treeData={nodeTree ? [nodeTree] : []}
|
treeData={[nodeTree]}
|
||||||
defaultExpandedKeys={[nodeTree.title]}
|
expandedKeys={expandedNodedefKeys}
|
||||||
|
selectedKeys={selectedNodedefKeys}
|
||||||
|
onExpand={(keys) => {
|
||||||
|
setExpandedNodedefKeys(keys);
|
||||||
|
}}
|
||||||
draggable={{ icon: false, nodeDraggable: (node) => !!node.isLeaf }}
|
draggable={{ icon: false, nodeDraggable: (node) => !!node.isLeaf }}
|
||||||
titleRender={(node) => (
|
titleRender={(node) => (
|
||||||
<div style={{ flex: 1, width: 0, minWidth: 0 }}>
|
<div style={{ flex: 1, width: 0, minWidth: 0 }}>
|
||||||
@@ -879,11 +903,14 @@ export const Explorer: FC = () => {
|
|||||||
)}
|
)}
|
||||||
onSelect={(_, info) => {
|
onSelect={(_, info) => {
|
||||||
const node = info.node;
|
const node = info.node;
|
||||||
if (node && node.isLeaf) {
|
if (node) {
|
||||||
|
if (node.isLeaf) {
|
||||||
workspace.onEditingNodeDef({
|
workspace.onEditingNodeDef({
|
||||||
data: node.def!,
|
data: node.def!,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
setSelectedNodedefKeys([node.path]);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
onDragStart={(e) => {
|
onDragStart={(e) => {
|
||||||
e.event.dataTransfer.setData("explore-node", e.node.def?.name ?? "");
|
e.event.dataTransfer.setData("explore-node", e.node.def?.name ?? "");
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { EditNode, EditTree, useWorkspace } from "@/contexts/workspace-context";
|
|||||||
import { NodeArg, NodeModel, TreeGraphData } from "@/misc/b3type";
|
import { NodeArg, NodeModel, TreeGraphData } from "@/misc/b3type";
|
||||||
import { checkOneof } from "@/misc/b3util";
|
import { checkOneof } from "@/misc/b3util";
|
||||||
import { Hotkey, isMacos } from "@/misc/keys";
|
import { Hotkey, isMacos } from "@/misc/keys";
|
||||||
|
import { mergeClassNames } from "@/misc/util";
|
||||||
import { EditOutlined } from "@ant-design/icons";
|
import { EditOutlined } from "@ant-design/icons";
|
||||||
import {
|
import {
|
||||||
AutoComplete,
|
AutoComplete,
|
||||||
@@ -57,8 +58,8 @@ const TreeInspector: FC = () => {
|
|||||||
<span style={{ fontSize: "18px", fontWeight: "600" }}>{t("tree.overview")}</span>
|
<span style={{ fontSize: "18px", fontWeight: "600" }}>{t("tree.overview")}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={isMacos ? undefined : "b3-overflow"}
|
className={mergeClassNames("b3-inspector-content", isMacos ? "" : "b3-overflow")}
|
||||||
style={{ overflow: "auto", height: "100%", padding: "24px" }}
|
style={{ overflow: "auto", height: "100%" }}
|
||||||
>
|
>
|
||||||
<Form form={form} labelCol={{ span: 8 }} onFinish={finish}>
|
<Form form={form} labelCol={{ span: 8 }} onFinish={finish}>
|
||||||
<Form.Item name="name" label={t("tree.name")}>
|
<Form.Item name="name" label={t("tree.name")}>
|
||||||
@@ -263,8 +264,8 @@ const NodeInspector: FC = () => {
|
|||||||
<span style={{ fontSize: "18px", fontWeight: "600" }}>{def.desc}</span>
|
<span style={{ fontSize: "18px", fontWeight: "600" }}>{def.desc}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={isMacos ? undefined : "b3-overflow"}
|
className={mergeClassNames("b3-inspector-content", isMacos ? "" : "b3-overflow")}
|
||||||
style={{ overflow: "auto", height: "100%", padding: "24px" }}
|
style={{ overflow: "auto", height: "100%" }}
|
||||||
>
|
>
|
||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
@@ -549,8 +550,8 @@ const NodeDefInspector: FC = () => {
|
|||||||
<span style={{ fontSize: "18px", fontWeight: "600" }}>{t("nodeDefinition")}</span>
|
<span style={{ fontSize: "18px", fontWeight: "600" }}>{t("nodeDefinition")}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={isMacos ? undefined : "b3-overflow"}
|
className={mergeClassNames("b3-inspector-content", isMacos ? "" : "b3-overflow")}
|
||||||
style={{ overflow: "auto", height: "100%", padding: "24px" }}
|
style={{ overflow: "auto", height: "100%" }}
|
||||||
>
|
>
|
||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
|
|||||||
@@ -177,9 +177,7 @@ G6.registerNode(
|
|||||||
|
|
||||||
// icon
|
// icon
|
||||||
const img = nodeDef.icon
|
const img = nodeDef.icon
|
||||||
? process.env.VITE_DEV_SERVER_URL && isMacos
|
? `file:///${workspace.workdir}/${nodeDef.icon}`
|
||||||
? `${Path.basename(workspace.workdir)}/${nodeDef.icon}`
|
|
||||||
: `${workspace.workdir}/${nodeDef.icon}`
|
|
||||||
: `./icons/${classify}.svg`;
|
: `./icons/${classify}.svg`;
|
||||||
addShape("image", {
|
addShape("image", {
|
||||||
attrs: {
|
attrs: {
|
||||||
|
|||||||
@@ -5,19 +5,23 @@ import { SearchOutlined } from "@ant-design/icons";
|
|||||||
import { Button, Flex, LayoutProps, Select } from "antd";
|
import { Button, Flex, LayoutProps, Select } from "antd";
|
||||||
import React, { FC, useMemo } from "react";
|
import React, { FC, useMemo } from "react";
|
||||||
import { Menu } from "./menu";
|
import { Menu } from "./menu";
|
||||||
|
import { NodeDef } from "@/misc/b3type";
|
||||||
|
|
||||||
interface OptionType {
|
interface OptionType {
|
||||||
label: string | React.ReactNode;
|
label: string | React.ReactNode;
|
||||||
value: string;
|
value: string;
|
||||||
path: string;
|
path?: string;
|
||||||
|
nodeDef?: NodeDef;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TitleBar: FC<LayoutProps> = () => {
|
export const TitleBar: FC<LayoutProps> = () => {
|
||||||
const workspace = {
|
const workspace = {
|
||||||
allFiles: useWorkspace((state) => state.allFiles),
|
allFiles: useWorkspace((state) => state.allFiles),
|
||||||
fileTree: useWorkspace((state) => state.fileTree),
|
fileTree: useWorkspace((state) => state.fileTree),
|
||||||
|
nodeDefs: useWorkspace((state) => state.nodeDefs),
|
||||||
isShowingSearch: useWorkspace((state) => state.isShowingSearch),
|
isShowingSearch: useWorkspace((state) => state.isShowingSearch),
|
||||||
onShowingSearch: useWorkspace((state) => state.onShowingSearch),
|
onShowingSearch: useWorkspace((state) => state.onShowingSearch),
|
||||||
|
onEditingNodeDef: useWorkspace((state) => state.onEditingNodeDef),
|
||||||
open: useWorkspace((state) => state.open),
|
open: useWorkspace((state) => state.open),
|
||||||
name: useWorkspace((state) => state.path),
|
name: useWorkspace((state) => state.path),
|
||||||
relative: useWorkspace((state) => state.relative),
|
relative: useWorkspace((state) => state.relative),
|
||||||
@@ -41,7 +45,23 @@ export const TitleBar: FC<LayoutProps> = () => {
|
|||||||
path: file.path,
|
path: file.path,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
options.sort((a, b) => a.path.localeCompare(b.path));
|
workspace.nodeDefs.forEach((def) => {
|
||||||
|
const value = def.name;
|
||||||
|
const desc = def.desc ?? "";
|
||||||
|
options.push({
|
||||||
|
label: (
|
||||||
|
<div>
|
||||||
|
{value}
|
||||||
|
<span> </span>
|
||||||
|
<span style={{ color: "gray", fontSize: "12px" }}>
|
||||||
|
{value} {desc}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
value: `${value.toLocaleLowerCase()} ${desc.toLocaleLowerCase()}`,
|
||||||
|
nodeDef: def,
|
||||||
|
});
|
||||||
|
});
|
||||||
return options;
|
return options;
|
||||||
}, [workspace.allFiles, workspace.fileTree]);
|
}, [workspace.allFiles, workspace.fileTree]);
|
||||||
return (
|
return (
|
||||||
@@ -103,17 +123,23 @@ export const TitleBar: FC<LayoutProps> = () => {
|
|||||||
onChange={(_, option) => {
|
onChange={(_, option) => {
|
||||||
if (!(option instanceof Array)) {
|
if (!(option instanceof Array)) {
|
||||||
workspace.onShowingSearch(false);
|
workspace.onShowingSearch(false);
|
||||||
|
if (option.path) {
|
||||||
workspace.open(option.path);
|
workspace.open(option.path);
|
||||||
|
} else if (option.nodeDef) {
|
||||||
|
workspace.onEditingNodeDef({
|
||||||
|
data: option.nodeDef,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
filterOption={(input, option) =>
|
filterOption={(input, option) =>
|
||||||
(option?.value ?? "").includes(input.toLocaleLowerCase())
|
(option?.value ?? "").includes(input.toLocaleLowerCase())
|
||||||
}
|
}
|
||||||
filterSort={(optionA, optionB) =>
|
// filterSort={(optionA, optionB) =>
|
||||||
(optionA?.value ?? "")
|
// (optionA?.value ?? "")
|
||||||
.toLowerCase()
|
// .toLowerCase()
|
||||||
.localeCompare((optionB?.value ?? "").toLowerCase())
|
// .localeCompare((optionB?.value ?? "").toLowerCase())
|
||||||
}
|
// }
|
||||||
options={searchOptions}
|
options={searchOptions}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
+5
-1
@@ -107,8 +107,12 @@ body {
|
|||||||
width: 12px !important;
|
width: 12px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.b3-inspector-content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.b3-inspector .ant-form-item {
|
.b3-inspector .ant-form-item {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.b3-inspector .ant-form-item-label {
|
.b3-inspector .ant-form-item-label {
|
||||||
|
|||||||
Reference in new issue
Block a user