UNPKG

@nocobase/flow-engine

Version:

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

265 lines (263 loc) 11.4 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 FlowErrorFallback_exports = {}; __export(FlowErrorFallback_exports, { FlowErrorFallback: () => FlowErrorFallback, FlowErrorFallbackModal: () => FlowErrorFallbackModal }); module.exports = __toCommonJS(FlowErrorFallback_exports); var import_antd = require("antd"); var import_react = __toESM(require("react")); var import_useFlowModel = require("../hooks/useFlowModel"); var import_utils = require("../utils"); const { Paragraph, Text } = import_antd.Typography; const FlowErrorFallbackInner = /* @__PURE__ */ __name(({ error, resetErrorBoundary }) => { var _a; const [loading, setLoading] = (0, import_react.useState)(false); const model = (0, import_useFlowModel.useFlowModel)(); const t = (0, import_utils.getT)(model); const handleCopyError = /* @__PURE__ */ __name(async () => { setLoading(true); try { const errorInfo = { message: error.message, stack: error.stack, modelInfo: model ? { uid: model.uid, className: model.constructor.name, props: model.props, stepParams: model.stepParams } : null, timestamp: (/* @__PURE__ */ new Date()).toISOString() }; await navigator.clipboard.writeText(JSON.stringify(errorInfo, null, 2)); console.log("Error information copied to clipboard"); } catch (err) { console.error("Failed to copy error information:", err); } setLoading(false); }, "handleCopyError"); const canDownloadLogs = (_a = model == null ? void 0 : model.context) == null ? void 0 : _a.api; const handleDownloadLogs = /* @__PURE__ */ __name(async () => { if (!canDownloadLogs) { console.error("API client not available"); return; } setLoading(true); try { const apiClient = model.context.api; const location = { pathname: window.location.pathname, search: window.location.search, hash: window.location.hash, href: window.location.href }; const res = await apiClient.request({ url: "logger:collect", method: "post", responseType: "blob", data: { error: { message: error.message, stack: error.stack }, location, modelInfo: model ? { uid: model.uid, className: model.constructor.name, props: model.props, stepParams: model.stepParams } : null } }); const url = window.URL.createObjectURL(new Blob([res.data], { type: "application/gzip" })); const link = document.createElement("a"); link.setAttribute("href", url); link.setAttribute("download", "logs.tar.gz"); link.click(); link.remove(); window.URL.revokeObjectURL(url); } catch (err) { console.error("Failed to download logs:", err); } setLoading(false); }, "handleDownloadLogs"); const subTitle = /* @__PURE__ */ import_react.default.createElement("span", null, t("This is likely a NocoBase internals bug. Please open an issue at"), " ", /* @__PURE__ */ import_react.default.createElement("a", { href: "https://github.com/nocobase/nocobase/issues", target: "_blank", rel: "noopener noreferrer" }, t("here")), model && /* @__PURE__ */ import_react.default.createElement("div", { style: { marginTop: "8px", fontSize: "12px", color: "#999" } }, "Model: ", model.constructor.name, " (uid: ", model.uid, ")")); return /* @__PURE__ */ import_react.default.createElement("div", { style: { backgroundColor: "white" } }, /* @__PURE__ */ import_react.default.createElement( import_antd.Result, { style: { maxWidth: "60vw", margin: "auto" }, status: "error", title: t("Render failed"), subTitle, extra: [ /* @__PURE__ */ import_react.default.createElement(import_antd.Button, { type: "primary", key: "feedback", href: "https://github.com/nocobase/nocobase/issues", target: "_blank" }, t("Feedback")), canDownloadLogs && /* @__PURE__ */ import_react.default.createElement(import_antd.Button, { key: "log", loading, onClick: handleDownloadLogs }, t("Download logs")), /* @__PURE__ */ import_react.default.createElement(import_antd.Button, { key: "copy", loading, onClick: handleCopyError }, t("Copy error info")), resetErrorBoundary && /* @__PURE__ */ import_react.default.createElement(import_antd.Button, { key: "retry", danger: true, onClick: resetErrorBoundary }, t("Try again")) ].filter(Boolean) }, /* @__PURE__ */ import_react.default.createElement(Paragraph, { copyable: { text: error.stack } }, /* @__PURE__ */ import_react.default.createElement(Text, { type: "danger", style: { whiteSpace: "pre-line", textAlign: "center" } }, error.stack)) )); }, "FlowErrorFallbackInner"); const FlowErrorFallback = /* @__PURE__ */ __name(({ error, resetErrorBoundary }) => { const [loading, setLoading] = (0, import_react.useState)(false); try { return /* @__PURE__ */ import_react.default.createElement(FlowErrorFallbackInner, { error, resetErrorBoundary }); } catch { const handleCopyError = /* @__PURE__ */ __name(async () => { setLoading(true); try { const errorInfo = { message: error.message, stack: error.stack, timestamp: (/* @__PURE__ */ new Date()).toISOString() }; await navigator.clipboard.writeText(JSON.stringify(errorInfo, null, 2)); console.log("Error information copied to clipboard"); } catch (err) { console.error("Failed to copy error information:", err); } setLoading(false); }, "handleCopyError"); const subTitle = /* @__PURE__ */ import_react.default.createElement("span", null, "This is likely a NocoBase internals bug. Please open an issue at ", /* @__PURE__ */ import_react.default.createElement("a", { href: "https://github.com/nocobase/nocobase/issues", target: "_blank", rel: "noopener noreferrer" }, "here")); return /* @__PURE__ */ import_react.default.createElement("div", { style: { backgroundColor: "white" } }, /* @__PURE__ */ import_react.default.createElement( import_antd.Result, { style: { maxWidth: "60vw", margin: "auto" }, status: "error", title: "Render failed", subTitle, extra: [ /* @__PURE__ */ import_react.default.createElement(import_antd.Button, { type: "primary", key: "feedback", href: "https://github.com/nocobase/nocobase/issues", target: "_blank" }, "Feedback"), /* @__PURE__ */ import_react.default.createElement(import_antd.Button, { key: "copy", loading, onClick: handleCopyError }, "Copy error info"), resetErrorBoundary && /* @__PURE__ */ import_react.default.createElement(import_antd.Button, { key: "retry", danger: true, onClick: resetErrorBoundary }, "Try again") ].filter(Boolean) }, /* @__PURE__ */ import_react.default.createElement(Paragraph, { copyable: { text: error.stack } }, /* @__PURE__ */ import_react.default.createElement(Text, { type: "danger", style: { whiteSpace: "pre-line", textAlign: "center" } }, error.stack)) )); } }, "FlowErrorFallback"); const FlowErrorFallbackModal = /* @__PURE__ */ __name(({ error, resetErrorBoundary, children }) => { const [open, setOpen] = (0, import_react.useState)(false); const defaultChildren = /* @__PURE__ */ import_react.default.createElement( Paragraph, { style: { display: "flex", marginBottom: 0 }, copyable: { text: error.message } }, /* @__PURE__ */ import_react.default.createElement( Text, { type: "danger", style: { whiteSpace: "nowrap", textOverflow: "ellipsis", overflow: "hidden", display: "inline-block", maxWidth: "200px" } }, "Error: ", error.message ) ); return /* @__PURE__ */ import_react.default.createElement(import_react.default.Fragment, null, /* @__PURE__ */ import_react.default.createElement("div", { onMouseOver: () => setOpen(true) }, children || defaultChildren), open && /* @__PURE__ */ import_react.default.createElement( "div", { style: { position: "fixed", top: 0, left: 0, right: 0, bottom: 0, backgroundColor: "rgba(0, 0, 0, 0.5)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 1e4 }, onClick: () => setOpen(false) }, /* @__PURE__ */ import_react.default.createElement( "div", { style: { backgroundColor: "#fff", borderRadius: "8px", padding: "24px", maxWidth: "60vw", maxHeight: "80vh", overflow: "auto", position: "relative" }, onClick: (e) => e.stopPropagation() }, /* @__PURE__ */ import_react.default.createElement( "button", { style: { position: "absolute", top: "8px", right: "12px", background: "none", border: "none", fontSize: "18px", cursor: "pointer", color: "#999" }, onClick: () => setOpen(false) }, "\xD7" ), /* @__PURE__ */ import_react.default.createElement(FlowErrorFallback, { error, resetErrorBoundary }) ) )); }, "FlowErrorFallbackModal"); FlowErrorFallback.Modal = FlowErrorFallbackModal; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { FlowErrorFallback, FlowErrorFallbackModal });