implement VarDefItem component
This commit is contained in:
1 parent
3a2f09541c
commit
0acd291c0c
1 file changed
+150
-218
+150
-218
@@ -12,9 +12,10 @@ import {
|
|||||||
Space,
|
Space,
|
||||||
Switch,
|
Switch,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
|
import useFormInstance from "antd/es/form/hooks/useFormInstance";
|
||||||
import TextArea from "antd/es/input/TextArea";
|
import TextArea from "antd/es/input/TextArea";
|
||||||
import { DefaultOptionType } from "antd/es/select";
|
import { DefaultOptionType } from "antd/es/select";
|
||||||
import { FC, useEffect, useMemo } from "react";
|
import { FC, useEffect, useMemo, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import Markdown from "react-markdown";
|
import Markdown from "react-markdown";
|
||||||
import { useDebounceCallback } from "usehooks-ts";
|
import { useDebounceCallback } from "usehooks-ts";
|
||||||
@@ -54,6 +55,86 @@ interface OptionType extends DefaultOptionType {
|
|||||||
value: string;
|
value: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface VarDefItem extends VarDef {
|
||||||
|
count?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VarDefItemProps {
|
||||||
|
id: number;
|
||||||
|
disabled?: boolean;
|
||||||
|
value?: VarDefItem;
|
||||||
|
onChange?: (vardef: VarDefItem) => void;
|
||||||
|
onRemove?: (index: number | number[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VarDefItem: FC<VarDefItemProps> = ({ id, value, onChange, onRemove, disabled }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const form = useFormInstance();
|
||||||
|
const [name, setName] = useState(value?.name ?? "");
|
||||||
|
const [desc, setDesc] = useState(value?.desc ?? "");
|
||||||
|
const { editing } = useWorkspace(
|
||||||
|
useShallow((state) => ({
|
||||||
|
editing: state.editing,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
|
||||||
|
const onSubmit = () => {
|
||||||
|
onChange?.({ name, desc });
|
||||||
|
form.submit();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Flex gap={4}>
|
||||||
|
<Space.Compact>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
cursor: "pointer",
|
||||||
|
alignItems: "center",
|
||||||
|
paddingLeft: "8px",
|
||||||
|
paddingRight: "8px",
|
||||||
|
maxWidth: "52px",
|
||||||
|
minWidth: "52px",
|
||||||
|
borderTopLeftRadius: "4px",
|
||||||
|
borderBottomLeftRadius: "4px",
|
||||||
|
borderLeft: "1px solid #3d506c",
|
||||||
|
borderTop: "1px solid #3d506c",
|
||||||
|
borderBottom: "1px solid #3d506c",
|
||||||
|
}}
|
||||||
|
onClick={() => editing?.dispatch("clickVar", name)}
|
||||||
|
>
|
||||||
|
<AimOutlined />
|
||||||
|
<span style={{ marginLeft: 4 }}>{value?.count ?? 0}</span>
|
||||||
|
</div>
|
||||||
|
<Input
|
||||||
|
disabled={disabled}
|
||||||
|
value={name}
|
||||||
|
placeholder={t("tree.vars.name")}
|
||||||
|
onBlur={onSubmit}
|
||||||
|
onChange={(e) => setName(e.target.value)}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
disabled={disabled}
|
||||||
|
value={desc}
|
||||||
|
placeholder={t("tree.vars.desc")}
|
||||||
|
onBlur={onSubmit}
|
||||||
|
onChange={(e) => setDesc(e.target.value)}
|
||||||
|
/>
|
||||||
|
</Space.Compact>
|
||||||
|
{!disabled && (
|
||||||
|
<MinusCircleOutlined
|
||||||
|
style={{ marginBottom: "6px" }}
|
||||||
|
onClick={() => {
|
||||||
|
onRemove?.(id);
|
||||||
|
form.submit();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{disabled && <div style={{ width: 20 }} />}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const TreeInspector: FC = () => {
|
const TreeInspector: FC = () => {
|
||||||
const workspace = useWorkspace(
|
const workspace = useWorkspace(
|
||||||
useShallow((state) => ({
|
useShallow((state) => ({
|
||||||
@@ -141,10 +222,33 @@ const TreeInspector: FC = () => {
|
|||||||
form.setFieldValue("export", workspace.editingTree.export !== false);
|
form.setFieldValue("export", workspace.editingTree.export !== false);
|
||||||
form.setFieldValue("firstid", workspace.editingTree.firstid);
|
form.setFieldValue("firstid", workspace.editingTree.firstid);
|
||||||
form.setFieldValue("group", groupDefs);
|
form.setFieldValue("group", groupDefs);
|
||||||
form.setFieldValue("declvar", workspace.editingTree.declvar);
|
form.setFieldValue(
|
||||||
form.setFieldValue("import", workspace.editingTree.import);
|
"declvar",
|
||||||
form.setFieldValue("subtree", workspace.editingTree.subtree);
|
workspace.editingTree.declvar.map((v) => ({
|
||||||
}, [workspace.editingTree, groupDefs]);
|
name: v.name,
|
||||||
|
desc: v.desc,
|
||||||
|
count: usingCount[v.name] ?? 0,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
form.setFieldValue(
|
||||||
|
"import",
|
||||||
|
workspace.editingTree.import.map((entry) => ({
|
||||||
|
path: entry.path,
|
||||||
|
vars: entry.vars.map((v) => ({
|
||||||
|
name: v.name,
|
||||||
|
count: usingCount[v.name] ?? 0,
|
||||||
|
})),
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
form.setFieldValue(
|
||||||
|
"subtree",
|
||||||
|
workspace.editingTree.subtree.map((v) => ({
|
||||||
|
name: v.name,
|
||||||
|
desc: v.desc,
|
||||||
|
count: usingCount[v.name] ?? 0,
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
}, [workspace.editingTree, groupDefs, usingCount]);
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const finish = (values: any) => {
|
const finish = (values: any) => {
|
||||||
@@ -153,19 +257,22 @@ const TreeInspector: FC = () => {
|
|||||||
desc: values.desc,
|
desc: values.desc,
|
||||||
export: values.export,
|
export: values.export,
|
||||||
firstid: Number(values.firstid),
|
firstid: Number(values.firstid),
|
||||||
group: (values.group as GroupDef[])
|
group: Array.from(new Set((values.group as GroupDef[]).map((v) => (v.value ? v.name : ""))))
|
||||||
.map((v) => (v.value ? v.name : ""))
|
|
||||||
.filter((v) => v)
|
.filter((v) => v)
|
||||||
.sort((a, b) => a.localeCompare(b)),
|
.sort((a, b) => a.localeCompare(b)),
|
||||||
declvar: (values.declvar as VarDef[])
|
declvar: (values.declvar as VarDef[])
|
||||||
.filter((v) => v && v.name)
|
.filter((v) => v && v.name)
|
||||||
|
.map((v) => ({
|
||||||
|
name: v.name,
|
||||||
|
desc: v.desc,
|
||||||
|
}))
|
||||||
.sort((a, b) => a.name.localeCompare(b.name)),
|
.sort((a, b) => a.name.localeCompare(b.name)),
|
||||||
import: (values.import as ImportDef[])
|
import: (values.import as ImportDef[])
|
||||||
.filter((v) => v && v.path)
|
.filter((v) => v && v.path)
|
||||||
.sort((a, b) => a.path.localeCompare(b.path))
|
.sort((a, b) => a.path.localeCompare(b.path))
|
||||||
.map((v) => ({
|
.map((v) => ({
|
||||||
path: v.path,
|
path: v.path,
|
||||||
vars: v.vars ?? [],
|
vars: (v.vars ?? []).map((v1) => ({ name: v1.name, desc: v1.desc })),
|
||||||
})),
|
})),
|
||||||
} as EditTree);
|
} as EditTree);
|
||||||
};
|
};
|
||||||
@@ -240,80 +347,31 @@ const TreeInspector: FC = () => {
|
|||||||
<Form.List name="declvar">
|
<Form.List name="declvar">
|
||||||
{(fields, { add, remove }, { errors }) => (
|
{(fields, { add, remove }, { errors }) => (
|
||||||
<div style={{ display: "flex", flexDirection: "column", rowGap: 0 }}>
|
<div style={{ display: "flex", flexDirection: "column", rowGap: 0 }}>
|
||||||
{fields.map((item) => {
|
{fields.map((item) => (
|
||||||
const vardef = workspace.editingTree.declvar[item.name] as VarDef | undefined;
|
<Form.Item
|
||||||
return (
|
key={item.key}
|
||||||
<Flex key={item.key} gap={4}>
|
name={item.name}
|
||||||
<Space.Compact
|
validateTrigger={["onChange", "onBlur"]}
|
||||||
className="b3-inspector-vars-item"
|
style={{ marginBottom: 2 }}
|
||||||
style={{ width: "100%", marginBottom: 2 }}
|
rules={[
|
||||||
>
|
{
|
||||||
<Form.Item
|
validator(_, value: VarDefItem) {
|
||||||
noStyle
|
if (!value.name || !/^[_\w]+\w*$/.test(value.name)) {
|
||||||
name={[item.name, "name"]}
|
return Promise.reject(new Error(t("tree.vars.invalidName")));
|
||||||
validateTrigger={["onChange", "onBlur"]}
|
}
|
||||||
rules={[
|
if (!value.desc) {
|
||||||
{
|
return Promise.reject(
|
||||||
validator(_, value) {
|
new Error(t("fieldRequired", { field: t("tree.vars.desc") }))
|
||||||
if (value && /^[_\w]+\w*$/.test(value)) {
|
);
|
||||||
return Promise.resolve();
|
}
|
||||||
}
|
return Promise.resolve();
|
||||||
return Promise.reject(new Error(t("tree.vars.invalidName")));
|
},
|
||||||
},
|
},
|
||||||
},
|
]}
|
||||||
]}
|
>
|
||||||
>
|
<VarDefItem id={item.name} onRemove={remove} />
|
||||||
<Input
|
</Form.Item>
|
||||||
addonBefore={
|
))}
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
cursor: "pointer",
|
|
||||||
alignItems: "center",
|
|
||||||
width: "33px",
|
|
||||||
}}
|
|
||||||
onClick={() =>
|
|
||||||
vardef && workspace.editing?.dispatch("clickVar", vardef.name)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<AimOutlined />
|
|
||||||
<span style={{ marginLeft: 4 }}>
|
|
||||||
{usingCount[vardef?.name ?? ""] ?? 0}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
placeholder={t("tree.vars.name")}
|
|
||||||
onBlur={form.submit}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
noStyle
|
|
||||||
name={[item.name, "desc"]}
|
|
||||||
validateTrigger={["onChange", "onBlur"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: t("fieldRequired", { field: t("tree.vars.desc") }),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
style={{ width: "60%" }}
|
|
||||||
placeholder={t("tree.vars.desc")}
|
|
||||||
onBlur={form.submit}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Space.Compact>
|
|
||||||
<MinusCircleOutlined
|
|
||||||
style={{ marginBottom: "6px" }}
|
|
||||||
onClick={() => {
|
|
||||||
remove(item.name);
|
|
||||||
form.submit();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
style={{
|
style={{
|
||||||
marginRight: fields.length === 0 ? undefined : "18px",
|
marginRight: fields.length === 0 ? undefined : "18px",
|
||||||
@@ -345,71 +403,11 @@ const TreeInspector: FC = () => {
|
|||||||
<Form.List name="subtree">
|
<Form.List name="subtree">
|
||||||
{(fields) => (
|
{(fields) => (
|
||||||
<div style={{ display: "flex", flexDirection: "column", rowGap: 0 }}>
|
<div style={{ display: "flex", flexDirection: "column", rowGap: 0 }}>
|
||||||
{fields.map((item, idx) => {
|
{fields.map((item) => (
|
||||||
const vardef = workspace.editingTree.subtree[item.name] as VarDef | undefined;
|
<Form.Item key={item.key} name={item.name} style={{ marginBottom: 2 }}>
|
||||||
return (
|
<VarDefItem id={item.name} disabled={true} />
|
||||||
<Flex key={item.key} gap={4}>
|
</Form.Item>
|
||||||
<Space.Compact
|
))}
|
||||||
className="b3-inspector-vars-item"
|
|
||||||
style={{ width: "100%", marginBottom: 0, paddingRight: 18 }}
|
|
||||||
>
|
|
||||||
<Form.Item noStyle name={[item.name, "id"]}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
paddingLeft: "8px",
|
|
||||||
paddingRight: "8px",
|
|
||||||
maxWidth: "52px",
|
|
||||||
minWidth: "52px",
|
|
||||||
borderTopLeftRadius: idx === 0 ? "4px" : 0,
|
|
||||||
borderBottomLeftRadius: idx === fields.length - 1 ? "4px" : 0,
|
|
||||||
borderLeft: "1px solid #3d506c",
|
|
||||||
borderTop: "1px solid #3d506c",
|
|
||||||
cursor: "pointer",
|
|
||||||
borderBottom:
|
|
||||||
idx === fields.length - 1 ? "1px solid #3d506c" : "none",
|
|
||||||
}}
|
|
||||||
onClick={() =>
|
|
||||||
vardef && workspace.editing?.dispatch("clickVar", vardef.name)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<AimOutlined />
|
|
||||||
<span style={{ marginLeft: 4 }}>
|
|
||||||
{usingCount[vardef?.name ?? ""] ?? 0}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item noStyle name={[item.name, "name"]}>
|
|
||||||
<Input
|
|
||||||
disabled={true}
|
|
||||||
placeholder={t("tree.vars.name")}
|
|
||||||
style={{
|
|
||||||
borderRadius: "0",
|
|
||||||
borderTop: "1px solid #3d506c",
|
|
||||||
borderBottom:
|
|
||||||
idx === fields.length - 1 ? "1px solid #3d506c" : "none",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item noStyle name={[item.name, "desc"]}>
|
|
||||||
<Input
|
|
||||||
disabled={true}
|
|
||||||
placeholder={t("tree.vars.desc")}
|
|
||||||
style={{
|
|
||||||
width: "90%",
|
|
||||||
borderTopRightRadius: idx === 0 ? "4px" : 0,
|
|
||||||
borderBottomRightRadius: idx === fields.length - 1 ? "4px" : 0,
|
|
||||||
borderTop: "1px solid #3d506c",
|
|
||||||
borderBottom:
|
|
||||||
idx === fields.length - 1 ? "1px solid #3d506c" : "none",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Space.Compact>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Form.List>
|
</Form.List>
|
||||||
@@ -456,77 +454,11 @@ const TreeInspector: FC = () => {
|
|||||||
<Form.List name={[item.name, "vars"]}>
|
<Form.List name={[item.name, "vars"]}>
|
||||||
{(vars) => (
|
{(vars) => (
|
||||||
<div style={{ display: "flex", flexDirection: "column", rowGap: 0 }}>
|
<div style={{ display: "flex", flexDirection: "column", rowGap: 0 }}>
|
||||||
{vars.map((v, idx) => {
|
{vars.map((v) => (
|
||||||
const entry = workspace.editingTree.import[item.name] as
|
<Form.Item key={v.key} name={v.name} style={{ marginBottom: 2 }}>
|
||||||
| ImportDef
|
<VarDefItem id={v.name} disabled={true} />
|
||||||
| undefined;
|
</Form.Item>
|
||||||
const vardef = entry?.vars[v.name] as VarDef | undefined;
|
))}
|
||||||
return (
|
|
||||||
<Flex key={v.key} gap={4}>
|
|
||||||
<Space.Compact
|
|
||||||
className="b3-inspector-vars-item"
|
|
||||||
style={{ width: "100%", marginBottom: 0, paddingRight: 18 }}
|
|
||||||
>
|
|
||||||
<Form.Item noStyle name={[v.name, "id"]}>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
paddingLeft: "8px",
|
|
||||||
paddingRight: "8px",
|
|
||||||
maxWidth: "52px",
|
|
||||||
minWidth: "52px",
|
|
||||||
borderTopLeftRadius: idx === 0 ? "4px" : 0,
|
|
||||||
borderBottomLeftRadius:
|
|
||||||
idx === vars.length - 1 ? "4px" : 0,
|
|
||||||
borderLeft: "1px solid #3d506c",
|
|
||||||
borderTop: "1px solid #3d506c",
|
|
||||||
borderBottom:
|
|
||||||
idx === vars.length - 1 ? "1px solid #3d506c" : "none",
|
|
||||||
cursor: "pointer",
|
|
||||||
}}
|
|
||||||
onClick={() =>
|
|
||||||
vardef &&
|
|
||||||
workspace.editing?.dispatch("clickVar", vardef.name)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<AimOutlined />
|
|
||||||
<span style={{ marginLeft: 4 }}>
|
|
||||||
{usingCount[vardef?.name ?? ""] ?? 0}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item noStyle name={[v.name, "name"]}>
|
|
||||||
<Input
|
|
||||||
disabled={true}
|
|
||||||
placeholder={t("tree.vars.name")}
|
|
||||||
style={{
|
|
||||||
borderRadius: "0",
|
|
||||||
borderTop: "1px solid #3d506c",
|
|
||||||
borderBottom:
|
|
||||||
idx === vars.length - 1 ? "1px solid #3d506c" : "none",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item noStyle name={[v.name, "desc"]}>
|
|
||||||
<Input
|
|
||||||
disabled={true}
|
|
||||||
placeholder={t("tree.vars.desc")}
|
|
||||||
style={{
|
|
||||||
width: "90%",
|
|
||||||
borderTopRightRadius: idx === 0 ? "4px" : 0,
|
|
||||||
borderBottomRightRadius:
|
|
||||||
idx === vars.length - 1 ? "4px" : 0,
|
|
||||||
borderTop: "1px solid #3d506c",
|
|
||||||
borderBottom:
|
|
||||||
idx === vars.length - 1 ? "1px solid #3d506c" : "none",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Space.Compact>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Form.List>
|
</Form.List>
|
||||||
|
|||||||
Reference in new issue
Block a user