@burdenoff/fluidgrids-fe-sdk 2026.1111.17 → 2026.1111.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AiStudioPage-kJHSsIcj.js → AiStudioPage-BHVEU4Wp.js} +2 -2
- package/dist/{SettingsPage-CgkRlCM5.js → SettingsPage-CJLZvv4J.js} +1485 -1484
- package/dist/{TemplatePreview-GthzCOSo.js → TemplatePreview-FayF6jxh.js} +1 -1
- package/dist/{WorkflowBuilder-DEi_9YOb.js → WorkflowBuilder-CPnXEL5J.js} +1 -1
- package/dist/{WorkflowBuilder-iPqXgbYr.js → WorkflowBuilder-YXRysvZc.js} +2 -2
- package/dist/WorkflowShareDialog-mbIwRQUY.js +168 -0
- package/dist/{WorkflowsList-CA20dVIl.js → WorkflowsList-DiiGyZkT.js} +2 -1
- package/dist/{agentTools-CkRJB7r5.js → agentTools-8s_25Q_F.js} +1 -1
- package/dist/{canvasNoteTools-CQIc7Oxg.js → canvasNoteTools-B6pYARgU.js} +1 -1
- package/dist/code-editor-field-9-GdVE_8.js +111 -0
- package/dist/{flow-builder-y2Y1iG4Y.js → flow-builder-CZDKRc6f.js} +245 -8638
- package/dist/{index-W2o__Nm6.d.ts → index-6JR2vD9J.d.ts} +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +13 -11
- package/dist/{node-detail-view-B91kXzIy.js → node-detail-view-CV4ZRwqh.js} +4 -2
- package/dist/node-editor-tab-body-DU-dh35X.js +174 -0
- package/dist/observability.d.ts +1 -1
- package/dist/popover-BJHvrFGR.js +472 -0
- package/dist/{quick-config-panel-DggPl1vY.js → quick-config-panel-ws3pLvbt.js} +2 -1
- package/dist/schedule-panel-C0mfGQSD.js +7542 -0
- package/dist/settings.js +1 -1
- package/dist/sidebar-node-editor-CR1PiZO-.js +177 -0
- package/dist/templates.js +1 -1
- package/dist/{useAgentDefinitions-Dpz0HDTq.js → useAgentDefinitions-B0dam3_o.js} +1 -396
- package/dist/useConnections-Cs7LCWEM.js +401 -0
- package/dist/{WorkflowShareDialog-B_gn968c.js → useWorkflowCodeExport-Bu2QYJzA.js} +4 -161
- package/dist/workflow-builder.js +2 -2
- package/dist/workflow-pages.d.ts +1 -1
- package/dist/workflow-pages.js +5 -5
- package/dist/workflows-list.js +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { t as __exportAll } from "./rolldown-runtime-hDbaFkMy.js";
|
|
3
3
|
import { t as ThemeProvider } from "./theme-provider-B3mIuz2d.js";
|
|
4
|
-
import { t as FlowBuilderPage } from "./flow-builder-
|
|
4
|
+
import { t as FlowBuilderPage } from "./flow-builder-CZDKRc6f.js";
|
|
5
5
|
import { a as useTemplateImportFlow, l as useImportWorkflowTemplate } from "./TemplateCard-DsC0KNH1.js";
|
|
6
6
|
import { t as QuotaExhaustedDialog } from "./QuotaExhaustedDialog-7IFSaLyi.js";
|
|
7
7
|
import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
|
|
@@ -6,7 +6,7 @@ import { d as Input } from "./dialog-Cjb4lB4D.js";
|
|
|
6
6
|
import { b as Card } from "./TemplateCard-DsC0KNH1.js";
|
|
7
7
|
import { t as cn } from "./cn-QqidFIgr.js";
|
|
8
8
|
import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
|
|
9
|
-
import {
|
|
9
|
+
import { S as FluidGridsMark, x as useNodeSelectedEvent } from "./flow-builder-CZDKRc6f.js";
|
|
10
10
|
import { useCallback, useEffect, useRef, useState } from "react";
|
|
11
11
|
import { Background, Controls, Handle, MarkerType, MiniMap, Position, ReactFlow, ReactFlowProvider, useReactFlow } from "@xyflow/react";
|
|
12
12
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { t as __exportAll } from "./rolldown-runtime-hDbaFkMy.js";
|
|
3
|
-
import {
|
|
3
|
+
import { g as useWorkflowReloadStore, h as releaseLeaseKeptForReload, t as FlowBuilderPage } from "./flow-builder-CZDKRc6f.js";
|
|
4
4
|
import { n as registerLiveCanvasHandler } from "./liveCanvas-D5ytXDp8.js";
|
|
5
5
|
import { _ as throwIfResultError, n as getFluidGridsClient, x as getFluidGridsConfig } from "./client-C9XSzSXr.js";
|
|
6
6
|
import { Er as WorkflowDefinitionDocument } from "./graphql-operation-types-kX-MMjgW.js";
|
|
@@ -12,7 +12,7 @@ import { l as useLazyWorkflowDefinition, n as useCreateWorkflow } from "./useWor
|
|
|
12
12
|
import { c as getWorkflowNodeTypes, o as buildNodeCheck, s as buildRequiredNodeTypes, v as useInstalledNodes } from "./TemplateCard-DsC0KNH1.js";
|
|
13
13
|
import { c as withoutGuidedTourIntent, l as decideMissingWorkflow, o as isGuidedTourIntent, s as pickGuidedTour, u as isCreateIntent } from "./firstWorkflow-C_h0KMB2.js";
|
|
14
14
|
import { f as BILLING_PLANS_PATH } from "./fluidgridsEvents-CNdcrUNN.js";
|
|
15
|
-
import {
|
|
15
|
+
import { T as CreateWorkflowRefusalDialog } from "./useWorkflowCodeExport-Bu2QYJzA.js";
|
|
16
16
|
import { Suspense, lazy, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
17
17
|
import { useLocation, useNavigate, useParams } from "react-router";
|
|
18
18
|
import { Icon } from "@iconify/react";
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as __exportAll } from "./rolldown-runtime-hDbaFkMy.js";
|
|
3
|
+
import { n as getFluidGridsClient } from "./client-C9XSzSXr.js";
|
|
4
|
+
import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
|
|
5
|
+
import { JF as WorkflowShareRole, hF as WorkflowAccess, nI as WorkflowVisibility, qF as WorkflowSharePrincipalType } from "./graphql-types-CDKVWH2R.js";
|
|
6
|
+
import { Mn as ShareWorkflowDocument, li as WorkflowSharingDocument } from "./graphql-operation-types-kX-MMjgW.js";
|
|
7
|
+
import { useMemo } from "react";
|
|
8
|
+
import { jsx } from "react/jsx-runtime";
|
|
9
|
+
import { ResourceShareDialog, createSharePrincipalLister } from "@burdenoff/fe-libs/connections";
|
|
10
|
+
|
|
11
|
+
// src/utils/workflow-sharing.ts
|
|
12
|
+
/** Whether someone reaching a workflow this way may change who it is shared with. */
|
|
13
|
+
function canShareWorkflow(access) {
|
|
14
|
+
return access === "OWNER" || access === "EDITOR" || access === "ADMINISTRATOR";
|
|
15
|
+
}
|
|
16
|
+
/** Whether someone reaching a workflow this way may change or run it. */
|
|
17
|
+
function canEditWorkflow(access) {
|
|
18
|
+
return access !== "VIEWER";
|
|
19
|
+
}
|
|
20
|
+
const VISIBILITY_OUT = {
|
|
21
|
+
WORKSPACE: "WORKSPACE",
|
|
22
|
+
RESTRICTED: "RESTRICTED"
|
|
23
|
+
};
|
|
24
|
+
const VISIBILITY_IN = {
|
|
25
|
+
["WORKSPACE"]: "WORKSPACE",
|
|
26
|
+
["RESTRICTED"]: "RESTRICTED"
|
|
27
|
+
};
|
|
28
|
+
const PRINCIPAL_OUT = {
|
|
29
|
+
USER: "USER",
|
|
30
|
+
GROUP: "GROUP",
|
|
31
|
+
PROJECT: "PROJECT"
|
|
32
|
+
};
|
|
33
|
+
const PRINCIPAL_IN = {
|
|
34
|
+
["USER"]: "USER",
|
|
35
|
+
["GROUP"]: "GROUP",
|
|
36
|
+
["PROJECT"]: "PROJECT"
|
|
37
|
+
};
|
|
38
|
+
const ROLE_OUT = {
|
|
39
|
+
VIEWER: "VIEWER",
|
|
40
|
+
EDITOR: "EDITOR"
|
|
41
|
+
};
|
|
42
|
+
const ROLE_IN = {
|
|
43
|
+
["VIEWER"]: "VIEWER",
|
|
44
|
+
["EDITOR"]: "EDITOR"
|
|
45
|
+
};
|
|
46
|
+
/** The service's answer as the dialog sees it; `name` is what the title shows. */
|
|
47
|
+
function toResourceSharing(sharing, name = sharing.workflowKey) {
|
|
48
|
+
const shares = sharing.shares.map((share) => ({
|
|
49
|
+
principalType: PRINCIPAL_IN[share.principalType],
|
|
50
|
+
principalId: share.principalId,
|
|
51
|
+
role: ROLE_IN[share.role]
|
|
52
|
+
}));
|
|
53
|
+
return {
|
|
54
|
+
id: sharing.workflowKey,
|
|
55
|
+
name,
|
|
56
|
+
ownerId: sharing.ownerId ?? "",
|
|
57
|
+
visibility: VISIBILITY_IN[sharing.visibility],
|
|
58
|
+
canManage: canShareWorkflow(sharing.myAccess),
|
|
59
|
+
administrator: sharing.canTransferOwnership,
|
|
60
|
+
shares
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/** The workflow service behind the generic Share dialog. */
|
|
64
|
+
function workflowSharingApi(client, listPrincipals) {
|
|
65
|
+
return {
|
|
66
|
+
async getSharing(workflowKey) {
|
|
67
|
+
const result = await client.query({
|
|
68
|
+
query: WorkflowSharingDocument,
|
|
69
|
+
variables: { workflowKey },
|
|
70
|
+
fetchPolicy: "network-only"
|
|
71
|
+
});
|
|
72
|
+
if (!result.data) throw new Error("Workflow not found");
|
|
73
|
+
return toResourceSharing(result.data.workflowSharing);
|
|
74
|
+
},
|
|
75
|
+
listPrincipals,
|
|
76
|
+
async share(input) {
|
|
77
|
+
const result = await client.mutate({
|
|
78
|
+
mutation: ShareWorkflowDocument,
|
|
79
|
+
variables: { input: {
|
|
80
|
+
workflowKey: input.resourceId,
|
|
81
|
+
visibility: VISIBILITY_OUT[input.visibility],
|
|
82
|
+
shares: input.shares.map((share) => ({
|
|
83
|
+
principalType: PRINCIPAL_OUT[share.principalType],
|
|
84
|
+
principalId: share.principalId,
|
|
85
|
+
role: ROLE_OUT[share.role]
|
|
86
|
+
})),
|
|
87
|
+
...input.ownerId ? { ownerId: input.ownerId } : {}
|
|
88
|
+
} }
|
|
89
|
+
});
|
|
90
|
+
if (!result.data) throw new Error("Workflow not found");
|
|
91
|
+
return toResourceSharing(result.data.shareWorkflow);
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// src/components/WorkflowShareDialog.tsx
|
|
97
|
+
/**
|
|
98
|
+
* WorkflowShareDialog — who can reach a workflow (BOFF-9726).
|
|
99
|
+
*
|
|
100
|
+
* The workflow version of fe-libs' ResourceShareDialog: a workflow is shared
|
|
101
|
+
* with people, groups or workspace projects as "Can view" or "Can edit", or
|
|
102
|
+
* left to the whole workspace. The workflow service decides who may change
|
|
103
|
+
* the sharing (its owner, an editor it is shared with, or a workspace admin)
|
|
104
|
+
* and answers NOT_FOUND to anyone else; this dialog only shows what the
|
|
105
|
+
* caller may do and sends the complete new sharing back.
|
|
106
|
+
*/
|
|
107
|
+
var WorkflowShareDialog_exports = /* @__PURE__ */ __exportAll({ WorkflowShareDialog: () => WorkflowShareDialog });
|
|
108
|
+
function workflowShareCopy(tr, name) {
|
|
109
|
+
return {
|
|
110
|
+
title: (loaded) => tr("fluidgrids.sharing.title", "Share {{name}}", { name: name || loaded }),
|
|
111
|
+
titleLoading: tr("fluidgrids.sharing.titleLoading", "Share workflow"),
|
|
112
|
+
loading: tr("fluidgrids.sharing.loading", "Loading sharing…"),
|
|
113
|
+
readOnly: tr("fluidgrids.sharing.readOnly", "Only the owner, editors and workspace admins can change who can open this workflow."),
|
|
114
|
+
save: tr("fluidgrids.sharing.save", "Save"),
|
|
115
|
+
cancel: tr("fluidgrids.sharing.cancel", "Cancel"),
|
|
116
|
+
close: tr("fluidgrids.sharing.close", "Close"),
|
|
117
|
+
owner: tr("fluidgrids.sharing.owner", "Owner"),
|
|
118
|
+
add: tr("fluidgrids.sharing.add", "Share with people, groups or projects"),
|
|
119
|
+
addPlaceholder: tr("fluidgrids.sharing.addPlaceholder", "Search by name or email"),
|
|
120
|
+
sharedWith: tr("fluidgrids.sharing.sharedWith", "Shared with"),
|
|
121
|
+
onlyOwner: tr("fluidgrids.sharing.onlyOwner", "No one else yet. Only the owner and workspace admins can open it."),
|
|
122
|
+
none: tr("fluidgrids.sharing.none", "No one in particular."),
|
|
123
|
+
principalType: {
|
|
124
|
+
USER: tr("fluidgrids.sharing.type.user", "Person"),
|
|
125
|
+
GROUP: tr("fluidgrids.sharing.type.group", "Group"),
|
|
126
|
+
PROJECT: tr("fluidgrids.sharing.type.project", "Project")
|
|
127
|
+
},
|
|
128
|
+
roleFor: (grantee) => tr("fluidgrids.sharing.roleFor", "Access for {{name}}", { name: grantee }),
|
|
129
|
+
remove: (grantee) => tr("fluidgrids.sharing.remove", "Stop sharing with {{name}}", { name: grantee }),
|
|
130
|
+
visibility: {
|
|
131
|
+
legend: tr("fluidgrids.sharing.visibility.label", "Who can open this workflow"),
|
|
132
|
+
restricted: tr("fluidgrids.sharing.visibility.restricted", "Only people I choose"),
|
|
133
|
+
restrictedHint: tr("fluidgrids.sharing.visibility.restrictedHint", "You, the people, groups or projects you share it with, and workspace admins. Everyone else cannot find it."),
|
|
134
|
+
workspace: tr("fluidgrids.sharing.visibility.workspace", "Everyone in this workspace"),
|
|
135
|
+
workspaceHint: tr("fluidgrids.sharing.visibility.workspaceHint", "Anyone in the workspace can open it, as their workspace role allows.")
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function WorkflowShareDialog({ open, onClose, workflowKey, workflowName, workspaceId, client, onShared, api: apiOverride }) {
|
|
140
|
+
const tr = useTr();
|
|
141
|
+
const api = useMemo(() => {
|
|
142
|
+
if (apiOverride) return apiOverride;
|
|
143
|
+
const apollo = client ?? getFluidGridsClient();
|
|
144
|
+
return workflowSharingApi(apollo, createSharePrincipalLister(apollo));
|
|
145
|
+
}, [apiOverride, client]);
|
|
146
|
+
const copy = useMemo(() => workflowShareCopy(tr, workflowName), [tr, workflowName]);
|
|
147
|
+
const roles = useMemo(() => [{
|
|
148
|
+
value: "VIEWER",
|
|
149
|
+
label: tr("fluidgrids.sharing.role.viewer", "Can view")
|
|
150
|
+
}, {
|
|
151
|
+
value: "EDITOR",
|
|
152
|
+
label: tr("fluidgrids.sharing.role.editor", "Can edit")
|
|
153
|
+
}], [tr]);
|
|
154
|
+
return /* @__PURE__ */ jsx(ResourceShareDialog, {
|
|
155
|
+
open,
|
|
156
|
+
onClose,
|
|
157
|
+
api,
|
|
158
|
+
resourceId: workflowKey,
|
|
159
|
+
workspaceId,
|
|
160
|
+
roles,
|
|
161
|
+
copy,
|
|
162
|
+
testIdPrefix: "share-workflow",
|
|
163
|
+
translate: tr,
|
|
164
|
+
onShared: onShared ? () => onShared() : void 0
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export { canShareWorkflow as i, WorkflowShareDialog_exports as n, canEditWorkflow as r, WorkflowShareDialog as t };
|
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
import { t as __exportAll } from "./rolldown-runtime-hDbaFkMy.js";
|
|
3
3
|
import { c as useImportWorkflow, h as useWorkflowDefinitions, l as useLazyWorkflowDefinition, n as useCreateWorkflow, o as useDeleteWorkflow, s as useDuplicateWorkflow, u as usePreviewN8nImport } from "./useWorkflows-BlVVu8NM.js";
|
|
4
4
|
import { Dt as createThenOpen, t as FluidGridsContext } from "./FluidGridsProvider-dvZSNtSW.js";
|
|
5
|
-
import { C as
|
|
5
|
+
import { C as typeScriptModuleFile, S as typeScriptImportSource, T as CreateWorkflowRefusalDialog, a as parseWorkflowImport, b as readProjectArchive, c as MAX_IMPORT_ARCHIVE_BYTES, d as checkTypeScriptImport, i as downloadWorkflowExport, l as MAX_IMPORT_SOURCE_BYTES, m as importFileKind, n as useExportWorkflowAs, o as CODE_EXPORT_FORMATS, p as importAcceptAttribute, s as ImportSourceError, u as assertImportByteSize, w as workflowNameFromFile, y as primaryImportModule } from "./useWorkflowCodeExport-Bu2QYJzA.js";
|
|
6
6
|
import { f as BILLING_PLANS_PATH, y as isQuotaExhaustedFailure } from "./fluidgridsEvents-CNdcrUNN.js";
|
|
7
7
|
import { H as useFlowStore } from "./node-operation-selection--oy-yEq_.js";
|
|
8
8
|
import { a as SdkPermissionGate, i as SdkPermissionButton, s as useFluidGridsPermission, t as FLUIDGRIDS_PERMISSIONS } from "./constants-B2lhWNoN.js";
|
|
9
9
|
import { t as QuotaExhaustedDialog } from "./QuotaExhaustedDialog-7IFSaLyi.js";
|
|
10
10
|
import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
|
|
11
11
|
import { CF as WorkflowExportFormat, gF as WorkflowAccessFilter } from "./graphql-types-CDKVWH2R.js";
|
|
12
|
+
import { i as canShareWorkflow, r as canEditWorkflow, t as WorkflowShareDialog } from "./WorkflowShareDialog-mbIwRQUY.js";
|
|
12
13
|
import { l as useFluidGridsFlag, t as FLUIDGRIDS_FLAGS } from "./feature-flags-DM5myWaD.js";
|
|
13
14
|
import { _ as throwIfResultError, m as describeOperationError, n as getFluidGridsClient } from "./client-C9XSzSXr.js";
|
|
14
15
|
import { $t as RenameWorkflowProjectDocument, G as DeleteWorkflowFolderDocument, Hr as WorkflowProjectsDocument, K as DeleteWorkflowProjectDocument, M as CreateWorkflowProjectDocument, Nr as WorkflowFoldersDocument, Qt as RenameWorkflowFolderDocument, Tt as MoveWorkflowFolderDocument, g as BulkMoveWorkflowsToFolderDocument, h as BulkDeleteWorkflowsDocument, j as CreateWorkflowFolderDocument, m as BulkAssignWorkflowsToProjectDocument } from "./graphql-operation-types-kX-MMjgW.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { At as useSaveStatusStore, J as paramsFromOperation, K as nodeTitle, L as createConfiguredNode, W as fixedParameterState, Y as selectedOperationOf, _ as registryNodeData, f as isNodeConfigsInitialized, o as NODE_CONFIGS, pt as autosaveAllowedFor, xt as isFlowComplete } from "./FluidGridsProvider-dvZSNtSW.js";
|
|
3
3
|
import { E as resolveOutputHandles, H as useFlowStore, T as resolveInputHandles } from "./node-operation-selection--oy-yEq_.js";
|
|
4
4
|
import { j as isNodeTypeHiddenFromPalette } from "./TemplateCard-DsC0KNH1.js";
|
|
5
|
-
import {
|
|
5
|
+
import { b as computeAttachPosition } from "./flow-builder-CZDKRc6f.js";
|
|
6
6
|
import { AgentToolError, defineAgentTool } from "@burdenoff/fe-libs/shared/agent-tools";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { n as useAgentMarksStore, r as toPlainText } from "./marksStore-DGCXjTmZ.js";
|
|
3
3
|
import { J as paramsFromOperation, K as nodeTitle, Y as selectedOperationOf } from "./FluidGridsProvider-dvZSNtSW.js";
|
|
4
4
|
import { H as useFlowStore } from "./node-operation-selection--oy-yEq_.js";
|
|
5
|
-
import {
|
|
5
|
+
import { _ as notesKeyOf } from "./flow-builder-CZDKRc6f.js";
|
|
6
6
|
import { AgentToolError, defineAgentTool } from "@burdenoff/fe-libs/shared/agent-tools";
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { t as __exportAll } from "./rolldown-runtime-hDbaFkMy.js";
|
|
3
|
+
import { g as toCodeMirrorDiagnostics } from "./node-operation-selection--oy-yEq_.js";
|
|
4
|
+
import { Fn as useBuilderReadOnly } from "./FluidGridsProvider-dvZSNtSW.js";
|
|
5
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
6
|
+
import { cn } from "@burdenoff/fe-libs/utils";
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
import CodeMirror, { EditorView } from "@uiw/react-codemirror";
|
|
9
|
+
import { lintGutter, setDiagnostics } from "@codemirror/lint";
|
|
10
|
+
|
|
11
|
+
// src/builder/components/ndv/code-editor-field.tsx
|
|
12
|
+
var code_editor_field_exports = /* @__PURE__ */ __exportAll({ CodeEditorField: () => CodeEditorField });
|
|
13
|
+
/**
|
|
14
|
+
* Loads the grammar for the selected language on demand (BOFF-6695). The
|
|
15
|
+
* lezer parsers are heavy and only one language is ever shown per editor, so
|
|
16
|
+
* each language pack is a separate chunk that loads when an editor for it
|
|
17
|
+
* mounts. `null` until the pack resolves: the editor renders as plain text
|
|
18
|
+
* for that first moment and reconfigures once highlighting arrives.
|
|
19
|
+
*/
|
|
20
|
+
function useLanguageExtension(language) {
|
|
21
|
+
const [extension, setExtension] = useState(null);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
let cancelled = false;
|
|
24
|
+
(language === "python" ? import("@codemirror/lang-python").then((m) => m.python()) : import("@codemirror/lang-javascript").then((m) => m.javascript({ typescript: language === "typescript" }))).then((ext) => {
|
|
25
|
+
if (!cancelled) setExtension(ext);
|
|
26
|
+
});
|
|
27
|
+
return () => {
|
|
28
|
+
cancelled = true;
|
|
29
|
+
};
|
|
30
|
+
}, [language]);
|
|
31
|
+
return extension;
|
|
32
|
+
}
|
|
33
|
+
function normalizeCodeLanguage(value) {
|
|
34
|
+
return typeof value === "string" && value.toLowerCase().startsWith("py") ? "python" : "javascript";
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Follows the app shell's `.dark` class on <html> so the editor theme matches
|
|
38
|
+
* the surrounding UI (fe-libs toggles that class; there is no context to read).
|
|
39
|
+
*/
|
|
40
|
+
function useIsDarkTheme() {
|
|
41
|
+
const [dark, setDark] = useState(() => typeof document !== "undefined" && document.documentElement.classList.contains("dark"));
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
const root = document.documentElement;
|
|
44
|
+
const observer = new MutationObserver(() => setDark(root.classList.contains("dark")));
|
|
45
|
+
observer.observe(root, {
|
|
46
|
+
attributes: true,
|
|
47
|
+
attributeFilter: ["class"]
|
|
48
|
+
});
|
|
49
|
+
return () => observer.disconnect();
|
|
50
|
+
}, []);
|
|
51
|
+
return dark;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* CodeMirror-backed editor for `code`-typed NDV parameters (n8n-style Code
|
|
55
|
+
* node). Purely presentational — the stored value stays a plain string in
|
|
56
|
+
* `args.state`, exactly like the single-line input it replaces.
|
|
57
|
+
*/
|
|
58
|
+
function CodeEditorField({ value, language, placeholder, label, onChange, readOnly: readOnlyProp = false, diagnostics, minHeight = "180px", maxHeight = "420px", className, "data-testid": testId }) {
|
|
59
|
+
const dark = useIsDarkTheme();
|
|
60
|
+
const withLint = diagnostics !== void 0;
|
|
61
|
+
const builderReadOnly = useBuilderReadOnly();
|
|
62
|
+
const readOnly = readOnlyProp || builderReadOnly;
|
|
63
|
+
const languageExtension = useLanguageExtension(language);
|
|
64
|
+
const extensions = useMemo(() => [
|
|
65
|
+
...languageExtension ? [languageExtension] : [],
|
|
66
|
+
...label ? [EditorView.contentAttributes.of({ "aria-label": label })] : [],
|
|
67
|
+
...withLint ? [lintGutter()] : []
|
|
68
|
+
], [
|
|
69
|
+
languageExtension,
|
|
70
|
+
label,
|
|
71
|
+
withLint
|
|
72
|
+
]);
|
|
73
|
+
const viewRef = useRef(null);
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
const view = viewRef.current;
|
|
76
|
+
if (!view || diagnostics === void 0) return;
|
|
77
|
+
view.dispatch(setDiagnostics(view.state, toCodeMirrorDiagnostics(view.state.doc.toString(), diagnostics)));
|
|
78
|
+
}, [diagnostics]);
|
|
79
|
+
return /* @__PURE__ */ jsx("div", {
|
|
80
|
+
"data-testid": testId,
|
|
81
|
+
className: cn("overflow-hidden rounded-md border border-input text-sm transition-colors focus-within:border-primary", className),
|
|
82
|
+
onKeyDown: (e) => e.stopPropagation(),
|
|
83
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
84
|
+
children: /* @__PURE__ */ jsx(CodeMirror, {
|
|
85
|
+
value,
|
|
86
|
+
onChange: readOnly ? void 0 : onChange,
|
|
87
|
+
extensions,
|
|
88
|
+
theme: dark ? "dark" : "light",
|
|
89
|
+
placeholder,
|
|
90
|
+
minHeight,
|
|
91
|
+
maxHeight,
|
|
92
|
+
editable: !readOnly,
|
|
93
|
+
readOnly,
|
|
94
|
+
onCreateEditor: (view) => {
|
|
95
|
+
viewRef.current = view;
|
|
96
|
+
if (diagnostics?.length) view.dispatch(setDiagnostics(view.state, toCodeMirrorDiagnostics(view.state.doc.toString(), diagnostics)));
|
|
97
|
+
},
|
|
98
|
+
basicSetup: {
|
|
99
|
+
lineNumbers: true,
|
|
100
|
+
foldGutter: true,
|
|
101
|
+
highlightActiveLine: !readOnly,
|
|
102
|
+
autocompletion: !readOnly,
|
|
103
|
+
bracketMatching: true,
|
|
104
|
+
closeBrackets: !readOnly,
|
|
105
|
+
indentOnInput: !readOnly
|
|
106
|
+
}
|
|
107
|
+
})
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export { code_editor_field_exports as n, normalizeCodeLanguage as r, CodeEditorField as t };
|