search in path or args
This commit is contained in:
1 parent
f09fd55343
commit
098894b63f
1 file changed
+83
-49
+83
-49
@@ -34,6 +34,14 @@ export interface EditorProps extends React.HTMLAttributes<HTMLElement> {
|
|||||||
onUpdate: () => void;
|
onUpdate: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface FilterOption {
|
||||||
|
results: string[];
|
||||||
|
index: number;
|
||||||
|
filterStr: string;
|
||||||
|
filterCase: boolean;
|
||||||
|
filterFocus: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
const createMenu = () => {
|
const createMenu = () => {
|
||||||
const t = i18n.t;
|
const t = i18n.t;
|
||||||
const MenuItem: FC<FlexProps> = (itemProps) => {
|
const MenuItem: FC<FlexProps> = (itemProps) => {
|
||||||
@@ -129,24 +137,27 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const menuItems = useMemo(() => createMenu(), [t]);
|
const menuItems = useMemo(() => createMenu(), [t]);
|
||||||
|
|
||||||
const [results, setResults] = useState<string[]>([]);
|
|
||||||
const [resultIndex, setResultIndex] = useState(0);
|
|
||||||
const [searchString, setSearchString] = useState("");
|
|
||||||
const [showingSearch, setShowingSearch] = useState(false);
|
const [showingSearch, setShowingSearch] = useState(false);
|
||||||
const [filterCase, setFilterCase] = useState(false);
|
const [filterOption, setFilterOption] = useState<FilterOption>({
|
||||||
const [filterFocus, setFilterFocus] = useState(false);
|
results: [],
|
||||||
|
index: 0,
|
||||||
|
filterStr: "",
|
||||||
|
filterCase: false,
|
||||||
|
filterFocus: false,
|
||||||
|
});
|
||||||
|
|
||||||
const onSearchChange = useDebounceCallback((filter: string) => {
|
const onSearchChange = useDebounceCallback((option: FilterOption) => {
|
||||||
const ids = filterNodes(filter, findDataById("1"));
|
option.results.length = 0;
|
||||||
setSearchString(filter);
|
filterNodes(option, findDataById("1"));
|
||||||
setResults(ids);
|
setFilterOption({
|
||||||
setResultIndex(0);
|
...option,
|
||||||
if (ids.length > 0) {
|
index: 0,
|
||||||
editor.graph.focusItem(ids[0]);
|
});
|
||||||
selectNode(ids[0]);
|
if (option.results.length > 0) {
|
||||||
}
|
editor.graph.focusItem(option.results[0]);
|
||||||
if (filter.length == 0) {
|
selectNode(option.results[0]);
|
||||||
restoreViewport();
|
} else {
|
||||||
|
selectNode(null);
|
||||||
}
|
}
|
||||||
}, 200);
|
}, 200);
|
||||||
|
|
||||||
@@ -202,39 +213,48 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
return editor.graph.findDataById(id) as TreeGraphData;
|
return editor.graph.findDataById(id) as TreeGraphData;
|
||||||
};
|
};
|
||||||
|
|
||||||
const includeString = (content: string | undefined, search: string) => {
|
const includeString = (content: string | undefined, option: FilterOption) => {
|
||||||
if (!content) {
|
if (!content) {
|
||||||
return false;
|
return false;
|
||||||
} else if (filterCase) {
|
} else if (option.filterCase) {
|
||||||
return content.includes(search);
|
return content.includes(option.filterStr);
|
||||||
} else {
|
} else {
|
||||||
return content.toLowerCase().includes(search.toLowerCase());
|
return content.toLowerCase().includes(option.filterStr.toLowerCase());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const filterNodes = (search: string, node: TreeGraphData | null, ids?: string[]): string[] => {
|
const filterNodes = (option: FilterOption, node: TreeGraphData | null) => {
|
||||||
ids ||= [];
|
if (node && option.filterStr) {
|
||||||
if (node && search) {
|
if (includeString(node.name, option) || includeString(node.desc || node.def.desc, option)) {
|
||||||
if (includeString(node.name, search) || includeString(node.desc || node.def.desc, search)) {
|
option.results.push(node.id);
|
||||||
ids.push(node.id);
|
|
||||||
} else if (node.input) {
|
} else if (node.input) {
|
||||||
for (const str of node.input) {
|
for (const str of node.input) {
|
||||||
if (includeString(str, search)) {
|
if (includeString(str, option)) {
|
||||||
ids.push(node.id);
|
option.results.push(node.id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (node.args) {
|
||||||
|
for (const str in node.args) {
|
||||||
|
if (includeString(str, option)) {
|
||||||
|
option.results.push(node.id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (node.output) {
|
} else if (node.output) {
|
||||||
for (const str of node.output) {
|
for (const str of node.output) {
|
||||||
if (includeString(str, search)) {
|
if (includeString(str, option)) {
|
||||||
ids.push(node.id);
|
option.results.push(node.id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (node.path) {
|
||||||
|
if (includeString(node.path, option)) {
|
||||||
|
option.results.push(node.id);
|
||||||
}
|
}
|
||||||
node.children?.forEach((child: TreeGraphData) => filterNodes(search, child, ids));
|
|
||||||
}
|
}
|
||||||
return ids;
|
node.children?.forEach((child: TreeGraphData) => filterNodes(option, child));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const isAncestor = (ancestor: TreeGraphData, node: TreeGraphData): boolean => {
|
const isAncestor = (ancestor: TreeGraphData, node: TreeGraphData): boolean => {
|
||||||
@@ -1025,21 +1045,22 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
}, [t]);
|
}, [t]);
|
||||||
|
|
||||||
const nextResult = () => {
|
const nextResult = () => {
|
||||||
|
const { results, index } = filterOption;
|
||||||
if (results.length > 0) {
|
if (results.length > 0) {
|
||||||
const idx = (resultIndex + 1) % results.length;
|
const idx = (index + 1) % results.length;
|
||||||
setResultIndex(idx);
|
|
||||||
editor.graph.focusItem(results[idx]);
|
editor.graph.focusItem(results[idx]);
|
||||||
selectNode(results[idx]);
|
selectNode(results[idx]);
|
||||||
|
setFilterOption({ ...filterOption, index: idx });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const prevResult = () => {
|
const prevResult = () => {
|
||||||
|
const { results, index } = filterOption;
|
||||||
if (results.length > 0) {
|
if (results.length > 0) {
|
||||||
const idx = (resultIndex + results.length - 1) % results.length;
|
const idx = (index + results.length - 1) % results.length;
|
||||||
setResultIndex(idx);
|
|
||||||
console.log(idx, results[idx]);
|
|
||||||
editor.graph.focusItem(results[idx]);
|
editor.graph.focusItem(results[idx]);
|
||||||
selectNode(results[idx]);
|
selectNode(results[idx]);
|
||||||
|
setFilterOption({ ...filterOption, index: idx });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1080,7 +1101,12 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
paddingBottom: "1px",
|
paddingBottom: "1px",
|
||||||
paddingRight: "2px",
|
paddingRight: "2px",
|
||||||
}}
|
}}
|
||||||
onChange={(e) => onSearchChange(e.currentTarget.value)}
|
onChange={(e) =>
|
||||||
|
onSearchChange({
|
||||||
|
...filterOption,
|
||||||
|
filterStr: e.currentTarget.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
onKeyDown={(e) => e.code === Hotkey.Enter && nextResult()}
|
onKeyDown={(e) => e.code === Hotkey.Enter && nextResult()}
|
||||||
suffix={
|
suffix={
|
||||||
<Flex gap="2px" style={{ alignItems: "center" }}>
|
<Flex gap="2px" style={{ alignItems: "center" }}>
|
||||||
@@ -1089,36 +1115,45 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
size="small"
|
size="small"
|
||||||
className={mergeClassNames(
|
className={mergeClassNames(
|
||||||
"b3-editor-button-filter",
|
"b3-editor-button-filter",
|
||||||
filterCase && "b3-editor-button-filter-selected"
|
filterOption.filterCase && "b3-editor-button-filter-selected"
|
||||||
)}
|
)}
|
||||||
icon={<VscCaseSensitive style={{ width: "18px", height: "18px" }} />}
|
icon={<VscCaseSensitive style={{ width: "18px", height: "18px" }} />}
|
||||||
onClick={() => {
|
onClick={() =>
|
||||||
setFilterCase(!filterCase);
|
onSearchChange({
|
||||||
onSearchChange(searchString);
|
...filterOption,
|
||||||
}}
|
filterCase: !filterOption.filterCase,
|
||||||
|
})
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
size="small"
|
size="small"
|
||||||
className={mergeClassNames(
|
className={mergeClassNames(
|
||||||
"b3-editor-button-filter",
|
"b3-editor-button-filter",
|
||||||
filterFocus && "b3-editor-button-filter-selected"
|
filterOption.filterFocus && "b3-editor-button-filter-selected"
|
||||||
)}
|
)}
|
||||||
icon={<RiFocus3Line />}
|
icon={<RiFocus3Line />}
|
||||||
onClick={() => setFilterFocus(!filterFocus)}
|
onClick={() =>
|
||||||
|
onSearchChange({
|
||||||
|
...filterOption,
|
||||||
|
filterFocus: !filterOption.filterFocus,
|
||||||
|
})
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<div style={{ padding: "0 10px 0 5px", minWidth: "40px" }}>
|
<div style={{ padding: "0 10px 0 5px", minWidth: "40px" }}>
|
||||||
{results.length ? `${resultIndex + 1}/${results.length}` : ""}
|
{filterOption.results.length
|
||||||
|
? `${filterOption.index + 1}/${filterOption.results.length}`
|
||||||
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
icon={<ArrowDownOutlined />}
|
icon={<ArrowDownOutlined />}
|
||||||
type="text"
|
type="text"
|
||||||
size="small"
|
size="small"
|
||||||
style={{ width: "30px" }}
|
style={{ width: "30px" }}
|
||||||
disabled={results.length == 0}
|
disabled={filterOption.results.length == 0}
|
||||||
onClick={nextResult}
|
onClick={nextResult}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
@@ -1126,7 +1161,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
type="text"
|
type="text"
|
||||||
size="small"
|
size="small"
|
||||||
style={{ width: "30px" }}
|
style={{ width: "30px" }}
|
||||||
disabled={results.length == 0}
|
disabled={filterOption.results.length == 0}
|
||||||
onClick={prevResult}
|
onClick={prevResult}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
@@ -1136,8 +1171,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
style={{ width: "30px" }}
|
style={{ width: "30px" }}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setShowingSearch(false);
|
setShowingSearch(false);
|
||||||
setResults([]);
|
setFilterOption({ ...filterOption, results: [], index: 0 });
|
||||||
setResultIndex(0);
|
|
||||||
keysRef.current?.focus();
|
keysRef.current?.focus();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in new issue
Block a user