@burdenoff/fluidgrids-fe-sdk 2026.918.2 → 2026.922.2
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-GFFW5WSB.js → WorkflowBuilder-XZPLGBCS.js} +5 -5
- package/dist/{WorkflowBuilder-GFFW5WSB.js.map → WorkflowBuilder-XZPLGBCS.js.map} +1 -1
- package/dist/{WorkflowsList-ZBMSG2WP.js → WorkflowsList-J6IDS3SR.js} +4 -4
- package/dist/{WorkflowsList-ZBMSG2WP.js.map → WorkflowsList-J6IDS3SR.js.map} +1 -1
- package/dist/{chunk-HY7K7SLI.js → chunk-3RWKQIV4.js} +957 -53
- package/dist/chunk-3RWKQIV4.js.map +1 -0
- package/dist/chunk-I3WUYESA.js +668 -0
- package/dist/chunk-I3WUYESA.js.map +1 -0
- package/dist/{chunk-YAADZDGX.js → chunk-K4U4WX4R.js} +3 -3
- package/dist/{chunk-YAADZDGX.js.map → chunk-K4U4WX4R.js.map} +1 -1
- package/dist/{chunk-77Y5WTBD.js → chunk-SU6UYGRW.js} +4 -4
- package/dist/{chunk-77Y5WTBD.js.map → chunk-SU6UYGRW.js.map} +1 -1
- package/dist/{chunk-TOFLHYUQ.js → chunk-TKUCCNEO.js} +4 -4
- package/dist/{chunk-TOFLHYUQ.js.map → chunk-TKUCCNEO.js.map} +1 -1
- package/dist/{chunk-YH2QC6D6.js → chunk-Y4AM4RTD.js} +4 -4
- package/dist/{chunk-YH2QC6D6.js.map → chunk-Y4AM4RTD.js.map} +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +10 -10
- package/dist/templates.js +3 -3
- package/dist/{workflow-builder-JKkdIJoP.d.ts → workflow-builder-BNWKK8C7.d.ts} +53 -2
- package/dist/workflow-builder.d.ts +1 -1
- package/dist/workflow-builder.js +4 -4
- package/dist/workflows-list.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-HY7K7SLI.js.map +0 -1
- package/dist/chunk-KT72XMAB.js +0 -379
- package/dist/chunk-KT72XMAB.js.map +0 -1
|
@@ -4,7 +4,7 @@ import { Badge as Badge$1, Button as Button$1 } from './chunk-DBOMRIP5.js';
|
|
|
4
4
|
import { getGlobalStoreClient, createGlobalStoreClient, setGlobalStoreClient, resetGlobalStoreClient } from './chunk-BQXHJIER.js';
|
|
5
5
|
import { GetMyNodeInstallationsDocument, BrowseWorkflowTemplatesDocument, InstallWorkflowNodeDocument, InstallPurchasedNodeDocument, BrowseWorkflowNodesDocument, UninstallWorkflowNodeDocument, CreateStoreOrderDocument, GetNodeInstallableVersionsDocument } from './chunk-6LXMUIR3.js';
|
|
6
6
|
import { deepClone, applyTemplateInputs } from './chunk-XQP33UJR.js';
|
|
7
|
-
import { useFlowStore, QuotaExhaustedDialog } from './chunk-
|
|
7
|
+
import { useFlowStore, QuotaExhaustedDialog } from './chunk-I3WUYESA.js';
|
|
8
8
|
import { SdkPermissionGate, FLUIDGRIDS_PERMISSIONS, SdkPermissionButton } from './chunk-UIY2HBWA.js';
|
|
9
9
|
import { cn as cn$1 } from './chunk-3ZYUGTIT.js';
|
|
10
10
|
import { useWorkflowVersions, useRestoreWorkflowVersion, useActivateWorkflow, useDeleteWorkflow, useDeactivateWorkflow } from './chunk-ELB3LXRJ.js';
|
|
@@ -37,7 +37,7 @@ import { ApolloProvider, useQuery, useMutation } from '@apollo/client/react';
|
|
|
37
37
|
import { TagBadge, TagsWidget } from '@burdenoff/fe-libs/tag';
|
|
38
38
|
import { gql as gql$1 } from '@apollo/client/core';
|
|
39
39
|
import 'jszip';
|
|
40
|
-
import { Sparkles, Star, Download, Eye, History, Loader2, Play, RotateCcw, Trash2, Maximize2, LayoutGrid, Plus, GitBranch, AlertCircle, Search, RefreshCw, CheckCircle2, Package, Info, Copy, BadgeCheck, DollarSign, Type, Code, Hash, List, Braces, Workflow, PlusCircle, ChevronDown, ChevronRight, Layers, X, AlertTriangle } from 'lucide-react';
|
|
40
|
+
import { Sparkles, Star, Download, Eye, History, Loader2, Play, RotateCcw, Trash2, Maximize2, Undo2, Redo2, LayoutGrid, Keyboard, Plus, GitBranch, AlertCircle, Search, RefreshCw, CheckCircle2, Package, Info, Copy, BadgeCheck, DollarSign, Type, Code, Hash, List, Braces, Workflow, PlusCircle, ChevronDown, ChevronRight, Layers, X, AlertTriangle } from 'lucide-react';
|
|
41
41
|
import { produce } from 'immer';
|
|
42
42
|
import { isEmpty } from 'radash';
|
|
43
43
|
import { animate, easeOut } from 'popmotion';
|
|
@@ -224,6 +224,245 @@ function stripSubmitActions(card) {
|
|
|
224
224
|
}
|
|
225
225
|
return result;
|
|
226
226
|
}
|
|
227
|
+
|
|
228
|
+
// src/builder/components/lib/expression-preview.ts
|
|
229
|
+
var PURE_EXPRESSION_REGEX = /^\{\{(.*)\}\}$/s;
|
|
230
|
+
var PURE_LEGACY_REGEX = /^\$\{(.*)\}$/s;
|
|
231
|
+
function containsExpressionSyntax(str) {
|
|
232
|
+
return typeof str === "string" && str.includes("{{");
|
|
233
|
+
}
|
|
234
|
+
function findEmbeddedExpressions(str) {
|
|
235
|
+
const matches = [];
|
|
236
|
+
let searchFrom = 0;
|
|
237
|
+
while (searchFrom < str.length) {
|
|
238
|
+
const start = str.indexOf("{{", searchFrom);
|
|
239
|
+
if (start === -1) break;
|
|
240
|
+
const end = str.indexOf("}}", start + 2);
|
|
241
|
+
if (end === -1) break;
|
|
242
|
+
matches.push({
|
|
243
|
+
full: str.slice(start, end + 2),
|
|
244
|
+
expression: str.slice(start + 2, end).trim()
|
|
245
|
+
});
|
|
246
|
+
searchFrom = end + 2;
|
|
247
|
+
}
|
|
248
|
+
return matches;
|
|
249
|
+
}
|
|
250
|
+
function toItems(value) {
|
|
251
|
+
if (value === void 0 || value === null) return [];
|
|
252
|
+
if (Array.isArray(value)) return value.map((entry) => ({ json: entry }));
|
|
253
|
+
return [{ json: value }];
|
|
254
|
+
}
|
|
255
|
+
var SAFE_GLOBALS = {
|
|
256
|
+
parseInt,
|
|
257
|
+
parseFloat,
|
|
258
|
+
isNaN,
|
|
259
|
+
isFinite,
|
|
260
|
+
Number,
|
|
261
|
+
String,
|
|
262
|
+
Boolean,
|
|
263
|
+
JSON,
|
|
264
|
+
Date,
|
|
265
|
+
Math,
|
|
266
|
+
Array,
|
|
267
|
+
Object,
|
|
268
|
+
console: {
|
|
269
|
+
log: () => void 0,
|
|
270
|
+
error: () => void 0,
|
|
271
|
+
warn: () => void 0
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
function buildExpressionSandbox(scope) {
|
|
275
|
+
const inputItems = toItems(scope.input);
|
|
276
|
+
const currentItem = inputItems[0] ?? { json: {} };
|
|
277
|
+
const itemsForNode = (nodeName) => toItems(scope.nodeOutputs[nodeName]);
|
|
278
|
+
const dollarNode = (nodeName) => {
|
|
279
|
+
const items = itemsForNode(nodeName);
|
|
280
|
+
const at = items[0] ?? { json: {} };
|
|
281
|
+
return {
|
|
282
|
+
item: at.json,
|
|
283
|
+
all: () => items,
|
|
284
|
+
first: () => items[0]?.json ?? {},
|
|
285
|
+
last: () => items[items.length - 1]?.json ?? {}
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
const nodeObject = {};
|
|
289
|
+
for (const nodeName of Object.keys(scope.nodeOutputs)) {
|
|
290
|
+
nodeObject[nodeName] = dollarNode(nodeName);
|
|
291
|
+
}
|
|
292
|
+
const now = /* @__PURE__ */ new Date();
|
|
293
|
+
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
|
294
|
+
return {
|
|
295
|
+
...SAFE_GLOBALS,
|
|
296
|
+
$json: currentItem.json,
|
|
297
|
+
$node: nodeObject,
|
|
298
|
+
$: dollarNode,
|
|
299
|
+
$items: (nodeName) => nodeName ? itemsForNode(nodeName) : inputItems,
|
|
300
|
+
$input: {
|
|
301
|
+
item: currentItem.json,
|
|
302
|
+
all: () => inputItems,
|
|
303
|
+
first: () => inputItems[0]?.json ?? {},
|
|
304
|
+
last: () => inputItems[inputItems.length - 1]?.json ?? {}
|
|
305
|
+
},
|
|
306
|
+
$workflow: {
|
|
307
|
+
id: scope.workflowKey,
|
|
308
|
+
name: scope.workflowKey,
|
|
309
|
+
version: scope.version
|
|
310
|
+
},
|
|
311
|
+
$execution: { id: scope.runId },
|
|
312
|
+
// Stubbed pending BOFF-7517 (Variables model) — mirrors the backend stub.
|
|
313
|
+
$vars: {},
|
|
314
|
+
// Never real env vars in the browser preview.
|
|
315
|
+
$env: {},
|
|
316
|
+
$now: now,
|
|
317
|
+
$today: today
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
function evaluateBare(expression, sandbox) {
|
|
321
|
+
const paramNames = Object.keys(sandbox);
|
|
322
|
+
const paramValues = Object.values(sandbox);
|
|
323
|
+
const fn = new Function(
|
|
324
|
+
...paramNames,
|
|
325
|
+
`"use strict"; return (${expression});`
|
|
326
|
+
);
|
|
327
|
+
return fn(...paramValues);
|
|
328
|
+
}
|
|
329
|
+
function stringifyForInterpolation(value) {
|
|
330
|
+
if (value === null || value === void 0) return "";
|
|
331
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
332
|
+
return String(value);
|
|
333
|
+
}
|
|
334
|
+
function previewNewSyntax(str, scope) {
|
|
335
|
+
const sandbox = buildExpressionSandbox(scope);
|
|
336
|
+
const pure = PURE_EXPRESSION_REGEX.exec(str);
|
|
337
|
+
try {
|
|
338
|
+
if (pure) {
|
|
339
|
+
const expression = pure[1]?.trim();
|
|
340
|
+
if (!expression) {
|
|
341
|
+
return { isTemplate: true, error: "Empty expression" };
|
|
342
|
+
}
|
|
343
|
+
return { isTemplate: true, value: evaluateBare(expression, sandbox) };
|
|
344
|
+
}
|
|
345
|
+
let result = str;
|
|
346
|
+
for (const match of findEmbeddedExpressions(str)) {
|
|
347
|
+
if (!match.expression) continue;
|
|
348
|
+
const value = evaluateBare(match.expression, sandbox);
|
|
349
|
+
result = result.replace(match.full, stringifyForInterpolation(value));
|
|
350
|
+
}
|
|
351
|
+
return { isTemplate: true, value: result };
|
|
352
|
+
} catch (error) {
|
|
353
|
+
return {
|
|
354
|
+
isTemplate: true,
|
|
355
|
+
error: error instanceof Error ? error.message : String(error)
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
function previewLegacySyntax(str, scope) {
|
|
360
|
+
const sandbox = {
|
|
361
|
+
...SAFE_GLOBALS,
|
|
362
|
+
output: scope.input,
|
|
363
|
+
TriggerInput: {},
|
|
364
|
+
WorkflowState: Object.fromEntries(
|
|
365
|
+
Object.entries(scope.nodeOutputs).map(([nodeId, output]) => [
|
|
366
|
+
nodeId,
|
|
367
|
+
{ output, status: "COMPLETED" }
|
|
368
|
+
])
|
|
369
|
+
),
|
|
370
|
+
RunContext: {
|
|
371
|
+
runId: scope.runId ?? "preview",
|
|
372
|
+
workflowKey: scope.workflowKey ?? "preview",
|
|
373
|
+
version: scope.version ?? "1.0.0"
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
const pure = PURE_LEGACY_REGEX.exec(str);
|
|
377
|
+
try {
|
|
378
|
+
if (pure) {
|
|
379
|
+
const expression = pure[1]?.trim();
|
|
380
|
+
if (!expression) return { isTemplate: true, error: "Empty expression" };
|
|
381
|
+
return { isTemplate: true, value: evaluateBare(expression, sandbox) };
|
|
382
|
+
}
|
|
383
|
+
if (!str.includes("${")) {
|
|
384
|
+
return { isTemplate: false };
|
|
385
|
+
}
|
|
386
|
+
let result = str;
|
|
387
|
+
const templateRegex = /\$\{([^}]+)\}/g;
|
|
388
|
+
for (const match of str.matchAll(templateRegex)) {
|
|
389
|
+
const expression = match[1]?.trim();
|
|
390
|
+
if (!expression) continue;
|
|
391
|
+
const value = evaluateBare(expression, sandbox);
|
|
392
|
+
result = result.replace(match[0], stringifyForInterpolation(value));
|
|
393
|
+
}
|
|
394
|
+
return { isTemplate: true, value: result };
|
|
395
|
+
} catch (error) {
|
|
396
|
+
return {
|
|
397
|
+
isTemplate: true,
|
|
398
|
+
error: error instanceof Error ? error.message : String(error)
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
function evaluateExpressionPreview(str, scope) {
|
|
403
|
+
if (typeof str !== "string" || str.trim() === "") {
|
|
404
|
+
return { isTemplate: false };
|
|
405
|
+
}
|
|
406
|
+
if (containsExpressionSyntax(str)) {
|
|
407
|
+
return previewNewSyntax(str, scope);
|
|
408
|
+
}
|
|
409
|
+
return previewLegacySyntax(str, scope);
|
|
410
|
+
}
|
|
411
|
+
var EXPRESSION_BUILTINS = [
|
|
412
|
+
{ insert: "$json", label: "$json", description: "Current item's data" },
|
|
413
|
+
{
|
|
414
|
+
insert: '$node["NodeName"]',
|
|
415
|
+
label: '$node["NodeName"]',
|
|
416
|
+
description: "Another node's current item"
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
insert: '$("NodeName")',
|
|
420
|
+
label: '$("NodeName")',
|
|
421
|
+
description: "Lineage helper: .item / .all() / .first() / .last()"
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
insert: "$items()",
|
|
425
|
+
label: "$items()",
|
|
426
|
+
description: "This node's input as a list of items"
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
insert: "$input",
|
|
430
|
+
label: "$input",
|
|
431
|
+
description: "Input helper: .item / .all() / .first() / .last()"
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
insert: "$workflow",
|
|
435
|
+
label: "$workflow",
|
|
436
|
+
description: "Workflow id / name / version"
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
insert: "$execution",
|
|
440
|
+
label: "$execution",
|
|
441
|
+
description: "Current execution id"
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
insert: "$vars",
|
|
445
|
+
label: "$vars",
|
|
446
|
+
description: "Workflow variables (coming soon)"
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
insert: "$env",
|
|
450
|
+
label: "$env",
|
|
451
|
+
description: "Allowlisted environment values"
|
|
452
|
+
},
|
|
453
|
+
{ insert: "$now", label: "$now", description: "Current date/time" },
|
|
454
|
+
{ insert: "$today", label: "$today", description: "Start of today" }
|
|
455
|
+
];
|
|
456
|
+
var AUTOCOMPLETE_LOOKBACK = 40;
|
|
457
|
+
function openExpressionPrefix(value, cursor) {
|
|
458
|
+
const windowStart = Math.max(0, cursor - AUTOCOMPLETE_LOOKBACK);
|
|
459
|
+
const before = value.slice(windowStart, cursor);
|
|
460
|
+
const openIndex = before.lastIndexOf("{{");
|
|
461
|
+
if (openIndex === -1) return null;
|
|
462
|
+
const between = before.slice(openIndex + 2);
|
|
463
|
+
if (between.includes("}}")) return null;
|
|
464
|
+
return between.trimStart();
|
|
465
|
+
}
|
|
227
466
|
function ExpressionEditor({
|
|
228
467
|
value,
|
|
229
468
|
onChange,
|
|
@@ -231,14 +470,18 @@ function ExpressionEditor({
|
|
|
231
470
|
className,
|
|
232
471
|
rows = 4,
|
|
233
472
|
label,
|
|
234
|
-
helpText
|
|
473
|
+
helpText,
|
|
474
|
+
nodeId
|
|
235
475
|
}) {
|
|
236
476
|
const tr = useTr();
|
|
237
477
|
const editorRef = useRef(null);
|
|
238
478
|
const [isFocused, setIsFocused] = useState(false);
|
|
479
|
+
const [suggestionsOpen, setSuggestionsOpen] = useState(false);
|
|
239
480
|
const handleChange = useCallback(
|
|
240
481
|
(e) => {
|
|
241
482
|
onChange(e.target.value);
|
|
483
|
+
const cursor = e.target.selectionStart;
|
|
484
|
+
setSuggestionsOpen(openExpressionPrefix(e.target.value, cursor) !== null);
|
|
242
485
|
},
|
|
243
486
|
[onChange]
|
|
244
487
|
);
|
|
@@ -260,6 +503,83 @@ function ExpressionEditor({
|
|
|
260
503
|
},
|
|
261
504
|
[value, onChange]
|
|
262
505
|
);
|
|
506
|
+
const applySuggestion = useCallback(
|
|
507
|
+
(insert) => {
|
|
508
|
+
const textarea = editorRef.current;
|
|
509
|
+
if (!textarea) {
|
|
510
|
+
insertTemplate(`{{ ${insert} }}`);
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
const cursor = textarea.selectionStart;
|
|
514
|
+
const windowStart = Math.max(0, cursor - AUTOCOMPLETE_LOOKBACK);
|
|
515
|
+
const before = value.slice(windowStart, cursor);
|
|
516
|
+
const openIndex = before.lastIndexOf("{{");
|
|
517
|
+
if (openIndex === -1) {
|
|
518
|
+
insertTemplate(`{{ ${insert} }}`);
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
const replaceStart = windowStart + openIndex;
|
|
522
|
+
const newValue = value.slice(0, replaceStart) + `{{ ${insert} }}` + value.slice(cursor);
|
|
523
|
+
onChange(newValue);
|
|
524
|
+
setSuggestionsOpen(false);
|
|
525
|
+
const cursorAfter = replaceStart + `{{ ${insert} }}`.length;
|
|
526
|
+
setTimeout(() => {
|
|
527
|
+
textarea.focus();
|
|
528
|
+
textarea.setSelectionRange(cursorAfter, cursorAfter);
|
|
529
|
+
}, 0);
|
|
530
|
+
},
|
|
531
|
+
[value, onChange, insertTemplate]
|
|
532
|
+
);
|
|
533
|
+
const cursorPos = editorRef.current?.selectionStart ?? value.length;
|
|
534
|
+
const filterText = suggestionsOpen ? openExpressionPrefix(value, cursorPos) ?? "" : "";
|
|
535
|
+
const suggestions = useMemo(() => {
|
|
536
|
+
if (!suggestionsOpen) return [];
|
|
537
|
+
const needle = filterText.toLowerCase();
|
|
538
|
+
return EXPRESSION_BUILTINS.filter(
|
|
539
|
+
(b) => b.label.toLowerCase().startsWith(needle || "$")
|
|
540
|
+
).slice(0, 8);
|
|
541
|
+
}, [suggestionsOpen, filterText]);
|
|
542
|
+
const logs = useFlowStore((s) => s.execution.logs);
|
|
543
|
+
const workflowKey = useFlowStore((s) => s.workflow.workflowKey);
|
|
544
|
+
const workflowVersion = useFlowStore((s) => s.workflow.version);
|
|
545
|
+
const previewScope = useMemo(() => {
|
|
546
|
+
const nodeOutputs = {};
|
|
547
|
+
let input = {};
|
|
548
|
+
let runId;
|
|
549
|
+
for (const log of logs) {
|
|
550
|
+
if (log.status !== "completed" || !log.output) continue;
|
|
551
|
+
nodeOutputs[log.nodeId] = log.output;
|
|
552
|
+
if (log.nodeId === nodeId) {
|
|
553
|
+
input = log.inputArgs ?? {};
|
|
554
|
+
runId = log.runId;
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
return { input, nodeOutputs, workflowKey, version: workflowVersion, runId };
|
|
558
|
+
}, [logs, nodeId, workflowKey, workflowVersion]);
|
|
559
|
+
const hasPreviewData = Object.keys(previewScope.input).length > 0;
|
|
560
|
+
const [preview, setPreview] = useState(null);
|
|
561
|
+
useEffect(() => {
|
|
562
|
+
if (!nodeId || !value.trim()) {
|
|
563
|
+
setPreview(null);
|
|
564
|
+
return;
|
|
565
|
+
}
|
|
566
|
+
const timer = setTimeout(() => {
|
|
567
|
+
setPreview(evaluateExpressionPreview(value, previewScope));
|
|
568
|
+
}, 200);
|
|
569
|
+
return () => clearTimeout(timer);
|
|
570
|
+
}, [value, previewScope, nodeId]);
|
|
571
|
+
const previewText = useMemo(() => {
|
|
572
|
+
if (!preview) return null;
|
|
573
|
+
if (!preview.isTemplate) return null;
|
|
574
|
+
if (preview.error) return null;
|
|
575
|
+
if (preview.value === void 0) return "undefined";
|
|
576
|
+
if (typeof preview.value === "string") return preview.value;
|
|
577
|
+
try {
|
|
578
|
+
return JSON.stringify(preview.value);
|
|
579
|
+
} catch {
|
|
580
|
+
return String(preview.value);
|
|
581
|
+
}
|
|
582
|
+
}, [preview]);
|
|
263
583
|
return /* @__PURE__ */ jsxs("div", { className: cn("space-y-2", className), children: [
|
|
264
584
|
label && /* @__PURE__ */ jsx("label", { className: "text-sm font-medium text-foreground", children: label }),
|
|
265
585
|
/* @__PURE__ */ jsxs(
|
|
@@ -270,7 +590,7 @@ function ExpressionEditor({
|
|
|
270
590
|
isFocused && "ring-2 ring-primary ring-offset-1"
|
|
271
591
|
),
|
|
272
592
|
children: [
|
|
273
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 px-2 py-1.5 border-b bg-muted/30", children: [
|
|
593
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-1 px-2 py-1.5 border-b bg-muted/30", children: [
|
|
274
594
|
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground mr-2", children: tr("fluidgrids.builder.expressionEditor.insertLabel", "Insert:") }),
|
|
275
595
|
/* @__PURE__ */ jsx(
|
|
276
596
|
"button",
|
|
@@ -298,29 +618,97 @@ function ExpressionEditor({
|
|
|
298
618
|
className: "text-xs px-2 py-0.5 rounded bg-primary/10 text-primary hover:bg-primary/20 transition-colors",
|
|
299
619
|
children: "${WorkflowState}"
|
|
300
620
|
}
|
|
621
|
+
),
|
|
622
|
+
/* @__PURE__ */ jsx("span", { className: "mx-1 h-4 w-px bg-border", "aria-hidden": "true" }),
|
|
623
|
+
/* @__PURE__ */ jsx(
|
|
624
|
+
"button",
|
|
625
|
+
{
|
|
626
|
+
type: "button",
|
|
627
|
+
onClick: () => insertTemplate("{{ $json. }}"),
|
|
628
|
+
className: "text-xs px-2 py-0.5 rounded bg-secondary/40 text-secondary-foreground hover:bg-secondary/60 transition-colors",
|
|
629
|
+
children: "{{ $json }}"
|
|
630
|
+
}
|
|
301
631
|
)
|
|
302
632
|
] }),
|
|
303
|
-
/* @__PURE__ */
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
633
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
634
|
+
/* @__PURE__ */ jsx(
|
|
635
|
+
"textarea",
|
|
636
|
+
{
|
|
637
|
+
ref: editorRef,
|
|
638
|
+
value,
|
|
639
|
+
onChange: handleChange,
|
|
640
|
+
onKeyUp: (e) => {
|
|
641
|
+
const target = e.currentTarget;
|
|
642
|
+
setSuggestionsOpen(
|
|
643
|
+
openExpressionPrefix(target.value, target.selectionStart) !== null
|
|
644
|
+
);
|
|
645
|
+
},
|
|
646
|
+
onFocus: () => setIsFocused(true),
|
|
647
|
+
onBlur: () => {
|
|
648
|
+
setIsFocused(false);
|
|
649
|
+
setTimeout(() => setSuggestionsOpen(false), 150);
|
|
650
|
+
},
|
|
651
|
+
placeholder: placeholder ?? tr(
|
|
652
|
+
"fluidgrids.builder.expressionEditor.defaultPlaceholder",
|
|
653
|
+
"Enter expression..."
|
|
654
|
+
),
|
|
655
|
+
rows,
|
|
656
|
+
spellCheck: false,
|
|
657
|
+
className: cn(
|
|
658
|
+
"w-full p-3 font-mono text-sm bg-background resize-none",
|
|
659
|
+
"focus:outline-none",
|
|
660
|
+
"placeholder:text-muted-foreground/50"
|
|
661
|
+
)
|
|
662
|
+
}
|
|
663
|
+
),
|
|
664
|
+
suggestionsOpen && suggestions.length > 0 && /* @__PURE__ */ jsx(
|
|
665
|
+
"div",
|
|
666
|
+
{
|
|
667
|
+
className: "absolute z-20 left-2 right-2 top-full mt-1 rounded-md border bg-popover shadow-md overflow-hidden",
|
|
668
|
+
role: "listbox",
|
|
669
|
+
"aria-label": tr(
|
|
670
|
+
"fluidgrids.builder.expressionEditor.autocompleteLabel",
|
|
671
|
+
"Expression variable suggestions"
|
|
672
|
+
),
|
|
673
|
+
children: suggestions.map((s) => /* @__PURE__ */ jsxs(
|
|
674
|
+
"button",
|
|
675
|
+
{
|
|
676
|
+
type: "button",
|
|
677
|
+
role: "option",
|
|
678
|
+
"aria-selected": false,
|
|
679
|
+
onMouseDown: (e) => {
|
|
680
|
+
e.preventDefault();
|
|
681
|
+
applySuggestion(s.insert);
|
|
682
|
+
},
|
|
683
|
+
className: "flex w-full items-baseline gap-2 px-3 py-1.5 text-left hover:bg-accent",
|
|
684
|
+
children: [
|
|
685
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono text-xs text-primary", children: s.label }),
|
|
686
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground truncate", children: s.description })
|
|
687
|
+
]
|
|
688
|
+
},
|
|
689
|
+
s.insert
|
|
690
|
+
))
|
|
691
|
+
}
|
|
692
|
+
)
|
|
693
|
+
] }),
|
|
694
|
+
nodeId && value.trim() && /* @__PURE__ */ jsx("div", { className: "border-t bg-muted/20 px-3 py-1.5 text-xs", children: preview?.error ? /* @__PURE__ */ jsxs("span", { className: "text-destructive", children: [
|
|
695
|
+
tr(
|
|
696
|
+
"fluidgrids.builder.expressionEditor.previewError",
|
|
697
|
+
"Preview error:"
|
|
698
|
+
),
|
|
699
|
+
" ",
|
|
700
|
+
preview.error
|
|
701
|
+
] }) : previewText !== null ? /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
|
|
702
|
+
tr(
|
|
703
|
+
"fluidgrids.builder.expressionEditor.previewLabel",
|
|
704
|
+
"Preview:"
|
|
705
|
+
),
|
|
706
|
+
" ",
|
|
707
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono text-foreground", children: previewText })
|
|
708
|
+
] }) : !hasPreviewData ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/70 italic", children: tr(
|
|
709
|
+
"fluidgrids.builder.expressionEditor.previewNoData",
|
|
710
|
+
'Run "Execute step" on this node to preview real values.'
|
|
711
|
+
) }) : null })
|
|
324
712
|
]
|
|
325
713
|
}
|
|
326
714
|
),
|
|
@@ -4021,6 +4409,72 @@ function nodeAccent(key) {
|
|
|
4021
4409
|
function tint(hex, pct = 14) {
|
|
4022
4410
|
return `color-mix(in srgb, ${hex} ${pct}%, transparent)`;
|
|
4023
4411
|
}
|
|
4412
|
+
function InlineEditableLabel({
|
|
4413
|
+
value,
|
|
4414
|
+
placeholder,
|
|
4415
|
+
editing,
|
|
4416
|
+
onStartEdit,
|
|
4417
|
+
onCommit,
|
|
4418
|
+
onCancel,
|
|
4419
|
+
className,
|
|
4420
|
+
inputClassName
|
|
4421
|
+
}) {
|
|
4422
|
+
const tr = useTr();
|
|
4423
|
+
const [draft, setDraft] = React2.useState(value);
|
|
4424
|
+
const inputRef = React2.useRef(null);
|
|
4425
|
+
React2.useEffect(() => {
|
|
4426
|
+
if (!editing) return;
|
|
4427
|
+
setDraft(value);
|
|
4428
|
+
const raf = requestAnimationFrame(() => {
|
|
4429
|
+
inputRef.current?.focus();
|
|
4430
|
+
inputRef.current?.select();
|
|
4431
|
+
});
|
|
4432
|
+
return () => cancelAnimationFrame(raf);
|
|
4433
|
+
}, [editing, value]);
|
|
4434
|
+
if (editing) {
|
|
4435
|
+
return /* @__PURE__ */ jsx(
|
|
4436
|
+
"input",
|
|
4437
|
+
{
|
|
4438
|
+
ref: inputRef,
|
|
4439
|
+
value: draft,
|
|
4440
|
+
onChange: (e) => setDraft(e.target.value),
|
|
4441
|
+
onClick: (e) => e.stopPropagation(),
|
|
4442
|
+
onDoubleClick: (e) => e.stopPropagation(),
|
|
4443
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
4444
|
+
onKeyDown: (e) => {
|
|
4445
|
+
e.stopPropagation();
|
|
4446
|
+
if (e.key === "Enter") {
|
|
4447
|
+
e.preventDefault();
|
|
4448
|
+
onCommit(draft.trim());
|
|
4449
|
+
} else if (e.key === "Escape") {
|
|
4450
|
+
e.preventDefault();
|
|
4451
|
+
onCancel();
|
|
4452
|
+
}
|
|
4453
|
+
},
|
|
4454
|
+
onBlur: () => onCommit(draft.trim()),
|
|
4455
|
+
className: cn(
|
|
4456
|
+
"min-w-0 flex-1 rounded border border-primary/50 bg-card px-1 text-inherit outline-none",
|
|
4457
|
+
inputClassName
|
|
4458
|
+
)
|
|
4459
|
+
}
|
|
4460
|
+
);
|
|
4461
|
+
}
|
|
4462
|
+
return /* @__PURE__ */ jsx(
|
|
4463
|
+
"span",
|
|
4464
|
+
{
|
|
4465
|
+
className: cn("cursor-text truncate", className),
|
|
4466
|
+
title: tr(
|
|
4467
|
+
"fluidgrids.builder.nodeCard.renameTooltip",
|
|
4468
|
+
"Double-click or press F2 to rename"
|
|
4469
|
+
),
|
|
4470
|
+
onDoubleClick: (e) => {
|
|
4471
|
+
e.stopPropagation();
|
|
4472
|
+
onStartEdit();
|
|
4473
|
+
},
|
|
4474
|
+
children: value || placeholder
|
|
4475
|
+
}
|
|
4476
|
+
);
|
|
4477
|
+
}
|
|
4024
4478
|
var NodeCard = React2.forwardRef(
|
|
4025
4479
|
({
|
|
4026
4480
|
className,
|
|
@@ -4034,6 +4488,8 @@ var NodeCard = React2.forwardRef(
|
|
|
4034
4488
|
onDelete,
|
|
4035
4489
|
isExecuting = false,
|
|
4036
4490
|
infoButton,
|
|
4491
|
+
disabled = false,
|
|
4492
|
+
onToggleDisabled,
|
|
4037
4493
|
children,
|
|
4038
4494
|
...props
|
|
4039
4495
|
}, ref) => {
|
|
@@ -4052,7 +4508,7 @@ var NodeCard = React2.forwardRef(
|
|
|
4052
4508
|
" ",
|
|
4053
4509
|
itemCount !== 1 ? tr("fluidgrids.builder.nodeCard.itemCountOther", "items") : tr("fluidgrids.builder.nodeCard.itemCountOne", "item")
|
|
4054
4510
|
] }) }),
|
|
4055
|
-
(onSettings || onExecute || onDelete || infoButton) && /* @__PURE__ */ jsxs(
|
|
4511
|
+
(onSettings || onExecute || onDelete || onToggleDisabled || infoButton) && /* @__PURE__ */ jsxs(
|
|
4056
4512
|
"div",
|
|
4057
4513
|
{
|
|
4058
4514
|
className: cn(
|
|
@@ -4106,6 +4562,29 @@ var NodeCard = React2.forwardRef(
|
|
|
4106
4562
|
}
|
|
4107
4563
|
),
|
|
4108
4564
|
infoButton,
|
|
4565
|
+
onToggleDisabled && /* @__PURE__ */ jsx(
|
|
4566
|
+
ToolbarButton2,
|
|
4567
|
+
{
|
|
4568
|
+
title: disabled ? tr(
|
|
4569
|
+
"fluidgrids.builder.nodeCard.enableTooltip",
|
|
4570
|
+
"Enable node"
|
|
4571
|
+
) : tr(
|
|
4572
|
+
"fluidgrids.builder.nodeCard.disableTooltip",
|
|
4573
|
+
"Disable node (skip on run)"
|
|
4574
|
+
),
|
|
4575
|
+
onClick: onToggleDisabled,
|
|
4576
|
+
children: /* @__PURE__ */ jsx(
|
|
4577
|
+
Icon,
|
|
4578
|
+
{
|
|
4579
|
+
icon: disabled ? "mdi:power" : "mdi:power-off",
|
|
4580
|
+
className: cn(
|
|
4581
|
+
"size-4",
|
|
4582
|
+
disabled ? "text-[var(--color-status-warning-text)]" : "text-muted-foreground"
|
|
4583
|
+
)
|
|
4584
|
+
}
|
|
4585
|
+
)
|
|
4586
|
+
}
|
|
4587
|
+
),
|
|
4109
4588
|
onDelete && /* @__PURE__ */ jsx(
|
|
4110
4589
|
ToolbarButton2,
|
|
4111
4590
|
{
|
|
@@ -4126,6 +4605,10 @@ var NodeCard = React2.forwardRef(
|
|
|
4126
4605
|
]
|
|
4127
4606
|
}
|
|
4128
4607
|
),
|
|
4608
|
+
disabled && /* @__PURE__ */ jsx("div", { className: "absolute -top-2 right-2 z-10", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 rounded-full border border-[var(--color-status-warning-border)] bg-[var(--color-status-warning-bg)] px-1.5 py-0.5 text-[9px] font-semibold uppercase tracking-wide text-[var(--color-status-warning-text)] shadow-sm", children: [
|
|
4609
|
+
/* @__PURE__ */ jsx(Icon, { icon: "mdi:power-off", className: "size-2.5" }),
|
|
4610
|
+
tr("fluidgrids.builder.nodeCard.disabledBadge", "Disabled")
|
|
4611
|
+
] }) }),
|
|
4129
4612
|
/* @__PURE__ */ jsxs(
|
|
4130
4613
|
"div",
|
|
4131
4614
|
{
|
|
@@ -4135,6 +4618,7 @@ var NodeCard = React2.forwardRef(
|
|
|
4135
4618
|
"relative w-72 rounded-xl border border-border bg-card shadow-sm will-change-transform",
|
|
4136
4619
|
statusRing,
|
|
4137
4620
|
executionStatus === "success" && "animate-success-glow",
|
|
4621
|
+
disabled && "opacity-50 grayscale-[0.6]",
|
|
4138
4622
|
className
|
|
4139
4623
|
),
|
|
4140
4624
|
style: {
|
|
@@ -4221,7 +4705,17 @@ function StatusCorner({
|
|
|
4221
4705
|
) });
|
|
4222
4706
|
}
|
|
4223
4707
|
var NodeCardHeader = React2.forwardRef(
|
|
4224
|
-
({
|
|
4708
|
+
({
|
|
4709
|
+
icon,
|
|
4710
|
+
appName,
|
|
4711
|
+
accentKey,
|
|
4712
|
+
missingCredentials = false,
|
|
4713
|
+
label,
|
|
4714
|
+
isRenaming = false,
|
|
4715
|
+
onStartRename,
|
|
4716
|
+
onCommitRename,
|
|
4717
|
+
onCancelRename
|
|
4718
|
+
}, ref) => {
|
|
4225
4719
|
const tr = useTr();
|
|
4226
4720
|
const accent = nodeAccent(accentKey);
|
|
4227
4721
|
return /* @__PURE__ */ jsxs("div", { ref, className: "flex items-center gap-2.5 px-3 pb-3 pt-4", children: [
|
|
@@ -4237,7 +4731,19 @@ var NodeCardHeader = React2.forwardRef(
|
|
|
4237
4731
|
children: /* @__PURE__ */ jsx(NodeTypeIcon, { icon, alt: appName, className: "size-[18px]" })
|
|
4238
4732
|
}
|
|
4239
4733
|
),
|
|
4240
|
-
/* @__PURE__ */ jsx(
|
|
4734
|
+
onStartRename && onCommitRename && onCancelRename ? /* @__PURE__ */ jsx(
|
|
4735
|
+
InlineEditableLabel,
|
|
4736
|
+
{
|
|
4737
|
+
value: label ?? "",
|
|
4738
|
+
placeholder: appName,
|
|
4739
|
+
editing: isRenaming,
|
|
4740
|
+
onStartEdit: onStartRename,
|
|
4741
|
+
onCommit: onCommitRename,
|
|
4742
|
+
onCancel: onCancelRename,
|
|
4743
|
+
className: "min-w-0 flex-1 truncate text-[11px] font-semibold uppercase tracking-wide text-muted-foreground",
|
|
4744
|
+
inputClassName: "text-[11px] font-semibold uppercase tracking-wide"
|
|
4745
|
+
}
|
|
4746
|
+
) : /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: label || appName }),
|
|
4241
4747
|
missingCredentials && /* @__PURE__ */ jsx(
|
|
4242
4748
|
"span",
|
|
4243
4749
|
{
|
|
@@ -4607,7 +5113,13 @@ function LogicNodeCard({
|
|
|
4607
5113
|
onSettings,
|
|
4608
5114
|
onExecute,
|
|
4609
5115
|
onDelete,
|
|
4610
|
-
infoButton
|
|
5116
|
+
infoButton,
|
|
5117
|
+
disabled = false,
|
|
5118
|
+
onToggleDisabled,
|
|
5119
|
+
isRenaming = false,
|
|
5120
|
+
onStartRename,
|
|
5121
|
+
onCommitRename,
|
|
5122
|
+
onCancelRename
|
|
4611
5123
|
}) {
|
|
4612
5124
|
const minHeight = Math.max(
|
|
4613
5125
|
64,
|
|
@@ -4630,6 +5142,8 @@ function LogicNodeCard({
|
|
|
4630
5142
|
onExecute,
|
|
4631
5143
|
onDelete,
|
|
4632
5144
|
infoButton,
|
|
5145
|
+
disabled,
|
|
5146
|
+
onToggleDisabled,
|
|
4633
5147
|
children: [
|
|
4634
5148
|
/* @__PURE__ */ jsxs(
|
|
4635
5149
|
"div",
|
|
@@ -4638,7 +5152,19 @@ function LogicNodeCard({
|
|
|
4638
5152
|
style: { minHeight },
|
|
4639
5153
|
children: [
|
|
4640
5154
|
/* @__PURE__ */ jsx("div", { className: "flex size-9 items-center justify-center rounded-lg bg-muted", children: /* @__PURE__ */ jsx(Icon, { icon, className: "size-5", style: { color: accent } }) }),
|
|
4641
|
-
/* @__PURE__ */ jsx(
|
|
5155
|
+
onStartRename && onCommitRename && onCancelRename ? /* @__PURE__ */ jsx(
|
|
5156
|
+
InlineEditableLabel,
|
|
5157
|
+
{
|
|
5158
|
+
value: title,
|
|
5159
|
+
placeholder: title,
|
|
5160
|
+
editing: isRenaming,
|
|
5161
|
+
onStartEdit: onStartRename,
|
|
5162
|
+
onCommit: onCommitRename,
|
|
5163
|
+
onCancel: onCancelRename,
|
|
5164
|
+
className: "max-w-full truncate text-sm font-semibold leading-tight",
|
|
5165
|
+
inputClassName: "text-sm font-semibold text-center"
|
|
5166
|
+
}
|
|
5167
|
+
) : /* @__PURE__ */ jsx("span", { className: "max-w-full truncate text-sm font-semibold leading-tight", children: title }),
|
|
4642
5168
|
subtitle && /* @__PURE__ */ jsx(
|
|
4643
5169
|
"span",
|
|
4644
5170
|
{
|
|
@@ -5927,14 +6453,24 @@ var getNodeMetadata = (value) => {
|
|
|
5927
6453
|
executingNodeId,
|
|
5928
6454
|
nodeStatuses,
|
|
5929
6455
|
nodeItemCounts,
|
|
5930
|
-
zustandSetNodes
|
|
6456
|
+
zustandSetNodes,
|
|
6457
|
+
renamingNodeId,
|
|
6458
|
+
toggleNodeDisabled,
|
|
6459
|
+
renameNode,
|
|
6460
|
+
startRename,
|
|
6461
|
+
endRename
|
|
5931
6462
|
] = useFlowStore(
|
|
5932
6463
|
useShallow((s) => [
|
|
5933
6464
|
s.execution.isExecuting,
|
|
5934
6465
|
s.execution.executingNodeId,
|
|
5935
6466
|
s.execution.nodeStatuses,
|
|
5936
6467
|
s.execution.nodeItemCounts,
|
|
5937
|
-
s.actions.nodes.setNodes
|
|
6468
|
+
s.actions.nodes.setNodes,
|
|
6469
|
+
s.workflow.renamingNodeId,
|
|
6470
|
+
s.actions.nodes.toggleDisabled,
|
|
6471
|
+
s.actions.nodes.renameNode,
|
|
6472
|
+
s.actions.nodes.startRename,
|
|
6473
|
+
s.actions.nodes.endRename
|
|
5938
6474
|
])
|
|
5939
6475
|
);
|
|
5940
6476
|
useEffect(() => {
|
|
@@ -5958,6 +6494,22 @@ var getNodeMetadata = (value) => {
|
|
|
5958
6494
|
const handleDeleteNode = () => {
|
|
5959
6495
|
deleteNode(id);
|
|
5960
6496
|
};
|
|
6497
|
+
const handleToggleDisabled = useCallback(() => {
|
|
6498
|
+
toggleNodeDisabled(id);
|
|
6499
|
+
}, [id, toggleNodeDisabled]);
|
|
6500
|
+
const isRenamingThisNode = renamingNodeId === id;
|
|
6501
|
+
const handleStartRename = useCallback(() => {
|
|
6502
|
+
startRename(id);
|
|
6503
|
+
}, [id, startRename]);
|
|
6504
|
+
const handleCommitRename = useCallback(
|
|
6505
|
+
(value2) => {
|
|
6506
|
+
renameNode(id, value2);
|
|
6507
|
+
},
|
|
6508
|
+
[id, renameNode]
|
|
6509
|
+
);
|
|
6510
|
+
const handleCancelRename = useCallback(() => {
|
|
6511
|
+
endRename();
|
|
6512
|
+
}, [endRename]);
|
|
5961
6513
|
const openNdv = useFlowStore((s) => s.actions.ndv.open);
|
|
5962
6514
|
const openQuickConfig = useFlowStore((s) => s.actions.quickConfig.open);
|
|
5963
6515
|
const clickTimerRef = useRef(null);
|
|
@@ -6020,6 +6572,8 @@ var getNodeMetadata = (value) => {
|
|
|
6020
6572
|
const nodeStatus = nodeStatuses[id] || "idle";
|
|
6021
6573
|
const executionStatus = nodeStatus === "success" ? "success" : nodeStatus === "error" ? "error" : nodeStatus === "running" ? "running" : "idle";
|
|
6022
6574
|
const itemCount = nodeItemCounts[id];
|
|
6575
|
+
const isDisabled = data?.disabled === true;
|
|
6576
|
+
const nodeLabel = data?.label || "";
|
|
6023
6577
|
const nodeKinds = data?.nodeData?.kind;
|
|
6024
6578
|
const pinnedOpType = (data?.operation_type || "").toLowerCase();
|
|
6025
6579
|
const isTrigger = pinnedOpType === "trigger" || (value?.type || "").toLowerCase().includes("trigger") || // Kind-based detection only when NO operation is pinned: dual-role
|
|
@@ -6084,7 +6638,13 @@ var getNodeMetadata = (value) => {
|
|
|
6084
6638
|
onSettings: handleOpenNdv,
|
|
6085
6639
|
onExecute: handleExecuteStep,
|
|
6086
6640
|
onDelete: handleDeleteNode,
|
|
6087
|
-
infoButton: /* @__PURE__ */ jsx(NodeInfoButtonWithModal, { metadata: nodeInfoMetadata })
|
|
6641
|
+
infoButton: /* @__PURE__ */ jsx(NodeInfoButtonWithModal, { metadata: nodeInfoMetadata }),
|
|
6642
|
+
disabled: isDisabled,
|
|
6643
|
+
onToggleDisabled: handleToggleDisabled,
|
|
6644
|
+
isRenaming: isRenamingThisNode,
|
|
6645
|
+
onStartRename: handleStartRename,
|
|
6646
|
+
onCommitRename: handleCommitRename,
|
|
6647
|
+
onCancelRename: handleCancelRename
|
|
6088
6648
|
}
|
|
6089
6649
|
),
|
|
6090
6650
|
/* @__PURE__ */ jsx(
|
|
@@ -6113,6 +6673,8 @@ var getNodeMetadata = (value) => {
|
|
|
6113
6673
|
onExecute: handleExecuteStep,
|
|
6114
6674
|
onDelete: handleDeleteNode,
|
|
6115
6675
|
infoButton: /* @__PURE__ */ jsx(NodeInfoButtonWithModal, { metadata: nodeInfoMetadata }),
|
|
6676
|
+
disabled: isDisabled,
|
|
6677
|
+
onToggleDisabled: handleToggleDisabled,
|
|
6116
6678
|
children: [
|
|
6117
6679
|
/* @__PURE__ */ jsx(
|
|
6118
6680
|
NodeCardHeader,
|
|
@@ -6120,7 +6682,12 @@ var getNodeMetadata = (value) => {
|
|
|
6120
6682
|
icon: meta.icon,
|
|
6121
6683
|
appName,
|
|
6122
6684
|
accentKey: value?.type || meta.title,
|
|
6123
|
-
missingCredentials
|
|
6685
|
+
missingCredentials,
|
|
6686
|
+
label: nodeLabel,
|
|
6687
|
+
isRenaming: isRenamingThisNode,
|
|
6688
|
+
onStartRename: handleStartRename,
|
|
6689
|
+
onCommitRename: handleCommitRename,
|
|
6690
|
+
onCancelRename: handleCancelRename
|
|
6124
6691
|
}
|
|
6125
6692
|
),
|
|
6126
6693
|
operationDisplay === "execute" && (value?.type || "").startsWith("internal:") || isTrigger ? (
|
|
@@ -13819,7 +14386,7 @@ var DEFAULT_CONFIG = {
|
|
|
13819
14386
|
maxTemplateLength: 1e4,
|
|
13820
14387
|
debug: false
|
|
13821
14388
|
};
|
|
13822
|
-
var
|
|
14389
|
+
var SAFE_GLOBALS2 = {
|
|
13823
14390
|
// Type conversion
|
|
13824
14391
|
parseInt,
|
|
13825
14392
|
parseFloat,
|
|
@@ -13866,7 +14433,7 @@ function parseTemplate(template) {
|
|
|
13866
14433
|
}
|
|
13867
14434
|
function buildSandbox(scope) {
|
|
13868
14435
|
return {
|
|
13869
|
-
...
|
|
14436
|
+
...SAFE_GLOBALS2,
|
|
13870
14437
|
output: scope.output,
|
|
13871
14438
|
TriggerInput: scope.TriggerInput,
|
|
13872
14439
|
WorkflowState: scope.WorkflowState,
|
|
@@ -17518,6 +18085,10 @@ function CustomDeletableEdge(props) {
|
|
|
17518
18085
|
const nodeStatuses = useFlowStore(
|
|
17519
18086
|
useShallow((s) => s.execution.nodeStatuses)
|
|
17520
18087
|
);
|
|
18088
|
+
const nodeItemCounts = useFlowStore(
|
|
18089
|
+
useShallow((s) => s.execution.nodeItemCounts)
|
|
18090
|
+
);
|
|
18091
|
+
const sourceItemCount = nodeItemCounts[source];
|
|
17521
18092
|
const sourceNodeStatus = nodeStatuses[source] || "idle";
|
|
17522
18093
|
const isRunning = sourceNodeStatus === "running";
|
|
17523
18094
|
const isSuccess = sourceNodeStatus === "success";
|
|
@@ -18417,6 +18988,26 @@ function CustomDeletableEdge(props) {
|
|
|
18417
18988
|
}
|
|
18418
18989
|
),
|
|
18419
18990
|
/* @__PURE__ */ jsxs(EdgeLabelRenderer, { children: [
|
|
18991
|
+
sourceItemCount !== void 0 && sourceItemCount > 0 && /* @__PURE__ */ jsx(
|
|
18992
|
+
"div",
|
|
18993
|
+
{
|
|
18994
|
+
className: "pointer-events-none absolute z-[999]",
|
|
18995
|
+
style: {
|
|
18996
|
+
transform: `translate(${labelX}px, ${labelY}px) translate(-50%, -100%) translateY(-10px)`
|
|
18997
|
+
},
|
|
18998
|
+
children: /* @__PURE__ */ jsxs("div", { className: "rounded-full border border-border bg-card px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground shadow-sm", children: [
|
|
18999
|
+
sourceItemCount,
|
|
19000
|
+
" ",
|
|
19001
|
+
sourceItemCount !== 1 ? tr(
|
|
19002
|
+
"fluidgrids.builder.edges.customDeletableEdge.itemCountOther",
|
|
19003
|
+
"items"
|
|
19004
|
+
) : tr(
|
|
19005
|
+
"fluidgrids.builder.edges.customDeletableEdge.itemCountOne",
|
|
19006
|
+
"item"
|
|
19007
|
+
)
|
|
19008
|
+
] })
|
|
19009
|
+
}
|
|
19010
|
+
),
|
|
18420
19011
|
/* @__PURE__ */ jsxs(
|
|
18421
19012
|
"div",
|
|
18422
19013
|
{
|
|
@@ -18809,6 +19400,276 @@ function computeMinimapRect(panelRect, bounds, margin) {
|
|
|
18809
19400
|
top = Math.min(Math.max(top, bounds.top + margin), maxTop);
|
|
18810
19401
|
return { left, top };
|
|
18811
19402
|
}
|
|
19403
|
+
var SHORTCUT_ROWS = [
|
|
19404
|
+
{
|
|
19405
|
+
labelKey: "fluidgrids.builder.shortcutsHelp.undo",
|
|
19406
|
+
labelDefault: "Undo",
|
|
19407
|
+
mac: "\u2318Z",
|
|
19408
|
+
other: "Ctrl+Z"
|
|
19409
|
+
},
|
|
19410
|
+
{
|
|
19411
|
+
labelKey: "fluidgrids.builder.shortcutsHelp.redo",
|
|
19412
|
+
labelDefault: "Redo",
|
|
19413
|
+
mac: "\u2318\u21E7Z",
|
|
19414
|
+
other: "Ctrl+Shift+Z / Ctrl+Y"
|
|
19415
|
+
},
|
|
19416
|
+
{
|
|
19417
|
+
labelKey: "fluidgrids.builder.shortcutsHelp.copy",
|
|
19418
|
+
labelDefault: "Copy selected node(s)",
|
|
19419
|
+
mac: "\u2318C",
|
|
19420
|
+
other: "Ctrl+C"
|
|
19421
|
+
},
|
|
19422
|
+
{
|
|
19423
|
+
labelKey: "fluidgrids.builder.shortcutsHelp.cut",
|
|
19424
|
+
labelDefault: "Cut selected node(s)",
|
|
19425
|
+
mac: "\u2318X",
|
|
19426
|
+
other: "Ctrl+X"
|
|
19427
|
+
},
|
|
19428
|
+
{
|
|
19429
|
+
labelKey: "fluidgrids.builder.shortcutsHelp.paste",
|
|
19430
|
+
labelDefault: "Paste \u2014 works across workflows/tabs",
|
|
19431
|
+
mac: "\u2318V",
|
|
19432
|
+
other: "Ctrl+V"
|
|
19433
|
+
},
|
|
19434
|
+
{
|
|
19435
|
+
labelKey: "fluidgrids.builder.shortcutsHelp.duplicate",
|
|
19436
|
+
labelDefault: "Duplicate selected node(s)",
|
|
19437
|
+
mac: "\u2318D",
|
|
19438
|
+
other: "Ctrl+D"
|
|
19439
|
+
},
|
|
19440
|
+
{
|
|
19441
|
+
labelKey: "fluidgrids.builder.shortcutsHelp.delete",
|
|
19442
|
+
labelDefault: "Delete selected node(s)/connection(s)",
|
|
19443
|
+
mac: "\u232B / Delete",
|
|
19444
|
+
other: "Backspace / Delete"
|
|
19445
|
+
},
|
|
19446
|
+
{
|
|
19447
|
+
labelKey: "fluidgrids.builder.shortcutsHelp.rename",
|
|
19448
|
+
labelDefault: "Rename the selected node",
|
|
19449
|
+
mac: "F2 or double-click its title",
|
|
19450
|
+
other: "F2 or double-click its title"
|
|
19451
|
+
},
|
|
19452
|
+
{
|
|
19453
|
+
labelKey: "fluidgrids.builder.shortcutsHelp.multiSelectClick",
|
|
19454
|
+
labelDefault: "Add a node to the selection",
|
|
19455
|
+
mac: "\u2318-click / \u2303-click",
|
|
19456
|
+
other: "Ctrl-click"
|
|
19457
|
+
},
|
|
19458
|
+
{
|
|
19459
|
+
labelKey: "fluidgrids.builder.shortcutsHelp.multiSelectBox",
|
|
19460
|
+
labelDefault: "Box-select multiple nodes",
|
|
19461
|
+
mac: "\u21E7-drag on empty canvas",
|
|
19462
|
+
other: "Shift-drag on empty canvas"
|
|
19463
|
+
},
|
|
19464
|
+
{
|
|
19465
|
+
labelKey: "fluidgrids.builder.shortcutsHelp.stickyNote",
|
|
19466
|
+
labelDefault: "Add a sticky note",
|
|
19467
|
+
mac: "\u21E7S",
|
|
19468
|
+
other: "Shift+S"
|
|
19469
|
+
},
|
|
19470
|
+
{
|
|
19471
|
+
labelKey: "fluidgrids.builder.shortcutsHelp.cancel",
|
|
19472
|
+
labelDefault: "Close a panel / cancel an edit",
|
|
19473
|
+
mac: "Esc",
|
|
19474
|
+
other: "Esc"
|
|
19475
|
+
},
|
|
19476
|
+
{
|
|
19477
|
+
labelKey: "fluidgrids.builder.shortcutsHelp.help",
|
|
19478
|
+
labelDefault: "Open this shortcuts panel",
|
|
19479
|
+
mac: "?",
|
|
19480
|
+
other: "?"
|
|
19481
|
+
}
|
|
19482
|
+
];
|
|
19483
|
+
function Kbd({ children }) {
|
|
19484
|
+
return /* @__PURE__ */ jsx("kbd", { className: "rounded border border-border bg-muted px-1.5 py-0.5 font-mono text-[11px] font-medium text-muted-foreground", children });
|
|
19485
|
+
}
|
|
19486
|
+
function ShortcutsHelpPanel({
|
|
19487
|
+
open,
|
|
19488
|
+
onOpenChange
|
|
19489
|
+
}) {
|
|
19490
|
+
const tr = useTr();
|
|
19491
|
+
const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform ?? "");
|
|
19492
|
+
return /* @__PURE__ */ jsx(Dialog$1, { open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent$1, { className: "max-w-lg", children: [
|
|
19493
|
+
/* @__PURE__ */ jsxs(DialogHeader$1, { children: [
|
|
19494
|
+
/* @__PURE__ */ jsx(DialogTitle$1, { children: tr("fluidgrids.builder.shortcutsHelp.title", "Keyboard shortcuts") }),
|
|
19495
|
+
/* @__PURE__ */ jsx(DialogDescription$1, { children: tr(
|
|
19496
|
+
"fluidgrids.builder.shortcutsHelp.description",
|
|
19497
|
+
"Speed up editing the workflow canvas."
|
|
19498
|
+
) })
|
|
19499
|
+
] }),
|
|
19500
|
+
/* @__PURE__ */ jsx("div", { className: "max-h-[60vh] space-y-0.5 overflow-y-auto pr-1", children: SHORTCUT_ROWS.map((row) => /* @__PURE__ */ jsxs(
|
|
19501
|
+
"div",
|
|
19502
|
+
{
|
|
19503
|
+
className: "flex items-center justify-between gap-4 rounded-md px-2 py-1.5 text-sm hover:bg-muted/50",
|
|
19504
|
+
children: [
|
|
19505
|
+
/* @__PURE__ */ jsx("span", { className: "text-foreground/80", children: tr(row.labelKey, row.labelDefault) }),
|
|
19506
|
+
/* @__PURE__ */ jsx(Kbd, { children: isMac ? row.mac : row.other })
|
|
19507
|
+
]
|
|
19508
|
+
},
|
|
19509
|
+
row.labelKey
|
|
19510
|
+
)) })
|
|
19511
|
+
] }) });
|
|
19512
|
+
}
|
|
19513
|
+
|
|
19514
|
+
// src/builder/lib/clipboard-payload.ts
|
|
19515
|
+
var CLIPBOARD_MARKER = "fluidgrids/flow-clipboard@1";
|
|
19516
|
+
function buildClipboardPayload(nodes, edges) {
|
|
19517
|
+
const selected = nodes.filter((n) => n.selected);
|
|
19518
|
+
const idSet = new Set(selected.map((n) => n.id));
|
|
19519
|
+
const internalEdges = edges.filter(
|
|
19520
|
+
(e) => idSet.has(e.source) && idSet.has(e.target)
|
|
19521
|
+
);
|
|
19522
|
+
return { marker: CLIPBOARD_MARKER, nodes: selected, edges: internalEdges };
|
|
19523
|
+
}
|
|
19524
|
+
function parseClipboardPayload(text) {
|
|
19525
|
+
if (!text) return null;
|
|
19526
|
+
let parsed;
|
|
19527
|
+
try {
|
|
19528
|
+
parsed = JSON.parse(text);
|
|
19529
|
+
} catch {
|
|
19530
|
+
return null;
|
|
19531
|
+
}
|
|
19532
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
19533
|
+
const rec = parsed;
|
|
19534
|
+
if (rec.marker !== CLIPBOARD_MARKER || !Array.isArray(rec.nodes)) {
|
|
19535
|
+
return null;
|
|
19536
|
+
}
|
|
19537
|
+
return {
|
|
19538
|
+
marker: CLIPBOARD_MARKER,
|
|
19539
|
+
nodes: rec.nodes,
|
|
19540
|
+
edges: Array.isArray(rec.edges) ? rec.edges : []
|
|
19541
|
+
};
|
|
19542
|
+
}
|
|
19543
|
+
|
|
19544
|
+
// src/builder/hooks/use-flow-clipboard.ts
|
|
19545
|
+
function useFlowClipboard() {
|
|
19546
|
+
const { getNodes, getEdges } = useReactFlow();
|
|
19547
|
+
const pasteNodes = useFlowStore((s) => s.actions.nodes.pasteNodes);
|
|
19548
|
+
const deleteNodes = useFlowStore((s) => s.actions.nodes.deleteNodes);
|
|
19549
|
+
const copySelection = useCallback(async () => {
|
|
19550
|
+
const payload = buildClipboardPayload(getNodes(), getEdges());
|
|
19551
|
+
if (payload.nodes.length === 0) return false;
|
|
19552
|
+
try {
|
|
19553
|
+
await navigator.clipboard.writeText(JSON.stringify(payload));
|
|
19554
|
+
return true;
|
|
19555
|
+
} catch {
|
|
19556
|
+
return false;
|
|
19557
|
+
}
|
|
19558
|
+
}, [getNodes, getEdges]);
|
|
19559
|
+
const cutSelection = useCallback(async () => {
|
|
19560
|
+
const selected = getNodes().filter((n) => n.selected);
|
|
19561
|
+
if (selected.length === 0) return false;
|
|
19562
|
+
const copied = await copySelection();
|
|
19563
|
+
if (!copied) return false;
|
|
19564
|
+
deleteNodes(selected);
|
|
19565
|
+
return true;
|
|
19566
|
+
}, [copySelection, deleteNodes, getNodes]);
|
|
19567
|
+
const pasteFromClipboard = useCallback(async () => {
|
|
19568
|
+
let text;
|
|
19569
|
+
try {
|
|
19570
|
+
text = await navigator.clipboard.readText();
|
|
19571
|
+
} catch {
|
|
19572
|
+
return false;
|
|
19573
|
+
}
|
|
19574
|
+
const payload = parseClipboardPayload(text);
|
|
19575
|
+
if (!payload || payload.nodes.length === 0) return false;
|
|
19576
|
+
pasteNodes({ nodes: payload.nodes, edges: payload.edges });
|
|
19577
|
+
return true;
|
|
19578
|
+
}, [pasteNodes]);
|
|
19579
|
+
return { copySelection, cutSelection, pasteFromClipboard };
|
|
19580
|
+
}
|
|
19581
|
+
|
|
19582
|
+
// src/builder/hooks/use-editor-shortcuts.ts
|
|
19583
|
+
function isEditableTarget(target) {
|
|
19584
|
+
const el = target;
|
|
19585
|
+
if (!el) return false;
|
|
19586
|
+
return el.tagName === "INPUT" || el.tagName === "TEXTAREA" || el.tagName === "SELECT" || el.isContentEditable;
|
|
19587
|
+
}
|
|
19588
|
+
function hasTextSelection() {
|
|
19589
|
+
const sel = typeof window !== "undefined" ? window.getSelection?.() : null;
|
|
19590
|
+
return !!sel && sel.toString().length > 0;
|
|
19591
|
+
}
|
|
19592
|
+
function useEditorShortcuts(options) {
|
|
19593
|
+
const readOnly = options?.readOnly ?? false;
|
|
19594
|
+
const onOpenHelp = options?.onOpenHelp;
|
|
19595
|
+
const { getNodes } = useReactFlow();
|
|
19596
|
+
const undo = useFlowStore((s) => s.actions.history.undo);
|
|
19597
|
+
const redo = useFlowStore((s) => s.actions.history.redo);
|
|
19598
|
+
const duplicateNodes = useFlowStore((s) => s.actions.nodes.duplicateNodes);
|
|
19599
|
+
const startRename = useFlowStore((s) => s.actions.nodes.startRename);
|
|
19600
|
+
const { copySelection, cutSelection, pasteFromClipboard } = useFlowClipboard();
|
|
19601
|
+
const insertStickyNote = useInsertStickyNote();
|
|
19602
|
+
useEffect(() => {
|
|
19603
|
+
if (readOnly) return;
|
|
19604
|
+
const onKeyDown = (e) => {
|
|
19605
|
+
const editable = isEditableTarget(e.target);
|
|
19606
|
+
const mod = e.metaKey || e.ctrlKey;
|
|
19607
|
+
if (!mod && !e.altKey && e.shiftKey && e.key.toLowerCase() === "s" && !editable) {
|
|
19608
|
+
e.preventDefault();
|
|
19609
|
+
insertStickyNote();
|
|
19610
|
+
return;
|
|
19611
|
+
}
|
|
19612
|
+
if (!mod && !editable && onOpenHelp && (e.key === "?" || e.shiftKey && e.key === "/")) {
|
|
19613
|
+
e.preventDefault();
|
|
19614
|
+
onOpenHelp();
|
|
19615
|
+
return;
|
|
19616
|
+
}
|
|
19617
|
+
if (!mod && !editable && e.key === "F2") {
|
|
19618
|
+
const selected = getNodes().filter((n) => n.selected);
|
|
19619
|
+
if (selected.length === 1 && selected[0]) {
|
|
19620
|
+
e.preventDefault();
|
|
19621
|
+
startRename(selected[0].id);
|
|
19622
|
+
}
|
|
19623
|
+
return;
|
|
19624
|
+
}
|
|
19625
|
+
if (!mod || editable) return;
|
|
19626
|
+
const key = e.key.toLowerCase();
|
|
19627
|
+
if (key === "z") {
|
|
19628
|
+
e.preventDefault();
|
|
19629
|
+
if (e.shiftKey) redo();
|
|
19630
|
+
else undo();
|
|
19631
|
+
return;
|
|
19632
|
+
}
|
|
19633
|
+
if (key === "y") {
|
|
19634
|
+
e.preventDefault();
|
|
19635
|
+
redo();
|
|
19636
|
+
return;
|
|
19637
|
+
}
|
|
19638
|
+
if ((key === "c" || key === "x") && !hasTextSelection()) {
|
|
19639
|
+
const hasSelection = getNodes().some((n) => n.selected);
|
|
19640
|
+
if (!hasSelection) return;
|
|
19641
|
+
e.preventDefault();
|
|
19642
|
+
void (key === "c" ? copySelection() : cutSelection());
|
|
19643
|
+
return;
|
|
19644
|
+
}
|
|
19645
|
+
if (key === "v") {
|
|
19646
|
+
e.preventDefault();
|
|
19647
|
+
void pasteFromClipboard();
|
|
19648
|
+
return;
|
|
19649
|
+
}
|
|
19650
|
+
if (key === "d") {
|
|
19651
|
+
const selectedIds = getNodes().filter((n) => n.selected).map((n) => n.id);
|
|
19652
|
+
if (selectedIds.length === 0) return;
|
|
19653
|
+
e.preventDefault();
|
|
19654
|
+
duplicateNodes(selectedIds);
|
|
19655
|
+
}
|
|
19656
|
+
};
|
|
19657
|
+
window.addEventListener("keydown", onKeyDown);
|
|
19658
|
+
return () => window.removeEventListener("keydown", onKeyDown);
|
|
19659
|
+
}, [
|
|
19660
|
+
readOnly,
|
|
19661
|
+
getNodes,
|
|
19662
|
+
undo,
|
|
19663
|
+
redo,
|
|
19664
|
+
duplicateNodes,
|
|
19665
|
+
startRename,
|
|
19666
|
+
copySelection,
|
|
19667
|
+
cutSelection,
|
|
19668
|
+
pasteFromClipboard,
|
|
19669
|
+
insertStickyNote,
|
|
19670
|
+
onOpenHelp
|
|
19671
|
+
]);
|
|
19672
|
+
}
|
|
18812
19673
|
var ZOOM_DURATION = 500;
|
|
18813
19674
|
var NODE_WIDTH = 220;
|
|
18814
19675
|
var NODE_HEIGHT = 80;
|
|
@@ -18869,6 +19730,7 @@ function CanvasControls() {
|
|
|
18869
19730
|
const isReadOnly = searchParams.get("readonly") === "true";
|
|
18870
19731
|
const [showMinimap, setShowMinimap] = useState(false);
|
|
18871
19732
|
const [edgesHidden, setEdgesHidden] = useState(false);
|
|
19733
|
+
const [shortcutsHelpOpen, setShortcutsHelpOpen] = useState(false);
|
|
18872
19734
|
const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
|
|
18873
19735
|
const [isDragging, setIsDragging] = useState(false);
|
|
18874
19736
|
const panelRef = useRef(null);
|
|
@@ -18878,6 +19740,18 @@ function CanvasControls() {
|
|
|
18878
19740
|
shallow
|
|
18879
19741
|
);
|
|
18880
19742
|
const { zoomIn, zoomOut, fitView, setEdges, getEdges, getNodes, setNodes } = useReactFlow();
|
|
19743
|
+
const [canUndo, canRedo, undo, redo] = useFlowStore(
|
|
19744
|
+
useShallow((s) => [
|
|
19745
|
+
s.history.past.length > 0,
|
|
19746
|
+
s.history.future.length > 0,
|
|
19747
|
+
s.actions.history.undo,
|
|
19748
|
+
s.actions.history.redo
|
|
19749
|
+
])
|
|
19750
|
+
);
|
|
19751
|
+
useEditorShortcuts({
|
|
19752
|
+
readOnly: isReadOnly,
|
|
19753
|
+
onOpenHelp: () => setShortcutsHelpOpen(true)
|
|
19754
|
+
});
|
|
18881
19755
|
const toggleEdges = useCallback(() => {
|
|
18882
19756
|
setEdgesHidden((prev) => {
|
|
18883
19757
|
const next = !prev;
|
|
@@ -18886,20 +19760,6 @@ function CanvasControls() {
|
|
|
18886
19760
|
});
|
|
18887
19761
|
}, [setEdges]);
|
|
18888
19762
|
const insertStickyNote = useInsertStickyNote();
|
|
18889
|
-
useEffect(() => {
|
|
18890
|
-
if (isReadOnly) return;
|
|
18891
|
-
const onKeyDown = (e) => {
|
|
18892
|
-
if (!e.shiftKey || e.key.toLowerCase() !== "s") return;
|
|
18893
|
-
if (e.metaKey || e.ctrlKey || e.altKey) return;
|
|
18894
|
-
const t = e.target;
|
|
18895
|
-
if (t && (t.tagName === "INPUT" || t.tagName === "TEXTAREA" || t.isContentEditable))
|
|
18896
|
-
return;
|
|
18897
|
-
e.preventDefault();
|
|
18898
|
-
insertStickyNote();
|
|
18899
|
-
};
|
|
18900
|
-
window.addEventListener("keydown", onKeyDown);
|
|
18901
|
-
return () => window.removeEventListener("keydown", onKeyDown);
|
|
18902
|
-
}, [insertStickyNote, isReadOnly]);
|
|
18903
19763
|
const tidyUp = useCallback(() => {
|
|
18904
19764
|
const nodes = getNodes().filter((n) => n.type !== STICKY_NOTE_TYPE);
|
|
18905
19765
|
const edges = getEdges();
|
|
@@ -19101,6 +19961,31 @@ function CanvasControls() {
|
|
|
19101
19961
|
}
|
|
19102
19962
|
),
|
|
19103
19963
|
!isReadOnly && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
19964
|
+
/* @__PURE__ */ jsx("div", { className: "w-px h-5 bg-card-foreground/10 mx-0.5" }),
|
|
19965
|
+
/* @__PURE__ */ jsx(
|
|
19966
|
+
ControlBtn,
|
|
19967
|
+
{
|
|
19968
|
+
title: tr(
|
|
19969
|
+
"fluidgrids.builder.canvasControls.undo",
|
|
19970
|
+
"Undo (Ctrl/Cmd+Z)"
|
|
19971
|
+
),
|
|
19972
|
+
disabled: !canUndo,
|
|
19973
|
+
onClick: undo,
|
|
19974
|
+
children: /* @__PURE__ */ jsx(Undo2, { className: "size-4" })
|
|
19975
|
+
}
|
|
19976
|
+
),
|
|
19977
|
+
/* @__PURE__ */ jsx(
|
|
19978
|
+
ControlBtn,
|
|
19979
|
+
{
|
|
19980
|
+
title: tr(
|
|
19981
|
+
"fluidgrids.builder.canvasControls.redo",
|
|
19982
|
+
"Redo (Ctrl/Cmd+Shift+Z)"
|
|
19983
|
+
),
|
|
19984
|
+
disabled: !canRedo,
|
|
19985
|
+
onClick: redo,
|
|
19986
|
+
children: /* @__PURE__ */ jsx(Redo2, { className: "size-4" })
|
|
19987
|
+
}
|
|
19988
|
+
),
|
|
19104
19989
|
/* @__PURE__ */ jsx("div", { className: "w-px h-5 bg-card-foreground/10 mx-0.5" }),
|
|
19105
19990
|
/* @__PURE__ */ jsx(
|
|
19106
19991
|
ControlBtn,
|
|
@@ -19144,10 +20029,29 @@ function CanvasControls() {
|
|
|
19144
20029
|
onClick: insertStickyNote,
|
|
19145
20030
|
children: /* @__PURE__ */ jsx(Icon, { icon: "mdi:note-plus-outline", className: "size-4" })
|
|
19146
20031
|
}
|
|
20032
|
+
),
|
|
20033
|
+
/* @__PURE__ */ jsx("div", { className: "w-px h-5 bg-card-foreground/10 mx-0.5" }),
|
|
20034
|
+
/* @__PURE__ */ jsx(
|
|
20035
|
+
ControlBtn,
|
|
20036
|
+
{
|
|
20037
|
+
title: tr(
|
|
20038
|
+
"fluidgrids.builder.canvasControls.shortcutsHelp",
|
|
20039
|
+
"Keyboard shortcuts (?)"
|
|
20040
|
+
),
|
|
20041
|
+
onClick: () => setShortcutsHelpOpen(true),
|
|
20042
|
+
children: /* @__PURE__ */ jsx(Keyboard, { className: "size-4" })
|
|
20043
|
+
}
|
|
19147
20044
|
)
|
|
19148
20045
|
] })
|
|
19149
20046
|
]
|
|
19150
20047
|
}
|
|
20048
|
+
),
|
|
20049
|
+
!isReadOnly && /* @__PURE__ */ jsx(
|
|
20050
|
+
ShortcutsHelpPanel,
|
|
20051
|
+
{
|
|
20052
|
+
open: shortcutsHelpOpen,
|
|
20053
|
+
onOpenChange: setShortcutsHelpOpen
|
|
20054
|
+
}
|
|
19151
20055
|
)
|
|
19152
20056
|
] });
|
|
19153
20057
|
}
|
|
@@ -23310,7 +24214,7 @@ var FlowBuilder = ({ readOnly = false }) => {
|
|
|
23310
24214
|
nodesDraggable: !isReadOnly,
|
|
23311
24215
|
nodesConnectable: !isReadOnly,
|
|
23312
24216
|
elementsSelectable: !isReadOnly,
|
|
23313
|
-
multiSelectionKeyCode: null,
|
|
24217
|
+
multiSelectionKeyCode: isReadOnly ? null : ["Meta", "Control"],
|
|
23314
24218
|
deleteKeyCode: isReadOnly ? null : deleteKeyCode,
|
|
23315
24219
|
snapGrid: [16, 16],
|
|
23316
24220
|
snapToGrid: true,
|
|
@@ -23436,5 +24340,5 @@ var FlowBuilderPage = ({
|
|
|
23436
24340
|
};
|
|
23437
24341
|
|
|
23438
24342
|
export { Card2 as Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, ConnectionFormDialog, ConnectionSelector, EntityTagPicker, FLUIDGRIDS_ENTITY_TYPES, FlowBuilderPage, FluidGridsProvider, ProviderPicker, SchemaConnectionForm, ScopePicker, TemplateCard, buildNodeCheck, buildRequiredNodeTypes, listCustomBlocks, mergeStickyNotes, refetchStoreNodes, registerCustomBlock, resolveUiSpec, stripSubmitActions, tagLabel, useAvailableTags, useConnection, useConnectionDialog, useConnections, useConnectionsByProvider, useCreateConnection, useCreateTag, useDraftEntityTags, useEntityTags, useFluidGridsContext, useImportWorkflowTemplate, useInitiateOAuth, useInstalledNodes, useNodeExecution, useProviderByKey, useProviderCatalog, useProviders, useReplaceEntityTags, useSearchTags, useTagEntity, useUntagEntity, useWorkflowTemplates };
|
|
23439
|
-
//# sourceMappingURL=chunk-
|
|
23440
|
-
//# sourceMappingURL=chunk-
|
|
24343
|
+
//# sourceMappingURL=chunk-3RWKQIV4.js.map
|
|
24344
|
+
//# sourceMappingURL=chunk-3RWKQIV4.js.map
|