@burdenoff/fluidgrids-fe-sdk 2026.1029.4 → 2026.1029.5
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/{WorkflowBuilder-BJC6RCJ6.js → WorkflowBuilder-EVZGOXZZ.js} +2 -1
- package/dist/assistant.d.ts +60 -1
- package/dist/assistant.js +1 -0
- package/dist/{chunk-E25BCOT6.js → chunk-JUA57OVN.js} +656 -3
- package/dist/chunk-PIKYQE7P.js +58 -0
- package/dist/index.js +3 -2
- package/dist/workflow-builder.js +2 -1
- package/package.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export { WorkflowBuilder } from './chunk-
|
|
1
|
+
export { WorkflowBuilder } from './chunk-JUA57OVN.js';
|
|
2
2
|
import './chunk-LGGHQ7UE.js';
|
|
3
|
+
import './chunk-PIKYQE7P.js';
|
|
3
4
|
import './chunk-O24MDGZY.js';
|
|
4
5
|
import './chunk-GEMNVFPK.js';
|
|
5
6
|
import './chunk-IEVSFCFS.js';
|
package/dist/assistant.d.ts
CHANGED
|
@@ -47,4 +47,63 @@ declare const AiCreditBalanceSlot: FC<FgAiCreditBalanceProps>;
|
|
|
47
47
|
*/
|
|
48
48
|
declare function notifyFluidGridsAiCreditsUpdated(): void;
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
/** Mirror of fe-libs' `AssistantPreviewRun`. */
|
|
51
|
+
interface FgAssistantRun {
|
|
52
|
+
readonly runId: string;
|
|
53
|
+
readonly conversationId: string;
|
|
54
|
+
readonly messageId: string;
|
|
55
|
+
/** The workspace the run started in. */
|
|
56
|
+
readonly workspaceId: string | null;
|
|
57
|
+
/** The actor the run started as. */
|
|
58
|
+
readonly actorId: string | null;
|
|
59
|
+
}
|
|
60
|
+
/** Mirror of fe-libs' `action-result` preview event: one approved write's root field. */
|
|
61
|
+
interface FgAssistantActionResult {
|
|
62
|
+
kind: "action-result";
|
|
63
|
+
run: FgAssistantRun;
|
|
64
|
+
action: {
|
|
65
|
+
id: string;
|
|
66
|
+
operation: string;
|
|
67
|
+
responseKey: string;
|
|
68
|
+
/** Approved inputs, with sensitive arguments omitted. */
|
|
69
|
+
arguments: Readonly<Record<string, unknown>>;
|
|
70
|
+
/** The redacted GraphQL response. */
|
|
71
|
+
result: unknown;
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Mirror of fe-libs' `AssistantPreviewEvent`. Only `action-result` is read;
|
|
76
|
+
* the other kinds are listed loosely so every fe-libs event is accepted.
|
|
77
|
+
*/
|
|
78
|
+
type FgAssistantPreviewEvent = FgAssistantActionResult | {
|
|
79
|
+
kind: "start" | "snapshot" | "end";
|
|
80
|
+
run: FgAssistantRun;
|
|
81
|
+
};
|
|
82
|
+
/** Mirror of fe-libs' `AssistantPreviewController`, headless. */
|
|
83
|
+
interface FgAssistantPreviewController {
|
|
84
|
+
onEvent: (event: FgAssistantPreviewEvent) => void;
|
|
85
|
+
}
|
|
86
|
+
interface FluidGridsAssistantLiveCanvasOptions {
|
|
87
|
+
/**
|
|
88
|
+
* The signed-in actor now. When given, a write from a run started by another
|
|
89
|
+
* actor (a late result after an account switch) is ignored. Read on every
|
|
90
|
+
* event, so it may read a token lazily.
|
|
91
|
+
*/
|
|
92
|
+
getActorId?: () => string | null;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Build the headless controller outside React (one per panel mount).
|
|
96
|
+
* `options` is read on every event.
|
|
97
|
+
*/
|
|
98
|
+
declare function createFluidGridsAssistantLiveCanvas(options?: FluidGridsAssistantLiveCanvasOptions): FgAssistantPreviewController;
|
|
99
|
+
/**
|
|
100
|
+
* The headless preview controller for the shared assistant panel, STABLE for
|
|
101
|
+
* the life of the calling component (fe-libs requires a stable controller).
|
|
102
|
+
* The latest `getActorId` is used on every event without changing identity.
|
|
103
|
+
*
|
|
104
|
+
* const liveCanvas = useFluidGridsAssistantLiveCanvas({ getActorId });
|
|
105
|
+
* const panelProps = useMemo(() => ({ ..., preview: liveCanvas }), [liveCanvas, ...]);
|
|
106
|
+
*/
|
|
107
|
+
declare function useFluidGridsAssistantLiveCanvas(options?: FluidGridsAssistantLiveCanvasOptions): FgAssistantPreviewController;
|
|
108
|
+
|
|
109
|
+
export { AiCreditBalanceSlot, FLUIDGRIDS_AI_CREDITS_UPDATED_EVENT, FLUIDGRIDS_AI_PRODUCT_KEY, type FgAiCreditBalanceProps, type FgAssistantActionResult, type FgAssistantPreviewController, type FgAssistantPreviewEvent, type FgAssistantRun, FluidGridsAiCreditsBridge, type FluidGridsAiCreditsBridgeProps, type FluidGridsAssistantLiveCanvasOptions, createFluidGridsAssistantLiveCanvas, notifyFluidGridsAiCreditsUpdated, useFluidGridsAssistantLiveCanvas };
|
package/dist/assistant.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { createFluidGridsAssistantLiveCanvas, useFluidGridsAssistantLiveCanvas } from './chunk-PIKYQE7P.js';
|
|
1
2
|
export { AiCreditBalanceSlot, FLUIDGRIDS_AI_CREDITS_UPDATED_EVENT, FLUIDGRIDS_AI_PRODUCT_KEY, FluidGridsAiCreditsBridge, notifyFluidGridsAiCreditsUpdated } from './chunk-Y53CVZVV.js';
|
|
2
3
|
export { FluidGridsAssistantBridge, useFluidGridsPageControls } from './chunk-PJAWNFJV.js';
|
|
3
4
|
import './chunk-62GWEYJ5.js';
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { isGuidedTourIntent, pickGuidedTour, withoutGuidedTourIntent, isCreateIntent, CreateWorkflowRefusalDialog, decideMissingWorkflow } from './chunk-LGGHQ7UE.js';
|
|
2
|
+
import { registerLiveCanvasHandler } from './chunk-PIKYQE7P.js';
|
|
2
3
|
import { useInstalledNodes, buildNodeCheck, FlowBuilderPage, buildRequiredNodeTypes } from './chunk-O24MDGZY.js';
|
|
3
4
|
import { useLazyWorkflowDefinition, useCreateWorkflow } from './chunk-SRE2JVSJ.js';
|
|
4
|
-
import { useFlowStore, refetchStoreNodes, BILLING_PLANS_PATH, codeBuildIdOf, mergeStickyNotes, blankWorkflowCreateInput, classifyCreateRefusal } from './chunk-2U56452G.js';
|
|
5
|
+
import { useFlowStore, refetchStoreNodes, BILLING_PLANS_PATH, codeBuildIdOf, mergeStickyNotes, blankWorkflowCreateInput, classifyCreateRefusal, useSaveStatusStore, workflowFingerprint, registerWorkflowNodeTypes, throwIfResultError } from './chunk-2U56452G.js';
|
|
6
|
+
import { getFluidGridsConfig } from './chunk-CY6KX4RG.js';
|
|
7
|
+
import { WorkflowDefinitionDocument } from './chunk-7PP6CRXS.js';
|
|
5
8
|
import { useTr } from './chunk-UULVIT25.js';
|
|
9
|
+
import { getFluidGridsClient } from './chunk-NTWG3CJX.js';
|
|
6
10
|
import { useLocation, useNavigate, useParams } from 'react-router';
|
|
7
11
|
import { toast } from 'sonner';
|
|
8
12
|
import { Icon } from '@iconify/react';
|
|
@@ -12,6 +16,654 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
|
12
16
|
import { ErrorBoundary } from '@burdenoff/fe-libs/shared/components';
|
|
13
17
|
import '@xyflow/react/dist/style.css';
|
|
14
18
|
|
|
19
|
+
// src/builder/live/canvas-base.ts
|
|
20
|
+
var base = null;
|
|
21
|
+
function currentCanvasBase() {
|
|
22
|
+
const flow = useFlowStore.getState();
|
|
23
|
+
if (!base || base.generation !== flow.loadGeneration || base.dbId !== flow.workflow.dbId) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return base;
|
|
27
|
+
}
|
|
28
|
+
function setCanvasBase(next) {
|
|
29
|
+
base = next;
|
|
30
|
+
}
|
|
31
|
+
function snapshotOf(state) {
|
|
32
|
+
const { workflow } = state;
|
|
33
|
+
return {
|
|
34
|
+
generation: state.loadGeneration,
|
|
35
|
+
dbId: workflow.dbId,
|
|
36
|
+
nodes: workflow.nodes,
|
|
37
|
+
edges: workflow.edges,
|
|
38
|
+
name: workflow.name ?? "",
|
|
39
|
+
alias: workflow.alias ?? ""
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function captureHydratedCanvasBase() {
|
|
43
|
+
const flow = useFlowStore.getState();
|
|
44
|
+
if (!flow.workflow.dbId || currentCanvasBase()) return false;
|
|
45
|
+
base = snapshotOf(flow);
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
function captureCanvasBaseIfInSync() {
|
|
49
|
+
const flow = useFlowStore.getState();
|
|
50
|
+
const { baseline } = useSaveStatusStore.getState();
|
|
51
|
+
if (!baseline || baseline.generation !== flow.loadGeneration) return false;
|
|
52
|
+
if (workflowFingerprint(flow.workflow) !== baseline.fingerprint) return false;
|
|
53
|
+
base = snapshotOf(flow);
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
function watchCanvasBase() {
|
|
57
|
+
if (!captureCanvasBaseIfInSync()) captureHydratedCanvasBase();
|
|
58
|
+
const unsubscribeStatus = useSaveStatusStore.subscribe((state, previous) => {
|
|
59
|
+
if (state.baseline !== previous.baseline) captureCanvasBaseIfInSync();
|
|
60
|
+
});
|
|
61
|
+
const unsubscribeFlow = useFlowStore.subscribe((state, previous) => {
|
|
62
|
+
if (state.loadGeneration !== previous.loadGeneration) base = null;
|
|
63
|
+
if (state.workflow.dbId && state.workflow !== previous.workflow) {
|
|
64
|
+
captureHydratedCanvasBase();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
return () => {
|
|
68
|
+
unsubscribeStatus();
|
|
69
|
+
unsubscribeFlow();
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// src/builder/live/assistant-writes.ts
|
|
74
|
+
var IN_PLACE = /* @__PURE__ */ new Set([
|
|
75
|
+
"updateWorkflowDefinition",
|
|
76
|
+
"pinNodeData",
|
|
77
|
+
"unpinNodeData",
|
|
78
|
+
"activateWorkflowDefinition",
|
|
79
|
+
"deactivateWorkflowDefinition"
|
|
80
|
+
]);
|
|
81
|
+
var VERSION_RESPONSE = /* @__PURE__ */ new Set([
|
|
82
|
+
"createWorkflowVersion",
|
|
83
|
+
"restoreWorkflowVersion"
|
|
84
|
+
]);
|
|
85
|
+
function isRecord(value) {
|
|
86
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
87
|
+
}
|
|
88
|
+
function text(value) {
|
|
89
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
90
|
+
}
|
|
91
|
+
function rootFieldResult(result, responseKey, operation) {
|
|
92
|
+
let value = result;
|
|
93
|
+
if (typeof value === "string") {
|
|
94
|
+
try {
|
|
95
|
+
value = JSON.parse(value);
|
|
96
|
+
} catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (!isRecord(value)) return null;
|
|
101
|
+
if (Array.isArray(value.errors) && value.errors.length > 0) return null;
|
|
102
|
+
const data = isRecord(value.data) ? value.data : value;
|
|
103
|
+
const root = data[responseKey] ?? data[operation];
|
|
104
|
+
return isRecord(root) ? root : null;
|
|
105
|
+
}
|
|
106
|
+
function classifyWorkflowWrite(action) {
|
|
107
|
+
const { operation, responseKey } = action;
|
|
108
|
+
const args = action.arguments ?? {};
|
|
109
|
+
const root = rootFieldResult(action.result, responseKey, operation);
|
|
110
|
+
if (IN_PLACE.has(operation)) {
|
|
111
|
+
const dbId = text(args.id) ?? text(root?.id);
|
|
112
|
+
return dbId ? { kind: "in-place", dbId } : null;
|
|
113
|
+
}
|
|
114
|
+
if (VERSION_RESPONSE.has(operation)) {
|
|
115
|
+
if (root?.success === false) return null;
|
|
116
|
+
const workflow = isRecord(root?.workflow) ? root.workflow : null;
|
|
117
|
+
const workflowKey = text(args.workflowKey) ?? text(workflow?.workflowKey);
|
|
118
|
+
if (!workflowKey) return null;
|
|
119
|
+
return {
|
|
120
|
+
kind: "new-version",
|
|
121
|
+
workflowKey,
|
|
122
|
+
version: text(workflow?.version),
|
|
123
|
+
dbId: text(workflow?.id)
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
if (operation === "applyWorkflowProposal") {
|
|
127
|
+
const workflowKey = text(root?.appliedWorkflowKey);
|
|
128
|
+
if (!workflowKey) return null;
|
|
129
|
+
return {
|
|
130
|
+
kind: "new-version",
|
|
131
|
+
workflowKey,
|
|
132
|
+
version: text(root?.appliedVersion),
|
|
133
|
+
dbId: text(root?.appliedWorkflowId)
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// src/builder/live/definition-canvas.ts
|
|
140
|
+
function isRecord2(value) {
|
|
141
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
142
|
+
}
|
|
143
|
+
function hasId(item) {
|
|
144
|
+
return isRecord2(item) && typeof item.id === "string" && item.id.length > 0;
|
|
145
|
+
}
|
|
146
|
+
function canvasFromDefinition(definitionJson) {
|
|
147
|
+
let definition = definitionJson;
|
|
148
|
+
if (typeof definition === "string") {
|
|
149
|
+
try {
|
|
150
|
+
definition = JSON.parse(definition);
|
|
151
|
+
} catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (!isRecord2(definition)) return null;
|
|
156
|
+
const data = isRecord2(definition.data) ? definition.data : definition;
|
|
157
|
+
if (!Array.isArray(data.nodes)) return null;
|
|
158
|
+
const nodes = mergeStickyNotes({
|
|
159
|
+
nodes: data.nodes,
|
|
160
|
+
stickyNotes: Array.isArray(data.stickyNotes) ? data.stickyNotes : []
|
|
161
|
+
}).filter(hasId);
|
|
162
|
+
const edges = (Array.isArray(data.edges) ? data.edges : []).filter(
|
|
163
|
+
hasId
|
|
164
|
+
);
|
|
165
|
+
return { nodes, edges };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// src/builder/live/graph-merge.ts
|
|
169
|
+
var VOLATILE_NODE_KEYS = /* @__PURE__ */ new Set([
|
|
170
|
+
"selected",
|
|
171
|
+
"dragging",
|
|
172
|
+
"resizing",
|
|
173
|
+
"measured",
|
|
174
|
+
"positionAbsolute"
|
|
175
|
+
]);
|
|
176
|
+
var VOLATILE_EDGE_KEYS = /* @__PURE__ */ new Set(["selected"]);
|
|
177
|
+
var NODE_STRUCTURE_KEYS = /* @__PURE__ */ new Set(["id", "type", "position", "data"]);
|
|
178
|
+
var CARRIED_NODE_KEYS = ["selected", "measured"];
|
|
179
|
+
var CARRIED_EDGE_KEYS = ["selected"];
|
|
180
|
+
function isRecord3(value) {
|
|
181
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
182
|
+
}
|
|
183
|
+
function stableStringify(value) {
|
|
184
|
+
return JSON.stringify(value, (_key, inner) => {
|
|
185
|
+
if (isRecord3(inner)) {
|
|
186
|
+
return Object.fromEntries(
|
|
187
|
+
Object.entries(inner).sort(
|
|
188
|
+
([a], [b]) => a < b ? -1 : a > b ? 1 : 0
|
|
189
|
+
)
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
return inner;
|
|
193
|
+
}) ?? "";
|
|
194
|
+
}
|
|
195
|
+
function canonicalNode(node) {
|
|
196
|
+
const entries = Object.entries(node);
|
|
197
|
+
const data = node.data;
|
|
198
|
+
const dataRecord = isRecord3(data) ? data : null;
|
|
199
|
+
const kept = entries.filter(([key]) => {
|
|
200
|
+
if (VOLATILE_NODE_KEYS.has(key)) return false;
|
|
201
|
+
if (NODE_STRUCTURE_KEYS.has(key)) return true;
|
|
202
|
+
return !(dataRecord && key in dataRecord);
|
|
203
|
+
});
|
|
204
|
+
const projected = Object.fromEntries(kept);
|
|
205
|
+
if (dataRecord) projected.data = savedNodeSettings(dataRecord);
|
|
206
|
+
return stableStringify(projected);
|
|
207
|
+
}
|
|
208
|
+
function savedNodeSettings(data) {
|
|
209
|
+
const nodeData = data.nodeData;
|
|
210
|
+
if (!isRecord3(nodeData)) return data;
|
|
211
|
+
const opName = data.operation_name;
|
|
212
|
+
const rawOps = nodeData.operations;
|
|
213
|
+
const ops = Array.isArray(rawOps) ? rawOps : isRecord3(rawOps) && Array.isArray(rawOps.operations) ? rawOps.operations : [];
|
|
214
|
+
const current = typeof opName === "string" && opName.length > 0 ? ops.find((op) => isRecord3(op) && op.name === opName) : void 0;
|
|
215
|
+
if (!current) {
|
|
216
|
+
const { nodeData: _unsaved, ...rest } = data;
|
|
217
|
+
return rest;
|
|
218
|
+
}
|
|
219
|
+
return { ...data, nodeData: { ...nodeData, operations: [current] } };
|
|
220
|
+
}
|
|
221
|
+
function canonicalEdge(edge) {
|
|
222
|
+
return stableStringify(
|
|
223
|
+
Object.fromEntries(
|
|
224
|
+
Object.entries(edge).filter(([key]) => !VOLATILE_EDGE_KEYS.has(key))
|
|
225
|
+
)
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
function indexById(items) {
|
|
229
|
+
const map = /* @__PURE__ */ new Map();
|
|
230
|
+
for (const item of items) {
|
|
231
|
+
if (typeof item?.id === "string" && !map.has(item.id))
|
|
232
|
+
map.set(item.id, item);
|
|
233
|
+
}
|
|
234
|
+
return map;
|
|
235
|
+
}
|
|
236
|
+
function carry(from, onto, keys) {
|
|
237
|
+
const carried = {};
|
|
238
|
+
for (const key of keys) {
|
|
239
|
+
if (key in from) carried[key] = from[key];
|
|
240
|
+
}
|
|
241
|
+
return Object.keys(carried).length === 0 ? onto : { ...onto, ...carried };
|
|
242
|
+
}
|
|
243
|
+
function mergeItems(kind, base2, local, remote, canonical, carriedKeys) {
|
|
244
|
+
const baseById = indexById(base2);
|
|
245
|
+
const localById = indexById(local);
|
|
246
|
+
const remoteById = indexById(remote);
|
|
247
|
+
const counts = { added: 0, updated: 0, removed: 0 };
|
|
248
|
+
const touched = [];
|
|
249
|
+
const conflicts = [];
|
|
250
|
+
const items = [];
|
|
251
|
+
let localEdits = false;
|
|
252
|
+
const conflict = (id, reason) => conflicts.push({ kind, id, reason });
|
|
253
|
+
for (const [id, mine] of localById) {
|
|
254
|
+
const original = baseById.get(id);
|
|
255
|
+
const theirs = remoteById.get(id);
|
|
256
|
+
const mineKey = canonical(mine);
|
|
257
|
+
if (!original) {
|
|
258
|
+
localEdits = true;
|
|
259
|
+
if (theirs && canonical(theirs) !== mineKey) conflict(id, "both-changed");
|
|
260
|
+
items.push(mine);
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
const originalKey = canonical(original);
|
|
264
|
+
const localChanged = mineKey !== originalKey;
|
|
265
|
+
if (localChanged) localEdits = true;
|
|
266
|
+
if (!theirs) {
|
|
267
|
+
if (localChanged) {
|
|
268
|
+
conflict(id, "deleted-remotely");
|
|
269
|
+
items.push(mine);
|
|
270
|
+
} else {
|
|
271
|
+
counts.removed += 1;
|
|
272
|
+
}
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
const theirsKey = canonical(theirs);
|
|
276
|
+
if (theirsKey === originalKey || theirsKey === mineKey) {
|
|
277
|
+
items.push(mine);
|
|
278
|
+
} else if (!localChanged) {
|
|
279
|
+
items.push(carry(mine, theirs, carriedKeys));
|
|
280
|
+
counts.updated += 1;
|
|
281
|
+
touched.push(id);
|
|
282
|
+
} else {
|
|
283
|
+
conflict(id, "both-changed");
|
|
284
|
+
items.push(mine);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
for (const [id, original] of baseById) {
|
|
288
|
+
if (localById.has(id)) continue;
|
|
289
|
+
localEdits = true;
|
|
290
|
+
const theirs = remoteById.get(id);
|
|
291
|
+
if (theirs && canonical(theirs) !== canonical(original)) {
|
|
292
|
+
conflict(id, "deleted-locally");
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
for (const [id, theirs] of remoteById) {
|
|
296
|
+
if (localById.has(id) || baseById.has(id)) continue;
|
|
297
|
+
items.push(theirs);
|
|
298
|
+
counts.added += 1;
|
|
299
|
+
touched.push(id);
|
|
300
|
+
}
|
|
301
|
+
return { items, counts, touched, conflicts, localEdits };
|
|
302
|
+
}
|
|
303
|
+
function mergeItemsWithoutBase(kind, local, remote, canonical) {
|
|
304
|
+
const localById = indexById(local);
|
|
305
|
+
const remoteById = indexById(remote);
|
|
306
|
+
const conflicts = [];
|
|
307
|
+
for (const [id, mine] of localById) {
|
|
308
|
+
const theirs = remoteById.get(id);
|
|
309
|
+
if (!theirs || canonical(theirs) !== canonical(mine)) {
|
|
310
|
+
conflicts.push({ kind, id, reason: "no-base" });
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
for (const id of remoteById.keys()) {
|
|
314
|
+
if (!localById.has(id)) conflicts.push({ kind, id, reason: "no-base" });
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
items: [...localById.values()],
|
|
318
|
+
counts: { added: 0, updated: 0, removed: 0 },
|
|
319
|
+
touched: [],
|
|
320
|
+
conflicts,
|
|
321
|
+
// Unknown, so assume the canvas holds edits: the save baseline stays.
|
|
322
|
+
localEdits: true
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
function mergeWorkflowGraph(base2, local, remote) {
|
|
326
|
+
const nodes = base2 ? mergeItems(
|
|
327
|
+
"node",
|
|
328
|
+
base2.nodes,
|
|
329
|
+
local.nodes,
|
|
330
|
+
remote.nodes,
|
|
331
|
+
canonicalNode,
|
|
332
|
+
CARRIED_NODE_KEYS
|
|
333
|
+
) : mergeItemsWithoutBase("node", local.nodes, remote.nodes, canonicalNode);
|
|
334
|
+
const edges = base2 ? mergeItems(
|
|
335
|
+
"edge",
|
|
336
|
+
base2.edges,
|
|
337
|
+
local.edges,
|
|
338
|
+
remote.edges,
|
|
339
|
+
canonicalEdge,
|
|
340
|
+
CARRIED_EDGE_KEYS
|
|
341
|
+
) : mergeItemsWithoutBase("edge", local.edges, remote.edges, canonicalEdge);
|
|
342
|
+
const nodeIds = new Set(nodes.items.map((node) => node.id));
|
|
343
|
+
const localEdgeIds = new Set(local.edges.map((edge) => edge.id));
|
|
344
|
+
const remoteTouched = new Set(edges.touched);
|
|
345
|
+
let detached = 0;
|
|
346
|
+
const keptEdges = edges.items.filter((edge) => {
|
|
347
|
+
const { source, target } = edge;
|
|
348
|
+
const attached = (typeof source !== "string" || nodeIds.has(source)) && (typeof target !== "string" || nodeIds.has(target));
|
|
349
|
+
if (attached) return true;
|
|
350
|
+
if (!localEdgeIds.has(edge.id)) {
|
|
351
|
+
edges.counts.added -= 1;
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
if (remoteTouched.has(edge.id)) edges.counts.updated -= 1;
|
|
355
|
+
edges.conflicts.push({ kind: "edge", id: edge.id, reason: "detached" });
|
|
356
|
+
detached += 1;
|
|
357
|
+
return false;
|
|
358
|
+
});
|
|
359
|
+
const total = (c) => c.added + c.updated + c.removed;
|
|
360
|
+
return {
|
|
361
|
+
nodes: nodes.items,
|
|
362
|
+
edges: keptEdges,
|
|
363
|
+
counts: { nodes: nodes.counts, edges: edges.counts },
|
|
364
|
+
touchedNodeIds: nodes.touched,
|
|
365
|
+
conflicts: [...nodes.conflicts, ...edges.conflicts],
|
|
366
|
+
changed: total(nodes.counts) + total(edges.counts) + detached > 0,
|
|
367
|
+
localEdits: nodes.localEdits || edges.localEdits
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
function mergeScalar(base2, local, remote) {
|
|
371
|
+
if (local === base2) return { value: remote, conflict: false };
|
|
372
|
+
return { value: local, conflict: remote !== base2 && remote !== local };
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// src/builder/live/live-canvas-sync.ts
|
|
376
|
+
var ASSISTANT_SYNC_HISTORY_KIND = "assistant:sync";
|
|
377
|
+
var SETTLE_MS = 1500;
|
|
378
|
+
var SEEN_LIMIT = 200;
|
|
379
|
+
function createLiveCanvasSync(deps) {
|
|
380
|
+
const now = deps.now ?? Date.now;
|
|
381
|
+
const seen = /* @__PURE__ */ new Set();
|
|
382
|
+
let running = null;
|
|
383
|
+
let queued = false;
|
|
384
|
+
const remember = (id) => {
|
|
385
|
+
if (seen.has(id)) return false;
|
|
386
|
+
seen.add(id);
|
|
387
|
+
if (seen.size > SEEN_LIMIT) {
|
|
388
|
+
const oldest = seen.values().next().value;
|
|
389
|
+
if (oldest !== void 0) seen.delete(oldest);
|
|
390
|
+
}
|
|
391
|
+
return true;
|
|
392
|
+
};
|
|
393
|
+
async function syncOnce() {
|
|
394
|
+
const flow = useFlowStore.getState();
|
|
395
|
+
const dbId = flow.workflow.dbId;
|
|
396
|
+
if (!dbId) return;
|
|
397
|
+
const generation = flow.loadGeneration;
|
|
398
|
+
let remote;
|
|
399
|
+
try {
|
|
400
|
+
remote = await deps.fetchDefinition(dbId);
|
|
401
|
+
} catch {
|
|
402
|
+
remote = null;
|
|
403
|
+
}
|
|
404
|
+
const after = useFlowStore.getState();
|
|
405
|
+
if (after.loadGeneration !== generation || after.workflow.dbId !== dbId) {
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
const canvas = remote ? canvasFromDefinition(remote.definitionJson) : null;
|
|
409
|
+
if (!remote || !canvas) {
|
|
410
|
+
deps.notify({ kind: "failed" });
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
applyRemote(remote, canvas);
|
|
414
|
+
}
|
|
415
|
+
function applyRemote(remote, canvas) {
|
|
416
|
+
const flow = useFlowStore.getState();
|
|
417
|
+
const { workflow, actions } = flow;
|
|
418
|
+
const localName = workflow.name ?? "";
|
|
419
|
+
const localAlias = workflow.alias ?? "";
|
|
420
|
+
const base2 = currentCanvasBase();
|
|
421
|
+
const merge = mergeWorkflowGraph(
|
|
422
|
+
base2,
|
|
423
|
+
{ nodes: workflow.nodes, edges: workflow.edges },
|
|
424
|
+
canvas
|
|
425
|
+
);
|
|
426
|
+
const remoteName = remote.name ?? localName;
|
|
427
|
+
const remoteAlias = remote.alias ?? "";
|
|
428
|
+
const name = base2 ? mergeScalar(base2.name, localName, remoteName) : { value: localName};
|
|
429
|
+
const alias = base2 ? mergeScalar(base2.alias, localAlias, remoteAlias) : { value: localAlias};
|
|
430
|
+
const localEdits = !base2 || merge.localEdits || localName !== base2.name || localAlias !== base2.alias;
|
|
431
|
+
if (merge.changed) {
|
|
432
|
+
deps.registerNodeTypes(merge.nodes);
|
|
433
|
+
actions.nodes.setNodes(merge.nodes, {
|
|
434
|
+
historyKind: ASSISTANT_SYNC_HISTORY_KIND
|
|
435
|
+
});
|
|
436
|
+
actions.edges.setEdges(merge.edges, { skipHistory: true });
|
|
437
|
+
}
|
|
438
|
+
const patch = {};
|
|
439
|
+
if (name.value !== localName) patch.name = name.value;
|
|
440
|
+
if (alias.value !== localAlias) patch.alias = alias.value;
|
|
441
|
+
if (remote.status && remote.status !== workflow.status) {
|
|
442
|
+
patch.status = remote.status;
|
|
443
|
+
}
|
|
444
|
+
if (Object.keys(patch).length > 0) actions.setWorkflow(patch);
|
|
445
|
+
const synced = useFlowStore.getState();
|
|
446
|
+
setCanvasBase({
|
|
447
|
+
generation: synced.loadGeneration,
|
|
448
|
+
dbId: synced.workflow.dbId,
|
|
449
|
+
nodes: canvas.nodes,
|
|
450
|
+
edges: canvas.edges,
|
|
451
|
+
name: remoteName,
|
|
452
|
+
alias: remoteAlias
|
|
453
|
+
});
|
|
454
|
+
const status = useSaveStatusStore.getState();
|
|
455
|
+
if ((merge.changed || Object.keys(patch).length > 0) && !localEdits && status.baseline && status.baseline.generation === synced.loadGeneration) {
|
|
456
|
+
status.actions.setBaseline({
|
|
457
|
+
fingerprint: workflowFingerprint(synced.workflow),
|
|
458
|
+
generation: synced.loadGeneration,
|
|
459
|
+
settleUntil: now() + SETTLE_MS,
|
|
460
|
+
editRevision: synced.editRevision
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
deps.onSynced?.(remote);
|
|
464
|
+
const renamed = patch.name !== void 0 || patch.alias !== void 0;
|
|
465
|
+
if (merge.changed || merge.conflicts.length > 0 || renamed) {
|
|
466
|
+
deps.notify({ kind: "applied", merge, renamed });
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
function scheduleSync() {
|
|
470
|
+
if (running) {
|
|
471
|
+
queued = true;
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
running = (async () => {
|
|
475
|
+
try {
|
|
476
|
+
do {
|
|
477
|
+
queued = false;
|
|
478
|
+
await syncOnce();
|
|
479
|
+
} while (queued);
|
|
480
|
+
} catch (error) {
|
|
481
|
+
console.error("[FluidGrids] assistant live canvas sync:", error);
|
|
482
|
+
} finally {
|
|
483
|
+
running = null;
|
|
484
|
+
}
|
|
485
|
+
})();
|
|
486
|
+
}
|
|
487
|
+
function handle(event) {
|
|
488
|
+
try {
|
|
489
|
+
const workspaceId = deps.workspaceId();
|
|
490
|
+
if (event.run.workspaceId && workspaceId && event.run.workspaceId !== workspaceId) {
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
const write = classifyWorkflowWrite(event.action);
|
|
494
|
+
if (!write) return;
|
|
495
|
+
const { workflow } = useFlowStore.getState();
|
|
496
|
+
if (!workflow.dbId) return;
|
|
497
|
+
if (write.kind === "in-place") {
|
|
498
|
+
if (write.dbId !== workflow.dbId) return;
|
|
499
|
+
if (!remember(event.action.id)) return;
|
|
500
|
+
scheduleSync();
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
const openKey = workflow.workflowKey || workflow.id;
|
|
504
|
+
if (write.workflowKey !== openKey) return;
|
|
505
|
+
if (write.dbId === workflow.dbId) {
|
|
506
|
+
if (remember(event.action.id)) scheduleSync();
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
if (write.version !== null && write.version === workflow.version) return;
|
|
510
|
+
if (!remember(event.action.id)) return;
|
|
511
|
+
deps.notify({
|
|
512
|
+
kind: "new-version",
|
|
513
|
+
workflowKey: write.workflowKey,
|
|
514
|
+
version: write.version
|
|
515
|
+
});
|
|
516
|
+
} catch (error) {
|
|
517
|
+
console.error("[FluidGrids] assistant live canvas:", error);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return {
|
|
521
|
+
handle,
|
|
522
|
+
idle: async () => {
|
|
523
|
+
while (running) await running;
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// src/builder/live/sync-notice.ts
|
|
529
|
+
var KEY = "fluidgrids.builder.assistantSync";
|
|
530
|
+
var NODE_PARTS = {
|
|
531
|
+
added: ["1 node added", "{{count}} nodes added"],
|
|
532
|
+
updated: ["1 node changed", "{{count}} nodes changed"],
|
|
533
|
+
removed: ["1 node removed", "{{count}} nodes removed"]
|
|
534
|
+
};
|
|
535
|
+
var EDGE_PARTS = {
|
|
536
|
+
added: ["1 connection added", "{{count}} connections added"],
|
|
537
|
+
updated: ["1 connection changed", "{{count}} connections changed"],
|
|
538
|
+
removed: ["1 connection removed", "{{count}} connections removed"]
|
|
539
|
+
};
|
|
540
|
+
function parts(tr, counts, kind) {
|
|
541
|
+
const words = kind === "nodes" ? NODE_PARTS : EDGE_PARTS;
|
|
542
|
+
return ["added", "updated", "removed"].filter((part) => counts[part] > 0).map((part) => {
|
|
543
|
+
const count = counts[part];
|
|
544
|
+
const [one, other] = words[part];
|
|
545
|
+
return count === 1 ? tr(`${KEY}.${kind}.${part}.one`, one) : tr(`${KEY}.${kind}.${part}.other`, other, { count });
|
|
546
|
+
});
|
|
547
|
+
}
|
|
548
|
+
function describeAppliedSync(tr, merge, renamed) {
|
|
549
|
+
const changes = [
|
|
550
|
+
...parts(tr, merge.counts.nodes, "nodes"),
|
|
551
|
+
...parts(tr, merge.counts.edges, "edges")
|
|
552
|
+
];
|
|
553
|
+
if (renamed) changes.push(tr(`${KEY}.renamed`, "name changed"));
|
|
554
|
+
const nodeConflicts = merge.conflicts.filter((c) => c.kind === "node").length;
|
|
555
|
+
const edgeConflicts = merge.conflicts.length - nodeConflicts;
|
|
556
|
+
let conflicts = null;
|
|
557
|
+
if (nodeConflicts > 0 || edgeConflicts > 0) {
|
|
558
|
+
const what = [
|
|
559
|
+
nodeConflicts === 1 ? tr(`${KEY}.conflicts.nodes.one`, "1 node") : nodeConflicts > 1 ? tr(`${KEY}.conflicts.nodes.other`, "{{count}} nodes", {
|
|
560
|
+
count: nodeConflicts
|
|
561
|
+
}) : null,
|
|
562
|
+
edgeConflicts === 1 ? tr(`${KEY}.conflicts.edges.one`, "1 connection") : edgeConflicts > 1 ? tr(`${KEY}.conflicts.edges.other`, "{{count}} connections", {
|
|
563
|
+
count: edgeConflicts
|
|
564
|
+
}) : null
|
|
565
|
+
].filter((item) => item !== null).join(tr(`${KEY}.and`, " and "));
|
|
566
|
+
conflicts = tr(
|
|
567
|
+
`${KEY}.conflicts.summary`,
|
|
568
|
+
"Kept your edits on {{what}} the assistant also changed",
|
|
569
|
+
{ what }
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
return {
|
|
573
|
+
title: tr(`${KEY}.title`, "Assistant updated this workflow"),
|
|
574
|
+
summary: changes.length > 0 ? changes.join(", ") : null,
|
|
575
|
+
conflicts
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
function describeNewVersion(tr, version) {
|
|
579
|
+
if (!version) {
|
|
580
|
+
return {
|
|
581
|
+
title: tr(
|
|
582
|
+
`${KEY}.newVersion.unknown`,
|
|
583
|
+
"The assistant saved a new version of this workflow"
|
|
584
|
+
),
|
|
585
|
+
action: null
|
|
586
|
+
};
|
|
587
|
+
}
|
|
588
|
+
return {
|
|
589
|
+
title: tr(
|
|
590
|
+
`${KEY}.newVersion.title`,
|
|
591
|
+
"The assistant saved version {{version}} of this workflow",
|
|
592
|
+
{ version }
|
|
593
|
+
),
|
|
594
|
+
action: tr(`${KEY}.newVersion.open`, "Open {{version}}", { version })
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
function describeFailedSync(tr) {
|
|
598
|
+
return tr(
|
|
599
|
+
`${KEY}.failed`,
|
|
600
|
+
"The assistant changed this workflow, but the canvas could not be refreshed. Reopen the workflow to see the change."
|
|
601
|
+
);
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// src/builder/live/assistant-live-canvas-host.tsx
|
|
605
|
+
async function fetchDefinition(dbId) {
|
|
606
|
+
const { data } = throwIfResultError(
|
|
607
|
+
await getFluidGridsClient().query({
|
|
608
|
+
query: WorkflowDefinitionDocument,
|
|
609
|
+
variables: { id: dbId },
|
|
610
|
+
fetchPolicy: "network-only"
|
|
611
|
+
})
|
|
612
|
+
);
|
|
613
|
+
return data?.workflowDefinition ?? null;
|
|
614
|
+
}
|
|
615
|
+
function AssistantLiveCanvasHost() {
|
|
616
|
+
const tr = useTr();
|
|
617
|
+
const navigate = useNavigate();
|
|
618
|
+
const latest = useRef({ tr, navigate });
|
|
619
|
+
useEffect(() => {
|
|
620
|
+
latest.current = { tr, navigate };
|
|
621
|
+
});
|
|
622
|
+
useEffect(() => {
|
|
623
|
+
const notify = (notice) => {
|
|
624
|
+
const { tr: t, navigate: go } = latest.current;
|
|
625
|
+
if (notice.kind === "failed") {
|
|
626
|
+
toast.error(describeFailedSync(t));
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
if (notice.kind === "new-version") {
|
|
630
|
+
const text3 = describeNewVersion(t, notice.version);
|
|
631
|
+
const { workflowKey, version } = notice;
|
|
632
|
+
toast.info(text3.title, {
|
|
633
|
+
dismissible: true,
|
|
634
|
+
duration: 1e4,
|
|
635
|
+
...text3.action && version ? {
|
|
636
|
+
action: {
|
|
637
|
+
label: text3.action,
|
|
638
|
+
onClick: () => go(`../workflow/${workflowKey}/${version}`)
|
|
639
|
+
}
|
|
640
|
+
} : {}
|
|
641
|
+
});
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
const text2 = describeAppliedSync(t, notice.merge, notice.renamed);
|
|
645
|
+
const description = [text2.summary, text2.conflicts].filter((line) => line !== null).join(". ");
|
|
646
|
+
const show = text2.conflicts ? toast.warning : toast.success;
|
|
647
|
+
show(text2.title, {
|
|
648
|
+
dismissible: true,
|
|
649
|
+
...description ? { description } : {}
|
|
650
|
+
});
|
|
651
|
+
};
|
|
652
|
+
const sync = createLiveCanvasSync({
|
|
653
|
+
fetchDefinition,
|
|
654
|
+
registerNodeTypes: registerWorkflowNodeTypes,
|
|
655
|
+
notify,
|
|
656
|
+
workspaceId: () => getFluidGridsConfig().workspaceId || null
|
|
657
|
+
});
|
|
658
|
+
const stopWatching = watchCanvasBase();
|
|
659
|
+
const unregister = registerLiveCanvasHandler(sync.handle);
|
|
660
|
+
return () => {
|
|
661
|
+
unregister();
|
|
662
|
+
stopWatching();
|
|
663
|
+
};
|
|
664
|
+
}, []);
|
|
665
|
+
return null;
|
|
666
|
+
}
|
|
15
667
|
var START_DELAY_MS = 800;
|
|
16
668
|
function StartGuidedTour() {
|
|
17
669
|
const location = useLocation();
|
|
@@ -118,9 +770,9 @@ function WorkflowItem({
|
|
|
118
770
|
try {
|
|
119
771
|
const { getGlobalStoreClient } = await import('./global-client-KLOVTVPP.js');
|
|
120
772
|
const { InstallWorkflowNodeDocument } = await import('./global-operations-D2USVOPM.js');
|
|
121
|
-
const { getFluidGridsConfig } = await import('./config-T7BQ7AO2.js');
|
|
773
|
+
const { getFluidGridsConfig: getFluidGridsConfig2 } = await import('./config-T7BQ7AO2.js');
|
|
122
774
|
const storeClient = getGlobalStoreClient();
|
|
123
|
-
const cfg =
|
|
775
|
+
const cfg = getFluidGridsConfig2();
|
|
124
776
|
for (let i = 0; i < nodesToInstall.length; i++) {
|
|
125
777
|
const node = nodesToInstall[i];
|
|
126
778
|
setInstallProgress({
|
|
@@ -552,6 +1204,7 @@ function WorkflowItem({
|
|
|
552
1204
|
}
|
|
553
1205
|
),
|
|
554
1206
|
workflow && !isLoading && /* @__PURE__ */ jsx(FlowBuilderPage, { workflow }),
|
|
1207
|
+
workflow && !isLoading && /* @__PURE__ */ jsx(AssistantLiveCanvasHost, {}),
|
|
555
1208
|
/* @__PURE__ */ jsx(GuidedTourStarter, { ready: Boolean(workflow && !isLoading) })
|
|
556
1209
|
] });
|
|
557
1210
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { useRef, useEffect, useMemo } from 'react';
|
|
2
|
+
|
|
3
|
+
var LIVE_CANVAS_RELAY_KEY = /* @__PURE__ */ Symbol.for(
|
|
4
|
+
"burdenoff.fluidgrids.liveCanvas"
|
|
5
|
+
);
|
|
6
|
+
function relaySlot() {
|
|
7
|
+
const scope = globalThis;
|
|
8
|
+
const existing = scope[LIVE_CANVAS_RELAY_KEY];
|
|
9
|
+
if (existing) return existing;
|
|
10
|
+
const created = { handler: null };
|
|
11
|
+
scope[LIVE_CANVAS_RELAY_KEY] = created;
|
|
12
|
+
return created;
|
|
13
|
+
}
|
|
14
|
+
function registerLiveCanvasHandler(next) {
|
|
15
|
+
const slot = relaySlot();
|
|
16
|
+
slot.handler = next;
|
|
17
|
+
return () => {
|
|
18
|
+
if (slot.handler === next) slot.handler = null;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function isActionResult(event) {
|
|
22
|
+
if (typeof event !== "object" || event === null) return false;
|
|
23
|
+
const candidate = event;
|
|
24
|
+
return candidate.kind === "action-result" && typeof candidate.run === "object" && candidate.run !== null && typeof candidate.action === "object" && candidate.action !== null && typeof candidate.action.operation === "string" && typeof candidate.action.id === "string";
|
|
25
|
+
}
|
|
26
|
+
function deliverLiveCanvasEvent(event, options = {}) {
|
|
27
|
+
try {
|
|
28
|
+
if (!isActionResult(event)) return;
|
|
29
|
+
const current = relaySlot().handler;
|
|
30
|
+
if (!current) return;
|
|
31
|
+
if (options.getActorId) {
|
|
32
|
+
const actorId = options.getActorId();
|
|
33
|
+
if (event.run.actorId !== null && actorId !== null && event.run.actorId !== actorId) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
current(event);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error("[FluidGrids] assistant live canvas:", error);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function createFluidGridsAssistantLiveCanvas(options = {}) {
|
|
43
|
+
return { onEvent: (event) => deliverLiveCanvasEvent(event, options) };
|
|
44
|
+
}
|
|
45
|
+
function useFluidGridsAssistantLiveCanvas(options = {}) {
|
|
46
|
+
const latest = useRef(options);
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
latest.current = options;
|
|
49
|
+
});
|
|
50
|
+
return useMemo(
|
|
51
|
+
() => ({
|
|
52
|
+
onEvent: (event) => deliverLiveCanvasEvent(event, latest.current)
|
|
53
|
+
}),
|
|
54
|
+
[]
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { createFluidGridsAssistantLiveCanvas, registerLiveCanvasHandler, useFluidGridsAssistantLiveCanvas };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export { Label } from './chunk-VTQVPNUQ.js';
|
|
2
2
|
export { WorkflowBuilder, WorkflowBuilderCore, WorkflowSearchRedirect } from './chunk-MNPZMFLF.js';
|
|
3
|
-
export { GuidedTourStarter, WorkflowBuilder as WorkflowBuilderPage } from './chunk-
|
|
3
|
+
export { GuidedTourStarter, WorkflowBuilder as WorkflowBuilderPage } from './chunk-JUA57OVN.js';
|
|
4
4
|
export { FirstWorkflowChecklist, FirstWorkflowChecklistView, WorkflowsList, useCreateWorkflowFirst } from './chunk-XTXT4NHE.js';
|
|
5
5
|
export { CreateWorkflowRefusalDialog, GUIDED_FIRST_WORKFLOW_NAV, GUIDED_FIRST_WORKFLOW_STATE, GUIDED_TOUR_STATE, firstWorkflowProgress, isGuidedTourIntent, pickGuidedTour } from './chunk-LGGHQ7UE.js';
|
|
6
|
+
import './chunk-PIKYQE7P.js';
|
|
6
7
|
import './chunk-AD3BXTJS.js';
|
|
7
8
|
export { ExecutionsListPage } from './chunk-DASEJQ4G.js';
|
|
8
9
|
import { usePendingHumanRequests, HumanRequestCard } from './chunk-6Y6I2ODM.js';
|
|
@@ -77,7 +78,7 @@ var WorkflowsList2 = lazy(
|
|
|
77
78
|
() => import('./WorkflowsList-2OYIXGWQ.js').then((m) => ({ default: m.WorkflowsList }))
|
|
78
79
|
);
|
|
79
80
|
var WorkflowBuilder3 = lazy(
|
|
80
|
-
() => import('./WorkflowBuilder-
|
|
81
|
+
() => import('./WorkflowBuilder-EVZGOXZZ.js').then((m) => ({
|
|
81
82
|
default: m.WorkflowBuilder
|
|
82
83
|
}))
|
|
83
84
|
);
|
package/dist/workflow-builder.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { WorkflowBuilder, WorkflowBuilderCore, WorkflowSearchRedirect } from './chunk-MNPZMFLF.js';
|
|
2
|
-
export { WorkflowBuilder as WorkflowBuilderPage } from './chunk-
|
|
2
|
+
export { WorkflowBuilder as WorkflowBuilderPage } from './chunk-JUA57OVN.js';
|
|
3
3
|
import './chunk-LGGHQ7UE.js';
|
|
4
|
+
import './chunk-PIKYQE7P.js';
|
|
4
5
|
import './chunk-O24MDGZY.js';
|
|
5
6
|
import './chunk-GEMNVFPK.js';
|
|
6
7
|
import './chunk-IEVSFCFS.js';
|