1
This commit is contained in:
parent
cec0962afd
commit
e7b914a2ae
@ -68,7 +68,7 @@ const WorkflowDesignInner: React.FC = () => {
|
|||||||
if (data) {
|
if (data) {
|
||||||
setNodes(data.nodes);
|
setNodes(data.nodes);
|
||||||
setEdges(data.edges);
|
setEdges(data.edges);
|
||||||
setWorkflowTitle(data.definition.name);
|
setWorkflowTitle(data.definition?.name || '未命名工作流');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -419,11 +419,16 @@ const WorkflowDesignInner: React.FC = () => {
|
|||||||
tagName === 'TEXTAREA' ||
|
tagName === 'TEXTAREA' ||
|
||||||
target.isContentEditable ||
|
target.isContentEditable ||
|
||||||
target.getAttribute('contenteditable') === 'true';
|
target.getAttribute('contenteditable') === 'true';
|
||||||
const isInDrawer = target.closest('.ant-drawer-body') !== null;
|
|
||||||
const isInModal = target.closest('.ant-modal') !== null;
|
|
||||||
|
|
||||||
// 在抽屉或模态框内,且在输入元素中时,允许原生行为
|
// 检查是否在 shadcn/ui Sheet、Dialog 或其他模态框内
|
||||||
const shouldSkipShortcut = isInputElement || isInDrawer || isInModal;
|
const isInSheet = target.closest('[role="dialog"]') !== null;
|
||||||
|
const isInModal = target.closest('[role="alertdialog"]') !== null;
|
||||||
|
const isInPopover = target.closest('[role="menu"]') !== null ||
|
||||||
|
target.closest('[role="listbox"]') !== null ||
|
||||||
|
target.closest('[data-radix-popper-content-wrapper]') !== null;
|
||||||
|
|
||||||
|
// 在模态框或弹窗内,或者在输入元素中时,允许原生行为
|
||||||
|
const shouldSkipShortcut = isInputElement || isInSheet || isInModal || isInPopover;
|
||||||
|
|
||||||
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
|
||||||
const ctrlKey = isMac ? e.metaKey : e.ctrlKey;
|
const ctrlKey = isMac ? e.metaKey : e.ctrlKey;
|
||||||
|
|||||||
@ -83,7 +83,7 @@ export const NotificationNodeDefinition: ConfigurableNodeDefinition = {
|
|||||||
default: ""
|
default: ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
required: ["nodeName", "nodeCode", "notificationType", "title", "content", "recipients"]
|
required: ["nodeName", "nodeCode", "notificationType", "title", "content"]
|
||||||
},
|
},
|
||||||
outputs: [{
|
outputs: [{
|
||||||
name: "status",
|
name: "status",
|
||||||
@ -91,8 +91,7 @@ export const NotificationNodeDefinition: ConfigurableNodeDefinition = {
|
|||||||
type: "string",
|
type: "string",
|
||||||
enum: ["SUCCESS", "FAILURE"],
|
enum: ["SUCCESS", "FAILURE"],
|
||||||
description: "执行的结果状态",
|
description: "执行的结果状态",
|
||||||
example: "SUCCESS",
|
example: "SUCCESS"
|
||||||
required: true
|
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ export enum NodeType {
|
|||||||
SCRIPT_TASK = 'SCRIPT_TASK',
|
SCRIPT_TASK = 'SCRIPT_TASK',
|
||||||
DEPLOY_NODE = 'DEPLOY_NODE',
|
DEPLOY_NODE = 'DEPLOY_NODE',
|
||||||
JENKINS_BUILD = 'JENKINS_BUILD',
|
JENKINS_BUILD = 'JENKINS_BUILD',
|
||||||
|
NOTIFICATION = 'NOTIFICATION',
|
||||||
GATEWAY_NODE = 'GATEWAY_NODE',
|
GATEWAY_NODE = 'GATEWAY_NODE',
|
||||||
SUB_PROCESS = 'SUB_PROCESS',
|
SUB_PROCESS = 'SUB_PROCESS',
|
||||||
CALL_ACTIVITY = 'CALL_ACTIVITY'
|
CALL_ACTIVITY = 'CALL_ACTIVITY'
|
||||||
|
|||||||
@ -15,77 +15,94 @@ export const convertJsonSchemaToZod = (jsonSchema: JSONSchema): z.ZodObject<any>
|
|||||||
|
|
||||||
Object.entries(jsonSchema.properties).forEach(([key, prop]: [string, any]) => {
|
Object.entries(jsonSchema.properties).forEach(([key, prop]: [string, any]) => {
|
||||||
let fieldSchema: z.ZodTypeAny;
|
let fieldSchema: z.ZodTypeAny;
|
||||||
|
const isRequired = Array.isArray(jsonSchema.required) && jsonSchema.required.includes(key);
|
||||||
|
|
||||||
// 根据类型创建 Zod Schema
|
// 如果有枚举,直接使用枚举(枚举会覆盖其他类型)
|
||||||
switch (prop.type) {
|
|
||||||
case 'string':
|
|
||||||
fieldSchema = z.string();
|
|
||||||
if (prop.format === 'email') {
|
|
||||||
fieldSchema = (fieldSchema as z.ZodString).email(prop.title ? `${prop.title}格式不正确` : '邮箱格式不正确');
|
|
||||||
} else if (prop.format === 'url') {
|
|
||||||
fieldSchema = (fieldSchema as z.ZodString).url(prop.title ? `${prop.title}格式不正确` : 'URL格式不正确');
|
|
||||||
}
|
|
||||||
if (prop.minLength) {
|
|
||||||
fieldSchema = (fieldSchema as z.ZodString).min(prop.minLength, `${prop.title || key}至少需要${prop.minLength}个字符`);
|
|
||||||
}
|
|
||||||
if (prop.maxLength) {
|
|
||||||
fieldSchema = (fieldSchema as z.ZodString).max(prop.maxLength, `${prop.title || key}最多${prop.maxLength}个字符`);
|
|
||||||
}
|
|
||||||
if (prop.pattern) {
|
|
||||||
fieldSchema = (fieldSchema as z.ZodString).regex(new RegExp(prop.pattern), `${prop.title || key}格式不正确`);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'number':
|
|
||||||
case 'integer':
|
|
||||||
fieldSchema = prop.type === 'integer' ? z.number().int() : z.number();
|
|
||||||
if (prop.minimum !== undefined) {
|
|
||||||
fieldSchema = (fieldSchema as z.ZodNumber).min(prop.minimum, `${prop.title || key}不能小于${prop.minimum}`);
|
|
||||||
}
|
|
||||||
if (prop.maximum !== undefined) {
|
|
||||||
fieldSchema = (fieldSchema as z.ZodNumber).max(prop.maximum, `${prop.title || key}不能大于${prop.maximum}`);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'boolean':
|
|
||||||
fieldSchema = z.boolean();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'array':
|
|
||||||
fieldSchema = z.array(z.any());
|
|
||||||
if (prop.minItems !== undefined) {
|
|
||||||
fieldSchema = (fieldSchema as z.ZodArray<any>).min(prop.minItems, `${prop.title || key}至少需要${prop.minItems}项`);
|
|
||||||
}
|
|
||||||
if (prop.maxItems !== undefined) {
|
|
||||||
fieldSchema = (fieldSchema as z.ZodArray<any>).max(prop.maxItems, `${prop.title || key}最多${prop.maxItems}项`);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'object':
|
|
||||||
fieldSchema = z.record(z.any());
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
fieldSchema = z.any();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理默认值
|
|
||||||
if (prop.default !== undefined) {
|
|
||||||
fieldSchema = fieldSchema.default(prop.default);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理枚举
|
|
||||||
if (prop.enum && Array.isArray(prop.enum)) {
|
if (prop.enum && Array.isArray(prop.enum)) {
|
||||||
const enumValues = prop.enum.map((v: any) => (typeof v === 'object' ? v.value : v));
|
const enumValues = prop.enum.map((v: any) => (typeof v === 'object' ? v.value : v));
|
||||||
fieldSchema = z.enum(enumValues as [string, ...string[]]);
|
fieldSchema = z.enum(enumValues as [string, ...string[]]);
|
||||||
}
|
|
||||||
|
|
||||||
// 处理必填字段
|
// 处理默认值
|
||||||
if (Array.isArray(jsonSchema.required) && jsonSchema.required.includes(key)) {
|
if (prop.default !== undefined) {
|
||||||
// 已经是必填的,不需要额外处理
|
fieldSchema = fieldSchema.default(prop.default);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理必填/可选
|
||||||
|
if (!isRequired) {
|
||||||
|
fieldSchema = fieldSchema.optional();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// 非必填字段设为 optional
|
// 根据类型创建 Zod Schema
|
||||||
fieldSchema = fieldSchema.optional();
|
switch (prop.type) {
|
||||||
|
case 'string': {
|
||||||
|
let stringSchema = z.string();
|
||||||
|
|
||||||
|
// 必填字段需要非空验证
|
||||||
|
if (isRequired) {
|
||||||
|
stringSchema = stringSchema.min(1, `${prop.title || key}不能为空`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prop.format === 'email') {
|
||||||
|
stringSchema = stringSchema.email(prop.title ? `${prop.title}格式不正确` : '邮箱格式不正确');
|
||||||
|
} else if (prop.format === 'url') {
|
||||||
|
stringSchema = stringSchema.url(prop.title ? `${prop.title}格式不正确` : 'URL格式不正确');
|
||||||
|
}
|
||||||
|
if (prop.minLength) {
|
||||||
|
stringSchema = stringSchema.min(prop.minLength, `${prop.title || key}至少需要${prop.minLength}个字符`);
|
||||||
|
}
|
||||||
|
if (prop.maxLength) {
|
||||||
|
stringSchema = stringSchema.max(prop.maxLength, `${prop.title || key}最多${prop.maxLength}个字符`);
|
||||||
|
}
|
||||||
|
if (prop.pattern) {
|
||||||
|
stringSchema = stringSchema.regex(new RegExp(prop.pattern), `${prop.title || key}格式不正确`);
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldSchema = stringSchema;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'number':
|
||||||
|
case 'integer':
|
||||||
|
fieldSchema = prop.type === 'integer' ? z.number().int() : z.number();
|
||||||
|
if (prop.minimum !== undefined) {
|
||||||
|
fieldSchema = (fieldSchema as z.ZodNumber).min(prop.minimum, `${prop.title || key}不能小于${prop.minimum}`);
|
||||||
|
}
|
||||||
|
if (prop.maximum !== undefined) {
|
||||||
|
fieldSchema = (fieldSchema as z.ZodNumber).max(prop.maximum, `${prop.title || key}不能大于${prop.maximum}`);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'boolean':
|
||||||
|
fieldSchema = z.boolean();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'array':
|
||||||
|
fieldSchema = z.array(z.any());
|
||||||
|
if (prop.minItems !== undefined) {
|
||||||
|
fieldSchema = (fieldSchema as z.ZodArray<any>).min(prop.minItems, `${prop.title || key}至少需要${prop.minItems}项`);
|
||||||
|
}
|
||||||
|
if (prop.maxItems !== undefined) {
|
||||||
|
fieldSchema = (fieldSchema as z.ZodArray<any>).max(prop.maxItems, `${prop.title || key}最多${prop.maxItems}项`);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'object':
|
||||||
|
fieldSchema = z.record(z.any());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fieldSchema = z.any();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理默认值
|
||||||
|
if (prop.default !== undefined) {
|
||||||
|
fieldSchema = fieldSchema.default(prop.default);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理可选字段
|
||||||
|
if (!isRequired) {
|
||||||
|
fieldSchema = fieldSchema.optional();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
shape[key] = fieldSchema;
|
shape[key] = fieldSchema;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user