UNPKG

n8n-editor-ui

Version:

Workflow Editor UI for n8n

204 lines (203 loc) 8.07 kB
import { C as computed, Gt as unref } from "./vue.runtime.esm-bundler-tP5dCd7J.js"; import { _t as useI18n } from "./_MapCache-ficiegRb.js"; import { Ji as stringSizeInBytes, N as useWorkflowsStore, Nt as useNodeTypesStore, O as useTelemetry, Yi as toMegaBytes, b as useExternalHooks, v as useToast, xn as useDataSchema } from "./builder.store-sBTWwxRU.js"; import { Da as jsonParse, Js as MAX_EXPECTED_REQUEST_SIZE, Oa as jsonStringify, Qi as getNodeOutputs, Ua as NodeConnectionTypes, Wn as PIN_DATA_NODE_TYPES_DENYLIST, Xs as MAX_WORKFLOW_SIZE, Ys as MAX_PINNED_DATA_SIZE, la as isSubNodeType } from "./constants-BbpucWL4.js"; import { r as useRootStore } from "./_baseOrderBy-B_6CV8x6.js"; function useNodeType(options = {}) { const nodeTypesStore = useNodeTypesStore(); const nodeType = computed(() => { if (options.nodeType) return unref(options.nodeType); const activeNode = unref(options.node); if (activeNode) return nodeTypesStore.getNodeType(activeNode.type, activeNode.typeVersion); return null; }); return { nodeType, isSubNodeType: computed(() => isSubNodeType(nodeType.value)), isMultipleOutputsNodeType: computed(() => { const outputs = nodeType.value?.outputs; if (typeof outputs === "string") return false; return (outputs ?? []).length > 1; }) }; } function usePinnedData(node, options = {}) { const rootStore = useRootStore(); const workflowsStore = useWorkflowsStore(); const toast = useToast(); const i18n = useI18n(); const telemetry = useTelemetry(); const externalHooks = useExternalHooks(); const { getInputDataWithPinned } = useDataSchema(); const workflowObject = computed(() => workflowsStore.workflowObject); const { isSubNodeType: isSubNodeType$1, isMultipleOutputsNodeType } = useNodeType({ node }); const data = computed(() => { const targetNode = unref(node); return targetNode ? workflowsStore.pinDataByNodeName(targetNode.name) : void 0; }); const hasData = computed(() => { return !!unref(node) && typeof data.value !== "undefined"; }); const isValidNodeType = computed(() => { const targetNode = unref(node); return !!targetNode && !isSubNodeType$1.value && !isMultipleOutputsNodeType.value && !PIN_DATA_NODE_TYPES_DENYLIST.includes(targetNode.type); }); function canPinNode(checkDataEmpty = false, outputIndex) { const targetNode = unref(node); if (targetNode === null || PIN_DATA_NODE_TYPES_DENYLIST.includes(targetNode.type)) return false; const nodeType = useNodeTypesStore().getNodeType(targetNode.type, targetNode.typeVersion); const dataToPin = getInputDataWithPinned(targetNode); if (!nodeType || checkDataEmpty && dataToPin.length === 0) return false; const outputs = getNodeOutputs(workflowObject.value, targetNode, nodeType).map((output) => typeof output === "string" ? { type: output } : output); const mainOutputs = outputs.filter((output) => output.type === NodeConnectionTypes.Main && output.category !== "error"); let indexAcceptable = true; if (outputIndex !== void 0) { const output = outputs[outputIndex]; if (outputs[outputIndex] === void 0) return false; indexAcceptable = output.type === NodeConnectionTypes.Main && output.category !== "error"; } return mainOutputs.length === 1 && indexAcceptable; } function isValidJSON(data$1) { try { JSON.parse(data$1); return true; } catch (error) { const title = i18n.baseText("runData.editOutputInvalid"); const toRemove = new RegExp(/JSON\.parse:|of the JSON data/, "g"); const message = error.message.replace(toRemove, "").trim(); const positionMatchRegEx = /at position (\d+)/; const positionMatch = error.message.match(positionMatchRegEx); error.message = message.charAt(0).toUpperCase() + message.slice(1); error.message = error.message.replace("Unexpected token ' in JSON", i18n.baseText("runData.editOutputInvalid.singleQuote")); if (positionMatch) { const position = parseInt(positionMatch[1], 10); const lineBreaksUpToPosition = (data$1.slice(0, position).match(/\n/g) || []).length; error.message = error.message.replace(positionMatchRegEx, i18n.baseText("runData.editOutputInvalid.atPosition", { interpolate: { position: `${position}` } })); error.message = `${i18n.baseText("runData.editOutputInvalid.onLine", { interpolate: { line: `${lineBreaksUpToPosition + 1}` } })} ${error.message}`; } toast.showError(error, title); return false; } } function getMaxPinnedDataSize() { return window.maxPinnedDataSize ?? 12582912; } function isValidSize(data$1) { const targetNode = unref(node); if (!targetNode) return false; if (typeof data$1 === "object") data$1 = JSON.stringify(data$1); const { pinData: currentPinData,...workflowObjectWithoutPinData } = workflowObject.value; const workflowJson = jsonStringify(workflowObjectWithoutPinData, { replaceCircularRefs: true }); const newPinData = { ...currentPinData, [targetNode.name]: data$1 }; const newPinDataSize = workflowsStore.getPinDataSize(newPinData); if (newPinDataSize > getMaxPinnedDataSize()) { toast.showError(new Error(i18n.baseText("ndv.pinData.error.tooLarge.description", { interpolate: { size: toMegaBytes(newPinDataSize), limit: toMegaBytes(getMaxPinnedDataSize()) } })), i18n.baseText("ndv.pinData.error.tooLarge.title")); return false; } const workflowSize = stringSizeInBytes(workflowJson) + newPinDataSize; const limit = MAX_WORKFLOW_SIZE - MAX_EXPECTED_REQUEST_SIZE; if (workflowSize > limit) { toast.showError(new Error(i18n.baseText("ndv.pinData.error.tooLargeWorkflow.description", { interpolate: { size: toMegaBytes(workflowSize), limit: toMegaBytes(limit) } })), i18n.baseText("ndv.pinData.error.tooLargeWorkflow.title")); return false; } return true; } function onSetDataSuccess({ source }) { const targetNode = unref(node); const displayMode = unref(options.displayMode); const runIndex = unref(options.runIndex); const telemetryPayload = { pinning_source: source, node_type: targetNode?.type, push_ref: rootStore.pushRef, data_size: stringSizeInBytes(data.value), view: displayMode, run_index: runIndex, workflow_id: workflowsStore.workflowId, node_id: targetNode?.id }; externalHooks.run("runData.onDataPinningSuccess", telemetryPayload); telemetry.track("Ndv data pinning success", telemetryPayload); } function onSetDataError({ errorType, source }) { const targetNode = unref(node); const displayMode = unref(options.displayMode); const runIndex = unref(options.runIndex); telemetry.track("Ndv data pinning failure", { pinning_source: source, node_type: targetNode?.type, push_ref: rootStore.pushRef, data_size: stringSizeInBytes(data.value), view: displayMode, run_index: runIndex, error_type: errorType }); } function setData(data$1, source) { const targetNode = unref(node); if (!targetNode) return; if (typeof data$1 === "string") { if (!isValidJSON(data$1)) { onSetDataError({ errorType: "invalid-json", source }); throw new Error("Invalid JSON"); } data$1 = jsonParse(data$1); } if (!isValidSize(data$1)) { onSetDataError({ errorType: "data-too-large", source }); throw new Error("Data too large"); } workflowsStore.pinData({ node: targetNode, data: data$1 }); onSetDataSuccess({ source }); } function onUnsetData({ source }) { const targetNode = unref(node); const runIndex = unref(options.runIndex); telemetry.track("User unpinned ndv data", { node_type: targetNode?.type, push_ref: rootStore.pushRef, run_index: runIndex, source, data_size: stringSizeInBytes(data.value) }); } function unsetData(source) { const targetNode = unref(node); if (!targetNode) return; onUnsetData({ source }); workflowsStore.unpinData({ node: targetNode }); } return { data, hasData, isValidNodeType, canPinNode, setData, onSetDataSuccess, onSetDataError, unsetData, onUnsetData, isValidJSON, isValidSize }; } export { useNodeType as n, usePinnedData as t };