support oneof for array type
This commit is contained in:
1 parent
826b69a587
commit
de9c9a48c9
6 files changed
+175
-117
No files matched your search
@@ -121,7 +121,7 @@
|
||||
"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.error": "Only one is allowed between input '{{input}}' and argument '{{desc}}({{arg}})'",
|
||||
"node.oneof.inputNotfound": "Input '{{input}}' not found",
|
||||
"node.outputVariable": "Output variables",
|
||||
"node.pasteDataError": "Paste data error",
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
"node.name": "节点名称",
|
||||
"node.noNodeSelected": "未选择任务节点",
|
||||
"node.notFound": "节点 “{{name}}” 不存在",
|
||||
"node.oneof.error": "输入项 “{{input}}” 和参数 “{{arg}}({{desc}})” 之中,只能选择设置其中之一",
|
||||
"node.oneof.error": "输入项 “{{input}}” 和参数 “{{desc}}({{arg}})” 之中,只能选择设置其中之一",
|
||||
"node.oneof.inputNotfound": "输入项“{{input}}”不存在",
|
||||
"node.outputVariable": "输出变量",
|
||||
"node.pasteDataError": "粘贴数据出错",
|
||||
|
||||
@@ -416,5 +416,19 @@
|
||||
}
|
||||
],
|
||||
"desc": "等待"
|
||||
},
|
||||
{
|
||||
"name": "TestOneof",
|
||||
"desc": "测试oneof",
|
||||
"type": "Action",
|
||||
"input": ["选项?"],
|
||||
"args": [
|
||||
{
|
||||
"name": "option",
|
||||
"desc": "选项",
|
||||
"type": "int[]?",
|
||||
"oneof": "选项"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -104,6 +104,15 @@
|
||||
"args": {
|
||||
"builtin": "afterRunFailure"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "13",
|
||||
"name": "TestOneof",
|
||||
"input": [
|
||||
"context"
|
||||
],
|
||||
"output": [],
|
||||
"args": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+143
-113
@@ -760,7 +760,7 @@ const NodeInspector: FC = () => {
|
||||
}
|
||||
});
|
||||
}
|
||||
data.args[arg.name] = arr;
|
||||
data.args[arg.name] = !isNodeArgOptional(arg) ? arr : arr.length ? arr : undefined;
|
||||
} else if (isJsonType(type)) {
|
||||
try {
|
||||
data.args[arg.name] = value === "null" ? null : JSON.parse(value);
|
||||
@@ -1070,7 +1070,7 @@ const NodeInspector: FC = () => {
|
||||
setFieldValue(`input.${i}`, value);
|
||||
validateFields([argName]);
|
||||
}
|
||||
if (!checkOneof(getFieldValue(argName) ?? "", value)) {
|
||||
if (!checkOneof(arg, getFieldValue(argName), value)) {
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
t("node.oneof.error", {
|
||||
@@ -1116,118 +1116,148 @@ const NodeInspector: FC = () => {
|
||||
const type = getNodeArgRawType(arg);
|
||||
if (isNodeArgArray(arg)) {
|
||||
return (
|
||||
<Form.Item key={`args.${arg.name}`}>
|
||||
<Form.List name={`args.${arg.name}`}>
|
||||
{(items, { add, remove }, { errors }) => (
|
||||
<div style={{ display: "flex", rowGap: 0, flexDirection: "column" }}>
|
||||
{items.map((item, idx) => (
|
||||
<Flex key={item.key} gap={4}>
|
||||
<Form.Item
|
||||
name={item.name}
|
||||
label={idx === 0 ? `${arg.desc}[${idx}]` : `[${idx}]`}
|
||||
validateTrigger={["onChange", "onBlur"]}
|
||||
style={{ width: "100%", marginBottom: 5 }}
|
||||
initialValue={
|
||||
isBoolType(type) ? arg.default ?? false : arg.default
|
||||
}
|
||||
valuePropName={isBoolType(type) ? "checked" : undefined}
|
||||
rules={[
|
||||
{
|
||||
required,
|
||||
message: t("fieldRequired", { field: arg.desc }),
|
||||
<Form.List
|
||||
key={`args.${arg.name}`}
|
||||
name={`args.${arg.name}`}
|
||||
rules={[
|
||||
{
|
||||
validator(_, value: unknown[]) {
|
||||
if (!arg.oneof) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
const idx = def.input?.findIndex(
|
||||
(input) => input.replace("?", "") === arg.oneof
|
||||
);
|
||||
if (idx === undefined || idx < 0) {
|
||||
return Promise.reject(
|
||||
new Error(t("node.oneof.inputNotfound", { input: arg.oneof }))
|
||||
);
|
||||
}
|
||||
const inputName = `input.${idx}`;
|
||||
if (!form.isFieldValidating(inputName)) {
|
||||
form.setFieldValue(`args.${arg.name}`, value);
|
||||
form.validateFields([inputName]);
|
||||
}
|
||||
if (!checkOneof(arg, value, form.getFieldValue(inputName))) {
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
t("node.oneof.error", {
|
||||
input: def.input![idx],
|
||||
arg: arg.name,
|
||||
desc: arg.desc ?? "",
|
||||
})
|
||||
)
|
||||
);
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
},
|
||||
]}
|
||||
>
|
||||
{(items, { add, remove }, { errors }) => (
|
||||
<div style={{ display: "flex", rowGap: 0, flexDirection: "column" }}>
|
||||
{items.map((item, idx) => (
|
||||
<Flex key={item.key} gap={4}>
|
||||
<Form.Item
|
||||
name={item.name}
|
||||
label={idx === 0 ? `${arg.desc}[${idx}]` : `[${idx}]`}
|
||||
validateTrigger={["onChange", "onBlur"]}
|
||||
style={{ width: "100%", marginBottom: 5 }}
|
||||
initialValue={isBoolType(type) ? arg.default ?? false : arg.default}
|
||||
valuePropName={isBoolType(type) ? "checked" : undefined}
|
||||
rules={[
|
||||
{
|
||||
required,
|
||||
message: t("fieldRequired", { field: arg.desc }),
|
||||
},
|
||||
() => ({
|
||||
validator(_, value) {
|
||||
return validateArg(
|
||||
editingNode.data,
|
||||
arg,
|
||||
value,
|
||||
workspace.usingVars
|
||||
);
|
||||
},
|
||||
() => ({
|
||||
validator(_, value) {
|
||||
return validateArg(
|
||||
editingNode.data,
|
||||
arg,
|
||||
value,
|
||||
workspace.usingVars
|
||||
);
|
||||
},
|
||||
}),
|
||||
]}
|
||||
>
|
||||
{!hasArgOptions(arg) && isStringType(type) && (
|
||||
<TextArea autoSize disabled={disabled} onBlur={submit} />
|
||||
)}
|
||||
{!hasArgOptions(arg) && isJsonType(type) && (
|
||||
<TextArea autoSize disabled={disabled} onBlur={submit} />
|
||||
)}
|
||||
{!hasArgOptions(arg) && isIntType(type) && (
|
||||
<InputNumber
|
||||
disabled={disabled}
|
||||
onBlur={submit}
|
||||
precision={0}
|
||||
/>
|
||||
)}
|
||||
{!hasArgOptions(arg) && isFloatType(type) && (
|
||||
<InputNumber disabled={disabled} onBlur={submit} />
|
||||
)}
|
||||
{!hasArgOptions(arg) && isBoolType(type) && (
|
||||
<Switch disabled={disabled} onChange={submit} />
|
||||
)}
|
||||
{!hasArgOptions(arg) && isExprType(type) && (
|
||||
<Input disabled={disabled} onBlur={submit} />
|
||||
)}
|
||||
{hasArgOptions(arg) && (
|
||||
<Select
|
||||
showSearch
|
||||
disabled={disabled}
|
||||
onBlur={submit}
|
||||
onChange={submit}
|
||||
options={(arg.options ?? []).map((option) => {
|
||||
return {
|
||||
value: option.value,
|
||||
label: `${option.name}(${option.value})`,
|
||||
};
|
||||
})}
|
||||
filterOption={(value, option) => {
|
||||
value = value.toUpperCase();
|
||||
return !!option?.label
|
||||
.toLocaleUpperCase()
|
||||
.includes(value.toUpperCase());
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<MinusCircleOutlined
|
||||
style={{ marginBottom: "6px" }}
|
||||
onClick={() => {
|
||||
remove(item.name);
|
||||
submit();
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
))}
|
||||
<Form.Item
|
||||
label={items.length === 0 ? arg.desc : undefined}
|
||||
style={{
|
||||
marginLeft: items.length === 0 ? undefined : "100px",
|
||||
marginRight: items.length === 0 ? undefined : "18px",
|
||||
alignItems: "end",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
type="dashed"
|
||||
onClick={() => {
|
||||
add(arg.default ?? isBoolType(type) ? false : "");
|
||||
if (isBoolType(type)) {
|
||||
submit();
|
||||
}
|
||||
}}
|
||||
style={{ width: "100%" }}
|
||||
icon={<PlusOutlined />}
|
||||
danger={items.length === 0 && !isNodeArgOptional(arg)}
|
||||
}),
|
||||
]}
|
||||
>
|
||||
{t("add")}
|
||||
</Button>
|
||||
<Form.ErrorList errors={errors} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
)}
|
||||
</Form.List>
|
||||
</Form.Item>
|
||||
{!hasArgOptions(arg) && isStringType(type) && (
|
||||
<TextArea autoSize disabled={disabled} onBlur={submit} />
|
||||
)}
|
||||
{!hasArgOptions(arg) && isJsonType(type) && (
|
||||
<TextArea autoSize disabled={disabled} onBlur={submit} />
|
||||
)}
|
||||
{!hasArgOptions(arg) && isIntType(type) && (
|
||||
<InputNumber disabled={disabled} onBlur={submit} precision={0} />
|
||||
)}
|
||||
{!hasArgOptions(arg) && isFloatType(type) && (
|
||||
<InputNumber disabled={disabled} onBlur={submit} />
|
||||
)}
|
||||
{!hasArgOptions(arg) && isBoolType(type) && (
|
||||
<Switch disabled={disabled} onChange={submit} />
|
||||
)}
|
||||
{!hasArgOptions(arg) && isExprType(type) && (
|
||||
<Input disabled={disabled} onBlur={submit} />
|
||||
)}
|
||||
{hasArgOptions(arg) && (
|
||||
<Select
|
||||
showSearch
|
||||
disabled={disabled}
|
||||
onBlur={submit}
|
||||
onChange={submit}
|
||||
options={(arg.options ?? []).map((option) => {
|
||||
return {
|
||||
value: option.value,
|
||||
label: `${option.name}(${option.value})`,
|
||||
};
|
||||
})}
|
||||
filterOption={(value, option) => {
|
||||
value = value.toUpperCase();
|
||||
return !!option?.label
|
||||
.toLocaleUpperCase()
|
||||
.includes(value.toUpperCase());
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<MinusCircleOutlined
|
||||
style={{ marginBottom: "6px" }}
|
||||
onClick={() => {
|
||||
remove(item.name);
|
||||
submit();
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
))}
|
||||
<Form.Item
|
||||
label={items.length === 0 ? arg.desc : undefined}
|
||||
style={{
|
||||
marginLeft: items.length === 0 ? undefined : "100px",
|
||||
marginRight: items.length === 0 ? undefined : "18px",
|
||||
alignItems: "end",
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
type="dashed"
|
||||
onClick={() => {
|
||||
add(arg.default ?? isBoolType(type) ? false : "");
|
||||
if (isBoolType(type)) {
|
||||
submit();
|
||||
}
|
||||
}}
|
||||
style={{ width: "100%" }}
|
||||
icon={<PlusOutlined />}
|
||||
danger={items.length === 0 && !isNodeArgOptional(arg)}
|
||||
>
|
||||
{t("add")}
|
||||
</Button>
|
||||
<Form.ErrorList errors={errors} />
|
||||
</Form.Item>
|
||||
</div>
|
||||
)}
|
||||
</Form.List>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
@@ -1264,7 +1294,7 @@ const NodeInspector: FC = () => {
|
||||
setFieldValue(`args.${arg.name}`, value);
|
||||
validateFields([inputName]);
|
||||
}
|
||||
if (!checkOneof(getFieldValue(inputName) ?? "", value)) {
|
||||
if (!checkOneof(arg, value, form.getFieldValue(inputName))) {
|
||||
return Promise.reject(
|
||||
new Error(
|
||||
t("node.oneof.error", {
|
||||
|
||||
+7
-2
@@ -307,7 +307,7 @@ export const checkNodeArg = (data: NodeData, conf: NodeDef, i: number, verbose?:
|
||||
}
|
||||
if (arg.oneof !== undefined) {
|
||||
const idx = conf.input?.findIndex((v) => v.startsWith(arg.oneof!)) ?? -1;
|
||||
if (!checkOneof(data.args?.[arg.name], data.input?.[idx])) {
|
||||
if (!checkOneof(arg, data.args?.[arg.name], data.input?.[idx])) {
|
||||
if (verbose) {
|
||||
error(
|
||||
data,
|
||||
@@ -321,7 +321,12 @@ export const checkNodeArg = (data: NodeData, conf: NodeDef, i: number, verbose?:
|
||||
return !hasError;
|
||||
};
|
||||
|
||||
export const checkOneof = (argValue: unknown, inputValue: unknown) => {
|
||||
export const checkOneof = (arg: NodeArg, argValue: unknown, inputValue: unknown) => {
|
||||
if (isNodeArgArray(arg)) {
|
||||
if (argValue instanceof Array && argValue.length === 0) {
|
||||
argValue = undefined;
|
||||
}
|
||||
}
|
||||
argValue = argValue === undefined ? "" : argValue;
|
||||
inputValue = inputValue ?? "";
|
||||
return (argValue !== "" && inputValue === "") || (argValue === "" && inputValue !== "");
|
||||
|
||||
Reference in new issue
Block a user