UNPKG

@nocobase/flow-engine

Version:

A standalone flow engine for NocoBase, managing workflows, models, and actions.

343 lines (341 loc) 14.5 kB
/** * This file is part of the NocoBase (R) project. * Copyright (c) 2020-2024 NocoBase Co., Ltd. * Authors: NocoBase Team. * * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License. * For more information, please refer to: https://www.nocobase.com/agreement. */ var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var StepRequiredSettingsDialog_exports = {}; __export(StepRequiredSettingsDialog_exports, { openRequiredParamsStepFormDialog: () => openRequiredParamsStepFormDialog }); module.exports = __toCommonJS(StepRequiredSettingsDialog_exports); var import_react = require("@formily/react"); var import_reactive = require("@formily/reactive"); var import_antd = require("antd"); var import_react2 = __toESM(require("react")); var import_flowContext = require("../../../../flowContext"); var import_useFlowSettingsContext = require("../../../../hooks/useFlowSettingsContext"); var import_utils = require("../../../../utils"); function hasRequiredParams(uiSchema, currentParams) { for (const [fieldKey, fieldSchema] of Object.entries(uiSchema)) { if (fieldSchema.required === true) { const value = currentParams[fieldKey]; if (value === void 0 || value === null || value === "") { return false; } } } return true; } __name(hasRequiredParams, "hasRequiredParams"); const SchemaField = (0, import_react.createSchemaField)(); const MultiStepContextProvider = /* @__PURE__ */ __name(({ model, requiredSteps, formStep, children }) => { const currentStepIndex = (formStep == null ? void 0 : formStep.current) ?? 0; const currentStepInfo = requiredSteps[currentStepIndex]; const flowRuntimeContext = import_react2.default.useMemo(() => { const { flowKey, step } = currentStepInfo; const flow = model.getFlow(flowKey); const ctx = new import_flowContext.FlowRuntimeContext(model, flowKey, "settings"); (0, import_utils.setupRuntimeContextSteps)(ctx, (flow == null ? void 0 : flow.steps) || {}, model, flowKey); ctx.defineProperty("currentStep", { value: step }); return ctx; }, [model, currentStepInfo]); return /* @__PURE__ */ import_react2.default.createElement(import_useFlowSettingsContext.FlowSettingsContextProvider, { value: flowRuntimeContext }, children); }, "MultiStepContextProvider"); const openRequiredParamsStepFormDialog = /* @__PURE__ */ __name(async ({ model, dialogWidth = 800, dialogTitle }) => { const t = (0, import_utils.getT)(model); const defaultTitle = dialogTitle || t("Step parameter configuration"); if (!model) { import_antd.message.error(t("Invalid model provided")); throw new Error(t("Invalid model provided")); } return new Promise((resolve, reject) => { (async () => { var _a, _b, _c; try { const allFlows = model.getFlows(); const requiredSteps = []; for (const [flowKey, flow] of allFlows) { for (const stepKey in flow.steps) { const step = flow.steps[stepKey]; if (step.paramsRequired || step.preset) { const mergedUiSchema = await (0, import_utils.resolveStepUiSchema)(model, flow, step); if (mergedUiSchema) { const currentStepParams = model.getStepParams(flowKey, stepKey) || {}; const hasAllRequiredParams = false; console.log(`Flow: ${flowKey}, Step: ${stepKey}, hasAllRequiredParams:`, hasAllRequiredParams); if (!hasAllRequiredParams) { requiredSteps.push({ flowKey, stepKey, step, uiSchema: mergedUiSchema, title: step.title || stepKey, flowTitle: flow.title || flowKey }); } } } } } console.log("Required steps:", requiredSteps); if (requiredSteps.length === 0) { resolve({}); return; } const initialValues = {}; for (const { flowKey, stepKey, step } of requiredSteps) { const stepParams = model.getStepParams(flowKey, stepKey) || {}; let actionDefaultParams = {}; if (step.use) { const action = (_b = (_a = model.flowEngine) == null ? void 0 : _a.getAction) == null ? void 0 : _b.call(_a, step.use); actionDefaultParams = action.defaultParams || {}; } const flowRuntimeContext = new import_flowContext.FlowRuntimeContext(model, flowKey, "settings"); const flow = model.getFlow(flowKey); if (flow) { (0, import_utils.setupRuntimeContextSteps)(flowRuntimeContext, flow.steps, model, flowKey); } flowRuntimeContext.defineProperty("currentStep", { value: step }); const resolvedActionDefaultParams = await (0, import_utils.resolveDefaultParams)(actionDefaultParams, flowRuntimeContext); const resolvedDefaultParams = await (0, import_utils.resolveDefaultParams)(step.defaultParams, flowRuntimeContext); const mergedParams = { ...(0, import_reactive.toJS)(resolvedActionDefaultParams), ...(0, import_reactive.toJS)(resolvedDefaultParams), ...(0, import_reactive.toJS)(stepParams) }; if (Object.keys(mergedParams).length > 0) { if (!initialValues[flowKey]) { initialValues[flowKey] = {}; } initialValues[flowKey][stepKey] = mergedParams; } } const stepPanes = {}; requiredSteps.forEach(({ flowKey, stepKey, uiSchema, title, flowTitle }) => { const stepId = `${flowKey}_${stepKey}`; stepPanes[stepId] = { type: "void", "x-component": "FormStep.StepPane", "x-component-props": { title: `${title}`, description: `Flow: ${flowTitle}` }, properties: { layout: { type: "void", "x-component": "FormLayout", "x-component-props": { layout: "vertical" }, properties: { [flowKey]: { type: "object", properties: { [stepKey]: { type: "object", properties: uiSchema } } } } } } }; }); const formSchema = requiredSteps.length === 1 ? { type: "object", properties: { // 直接渲染单个步骤的内容,不显示步骤指示器 ...Object.values(stepPanes)[0].properties } } : { type: "object", properties: { step: { type: "void", "x-component": "FormStep", "x-component-props": { formStep: "{{formStep}}" }, properties: stepPanes } } }; const { FormDialog, FormStep } = await import("@formily/antd-v5"); const formStep = requiredSteps.length > 1 ? FormStep.createFormStep(0) : null; const flowEngine = model.flowEngine; const scopes = { formStep, totalSteps: requiredSteps.length, requiredSteps, useFlowSettingsContext: import_useFlowSettingsContext.useFlowSettingsContext, ...(_c = flowEngine.flowSettings) == null ? void 0 : _c.scopes }; const formDialog = FormDialog( { title: dialogTitle || t("Step parameter configuration"), width: dialogWidth, footer: null, // 移除默认的底部按钮,使用自定义的导航按钮 destroyOnClose: true }, (form) => { var _a2; const handleSubmit = /* @__PURE__ */ __name(async () => { try { await form.submit(); const currentValues = form.values; requiredSteps.forEach(({ flowKey, stepKey }) => { var _a3; const stepValues = (_a3 = currentValues[flowKey]) == null ? void 0 : _a3[stepKey]; if (stepValues) { model.setStepParams(flowKey, stepKey, stepValues); } }); await model.saveStepParams(); resolve(currentValues); formDialog.close(); } catch (error) { console.error(t("Error submitting form"), ":", error); } }, "handleSubmit"); const handleClose = /* @__PURE__ */ __name(() => { formDialog.close(); resolve({}); }, "handleClose"); const dialogScopes = { ...scopes, closeDialog: handleClose, handleNext: /* @__PURE__ */ __name(() => { form.validate().then(() => { if (formStep) { formStep.next(); } }).catch((errors) => { console.log(t("Form validation failed"), ":", errors); }); }, "handleNext") }; const compiledFormSchema = (0, import_utils.compileUiSchema)(dialogScopes, formSchema); return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement(MultiStepContextProvider, { model, requiredSteps, formStep }, /* @__PURE__ */ import_react2.default.createElement( SchemaField, { schema: compiledFormSchema, components: { FormStep, ...(_a2 = flowEngine.flowSettings) == null ? void 0 : _a2.components }, scope: dialogScopes } )), /* @__PURE__ */ import_react2.default.createElement(import_react.FormConsumer, null, () => /* @__PURE__ */ import_react2.default.createElement( "div", { style: { display: "flex", justifyContent: "flex-end", gap: 8, marginTop: 24, paddingTop: 16, borderTop: "1px solid #f0f0f0" } }, requiredSteps.length === 1 ? /* @__PURE__ */ import_react2.default.createElement(import_antd.Button, { type: "primary", onClick: handleSubmit }, t("Complete configuration")) : /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement( import_antd.Button, { disabled: !(formStep == null ? void 0 : formStep.allowBack), onClick: () => { if (formStep) { formStep.back(); } } }, t("Previous step") ), /* @__PURE__ */ import_react2.default.createElement( import_antd.Button, { disabled: !(formStep == null ? void 0 : formStep.allowNext), type: "primary", onClick: () => { form.validate().then(() => { if (formStep) { formStep.next(); } }).catch((errors) => { console.log(t("Form validation failed"), ":", errors); }); }, style: { display: ((formStep == null ? void 0 : formStep.current) ?? 0) < requiredSteps.length - 1 ? "inline-block" : "none" } }, t("Next step") ), /* @__PURE__ */ import_react2.default.createElement( import_antd.Button, { disabled: formStep == null ? void 0 : formStep.allowNext, type: "primary", onClick: handleSubmit, style: { display: ((formStep == null ? void 0 : formStep.current) ?? 0) >= requiredSteps.length - 1 ? "inline-block" : "none" } }, t("Complete configuration") )) ))); } ); formDialog.open({ initialValues: (0, import_utils.compileUiSchema)(scopes, initialValues) }); } catch (error) { reject(new Error(`${t("Failed to import FormDialog or FormStep")}: ${error.message}`)); } })(); }).catch((e) => { console.error(e); }); }, "openRequiredParamsStepFormDialog"); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { openRequiredParamsStepFormDialog });