@burdenoff/fluidgrids-fe-sdk 2026.1029.6 → 2026.1029.8
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/ExecutionDetailPage-H6R3ZIXN.js +22 -0
- package/dist/{WorkflowsList-VA2HRYFG.js → ExecutionsListPage-TLD2E442.js} +9 -9
- package/dist/{WorkflowBuilder-PORH3H6P.js → WorkflowBuilder-XVHY7XWJ.js} +12 -12
- package/dist/{ExecutionsListPage-SCPWUXUL.js → WorkflowsList-3GXXXURR.js} +9 -8
- package/dist/{chunk-MNY2UNQH.js → chunk-2NG5VZWI.js} +1 -1
- package/dist/{chunk-CY6KX4RG.js → chunk-6AMNEX2Y.js} +6 -1
- package/dist/{chunk-LPGQTSI2.js → chunk-6CKDGT2N.js} +3 -3
- package/dist/{chunk-U6KI4AKI.js → chunk-6TMLIQHB.js} +199 -1
- package/dist/{chunk-LTVAUZ3M.js → chunk-G3KZOX52.js} +3 -3
- package/dist/{chunk-7PP6CRXS.js → chunk-GQTEHWWY.js} +26 -8
- package/dist/{chunk-LB62TAF7.js → chunk-H4AZBUWM.js} +1 -1
- package/dist/{chunk-57RS7DXZ.js → chunk-HWEKWYXQ.js} +117 -8
- package/dist/{chunk-7B2GRTUL.js → chunk-LJGC7RAL.js} +164 -101
- package/dist/{chunk-4TGUNOQQ.js → chunk-NAYPOEYM.js} +391 -112
- package/dist/{chunk-BWAUFSHC.js → chunk-NNPXN4DI.js} +5 -5
- package/dist/{chunk-QZM6EDGK.js → chunk-NUBPALBK.js} +1 -1
- package/dist/{chunk-YSUSSIWU.js → chunk-R7VHURPQ.js} +1 -1
- package/dist/{chunk-7SSZUX6E.js → chunk-S4JYBJ4X.js} +2 -2
- package/dist/{chunk-WTGBHE3J.js → chunk-T22LICGX.js} +118 -96
- package/dist/{chunk-63ZMEHZ4.js → chunk-TJ6RUV4R.js} +937 -26
- package/dist/{chunk-H364USFF.js → chunk-UIDJT3YK.js} +1 -1
- package/dist/{chunk-4XAPSIHY.js → chunk-UWNCFMHV.js} +183 -26
- package/dist/{chunk-MDPBO52Q.js → chunk-V5PA5KGV.js} +2 -2
- package/dist/{chunk-MQI7NH4Z.js → chunk-VEZ7G2FE.js} +145 -8
- package/dist/{chunk-YHTRCQ5M.js → chunk-WEXO3KAY.js} +4 -4
- package/dist/{chunk-7LFAWWVF.js → chunk-WTP343PG.js} +2 -2
- package/dist/{chunk-Z6EWB5ZG.js → chunk-X2J4ZXKD.js} +1492 -98
- package/dist/{chunk-6XZCYLAQ.js → chunk-XJBCRDWZ.js} +3 -3
- package/dist/{chunk-AVMI3XLM.js → chunk-XMKYZP6Q.js} +282 -18
- package/dist/{chunk-5GD6OXYW.js → chunk-Z6I6A47T.js} +1 -1
- package/dist/{config-T7BQ7AO2.js → config-VM7FTHMZ.js} +1 -1
- package/dist/executions.js +13 -13
- package/dist/history.js +5 -5
- package/dist/index.d.ts +2588 -26
- package/dist/index.js +36 -36
- package/dist/nodes.js +2 -2
- package/dist/observability.js +7 -7
- package/dist/settings.js +7 -7
- package/dist/templates.js +11 -11
- package/dist/{workflow-builder-CZFczcE7.d.ts → workflow-builder-BMGVSwpy.d.ts} +7 -0
- package/dist/workflow-builder.d.ts +1 -1
- package/dist/workflow-builder.js +13 -13
- package/dist/workflows-list.js +9 -9
- package/package.json +1 -1
- package/dist/ExecutionDetailPage-M6JAWY4Q.js +0 -21
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { cn as cn$1 } from './chunk-JL7CASN5.js';
|
|
2
2
|
import { getGlobalStoreClient, createGlobalStoreClient, setGlobalStoreClient, resetGlobalStoreClient } from './chunk-PXIFUMLA.js';
|
|
3
|
-
import { getFluidGridsConfig, validateTrustedOrigin, resetFluidGridsExecutionState, setFluidGridsConfig, resetFluidGridsConfig } from './chunk-
|
|
3
|
+
import { getFluidGridsConfig, validateTrustedOrigin, resetFluidGridsExecutionState, setFluidGridsConfig, resetFluidGridsConfig } from './chunk-6AMNEX2Y.js';
|
|
4
4
|
import { GetMyNodeInstallationsDocument } from './chunk-JUUYPCFY.js';
|
|
5
|
-
import { fetchAllNodeEndpointConfigs, NodeManifestDocument, UpdateWorkflowDefinitionDocument, CreateWorkflowDefinitionDocument, CreateWorkflowVersionDocument, ExecuteStepDocument, TriggerWorkflowDocument, RunFromNodeDocument, ExecutionDetailDocument, WorkflowDefinitionDocument, WorkflowRunDocument } from './chunk-
|
|
5
|
+
import { fetchAllNodeEndpointConfigs, NodeManifestDocument, UpdateWorkflowDefinitionDocument, CreateWorkflowDefinitionDocument, CreateWorkflowVersionDocument, ExecuteStepDocument, TriggerWorkflowDocument, RunFromNodeDocument, ExecutionDetailDocument, WorkflowDefinitionDocument, WorkflowRunDocument } from './chunk-GQTEHWWY.js';
|
|
6
6
|
import { useTr, ENGLISH_FALLBACK_TRANSLATOR, FluidGridsTranslationProvider } from './chunk-UULVIT25.js';
|
|
7
7
|
import { waitForFluidGridsClient, getFluidGridsClient, getFluidGridsClientSafe, createFluidGridsClient, setFluidGridsClient, resetFluidGridsClient } from './chunk-NTWG3CJX.js';
|
|
8
|
+
import * as React2 from 'react';
|
|
9
|
+
import { forwardRef, useState, useImperativeHandle, useRef, useEffect, useMemo, createContext, memo, useCallback, useContext, useSyncExternalStore, cloneElement } from 'react';
|
|
10
|
+
import { useOptionalFeatureFlags } from '@burdenoff/fe-libs/shared/feature-flags';
|
|
8
11
|
import { CombinedGraphQLErrors, ServerError } from '@apollo/client/errors';
|
|
9
12
|
import { dispatchUpgradePrompt } from '@burdenoff/fe-libs/shared/components';
|
|
10
13
|
import { nanoid } from 'nanoid/non-secure';
|
|
11
14
|
import { addEdge, applyEdgeChanges, applyNodeChanges, useReactFlow, NodeResizer, getConnectedEdges, useStore, Handle, Position, useUpdateNodeInternals, useNodeId } from '@xyflow/react';
|
|
12
15
|
import { create } from 'zustand';
|
|
13
16
|
import { produce } from 'immer';
|
|
14
|
-
import * as React2 from 'react';
|
|
15
|
-
import { forwardRef, useState, useImperativeHandle, useRef, useEffect, useMemo, createContext, memo, useCallback, useSyncExternalStore, useContext, cloneElement } from 'react';
|
|
16
|
-
import { useOptionalFeatureFlags } from '@burdenoff/fe-libs/shared/feature-flags';
|
|
17
17
|
import { Textarea, Input, Button, Card, Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuItem, DropdownMenuSeparator } from '@burdenoff/fe-libs/ui';
|
|
18
18
|
import { cn } from '@burdenoff/fe-libs/utils';
|
|
19
19
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
@@ -34,6 +34,104 @@ import { useParams, useNavigate } from 'react-router';
|
|
|
34
34
|
import { useShallow } from 'zustand/shallow';
|
|
35
35
|
import { InfoCircledIcon } from '@radix-ui/react-icons';
|
|
36
36
|
|
|
37
|
+
// src/feature-flags/durable-nodes.ts
|
|
38
|
+
var DURABLE_FUNCTION_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
39
|
+
"internal:code-workflow",
|
|
40
|
+
"internal:wait-for-signal"
|
|
41
|
+
]);
|
|
42
|
+
function isDurableFunctionNodeType(nodeType) {
|
|
43
|
+
return !!nodeType && DURABLE_FUNCTION_NODE_TYPES.has(nodeType);
|
|
44
|
+
}
|
|
45
|
+
function isNodeTypeHiddenFromPalette(nodeType, durableFunctionsEnabled = false) {
|
|
46
|
+
return !durableFunctionsEnabled && isDurableFunctionNodeType(nodeType);
|
|
47
|
+
}
|
|
48
|
+
function filterPaletteNodes(nodes, durableFunctionsEnabled = false) {
|
|
49
|
+
if (durableFunctionsEnabled) return nodes;
|
|
50
|
+
if (!nodes.some((node) => isDurableFunctionNodeType(node.type))) return nodes;
|
|
51
|
+
return nodes.filter((node) => !isDurableFunctionNodeType(node.type));
|
|
52
|
+
}
|
|
53
|
+
var FLUIDGRIDS_FLAGS = {
|
|
54
|
+
/**
|
|
55
|
+
* Operational kill switch for log stream destinations (webhook, syslog,
|
|
56
|
+
* Sentry). Defaults on; an admin turning it off hides the Log streaming
|
|
57
|
+
* settings and the backend rejects destination writes with FEATURE_DISABLED.
|
|
58
|
+
*/
|
|
59
|
+
logStreams: "fluidgrids.log-streams",
|
|
60
|
+
/**
|
|
61
|
+
* Code-first workflows (BOFF-9902): the builder's Code view, Export as
|
|
62
|
+
* TypeScript / Python and TypeScript import. A rollout gate, not a kill
|
|
63
|
+
* switch, so it defaults OFF: the controls stay hidden until tenant-svc
|
|
64
|
+
* evaluates the flag on for the workspace, including when the shell mounts
|
|
65
|
+
* no FeatureFlagProvider or the evaluation is still loading.
|
|
66
|
+
*/
|
|
67
|
+
codeFirst: "fluidgrids.code-first",
|
|
68
|
+
/**
|
|
69
|
+
* Durable functions (BOFF-9905): the Code Workflow and Wait for Signal
|
|
70
|
+
* nodes, run history, signals and the source editor. A rollout gate like
|
|
71
|
+
* `codeFirst`, so it defaults OFF and fails closed. The durable nodes are
|
|
72
|
+
* shown in the palette only while both this flag and `codeFirst` are on.
|
|
73
|
+
*/
|
|
74
|
+
durableFunctions: "fluidgrids.durable-functions",
|
|
75
|
+
/**
|
|
76
|
+
* Durable-function parity (BOFF-9905, spec code-first 11): workflow ids and
|
|
77
|
+
* run chains, run metadata, what a run is waiting on, run counts,
|
|
78
|
+
* completion callbacks, versioning (rollouts, drainage, per-run overrides)
|
|
79
|
+
* and the history caps. A rollout gate like `durableFunctions`, so it
|
|
80
|
+
* defaults OFF and fails closed; the parity surfaces show only while this
|
|
81
|
+
* flag, `durableFunctions` and `codeFirst` are all on.
|
|
82
|
+
*/
|
|
83
|
+
durableParity: "fluidgrids.durable-parity"
|
|
84
|
+
};
|
|
85
|
+
var FLUIDGRIDS_FLAG_DEFAULTS = {
|
|
86
|
+
[FLUIDGRIDS_FLAGS.logStreams]: true,
|
|
87
|
+
[FLUIDGRIDS_FLAGS.codeFirst]: false,
|
|
88
|
+
[FLUIDGRIDS_FLAGS.durableFunctions]: false,
|
|
89
|
+
[FLUIDGRIDS_FLAGS.durableParity]: false
|
|
90
|
+
};
|
|
91
|
+
var settledEvaluations = /* @__PURE__ */ new WeakMap();
|
|
92
|
+
function evaluationsUsable(context) {
|
|
93
|
+
const { evaluations } = context;
|
|
94
|
+
if (!evaluations) return !context.isLoading;
|
|
95
|
+
const workspace = context.workspaceId ?? null;
|
|
96
|
+
const settledFor = settledEvaluations.get(evaluations);
|
|
97
|
+
if (context.isLoading)
|
|
98
|
+
return settledFor !== void 0 && settledFor === workspace;
|
|
99
|
+
if (settledFor === void 0) {
|
|
100
|
+
settledEvaluations.set(evaluations, workspace);
|
|
101
|
+
return true;
|
|
102
|
+
}
|
|
103
|
+
return settledFor === workspace;
|
|
104
|
+
}
|
|
105
|
+
function resolveFluidGridsFlag(context, flag) {
|
|
106
|
+
const fallback = FLUIDGRIDS_FLAG_DEFAULTS[flag];
|
|
107
|
+
if (!context) return fallback;
|
|
108
|
+
if (fallback) {
|
|
109
|
+
if (context.isLoading) return fallback;
|
|
110
|
+
const evaluation2 = context.getEvaluation(flag);
|
|
111
|
+
return evaluation2 ? Boolean(evaluation2.value) : fallback;
|
|
112
|
+
}
|
|
113
|
+
if (context.error || !evaluationsUsable(context)) return false;
|
|
114
|
+
const evaluation = context.getEvaluation(flag);
|
|
115
|
+
return !!evaluation && !evaluation.errorCode && evaluation.value === true;
|
|
116
|
+
}
|
|
117
|
+
function useFluidGridsFlag(flag) {
|
|
118
|
+
const context = useOptionalFeatureFlags();
|
|
119
|
+
return useMemo(() => resolveFluidGridsFlag(context, flag), [context, flag]);
|
|
120
|
+
}
|
|
121
|
+
function useDurableFunctionNodesEnabled() {
|
|
122
|
+
const context = useOptionalFeatureFlags();
|
|
123
|
+
return useMemo(
|
|
124
|
+
() => resolveFluidGridsFlag(context, FLUIDGRIDS_FLAGS.codeFirst) && resolveFluidGridsFlag(context, FLUIDGRIDS_FLAGS.durableFunctions),
|
|
125
|
+
[context]
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
function resolveDurableParity(context) {
|
|
129
|
+
return resolveFluidGridsFlag(context, FLUIDGRIDS_FLAGS.codeFirst) && resolveFluidGridsFlag(context, FLUIDGRIDS_FLAGS.durableFunctions) && resolveFluidGridsFlag(context, FLUIDGRIDS_FLAGS.durableParity);
|
|
130
|
+
}
|
|
131
|
+
function useDurableParityEnabled() {
|
|
132
|
+
const context = useOptionalFeatureFlags();
|
|
133
|
+
return useMemo(() => resolveDurableParity(context), [context]);
|
|
134
|
+
}
|
|
37
135
|
function describeGraphQLError(error) {
|
|
38
136
|
const code = typeof error.extensions?.code === "string" ? error.extensions.code : void 0;
|
|
39
137
|
switch (code) {
|
|
@@ -1240,88 +1338,6 @@ if (typeof window !== "undefined" && import.meta.env?.DEV) {
|
|
|
1240
1338
|
window.__fgFlowStore = useFlowStore;
|
|
1241
1339
|
}
|
|
1242
1340
|
|
|
1243
|
-
// src/feature-flags/durable-nodes.ts
|
|
1244
|
-
var DURABLE_FUNCTION_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
1245
|
-
"internal:code-workflow",
|
|
1246
|
-
"internal:wait-for-signal"
|
|
1247
|
-
]);
|
|
1248
|
-
function isDurableFunctionNodeType(nodeType) {
|
|
1249
|
-
return !!nodeType && DURABLE_FUNCTION_NODE_TYPES.has(nodeType);
|
|
1250
|
-
}
|
|
1251
|
-
function isNodeTypeHiddenFromPalette(nodeType, durableFunctionsEnabled = false) {
|
|
1252
|
-
return !durableFunctionsEnabled && isDurableFunctionNodeType(nodeType);
|
|
1253
|
-
}
|
|
1254
|
-
function filterPaletteNodes(nodes, durableFunctionsEnabled = false) {
|
|
1255
|
-
if (durableFunctionsEnabled) return nodes;
|
|
1256
|
-
if (!nodes.some((node) => isDurableFunctionNodeType(node.type))) return nodes;
|
|
1257
|
-
return nodes.filter((node) => !isDurableFunctionNodeType(node.type));
|
|
1258
|
-
}
|
|
1259
|
-
var FLUIDGRIDS_FLAGS = {
|
|
1260
|
-
/**
|
|
1261
|
-
* Operational kill switch for log stream destinations (webhook, syslog,
|
|
1262
|
-
* Sentry). Defaults on; an admin turning it off hides the Log streaming
|
|
1263
|
-
* settings and the backend rejects destination writes with FEATURE_DISABLED.
|
|
1264
|
-
*/
|
|
1265
|
-
logStreams: "fluidgrids.log-streams",
|
|
1266
|
-
/**
|
|
1267
|
-
* Code-first workflows (BOFF-9902): the builder's Code view, Export as
|
|
1268
|
-
* TypeScript / Python and TypeScript import. A rollout gate, not a kill
|
|
1269
|
-
* switch, so it defaults OFF: the controls stay hidden until tenant-svc
|
|
1270
|
-
* evaluates the flag on for the workspace, including when the shell mounts
|
|
1271
|
-
* no FeatureFlagProvider or the evaluation is still loading.
|
|
1272
|
-
*/
|
|
1273
|
-
codeFirst: "fluidgrids.code-first",
|
|
1274
|
-
/**
|
|
1275
|
-
* Durable functions (BOFF-9905): the Code Workflow and Wait for Signal
|
|
1276
|
-
* nodes, run history, signals and the source editor. A rollout gate like
|
|
1277
|
-
* `codeFirst`, so it defaults OFF and fails closed. The durable nodes are
|
|
1278
|
-
* shown in the palette only while both this flag and `codeFirst` are on.
|
|
1279
|
-
*/
|
|
1280
|
-
durableFunctions: "fluidgrids.durable-functions"
|
|
1281
|
-
};
|
|
1282
|
-
var FLUIDGRIDS_FLAG_DEFAULTS = {
|
|
1283
|
-
[FLUIDGRIDS_FLAGS.logStreams]: true,
|
|
1284
|
-
[FLUIDGRIDS_FLAGS.codeFirst]: false,
|
|
1285
|
-
[FLUIDGRIDS_FLAGS.durableFunctions]: false
|
|
1286
|
-
};
|
|
1287
|
-
var settledEvaluations = /* @__PURE__ */ new WeakMap();
|
|
1288
|
-
function evaluationsUsable(context) {
|
|
1289
|
-
const { evaluations } = context;
|
|
1290
|
-
if (!evaluations) return !context.isLoading;
|
|
1291
|
-
const workspace = context.workspaceId ?? null;
|
|
1292
|
-
const settledFor = settledEvaluations.get(evaluations);
|
|
1293
|
-
if (context.isLoading)
|
|
1294
|
-
return settledFor !== void 0 && settledFor === workspace;
|
|
1295
|
-
if (settledFor === void 0) {
|
|
1296
|
-
settledEvaluations.set(evaluations, workspace);
|
|
1297
|
-
return true;
|
|
1298
|
-
}
|
|
1299
|
-
return settledFor === workspace;
|
|
1300
|
-
}
|
|
1301
|
-
function resolveFluidGridsFlag(context, flag) {
|
|
1302
|
-
const fallback = FLUIDGRIDS_FLAG_DEFAULTS[flag];
|
|
1303
|
-
if (!context) return fallback;
|
|
1304
|
-
if (fallback) {
|
|
1305
|
-
if (context.isLoading) return fallback;
|
|
1306
|
-
const evaluation2 = context.getEvaluation(flag);
|
|
1307
|
-
return evaluation2 ? Boolean(evaluation2.value) : fallback;
|
|
1308
|
-
}
|
|
1309
|
-
if (context.error || !evaluationsUsable(context)) return false;
|
|
1310
|
-
const evaluation = context.getEvaluation(flag);
|
|
1311
|
-
return !!evaluation && !evaluation.errorCode && evaluation.value === true;
|
|
1312
|
-
}
|
|
1313
|
-
function useFluidGridsFlag(flag) {
|
|
1314
|
-
const context = useOptionalFeatureFlags();
|
|
1315
|
-
return useMemo(() => resolveFluidGridsFlag(context, flag), [context, flag]);
|
|
1316
|
-
}
|
|
1317
|
-
function useDurableFunctionNodesEnabled() {
|
|
1318
|
-
const context = useOptionalFeatureFlags();
|
|
1319
|
-
return useMemo(
|
|
1320
|
-
() => resolveFluidGridsFlag(context, FLUIDGRIDS_FLAGS.codeFirst) && resolveFluidGridsFlag(context, FLUIDGRIDS_FLAGS.durableFunctions),
|
|
1321
|
-
[context]
|
|
1322
|
-
);
|
|
1323
|
-
}
|
|
1324
|
-
|
|
1325
1341
|
// src/modules/executions/utils/signal-targets.ts
|
|
1326
1342
|
function isRecord3(value) {
|
|
1327
1343
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -4540,6 +4556,11 @@ function useDeleteNode() {
|
|
|
4540
4556
|
[deleteElements, getEdges, getNode, deleteNodes]
|
|
4541
4557
|
);
|
|
4542
4558
|
}
|
|
4559
|
+
var BuilderReadOnlyContext = createContext(false);
|
|
4560
|
+
var BuilderReadOnlyProvider = BuilderReadOnlyContext.Provider;
|
|
4561
|
+
function useBuilderReadOnly() {
|
|
4562
|
+
return useContext(BuilderReadOnlyContext);
|
|
4563
|
+
}
|
|
4543
4564
|
|
|
4544
4565
|
// src/builder/contants/symbols.ts
|
|
4545
4566
|
var NODE_TYPE_DRAG_DATA_FORMAT = "application/flow-builder.node-type";
|
|
@@ -4589,6 +4610,7 @@ function StickyNoteNodeComponent({
|
|
|
4589
4610
|
const { setNodes, getNode } = useReactFlow();
|
|
4590
4611
|
const zustandSetNodes = useFlowStore((s) => s.actions.nodes.setNodes);
|
|
4591
4612
|
const deleteNode = useDeleteNode();
|
|
4613
|
+
const readOnly = useBuilderReadOnly();
|
|
4592
4614
|
const [editing, setEditing] = useState(false);
|
|
4593
4615
|
const [showPalette, setShowPalette] = useState(false);
|
|
4594
4616
|
const [draft, setDraft] = useState(String(data.content ?? ""));
|
|
@@ -4664,7 +4686,7 @@ function StickyNoteNodeComponent({
|
|
|
4664
4686
|
/* @__PURE__ */ jsx(
|
|
4665
4687
|
NodeResizer,
|
|
4666
4688
|
{
|
|
4667
|
-
isVisible: !!selected,
|
|
4689
|
+
isVisible: !!selected && !readOnly,
|
|
4668
4690
|
minWidth: STICKY_MIN_SIZE.width,
|
|
4669
4691
|
minHeight: STICKY_MIN_SIZE.height,
|
|
4670
4692
|
lineStyle: { border: "none", zIndex: 20 },
|
|
@@ -4682,7 +4704,9 @@ function StickyNoteNodeComponent({
|
|
|
4682
4704
|
{
|
|
4683
4705
|
className: cn(
|
|
4684
4706
|
"absolute right-1 z-30 flex items-center gap-0.5 rounded-lg border border-border bg-card p-0.5 shadow-md transition-all duration-150",
|
|
4685
|
-
selected || showPalette ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0 group-hover:pointer-events-auto group-hover:opacity-100"
|
|
4707
|
+
selected || showPalette ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0 group-hover:pointer-events-auto group-hover:opacity-100",
|
|
4708
|
+
// Nothing to change on a read-only canvas (BOFF-9725).
|
|
4709
|
+
readOnly && "hidden"
|
|
4686
4710
|
),
|
|
4687
4711
|
style: { top: -15 },
|
|
4688
4712
|
onDoubleClick: (e) => e.stopPropagation(),
|
|
@@ -4770,12 +4794,13 @@ function StickyNoteNodeComponent({
|
|
|
4770
4794
|
},
|
|
4771
4795
|
onDoubleClick: (e) => {
|
|
4772
4796
|
e.stopPropagation();
|
|
4773
|
-
startEditing();
|
|
4797
|
+
if (!readOnly) startEditing();
|
|
4774
4798
|
},
|
|
4775
4799
|
children: editing ? /* @__PURE__ */ jsx(
|
|
4776
4800
|
"textarea",
|
|
4777
4801
|
{
|
|
4778
4802
|
ref: textareaRef,
|
|
4803
|
+
readOnly,
|
|
4779
4804
|
value: draft,
|
|
4780
4805
|
onChange: (e) => setDraft(e.target.value),
|
|
4781
4806
|
onBlur: commitEdit,
|
|
@@ -6564,8 +6589,26 @@ var PERMANENT_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
|
6564
6589
|
"FAILED_PRECONDITION",
|
|
6565
6590
|
"CONFLICT"
|
|
6566
6591
|
]);
|
|
6592
|
+
function textOf(value) {
|
|
6593
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
6594
|
+
}
|
|
6595
|
+
function findSaveConflict(error) {
|
|
6596
|
+
const extensions = collectExtensions(error).find(
|
|
6597
|
+
(ext) => ext.code === "CONFLICT" && (ext.reason === "STALE_REVISION" || ext.reason === "EDIT_LEASE_HELD")
|
|
6598
|
+
);
|
|
6599
|
+
if (!extensions) return null;
|
|
6600
|
+
const revision = extensions.currentRevision;
|
|
6601
|
+
return {
|
|
6602
|
+
reason: extensions.reason,
|
|
6603
|
+
currentRevision: typeof revision === "number" && Number.isFinite(revision) ? revision : null,
|
|
6604
|
+
currentStatus: textOf(extensions.currentStatus),
|
|
6605
|
+
updatedById: textOf(extensions.updatedById),
|
|
6606
|
+
holderActorId: textOf(extensions.holderActorId)
|
|
6607
|
+
};
|
|
6608
|
+
}
|
|
6567
6609
|
function classifySaveFailure(error) {
|
|
6568
6610
|
if (findQuotaRefusal(error)) return "quota";
|
|
6611
|
+
if (findSaveConflict(error)) return "conflict";
|
|
6569
6612
|
if (errorCodesOf(error).some((code) => PERMANENT_ERROR_CODES.has(code))) {
|
|
6570
6613
|
return "permanent";
|
|
6571
6614
|
}
|
|
@@ -6675,6 +6718,196 @@ function editStateOf(baseline, current, now) {
|
|
|
6675
6718
|
return "dirty";
|
|
6676
6719
|
}
|
|
6677
6720
|
|
|
6721
|
+
// src/builder/lib/workflow-revisions.ts
|
|
6722
|
+
var known = /* @__PURE__ */ new Map();
|
|
6723
|
+
function rememberRevision(dbId, revision) {
|
|
6724
|
+
if (!dbId || typeof revision !== "number" || !Number.isFinite(revision)) {
|
|
6725
|
+
return;
|
|
6726
|
+
}
|
|
6727
|
+
const current = known.get(dbId);
|
|
6728
|
+
if (current === void 0 || revision > current) known.set(dbId, revision);
|
|
6729
|
+
}
|
|
6730
|
+
function rememberOwnStatusChange(dbId, revision) {
|
|
6731
|
+
if (!dbId || typeof revision !== "number") return;
|
|
6732
|
+
const current = known.get(dbId);
|
|
6733
|
+
if (current !== void 0 && revision === current + 1) {
|
|
6734
|
+
known.set(dbId, revision);
|
|
6735
|
+
}
|
|
6736
|
+
}
|
|
6737
|
+
function revisionOf(dbId) {
|
|
6738
|
+
return dbId ? known.get(dbId) : void 0;
|
|
6739
|
+
}
|
|
6740
|
+
|
|
6741
|
+
// src/builder/lib/edit-session.ts
|
|
6742
|
+
var SESSION_ID_PATTERN = /^[A-Za-z0-9_-]{8,64}$/;
|
|
6743
|
+
function randomSessionId() {
|
|
6744
|
+
const cryptoApi = globalThis.crypto;
|
|
6745
|
+
if (cryptoApi?.randomUUID) return cryptoApi.randomUUID();
|
|
6746
|
+
const bytes = new Uint8Array(16);
|
|
6747
|
+
cryptoApi?.getRandomValues?.(bytes);
|
|
6748
|
+
if (bytes.every((byte) => byte === 0)) {
|
|
6749
|
+
for (let i = 0; i < bytes.length; i += 1) {
|
|
6750
|
+
bytes[i] = Math.floor(Math.random() * 256);
|
|
6751
|
+
}
|
|
6752
|
+
}
|
|
6753
|
+
return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join(
|
|
6754
|
+
""
|
|
6755
|
+
);
|
|
6756
|
+
}
|
|
6757
|
+
var EDIT_SESSION_ID = randomSessionId();
|
|
6758
|
+
var storageKey = (workflowKey) => `fluidgrids.builder.editSession.${workflowKey}`;
|
|
6759
|
+
function rememberSessionForReload(storage, workflowKey, sessionId) {
|
|
6760
|
+
try {
|
|
6761
|
+
storage?.setItem(storageKey(workflowKey), sessionId);
|
|
6762
|
+
} catch {
|
|
6763
|
+
}
|
|
6764
|
+
}
|
|
6765
|
+
function sessionBeforeReload(storage, workflowKey, currentSessionId = EDIT_SESSION_ID) {
|
|
6766
|
+
try {
|
|
6767
|
+
const stored = storage?.getItem(storageKey(workflowKey)) ?? null;
|
|
6768
|
+
if (!stored || stored === currentSessionId) return null;
|
|
6769
|
+
return SESSION_ID_PATTERN.test(stored) ? stored : null;
|
|
6770
|
+
} catch {
|
|
6771
|
+
return null;
|
|
6772
|
+
}
|
|
6773
|
+
}
|
|
6774
|
+
function forgetSessionForReload(storage, workflowKey) {
|
|
6775
|
+
try {
|
|
6776
|
+
storage?.removeItem(storageKey(workflowKey));
|
|
6777
|
+
} catch {
|
|
6778
|
+
}
|
|
6779
|
+
}
|
|
6780
|
+
|
|
6781
|
+
// src/builder/lib/edit-lease.ts
|
|
6782
|
+
var LEASE_RENEW_MS = 2e4;
|
|
6783
|
+
var LEASE_VIEW_POLL_MS = 1e4;
|
|
6784
|
+
var LEASE_IDLE_RELEASE_MS = 15 * 6e4;
|
|
6785
|
+
function isLocked(phase) {
|
|
6786
|
+
return phase === "viewing" || phase === "lost" || phase === "idle" || phase === "reloading";
|
|
6787
|
+
}
|
|
6788
|
+
function phaseAfterAcquire(previous, answer) {
|
|
6789
|
+
if (!answer.available) {
|
|
6790
|
+
return isLocked(previous) || previous === "holding" ? previous : "unavailable";
|
|
6791
|
+
}
|
|
6792
|
+
if (answer.heldBySelf) return "holding";
|
|
6793
|
+
if (answer.held) return previous === "holding" ? "lost" : "viewing";
|
|
6794
|
+
return previous;
|
|
6795
|
+
}
|
|
6796
|
+
function phaseAfterTakeOver(answer) {
|
|
6797
|
+
if (!answer.available) return "unavailable";
|
|
6798
|
+
return answer.heldBySelf ? "reloading" : "viewing";
|
|
6799
|
+
}
|
|
6800
|
+
function releasesOnClose(phase) {
|
|
6801
|
+
return phase === "starting" || phase === "holding" || phase === "unavailable";
|
|
6802
|
+
}
|
|
6803
|
+
var LEASE_CALL_MAX_WAIT_MS = 15e3;
|
|
6804
|
+
function leaseCallQueue(maxWaitMs = LEASE_CALL_MAX_WAIT_MS) {
|
|
6805
|
+
const tails = /* @__PURE__ */ new Map();
|
|
6806
|
+
return {
|
|
6807
|
+
run(workflowKey, call) {
|
|
6808
|
+
const previous = tails.get(workflowKey) ?? Promise.resolve();
|
|
6809
|
+
const result = previous.then(call);
|
|
6810
|
+
const tail = previous.then(
|
|
6811
|
+
() => new Promise((resolve) => {
|
|
6812
|
+
const timer = setTimeout(resolve, maxWaitMs);
|
|
6813
|
+
const done = () => {
|
|
6814
|
+
clearTimeout(timer);
|
|
6815
|
+
resolve();
|
|
6816
|
+
};
|
|
6817
|
+
result.then(done, done);
|
|
6818
|
+
})
|
|
6819
|
+
);
|
|
6820
|
+
tails.set(workflowKey, tail);
|
|
6821
|
+
void tail.then(() => {
|
|
6822
|
+
if (tails.get(workflowKey) === tail) tails.delete(workflowKey);
|
|
6823
|
+
});
|
|
6824
|
+
return result;
|
|
6825
|
+
}
|
|
6826
|
+
};
|
|
6827
|
+
}
|
|
6828
|
+
function shouldReleaseForIdle(phase, lastInputAt, now) {
|
|
6829
|
+
return phase === "holding" && now - lastInputAt >= LEASE_IDLE_RELEASE_MS;
|
|
6830
|
+
}
|
|
6831
|
+
function tickAction(phase, state, now) {
|
|
6832
|
+
if (phase === "holding" || phase === "unavailable") {
|
|
6833
|
+
return now - state.lastRenewAt >= LEASE_RENEW_MS ? "renew" : "none";
|
|
6834
|
+
}
|
|
6835
|
+
if (phase === "viewing" || phase === "lost" || phase === "idle") {
|
|
6836
|
+
return state.visible && now - state.lastPeekAt >= LEASE_VIEW_POLL_MS ? "peek" : "none";
|
|
6837
|
+
}
|
|
6838
|
+
return "none";
|
|
6839
|
+
}
|
|
6840
|
+
function bannerOf(state) {
|
|
6841
|
+
switch (state.phase) {
|
|
6842
|
+
case "viewing":
|
|
6843
|
+
return state.held ? {
|
|
6844
|
+
kind: "editing",
|
|
6845
|
+
actorId: state.holderActorId,
|
|
6846
|
+
self: state.heldByCaller
|
|
6847
|
+
} : { kind: "free" };
|
|
6848
|
+
case "lost":
|
|
6849
|
+
return {
|
|
6850
|
+
kind: "taken",
|
|
6851
|
+
actorId: state.takenBy,
|
|
6852
|
+
self: state.takenByCaller
|
|
6853
|
+
};
|
|
6854
|
+
case "idle":
|
|
6855
|
+
return { kind: "idle" };
|
|
6856
|
+
case "reloading":
|
|
6857
|
+
return { kind: "reloading" };
|
|
6858
|
+
default:
|
|
6859
|
+
return null;
|
|
6860
|
+
}
|
|
6861
|
+
}
|
|
6862
|
+
var IDLE = {
|
|
6863
|
+
workflowKey: null,
|
|
6864
|
+
phase: "inactive",
|
|
6865
|
+
held: false,
|
|
6866
|
+
holderActorId: null,
|
|
6867
|
+
heldByCaller: false,
|
|
6868
|
+
takenBy: null,
|
|
6869
|
+
takenByCaller: false
|
|
6870
|
+
};
|
|
6871
|
+
function commitFocusedEdit() {
|
|
6872
|
+
if (typeof document === "undefined") return;
|
|
6873
|
+
const focused = document.activeElement;
|
|
6874
|
+
if (!focused || typeof focused.blur !== "function") return;
|
|
6875
|
+
const editable = focused.isContentEditable || typeof focused.matches === "function" && focused.matches("input, textarea, select");
|
|
6876
|
+
if (editable) focused.blur();
|
|
6877
|
+
}
|
|
6878
|
+
var useEditLeaseStore = create()((set, get) => ({
|
|
6879
|
+
...IDLE,
|
|
6880
|
+
actions: {
|
|
6881
|
+
begin: (workflowKey) => set(
|
|
6882
|
+
(state) => (
|
|
6883
|
+
// A reload of the same workflow keeps "reloading" (and its lock)
|
|
6884
|
+
// until the lease is confirmed again.
|
|
6885
|
+
state.workflowKey === workflowKey && state.phase === "reloading" ? state : { ...IDLE, workflowKey, phase: "starting" }
|
|
6886
|
+
)
|
|
6887
|
+
),
|
|
6888
|
+
record: (phase, answer) => {
|
|
6889
|
+
if (isLocked(phase) && !isLocked(get().phase)) commitFocusedEdit();
|
|
6890
|
+
set(() => {
|
|
6891
|
+
if (!answer || !answer.available) return { phase };
|
|
6892
|
+
const holderActorId = answer.held ? answer.holderActorId ?? null : null;
|
|
6893
|
+
const heldByCaller = answer.held && !!answer.heldByCaller;
|
|
6894
|
+
const taken = phase !== "lost" ? { takenBy: null, takenByCaller: false } : answer.held ? { takenBy: holderActorId, takenByCaller: heldByCaller } : {};
|
|
6895
|
+
return {
|
|
6896
|
+
phase,
|
|
6897
|
+
held: answer.held,
|
|
6898
|
+
holderActorId,
|
|
6899
|
+
heldByCaller,
|
|
6900
|
+
...taken
|
|
6901
|
+
};
|
|
6902
|
+
});
|
|
6903
|
+
},
|
|
6904
|
+
reset: () => set({ ...IDLE })
|
|
6905
|
+
}
|
|
6906
|
+
}));
|
|
6907
|
+
function useEditLeaseLocked() {
|
|
6908
|
+
return useEditLeaseStore((s) => isLocked(s.phase));
|
|
6909
|
+
}
|
|
6910
|
+
|
|
6678
6911
|
// src/builder/lib/workflow-save-snapshot.ts
|
|
6679
6912
|
function snapshotForSave(workflow, generation, route = {}) {
|
|
6680
6913
|
const copy = {
|
|
@@ -6712,7 +6945,8 @@ var PRISTINE = {
|
|
|
6712
6945
|
baseline: null,
|
|
6713
6946
|
quotaExhausted: false,
|
|
6714
6947
|
leaveRequest: null,
|
|
6715
|
-
autosavePaused: false
|
|
6948
|
+
autosavePaused: false,
|
|
6949
|
+
conflictOpen: false
|
|
6716
6950
|
};
|
|
6717
6951
|
var useSaveStatusStore = create()((set) => ({
|
|
6718
6952
|
...PRISTINE,
|
|
@@ -6729,10 +6963,15 @@ var useSaveStatusStore = create()((set) => ({
|
|
|
6729
6963
|
failure: null,
|
|
6730
6964
|
incomplete: false,
|
|
6731
6965
|
autosavePaused: false,
|
|
6966
|
+
conflictOpen: false,
|
|
6732
6967
|
lastSavedAt: at
|
|
6733
6968
|
} : { saving: false }
|
|
6734
6969
|
),
|
|
6735
|
-
saveFailed: (failure) => set({
|
|
6970
|
+
saveFailed: (failure) => set({
|
|
6971
|
+
saving: false,
|
|
6972
|
+
failure,
|
|
6973
|
+
conflictOpen: failure.conflict?.reason === "STALE_REVISION"
|
|
6974
|
+
}),
|
|
6736
6975
|
clearFailure: () => set({ failure: null }),
|
|
6737
6976
|
setQuotaExhausted: (quotaExhausted) => set({ quotaExhausted }),
|
|
6738
6977
|
setAutosaveEnabled: (autosaveEnabled) => {
|
|
@@ -6741,6 +6980,7 @@ var useSaveStatusStore = create()((set) => ({
|
|
|
6741
6980
|
},
|
|
6742
6981
|
requestLeave: (leaveRequest) => set({ leaveRequest }),
|
|
6743
6982
|
setAutosavePaused: (autosavePaused) => set({ autosavePaused }),
|
|
6983
|
+
setConflictOpen: (conflictOpen) => set({ conflictOpen }),
|
|
6744
6984
|
reset: () => set({ ...PRISTINE })
|
|
6745
6985
|
}
|
|
6746
6986
|
}));
|
|
@@ -6859,13 +7099,15 @@ function useSaveWorkflow() {
|
|
|
6859
7099
|
const { bus, workspaceId } = useFluidGridsAnalytics();
|
|
6860
7100
|
const setWorkflow = useFlowStore((s) => s.actions.setWorkflow);
|
|
6861
7101
|
const performSave = useCallback(
|
|
6862
|
-
async (snapshot, silent) => {
|
|
7102
|
+
async (snapshot, silent, asNewVersion) => {
|
|
6863
7103
|
const stillOpen = () => useFlowStore.getState().loadGeneration === snapshot.generation;
|
|
6864
7104
|
try {
|
|
6865
7105
|
const { workflow } = snapshot;
|
|
6866
7106
|
const mintedKey = snapshot.key ? null : v4();
|
|
6867
7107
|
const workflowKey = snapshot.key || mintedKey || "";
|
|
6868
|
-
const
|
|
7108
|
+
const forkRequested = asNewVersion && !!workflow.dbId;
|
|
7109
|
+
const isDraft = !forkRequested && (!workflow.status || workflow.status === "DRAFT");
|
|
7110
|
+
const expectedRevision = revisionOf(workflow.dbId);
|
|
6869
7111
|
const client = getFluidGridsClient();
|
|
6870
7112
|
const { preparedWorkflow, owned } = builderDefinition(
|
|
6871
7113
|
snapshot,
|
|
@@ -6891,7 +7133,11 @@ function useSaveWorkflow() {
|
|
|
6891
7133
|
description: workflow.name || "Workflow update",
|
|
6892
7134
|
// null (not undefined) so an emptied alias field actually
|
|
6893
7135
|
// CLEARS the alias — undefined is dropped by the resolver.
|
|
6894
|
-
alias: workflow.alias?.trim() ? workflow.alias.trim() : null
|
|
7136
|
+
alias: workflow.alias?.trim() ? workflow.alias.trim() : null,
|
|
7137
|
+
// Refused instead of overwriting a change made elsewhere,
|
|
7138
|
+
// or a save from a page that no longer holds the edit lease.
|
|
7139
|
+
...expectedRevision !== void 0 ? { expectedRevision } : {},
|
|
7140
|
+
editSessionId: EDIT_SESSION_ID
|
|
6895
7141
|
}
|
|
6896
7142
|
}
|
|
6897
7143
|
})
|
|
@@ -6901,6 +7147,7 @@ function useSaveWorkflow() {
|
|
|
6901
7147
|
}
|
|
6902
7148
|
savedVersion = data.updateWorkflowDefinition.version;
|
|
6903
7149
|
savedDbId = data.updateWorkflowDefinition.id;
|
|
7150
|
+
rememberRevision(savedDbId, data.updateWorkflowDefinition.revision);
|
|
6904
7151
|
operation = "updated";
|
|
6905
7152
|
if (!silent) {
|
|
6906
7153
|
toast.success("Workflow saved", {
|
|
@@ -6928,6 +7175,7 @@ function useSaveWorkflow() {
|
|
|
6928
7175
|
}
|
|
6929
7176
|
savedVersion = data.createWorkflowDefinition.version;
|
|
6930
7177
|
savedDbId = data.createWorkflowDefinition.id;
|
|
7178
|
+
rememberRevision(savedDbId, data.createWorkflowDefinition.revision);
|
|
6931
7179
|
operation = "created";
|
|
6932
7180
|
emitWorkflowCreated(bus, {
|
|
6933
7181
|
workspaceId,
|
|
@@ -6968,7 +7216,15 @@ function useSaveWorkflow() {
|
|
|
6968
7216
|
// pointer — the backend clears it from siblings). Included
|
|
6969
7217
|
// only when set so saves without an alias don't depend on the
|
|
6970
7218
|
// new schema field being deployed.
|
|
6971
|
-
...workflow.alias?.trim() ? { alias: workflow.alias.trim() } : {}
|
|
7219
|
+
...workflow.alias?.trim() ? { alias: workflow.alias.trim() } : {},
|
|
7220
|
+
// A save of an ACTIVE or ARCHIVED version claims it, so two
|
|
7221
|
+
// pages that loaded it never create rival drafts. Keeping
|
|
7222
|
+
// the canvas as a new version on purpose skips the claim.
|
|
7223
|
+
...forkRequested ? {} : {
|
|
7224
|
+
baseVersion: workflow.version,
|
|
7225
|
+
...expectedRevision !== void 0 ? { expectedRevision } : {},
|
|
7226
|
+
editSessionId: EDIT_SESSION_ID
|
|
7227
|
+
}
|
|
6972
7228
|
}
|
|
6973
7229
|
}
|
|
6974
7230
|
})
|
|
@@ -6981,6 +7237,7 @@ function useSaveWorkflow() {
|
|
|
6981
7237
|
const newWorkflow = data.createWorkflowVersion.workflow;
|
|
6982
7238
|
savedVersion = newWorkflow?.version ?? workflow.version;
|
|
6983
7239
|
savedDbId = newWorkflow?.id ?? workflow.dbId;
|
|
7240
|
+
rememberRevision(newWorkflow?.id, newWorkflow?.revision);
|
|
6984
7241
|
operation = "versioned";
|
|
6985
7242
|
if (stillOpen()) {
|
|
6986
7243
|
setWorkflow({
|
|
@@ -7026,15 +7283,30 @@ function useSaveWorkflow() {
|
|
|
7026
7283
|
console.error("Error saving workflow:", message);
|
|
7027
7284
|
const cause = error instanceof Error ? error.cause : void 0;
|
|
7028
7285
|
const quotaExhausted2 = isQuotaExhaustedFailure(cause) || isQuotaExhaustedFailure(error);
|
|
7029
|
-
|
|
7286
|
+
const conflict = findSaveConflict(error);
|
|
7287
|
+
if (!quotaExhausted2 && !conflict && !silent) {
|
|
7030
7288
|
toast.error("Failed to save workflow", {
|
|
7031
7289
|
description: message
|
|
7032
7290
|
});
|
|
7033
7291
|
}
|
|
7292
|
+
if (conflict?.reason === "EDIT_LEASE_HELD" && stillOpen()) {
|
|
7293
|
+
const lease = useEditLeaseStore.getState();
|
|
7294
|
+
const answer = {
|
|
7295
|
+
available: true,
|
|
7296
|
+
held: true,
|
|
7297
|
+
heldBySelf: false,
|
|
7298
|
+
holderActorId: conflict.holderActorId
|
|
7299
|
+
};
|
|
7300
|
+
lease.actions.record(phaseAfterAcquire(lease.phase, answer), answer);
|
|
7301
|
+
}
|
|
7034
7302
|
return {
|
|
7035
7303
|
saved: false,
|
|
7036
7304
|
quotaExhausted: quotaExhausted2,
|
|
7037
|
-
failure: {
|
|
7305
|
+
failure: {
|
|
7306
|
+
message,
|
|
7307
|
+
kind: classifySaveFailure(error),
|
|
7308
|
+
...conflict ? { conflict } : {}
|
|
7309
|
+
}
|
|
7038
7310
|
};
|
|
7039
7311
|
}
|
|
7040
7312
|
},
|
|
@@ -7050,7 +7322,11 @@ function useSaveWorkflow() {
|
|
|
7050
7322
|
statusActions.beginSave();
|
|
7051
7323
|
statusActions.setQuotaExhausted(false);
|
|
7052
7324
|
}
|
|
7053
|
-
const outcome = await performSave(
|
|
7325
|
+
const outcome = await performSave(
|
|
7326
|
+
snapshot,
|
|
7327
|
+
options.silent ?? false,
|
|
7328
|
+
options.asNewVersion ?? false
|
|
7329
|
+
);
|
|
7054
7330
|
recordSaveOutcome(outcome, {
|
|
7055
7331
|
open: isOpen(),
|
|
7056
7332
|
baseline: {
|
|
@@ -7824,6 +8100,7 @@ function AdapterPort({
|
|
|
7824
8100
|
const onConnect = useFlowStore((s) => s.actions.edges.onConnect);
|
|
7825
8101
|
const [pickerOpen, setPickerOpen] = useState(false);
|
|
7826
8102
|
const candidates = useCompatibleSubNodes(adapter);
|
|
8103
|
+
const readOnly = useBuilderReadOnly();
|
|
7827
8104
|
const connectionCount = edges.filter(
|
|
7828
8105
|
(e) => e.source === nodeId && e.sourceHandle === adapter.name
|
|
7829
8106
|
).length;
|
|
@@ -7877,7 +8154,7 @@ function AdapterPort({
|
|
|
7877
8154
|
adapter?.required && /* @__PURE__ */ jsx("span", { className: "text-[var(--color-status-error-text)] absolute -right-2 top-[1px]", children: "*" })
|
|
7878
8155
|
] }) }),
|
|
7879
8156
|
/* @__PURE__ */ jsxs("div", { className: "mt-16 flex flex-col items-center gap-1.5", children: [
|
|
7880
|
-
!isAtMaxConnections && /* @__PURE__ */ jsx(
|
|
8157
|
+
!isAtMaxConnections && !readOnly && /* @__PURE__ */ jsx(
|
|
7881
8158
|
"button",
|
|
7882
8159
|
{
|
|
7883
8160
|
type: "button",
|
|
@@ -8008,6 +8285,7 @@ function SubNodeComponent({
|
|
|
8008
8285
|
}) {
|
|
8009
8286
|
const meta = useMemo(() => getNodeDetail(nodeType), [nodeType]);
|
|
8010
8287
|
const deleteNode = useDeleteNode();
|
|
8288
|
+
const readOnly = useBuilderReadOnly();
|
|
8011
8289
|
const [showNodePropertiesOf] = useFlowStore(
|
|
8012
8290
|
useShallow((s) => [s.actions.sidebar.showNodePropertiesOf])
|
|
8013
8291
|
);
|
|
@@ -8053,7 +8331,7 @@ function SubNodeComponent({
|
|
|
8053
8331
|
}
|
|
8054
8332
|
),
|
|
8055
8333
|
/* @__PURE__ */ jsx("span", { className: "mt-1.5 text-xs text-[var(--color-text-secondary)] font-medium text-center max-w-24 leading-tight", children: data?.label || data?.args?.state?.operation || meta.title }),
|
|
8056
|
-
/* @__PURE__ */ jsx(
|
|
8334
|
+
!readOnly && /* @__PURE__ */ jsx(
|
|
8057
8335
|
"button",
|
|
8058
8336
|
{
|
|
8059
8337
|
onClick: () => deleteNode(id),
|
|
@@ -8125,8 +8403,9 @@ var getNodeMetadata = (value) => {
|
|
|
8125
8403
|
s.actions.nodes.endRename
|
|
8126
8404
|
])
|
|
8127
8405
|
);
|
|
8406
|
+
const readOnly = useBuilderReadOnly();
|
|
8128
8407
|
useEffect(() => {
|
|
8129
|
-
if (nodeType !== "integration/channel") return;
|
|
8408
|
+
if (readOnly || nodeType !== "integration/channel") return;
|
|
8130
8409
|
const nodeData = data;
|
|
8131
8410
|
const explicitRole = nodeData?.args?.state?.role;
|
|
8132
8411
|
const hasIncomingEdge = edges.some((e) => e.target === id);
|
|
@@ -8153,7 +8432,7 @@ var getNodeMetadata = (value) => {
|
|
|
8153
8432
|
zustandSetNodes(updated);
|
|
8154
8433
|
return updated;
|
|
8155
8434
|
});
|
|
8156
|
-
}, [nodeType, id, edges, data, setNodes, zustandSetNodes]);
|
|
8435
|
+
}, [readOnly, nodeType, id, edges, data, setNodes, zustandSetNodes]);
|
|
8157
8436
|
const { executeStep } = useNodeExecution();
|
|
8158
8437
|
const deleteNode = useDeleteNode();
|
|
8159
8438
|
const handleDeleteNode = () => {
|
|
@@ -8311,12 +8590,12 @@ var getNodeMetadata = (value) => {
|
|
|
8311
8590
|
onDoubleClick: handleOpenNdv,
|
|
8312
8591
|
onSettings: handleOpenNdv,
|
|
8313
8592
|
onExecute: handleExecuteStep,
|
|
8314
|
-
onDelete: handleDeleteNode,
|
|
8593
|
+
onDelete: readOnly ? void 0 : handleDeleteNode,
|
|
8315
8594
|
infoButton: /* @__PURE__ */ jsx(NodeInfoButtonWithModal, { metadata: nodeInfoMetadata }),
|
|
8316
8595
|
disabled: isDisabled,
|
|
8317
|
-
onToggleDisabled: handleToggleDisabled,
|
|
8318
|
-
isRenaming: isRenamingThisNode,
|
|
8319
|
-
onStartRename: handleStartRename,
|
|
8596
|
+
onToggleDisabled: readOnly ? void 0 : handleToggleDisabled,
|
|
8597
|
+
isRenaming: isRenamingThisNode && !readOnly,
|
|
8598
|
+
onStartRename: readOnly ? void 0 : handleStartRename,
|
|
8320
8599
|
onCommitRename: handleCommitRename,
|
|
8321
8600
|
onCancelRename: handleCancelRename
|
|
8322
8601
|
}
|
|
@@ -8345,10 +8624,10 @@ var getNodeMetadata = (value) => {
|
|
|
8345
8624
|
isExecuting: isThisNodeExecuting,
|
|
8346
8625
|
onSettings: handleOpenNdv,
|
|
8347
8626
|
onExecute: handleExecuteStep,
|
|
8348
|
-
onDelete: handleDeleteNode,
|
|
8627
|
+
onDelete: readOnly ? void 0 : handleDeleteNode,
|
|
8349
8628
|
infoButton: /* @__PURE__ */ jsx(NodeInfoButtonWithModal, { metadata: nodeInfoMetadata }),
|
|
8350
8629
|
disabled: isDisabled,
|
|
8351
|
-
onToggleDisabled: handleToggleDisabled,
|
|
8630
|
+
onToggleDisabled: readOnly ? void 0 : handleToggleDisabled,
|
|
8352
8631
|
children: [
|
|
8353
8632
|
/* @__PURE__ */ jsx(
|
|
8354
8633
|
NodeCardHeader,
|
|
@@ -8358,8 +8637,8 @@ var getNodeMetadata = (value) => {
|
|
|
8358
8637
|
accentKey: value?.type || meta.title,
|
|
8359
8638
|
missingCredentials,
|
|
8360
8639
|
label: nodeLabel,
|
|
8361
|
-
isRenaming: isRenamingThisNode,
|
|
8362
|
-
onStartRename: handleStartRename,
|
|
8640
|
+
isRenaming: isRenamingThisNode && !readOnly,
|
|
8641
|
+
onStartRename: readOnly ? void 0 : handleStartRename,
|
|
8363
8642
|
onCommitRename: handleCommitRename,
|
|
8364
8643
|
onCancelRename: handleCancelRename
|
|
8365
8644
|
}
|
|
@@ -9569,4 +9848,4 @@ function useNodeExecution() {
|
|
|
9569
9848
|
};
|
|
9570
9849
|
}
|
|
9571
9850
|
|
|
9572
|
-
export { ALLOW_ALL_PERMISSIONS, AUTOSAVE_DEBOUNCE_MS, AUTOSAVE_RETRY_DELAYS_MS, AVAILABLE_NODES, BILLING_PLANS_PATH, CODE_WORKFLOW_NODE_TYPE, ConnectionFormDialog, ConnectionSelector, DURABLE_FUNCTION_NODE_TYPES, ExpressionEditor, FLUIDGRIDS_FLAGS, FLUIDGRIDS_FLAG_DEFAULTS, FLUIDGRIDS_PERMISSIONS, FluidGridsContext, FluidGridsPermissionsProvider, FluidGridsProvider, NODES, NODES_METADATA, NODE_CONFIGS, NODE_OPERATION_DRAG_DATA_FORMAT, NODE_TYPES, NODE_TYPE_DRAG_DATA_FORMAT, NodePropertyPanel, NodeTypeIcon, RUNS_QUOTA_NAME, STICKY_NOTE_TYPE, SdkPermissionButton, SdkPermissionGate, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, WORKFLOWS_QUOTA_NAME, blankWorkflowCreateInput, buildOperationSeed, buildStickyNode, canAutosave, canRenderOperationPanel, canSignalRun, changedSourceFiles, childRunIdOf, classifyCreateRefusal, clearCodeWorkflowDefinitionCache, codeBuildIdOf, components_default, createConfiguredNode, createThenOpen, declaredOutputFields, declaredSignals, defaultSourcePath, describeOperationError, diagnosticsByPath, editStateOf, emitNodeInstalled, emitRunFailed, emitRunLimitHit, emitRunStarted, emitTemplateUsed, emitUpgradeClicked, emitWorkflowCreated, emitWorkflowLimitHit, emitWorkflowPublished, ensureNodeConfigsLoaded, evaluatePermissionCheck, fieldsFromIO, fieldsFromValue, filterPaletteNodes, findQuotaRefusal, formatParameterValue, getNodeDetail, getNodeMetadata, inAppLeaveTarget, interfaceFields, interfaceHandlers, isDurableFunctionNodeType, isEditableSourcePath, isForbiddenError, isImageIcon, isNodeConfigsInitialized, isNodeTrigger, isNodeTypeHiddenFromPalette, isParamVisible, isQuotaExhaustedFailure, isTriggerOperation, leaveNeedsConfirmation, listCustomBlocks, liveInternalOperations, mergeStickyNotes, nodeAccent, nodesOf, onNodeTypesUpdate, openRunQuotaUpgradePrompt, parseParameterValue, parseRawSignalPayload, pathToExpression, payloadFromCardValues, projectLanguage, readCodeWorkflowState, readDisplayOptions, refetchStoreNodes, registerCustomBlock, registerWorkflowNodeTypes, resolveInputHandles, resolveNodeOperation, resolveOperationName, resolveOutputHandles, resolveUiSpec, runPreparationOf, runSignalTargets, runTriggerFromMode, saveIndicatorOf, savesInPlace, signalPayloadCard, snapshotForSave, sourceLanguageOf, stripSubmitActions, structuredParameterType, subscribeWorkflowSaved, synchronizeOperationUpdate, throwIfResultError, toCodeMirrorDiagnostics, useAgentDefinitionList, useAgentDefinitions, useCodeWorkflowInterface, useConnection, useConnections, useConnectionsByProvider, useCreateConnection, useDurableFunctionNodesEnabled, useFlowStore, useFluidGridsAnalytics, useFluidGridsContext, useFluidGridsFlag, useFluidGridsPermission, useInitiateOAuth, useInsertNode, useIsValidConnection, useNodeExecution, useNodeRegistryRevision, useProviders, useSaveStatusStore, useSaveWorkflow, workflowFingerprint };
|
|
9851
|
+
export { ALLOW_ALL_PERMISSIONS, AUTOSAVE_DEBOUNCE_MS, AUTOSAVE_RETRY_DELAYS_MS, AVAILABLE_NODES, BILLING_PLANS_PATH, BuilderReadOnlyProvider, CODE_WORKFLOW_NODE_TYPE, ConnectionFormDialog, ConnectionSelector, DURABLE_FUNCTION_NODE_TYPES, EDIT_SESSION_ID, ExpressionEditor, FLUIDGRIDS_FLAGS, FLUIDGRIDS_FLAG_DEFAULTS, FLUIDGRIDS_PERMISSIONS, FluidGridsContext, FluidGridsPermissionsProvider, FluidGridsProvider, NODES, NODES_METADATA, NODE_CONFIGS, NODE_OPERATION_DRAG_DATA_FORMAT, NODE_TYPES, NODE_TYPE_DRAG_DATA_FORMAT, NodePropertyPanel, NodeTypeIcon, RUNS_QUOTA_NAME, STICKY_NOTE_TYPE, SdkPermissionButton, SdkPermissionGate, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, WORKFLOWS_QUOTA_NAME, bannerOf, blankWorkflowCreateInput, buildOperationSeed, buildStickyNode, canAutosave, canRenderOperationPanel, canSignalRun, changedSourceFiles, childRunIdOf, classifyCreateRefusal, clearCodeWorkflowDefinitionCache, codeBuildIdOf, components_default, createConfiguredNode, createThenOpen, declaredOutputFields, declaredSignals, defaultSourcePath, describeOperationError, diagnosticsByPath, editStateOf, emitNodeInstalled, emitRunFailed, emitRunLimitHit, emitRunStarted, emitTemplateUsed, emitUpgradeClicked, emitWorkflowCreated, emitWorkflowLimitHit, emitWorkflowPublished, ensureNodeConfigsLoaded, evaluatePermissionCheck, fieldsFromIO, fieldsFromValue, filterPaletteNodes, findQuotaRefusal, findSaveConflict, forgetSessionForReload, formatParameterValue, getNodeDetail, getNodeMetadata, inAppLeaveTarget, interfaceFields, interfaceHandlers, isDurableFunctionNodeType, isEditableSourcePath, isForbiddenError, isImageIcon, isLocked, isNodeConfigsInitialized, isNodeTrigger, isNodeTypeHiddenFromPalette, isParamVisible, isQuotaExhaustedFailure, isTriggerOperation, leaseCallQueue, leaveNeedsConfirmation, listCustomBlocks, liveInternalOperations, loadDefinitionJson, mergeStickyNotes, nodeAccent, nodesOf, onNodeTypesUpdate, openRunQuotaUpgradePrompt, parseParameterValue, parseRawSignalPayload, pathToExpression, payloadFromCardValues, phaseAfterAcquire, phaseAfterTakeOver, projectLanguage, readCodeWorkflowState, readDisplayOptions, refetchStoreNodes, registerCustomBlock, registerWorkflowNodeTypes, releasesOnClose, rememberOwnStatusChange, rememberRevision, rememberSessionForReload, resolveInputHandles, resolveNodeOperation, resolveOperationName, resolveOutputHandles, resolveUiSpec, runPreparationOf, runSignalTargets, runTriggerFromMode, saveIndicatorOf, savesInPlace, sessionBeforeReload, shouldReleaseForIdle, signalPayloadCard, snapshotForSave, sourceLanguageOf, stripSubmitActions, structuredParameterType, subscribeWorkflowSaved, synchronizeOperationUpdate, throwIfResultError, tickAction, toCodeMirrorDiagnostics, useAgentDefinitionList, useAgentDefinitions, useBuilderReadOnly, useCodeWorkflowInterface, useConnection, useConnections, useConnectionsByProvider, useCreateConnection, useDurableFunctionNodesEnabled, useDurableParityEnabled, useEditLeaseLocked, useEditLeaseStore, useFlowStore, useFluidGridsAnalytics, useFluidGridsContext, useFluidGridsFlag, useFluidGridsPermission, useInitiateOAuth, useInsertNode, useIsValidConnection, useNodeExecution, useNodeRegistryRevision, useProviders, useSaveStatusStore, useSaveWorkflow, workflowFingerprint };
|