refactor code
This commit is contained in:
@@ -5,7 +5,7 @@ import { Button, Card, Popover } from "antd";
|
||||
import SharedNode, { type SharedNodeProps } from "./_SharedNode";
|
||||
import AddNode from "./AddNode";
|
||||
import ConditionNodeConfigForm, { ConditionItem, ConditionNodeConfigFormFieldValues, ConditionNodeConfigFormInstance } from "./ConditionNodeConfigForm";
|
||||
import { Expr, WorkflowNodeIoValueType, Value } from "@/domain/workflow";
|
||||
import { Expr, WorkflowNodeIoValueType, ExprType } from "@/domain/workflow";
|
||||
import { produce } from "immer";
|
||||
import { useWorkflowStore } from "@/stores/workflow";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
@@ -32,7 +32,7 @@ const ConditionNode = ({ node, disabled, branchId, branchIndex }: ConditionNodeP
|
||||
const selectors = condition.leftSelector.split("#");
|
||||
const t = selectors[2] as WorkflowNodeIoValueType;
|
||||
const left: Expr = {
|
||||
type: "var",
|
||||
type: ExprType.Var,
|
||||
selector: {
|
||||
id: selectors[0],
|
||||
name: selectors[1],
|
||||
@@ -40,27 +40,10 @@ const ConditionNode = ({ node, disabled, branchId, branchIndex }: ConditionNodeP
|
||||
},
|
||||
};
|
||||
|
||||
let value: Value = condition.rightValue;
|
||||
switch (t) {
|
||||
case "boolean":
|
||||
if (value === "true") {
|
||||
value = true;
|
||||
} else if (value === "false") {
|
||||
value = false;
|
||||
}
|
||||
break;
|
||||
case "number":
|
||||
value = parseInt(value as string);
|
||||
break;
|
||||
case "string":
|
||||
value = value as string;
|
||||
break;
|
||||
}
|
||||
|
||||
const right: Expr = { type: "const", value: value, valueType: t };
|
||||
const right: Expr = { type: ExprType.Const, value: condition.rightValue, valueType: t };
|
||||
|
||||
return {
|
||||
type: "compare",
|
||||
type: ExprType.Compare,
|
||||
op: condition.operator,
|
||||
left,
|
||||
right,
|
||||
@@ -77,7 +60,7 @@ const ConditionNode = ({ node, disabled, branchId, branchIndex }: ConditionNodeP
|
||||
|
||||
for (let i = 1; i < values.conditions.length; i++) {
|
||||
expr = {
|
||||
type: "logical",
|
||||
type: ExprType.Logical,
|
||||
op: values.logicalOperator,
|
||||
left: expr,
|
||||
right: createComparisonExpr(values.conditions[i]),
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
WorkflowNode,
|
||||
workflowNodeIOOptions,
|
||||
WorkflowNodeIoValueType,
|
||||
ExprType,
|
||||
} from "@/domain/workflow";
|
||||
import { FormInstance } from "antd";
|
||||
import { useZustandShallowSelector } from "@/hooks";
|
||||
@@ -58,7 +59,7 @@ const initFormModel = (): ConditionNodeConfigFormFieldValues => {
|
||||
rightValue: "",
|
||||
},
|
||||
],
|
||||
logicalOperator: "and",
|
||||
logicalOperator: LogicalOperator.And,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -67,10 +68,10 @@ const expressionToForm = (expr?: Expr): ConditionNodeConfigFormFieldValues => {
|
||||
if (!expr) return initFormModel();
|
||||
|
||||
const conditions: ConditionItem[] = [];
|
||||
let logicalOp: LogicalOperator = "and";
|
||||
let logicalOp: LogicalOperator = LogicalOperator.And;
|
||||
|
||||
const extractComparisons = (expr: Expr): void => {
|
||||
if (expr.type === "compare") {
|
||||
if (expr.type === ExprType.Compare) {
|
||||
// 确保左侧是变量,右侧是常量
|
||||
if (isVarExpr(expr.left) && isConstExpr(expr.right)) {
|
||||
conditions.push({
|
||||
@@ -79,7 +80,7 @@ const expressionToForm = (expr?: Expr): ConditionNodeConfigFormFieldValues => {
|
||||
rightValue: String(expr.right.value),
|
||||
});
|
||||
}
|
||||
} else if (expr.type === "logical") {
|
||||
} else if (expr.type === ExprType.Logical) {
|
||||
logicalOp = expr.op;
|
||||
extractComparisons(expr.left);
|
||||
extractComparisons(expr.right);
|
||||
@@ -304,25 +305,18 @@ const formToExpression = (values: ConditionNodeConfigFormFieldValues): Expr => {
|
||||
const type = typeStr as WorkflowNodeIoValueType;
|
||||
|
||||
const left: Expr = {
|
||||
type: "var",
|
||||
type: ExprType.Var,
|
||||
selector: { id, name, type },
|
||||
};
|
||||
|
||||
let rightValue: any = condition.rightValue;
|
||||
if (type === "number") {
|
||||
rightValue = Number(condition.rightValue);
|
||||
} else if (type === "boolean") {
|
||||
rightValue = condition.rightValue === "true";
|
||||
}
|
||||
|
||||
const right: Expr = {
|
||||
type: "const",
|
||||
value: rightValue,
|
||||
type: ExprType.Const,
|
||||
value: condition.rightValue,
|
||||
valueType: type,
|
||||
};
|
||||
|
||||
return {
|
||||
type: "compare",
|
||||
type: ExprType.Compare,
|
||||
op: condition.operator,
|
||||
left,
|
||||
right,
|
||||
@@ -339,7 +333,7 @@ const formToExpression = (values: ConditionNodeConfigFormFieldValues): Expr => {
|
||||
|
||||
for (let i = 1; i < values.conditions.length; i++) {
|
||||
expr = {
|
||||
type: "logical",
|
||||
type: ExprType.Logical,
|
||||
op: values.logicalOperator,
|
||||
left: expr,
|
||||
right: createComparisonExpr(values.conditions[i]),
|
||||
|
||||
@@ -39,7 +39,7 @@ const InspectNode = ({ node, disabled }: InspectNodeProps) => {
|
||||
const config = (node.config as WorkflowNodeConfigForInspect) ?? {};
|
||||
return (
|
||||
<Flex className="size-full overflow-hidden" align="center" gap={8}>
|
||||
<Typography.Text className="truncate">{config.domain ?? ""}</Typography.Text>
|
||||
<Typography.Text className="truncate">{config.host ?? ""}</Typography.Text>
|
||||
</Flex>
|
||||
);
|
||||
}, [node]);
|
||||
|
||||
@@ -7,7 +7,7 @@ import { z } from "zod";
|
||||
import { type WorkflowNodeConfigForInspect } from "@/domain/workflow";
|
||||
import { useAntdForm } from "@/hooks";
|
||||
|
||||
import { validDomainName, validPortNumber } from "@/utils/validators";
|
||||
import { validDomainName, validIPv4Address, validPortNumber } from "@/utils/validators";
|
||||
|
||||
type InspectNodeConfigFormFieldValues = Partial<WorkflowNodeConfigForInspect>;
|
||||
|
||||
@@ -29,6 +29,8 @@ const initFormModel = (): InspectNodeConfigFormFieldValues => {
|
||||
return {
|
||||
domain: "",
|
||||
port: "443",
|
||||
path: "",
|
||||
host: "",
|
||||
};
|
||||
};
|
||||
|
||||
@@ -37,12 +39,14 @@ const InspectNodeConfigForm = forwardRef<InspectNodeConfigFormInstance, InspectN
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formSchema = z.object({
|
||||
domain: z.string().refine((val) => validDomainName(val), {
|
||||
message: t("workflow_node.inspect.form.domain.placeholder"),
|
||||
host: z.string().refine((val) => validIPv4Address(val) || validDomainName(val), {
|
||||
message: t("workflow_node.inspect.form.host.placeholder"),
|
||||
}),
|
||||
domain: z.string().optional(),
|
||||
port: z.string().refine((val) => validPortNumber(val), {
|
||||
message: t("workflow_node.inspect.form.port.placeholder"),
|
||||
}),
|
||||
path: z.string().optional(),
|
||||
});
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const { form: formInst, formProps } = useAntdForm({
|
||||
@@ -70,13 +74,21 @@ const InspectNodeConfigForm = forwardRef<InspectNodeConfigFormInstance, InspectN
|
||||
|
||||
return (
|
||||
<Form className={className} style={style} {...formProps} disabled={disabled} layout="vertical" scrollToFirstError onValuesChange={handleFormChange}>
|
||||
<Form.Item name="domain" label={t("workflow_node.inspect.form.domain.label")} rules={[formRule]}>
|
||||
<Input variant="filled" placeholder={t("workflow_node.inspect.form.domain.placeholder")} />
|
||||
<Form.Item name="host" label={t("workflow_node.inspect.form.host.label")} rules={[formRule]}>
|
||||
<Input variant="filled" placeholder={t("workflow_node.inspect.form.host.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="port" label={t("workflow_node.inspect.form.port.label")} rules={[formRule]}>
|
||||
<Input variant="filled" placeholder={t("workflow_node.inspect.form.port.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="domain" label={t("workflow_node.inspect.form.domain.label")} rules={[formRule]}>
|
||||
<Input variant="filled" placeholder={t("workflow_node.inspect.form.domain.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item name="path" label={t("workflow_node.inspect.form.path.label")} rules={[formRule]}>
|
||||
<Input variant="filled" placeholder={t("workflow_node.inspect.form.path.placeholder")} />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ const workflowNodeTypeDefaultInputs: Map<WorkflowNodeType, WorkflowNodeIO[]> = n
|
||||
name: "certificate",
|
||||
type: "certificate",
|
||||
required: true,
|
||||
label: "证书",
|
||||
label: i18n.t("workflow.variables.certificate.label"),
|
||||
},
|
||||
],
|
||||
],
|
||||
@@ -82,7 +82,7 @@ const workflowNodeTypeDefaultOutputs: Map<WorkflowNodeType, WorkflowNodeIO[]> =
|
||||
name: "certificate",
|
||||
type: "certificate",
|
||||
required: true,
|
||||
label: "证书",
|
||||
label: i18n.t("workflow.variables.certificate.label"),
|
||||
},
|
||||
],
|
||||
],
|
||||
@@ -93,7 +93,7 @@ const workflowNodeTypeDefaultOutputs: Map<WorkflowNodeType, WorkflowNodeIO[]> =
|
||||
name: "certificate",
|
||||
type: "certificate",
|
||||
required: true,
|
||||
label: "证书",
|
||||
label: i18n.t("workflow.variables.certificate.label"),
|
||||
},
|
||||
],
|
||||
],
|
||||
@@ -104,7 +104,7 @@ const workflowNodeTypeDefaultOutputs: Map<WorkflowNodeType, WorkflowNodeIO[]> =
|
||||
name: "certificate",
|
||||
type: "certificate",
|
||||
required: true,
|
||||
label: "证书",
|
||||
label: i18n.t("workflow.variables.certificate.label"),
|
||||
},
|
||||
],
|
||||
],
|
||||
@@ -161,6 +161,8 @@ export type WorkflowNodeConfigForUpload = {
|
||||
export type WorkflowNodeConfigForInspect = {
|
||||
domain: string;
|
||||
port: string;
|
||||
host: string;
|
||||
path: string;
|
||||
};
|
||||
|
||||
export type WorkflowNodeConfigForDeploy = {
|
||||
@@ -200,14 +202,20 @@ export type WorkflowNodeIO = {
|
||||
valueSelector?: WorkflowNodeIOValueSelector;
|
||||
};
|
||||
|
||||
export const VALUE_TYPES = Object.freeze({
|
||||
STRING: "string",
|
||||
NUMBER: "number",
|
||||
BOOLEAN: "boolean",
|
||||
} as const);
|
||||
|
||||
export type WorkflowNodeIoValueType = (typeof VALUE_TYPES)[keyof typeof VALUE_TYPES];
|
||||
|
||||
export type WorkflowNodeIOValueSelector = {
|
||||
id: string;
|
||||
name: string;
|
||||
type: WorkflowNodeIoValueType;
|
||||
};
|
||||
|
||||
export type WorkflowNodeIoValueType = "string" | "number" | "boolean";
|
||||
|
||||
type WorkflowNodeIOOptions = {
|
||||
label: string;
|
||||
value: string;
|
||||
@@ -224,12 +232,12 @@ export const workflowNodeIOOptions = (node: WorkflowNode) => {
|
||||
switch (output.type) {
|
||||
case "certificate":
|
||||
rs.options.push({
|
||||
label: `${node.name} - ${output.label} - 是否有效`,
|
||||
label: `${node.name} - ${output.label} - ${i18n.t("workflow.variables.is_validated.label")}`,
|
||||
value: `${node.id}#${output.name}.validated#boolean`,
|
||||
});
|
||||
|
||||
rs.options.push({
|
||||
label: `${node.name} - ${output.label} - 剩余天数`,
|
||||
label: `${node.name} - ${output.label} - ${i18n.t("workflow.variables.days_left.label")}`,
|
||||
value: `${node.id}#${output.name}.daysLeft#number`,
|
||||
});
|
||||
break;
|
||||
@@ -254,22 +262,34 @@ export type Value = string | number | boolean;
|
||||
|
||||
export type ComparisonOperator = ">" | "<" | ">=" | "<=" | "==" | "!=" | "is";
|
||||
|
||||
export type LogicalOperator = "and" | "or" | "not";
|
||||
export enum LogicalOperator {
|
||||
And = "and",
|
||||
Or = "or",
|
||||
Not = "not",
|
||||
}
|
||||
|
||||
export type ConstExpr = { type: "const"; value: Value; valueType: WorkflowNodeIoValueType };
|
||||
export type VarExpr = { type: "var"; selector: WorkflowNodeIOValueSelector };
|
||||
export type CompareExpr = { type: "compare"; op: ComparisonOperator; left: Expr; right: Expr };
|
||||
export type LogicalExpr = { type: "logical"; op: LogicalOperator; left: Expr; right: Expr };
|
||||
export type NotExpr = { type: "not"; expr: Expr };
|
||||
export enum ExprType {
|
||||
Const = "const",
|
||||
Var = "var",
|
||||
Compare = "compare",
|
||||
Logical = "logical",
|
||||
Not = "not",
|
||||
}
|
||||
|
||||
export type ConstExpr = { type: ExprType.Const; value: string; valueType: WorkflowNodeIoValueType };
|
||||
export type VarExpr = { type: ExprType.Var; selector: WorkflowNodeIOValueSelector };
|
||||
export type CompareExpr = { type: ExprType.Compare; op: ComparisonOperator; left: Expr; right: Expr };
|
||||
export type LogicalExpr = { type: ExprType.Logical; op: LogicalOperator; left: Expr; right: Expr };
|
||||
export type NotExpr = { type: ExprType.Not; expr: Expr };
|
||||
|
||||
export type Expr = ConstExpr | VarExpr | CompareExpr | LogicalExpr | NotExpr;
|
||||
|
||||
export const isConstExpr = (expr: Expr): expr is ConstExpr => {
|
||||
return expr.type === "const";
|
||||
return expr.type === ExprType.Const;
|
||||
};
|
||||
|
||||
export const isVarExpr = (expr: Expr): expr is VarExpr => {
|
||||
return expr.type === "var";
|
||||
return expr.type === ExprType.Var;
|
||||
};
|
||||
|
||||
// #endregion
|
||||
|
||||
@@ -53,5 +53,9 @@
|
||||
"workflow.detail.orchestration.action.run": "Run",
|
||||
"workflow.detail.orchestration.action.run.confirm": "You have unreleased changes. Do you really want to run this workflow based on the latest released version?",
|
||||
"workflow.detail.orchestration.action.run.prompt": "Running... Please check the history later",
|
||||
"workflow.detail.runs.tab": "History runs"
|
||||
"workflow.detail.runs.tab": "History runs",
|
||||
|
||||
"workflow.variables.is_validated.label": "Is valid",
|
||||
"workflow.variables.days_left.label": "Days left",
|
||||
"workflow.variables.certificate.label": "Certificate"
|
||||
}
|
||||
|
||||
@@ -806,6 +806,10 @@
|
||||
"workflow_node.inspect.form.domain.placeholder": "Please enter domain name",
|
||||
"workflow_node.inspect.form.port.label": "Port",
|
||||
"workflow_node.inspect.form.port.placeholder": "Please enter port",
|
||||
"workflow_node.inspect.form.host.label": "Host",
|
||||
"workflow_node.inspect.form.host.placeholder": "Please enter host",
|
||||
"workflow_node.inspect.form.path.label": "Path",
|
||||
"workflow_node.inspect.form.path.placeholder": "Please enter path",
|
||||
|
||||
"workflow_node.notify.label": "Notification",
|
||||
"workflow_node.notify.form.subject.label": "Subject",
|
||||
|
||||
@@ -53,5 +53,9 @@
|
||||
"workflow.detail.orchestration.action.run": "执行",
|
||||
"workflow.detail.orchestration.action.run.confirm": "你有尚未发布的更改。确定要以最近一次发布的版本继续执行吗?",
|
||||
"workflow.detail.orchestration.action.run.prompt": "执行中……请稍后查看执行历史",
|
||||
"workflow.detail.runs.tab": "执行历史"
|
||||
"workflow.detail.runs.tab": "执行历史",
|
||||
|
||||
"workflow.variables.is_validated.label": "是否有效",
|
||||
"workflow.variables.days_left.label": "剩余天数",
|
||||
"workflow.variables.certificate.label": "证书"
|
||||
}
|
||||
|
||||
@@ -805,6 +805,10 @@
|
||||
"workflow_node.inspect.form.domain.placeholder": "请输入要检查的网站域名",
|
||||
"workflow_node.inspect.form.port.label": "端口号",
|
||||
"workflow_node.inspect.form.port.placeholder": "请输入要检查的端口号",
|
||||
"workflow_node.inspect.form.host.label": "Host",
|
||||
"workflow_node.inspect.form.host.placeholder": "请输入 Host",
|
||||
"workflow_node.inspect.form.path.label": "Path",
|
||||
"workflow_node.inspect.form.path.placeholder": "请输入 Path",
|
||||
|
||||
"workflow_node.notify.label": "推送通知",
|
||||
"workflow_node.notify.form.subject.label": "通知主题",
|
||||
|
||||
Reference in New Issue
Block a user