@burdenoff/fluidgrids-fe-sdk 2026.1105.2 → 2026.1105.3
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/README.md +30 -0
- package/dist/{ExecutionDetailPage-HQB2SWBP.js → ExecutionDetailPage-JXGPSLS3.js} +9 -7
- package/dist/{ExecutionsListPage-RSLL634L.js → ExecutionsListPage-U3TC5JUI.js} +8 -6
- package/dist/{WorkflowBuilder-E3PNZX74.js → WorkflowBuilder-6DOD6WWH.js} +13 -10
- package/dist/{WorkflowsList-473FRRP2.js → WorkflowsList-XOWRQNST.js} +9 -7
- package/dist/{agentTools-5N3ZEZDW.js → agentTools-YQBN33WG.js} +6 -4
- package/dist/{chunk-XFH6SLDK.js → chunk-22U3TUKZ.js} +1 -1
- package/dist/{chunk-QFC6E3WD.js → chunk-2WUVF4EQ.js} +1 -1
- package/dist/{chunk-W5WML3OO.js → chunk-3MZOYJ5I.js} +1 -1
- package/dist/{chunk-3XUWPDKJ.js → chunk-3ZYRLGDF.js} +5 -5
- package/dist/{chunk-SALZ3LQB.js → chunk-4NNF7DIB.js} +1 -1
- package/dist/chunk-5DVP2UYH.js +1924 -0
- package/dist/{chunk-CH3YUGWR.js → chunk-EKDUYCTS.js} +4 -4
- package/dist/{chunk-Y6M7K4UG.js → chunk-FVWRGL7S.js} +1 -1
- package/dist/{chunk-2KUZBEWW.js → chunk-G33OMSW6.js} +6 -5
- package/dist/{chunk-6IS7EXIY.js → chunk-G774FI2E.js} +2 -2
- package/dist/{chunk-5CFCFA6O.js → chunk-IJ7UIDCW.js} +6 -5
- package/dist/chunk-JYYN3CLL.js +32 -0
- package/dist/{chunk-GKFMK7FF.js → chunk-KAWRHIJZ.js} +1 -1
- package/dist/{chunk-QPLFALVV.js → chunk-KN37RIFC.js} +4 -3
- package/dist/{chunk-AASHQI77.js → chunk-KZCNJAMK.js} +2 -1
- package/dist/{chunk-X25NCWG2.js → chunk-LDWBMCX4.js} +4 -3
- package/dist/{chunk-CNKTQ5MG.js → chunk-MA6I4KY5.js} +2 -2
- package/dist/{chunk-O7CJJNW6.js → chunk-MP44TAOO.js} +2 -2
- package/dist/{chunk-6ZK4MRVA.js → chunk-MY7SEUXM.js} +1 -1
- package/dist/{chunk-62CCBMDC.js → chunk-NMQENSPW.js} +12 -11
- package/dist/{chunk-HK76ZUAK.js → chunk-NZFPCTIS.js} +4 -4
- package/dist/chunk-SDZEAIIE.js +9 -0
- package/dist/{chunk-64JN2TVX.js → chunk-TJAG2DQT.js} +8 -37
- package/dist/{chunk-TNFBRXU7.js → chunk-TLHX4DK4.js} +6 -5
- package/dist/{chunk-J3YQCEP3.js → chunk-VESQH55Q.js} +1 -1
- package/dist/{chunk-OCJTTHTS.js → chunk-Y7FKJJMF.js} +1 -9
- package/dist/{chunk-QFGZXWTM.js → chunk-YGOGJDN4.js} +1 -1
- package/dist/{chunk-3QCRKKTI.js → chunk-ZBPRNWKY.js} +234 -2145
- package/dist/{chunk-AJVU5YW6.js → chunk-ZLBTUCC2.js} +3 -2
- package/dist/code-editor-field-WWPDMF4O.js +3 -0
- package/dist/executions.js +10 -8
- package/dist/history.js +8 -5
- package/dist/index.js +36 -33
- package/dist/{node-detail-view-WIWW5N6N.js → node-detail-view-U5HOP2WX.js} +10 -8
- package/dist/observability.js +6 -4
- package/dist/{quick-config-panel-O64TXXK3.js → quick-config-panel-XAISBW6Y.js} +8 -6
- package/dist/settings.js +7 -5
- package/dist/templates.js +12 -9
- package/dist/workflow-builder.js +14 -11
- package/dist/workflow-preview.d.ts +158 -0
- package/dist/workflow-preview.js +721 -0
- package/dist/workflows-list.js +9 -7
- package/package.json +5 -1
- package/dist/code-editor-field-XWUVOKTA.js +0 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { SdkPermissionGate, FLUIDGRIDS_PERMISSIONS } from './chunk-5375NUIO.js';
|
|
2
|
-
import { useBuilderReadOnly
|
|
2
|
+
import { useBuilderReadOnly } from './chunk-SDZEAIIE.js';
|
|
3
|
+
import { STICKY_NOTE_TYPE, useFlowStore, resolveOperationName, synchronizeOperationUpdate, isNodeTrigger, resolveOutputHandles, resolveInputHandles, outputHandlesSpacerHeight, WAIT_FOR_SIGNAL_NODE_TYPE, CODE_WORKFLOW_NODE_TYPE, readSignalName, LogicNodeCard, NodeCard, NodeCardHeader, NodeCardBody, InputHandles, OutputHandles, NodeTypeIcon, nodeAccent, readCodeWorkflowState, partitionStickyNotes, interfaceFields, interfaceHandlers } from './chunk-5DVP2UYH.js';
|
|
3
4
|
import { getGlobalStoreClient, createGlobalStoreClient, setGlobalStoreClient, resetGlobalStoreClient } from './chunk-AU7LACOY.js';
|
|
4
5
|
import { GetMyNodeInstallationsDocument } from './chunk-G77IGC3Y.js';
|
|
5
6
|
import { fetchAllNodeEndpointConfigs, NodeManifestDocument, UpdateWorkflowDefinitionDocument, CreateWorkflowDefinitionDocument, CreateWorkflowVersionDocument, ExecuteStepDocument, TriggerWorkflowDocument, RunFromNodeDocument, ExecutionDetailDocument, WorkflowDefinitionDocument, WorkflowRunDocument } from './chunk-Z3ABLERJ.js';
|
|
@@ -7,21 +8,18 @@ import { useTr, ENGLISH_FALLBACK_TRANSLATOR, FluidGridsTranslationProvider } fro
|
|
|
7
8
|
import { waitForFluidGridsClient, getFluidGridsClient, getFluidGridsClientSafe, createFluidGridsClient, setFluidGridsClient, resetFluidGridsClient } from './chunk-3IXU7WUC.js';
|
|
8
9
|
import { throwIfResultError, emitFluidGridsEvent, emitOperationErrorEvent, describeOperationError, emitRunCompletedOnce } from './chunk-US5QSLPV.js';
|
|
9
10
|
import { getFluidGridsConfig, validateTrustedOrigin, resetFluidGridsExecutionState, resetFluidGridsConfig, setFluidGridsConfig } from './chunk-UEG2WC3G.js';
|
|
10
|
-
import * as React from 'react';
|
|
11
11
|
import { memo, forwardRef, useState, useImperativeHandle, useRef, useEffect, useMemo, createContext, useCallback, useSyncExternalStore, useContext } from 'react';
|
|
12
12
|
import { useOptionalFeatureFlags } from '@burdenoff/fe-libs/shared/feature-flags';
|
|
13
13
|
import { dispatchUpgradePrompt } from '@burdenoff/fe-libs/shared/components';
|
|
14
|
-
import { nanoid } from 'nanoid/non-secure';
|
|
15
|
-
import {
|
|
16
|
-
import { create } from 'zustand';
|
|
17
|
-
import { produce } from 'immer';
|
|
14
|
+
import { nanoid as nanoid$1 } from 'nanoid/non-secure';
|
|
15
|
+
import { useReactFlow, NodeResizer, getConnectedEdges, useStore, Handle, Position } from '@xyflow/react';
|
|
18
16
|
import { Icon } from '@iconify/react';
|
|
19
|
-
import { nanoid
|
|
17
|
+
import { nanoid } from 'nanoid';
|
|
20
18
|
import ReactMarkdown from 'react-markdown';
|
|
21
19
|
import { cn } from '@burdenoff/fe-libs/utils';
|
|
22
|
-
import {
|
|
20
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
23
21
|
import { toast } from 'sonner';
|
|
24
|
-
import { nodeCategoryColor
|
|
22
|
+
import { nodeCategoryColor } from '@burdenoff/fe-libs/shared/utils';
|
|
25
23
|
import { gql } from '@apollo/client';
|
|
26
24
|
import { Textarea, Input, Button, Card, Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogDescription, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLabel, DropdownMenuItem, DropdownMenuSeparator, AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel } from '@burdenoff/fe-libs/ui';
|
|
27
25
|
import * as AdaptiveCards from 'adaptivecards';
|
|
@@ -31,6 +29,7 @@ import { v4 } from 'uuid';
|
|
|
31
29
|
import { useParams, useNavigate } from 'react-router';
|
|
32
30
|
import { useEventBus } from '@burdenoff/fe-libs/shared/events';
|
|
33
31
|
import { ApolloProvider } from '@apollo/client/react';
|
|
32
|
+
import { create } from 'zustand';
|
|
34
33
|
import { useShallow } from 'zustand/shallow';
|
|
35
34
|
import { InfoCircledIcon } from '@radix-ui/react-icons';
|
|
36
35
|
import { Button as Button$1 } from '@burdenoff/fe-libs/button';
|
|
@@ -510,901 +509,6 @@ function openRunQuotaUpgradePrompt(error, tr = ENGLISH_FALLBACK_TRANSLATOR, anal
|
|
|
510
509
|
});
|
|
511
510
|
return true;
|
|
512
511
|
}
|
|
513
|
-
|
|
514
|
-
// src/builder/lib/node-role.ts
|
|
515
|
-
function isRecord(value) {
|
|
516
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
517
|
-
}
|
|
518
|
-
function readRecord(value) {
|
|
519
|
-
return isRecord(value) ? value : void 0;
|
|
520
|
-
}
|
|
521
|
-
function readString(value) {
|
|
522
|
-
return typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
523
|
-
}
|
|
524
|
-
function operationRole(operation) {
|
|
525
|
-
const metadata = readRecord(operation);
|
|
526
|
-
const role = readString(metadata?.role);
|
|
527
|
-
if (role) return role === "trigger" ? "trigger" : "action";
|
|
528
|
-
const type = readString(metadata?.type);
|
|
529
|
-
if (type === "trigger" || type === "subscription" || readString(metadata?.delivery)) {
|
|
530
|
-
return "trigger";
|
|
531
|
-
}
|
|
532
|
-
if (type === "action" || type === "query" || type === "mutation") {
|
|
533
|
-
return "action";
|
|
534
|
-
}
|
|
535
|
-
return void 0;
|
|
536
|
-
}
|
|
537
|
-
function isTriggerOperation(operation) {
|
|
538
|
-
return operationRole(operation) === "trigger";
|
|
539
|
-
}
|
|
540
|
-
function isLegacyTriggerType(type) {
|
|
541
|
-
return type === "trigger" || type.startsWith("trigger:") || type.startsWith("internal:schedule") || type.startsWith("internal:webhook") || type.startsWith("internal:api") || type.startsWith("internal:form") || type.startsWith("internal:mcp") || type.endsWith("_trigger") || type.endsWith("Trigger") || type.endsWith("-trigger");
|
|
542
|
-
}
|
|
543
|
-
function getSelectedOperationRole(nodeType, nodeData) {
|
|
544
|
-
const data = readRecord(nodeData);
|
|
545
|
-
const operationName = data?.operation_name;
|
|
546
|
-
if (typeof operationName !== "string" || !operationName.trim())
|
|
547
|
-
return void 0;
|
|
548
|
-
const manifest = readRecord(data?.nodeData);
|
|
549
|
-
const declared = manifest?.operations;
|
|
550
|
-
const operations = Array.isArray(declared) ? declared : readRecord(declared)?.operations;
|
|
551
|
-
const operation = Array.isArray(operations) ? operations.find(
|
|
552
|
-
(entry) => readRecord(entry)?.name === operationName
|
|
553
|
-
) : void 0;
|
|
554
|
-
const selectedRole = operationRole(operation) ?? operationRole({ type: data?.operation_type });
|
|
555
|
-
if (selectedRole) return selectedRole;
|
|
556
|
-
if (nodeType === "integration/channel" || nodeType?.startsWith("store/")) {
|
|
557
|
-
return operationName.startsWith("on") ? "trigger" : "action";
|
|
558
|
-
}
|
|
559
|
-
return void 0;
|
|
560
|
-
}
|
|
561
|
-
function isNodeTrigger(node) {
|
|
562
|
-
const data = readRecord(node.data);
|
|
563
|
-
const selectedRole = getSelectedOperationRole(node.type, data);
|
|
564
|
-
if (selectedRole) return selectedRole === "trigger";
|
|
565
|
-
const state = readRecord(readRecord(data?.args)?.state);
|
|
566
|
-
for (const legacyRole of [data?.role, state?.role]) {
|
|
567
|
-
const explicitRole = readString(legacyRole);
|
|
568
|
-
if (explicitRole === "trigger" || explicitRole === "action") {
|
|
569
|
-
return explicitRole === "trigger";
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
const savedRole = operationRole({ type: data?.operation_type });
|
|
573
|
-
if (savedRole) return savedRole === "trigger";
|
|
574
|
-
const type = node.type ?? "";
|
|
575
|
-
if (isLegacyTriggerType(type)) return true;
|
|
576
|
-
const manifest = readRecord(data?.nodeData);
|
|
577
|
-
if (!data?.operation_name && Array.isArray(manifest?.kind) && manifest.kind.includes("trigger")) {
|
|
578
|
-
return true;
|
|
579
|
-
}
|
|
580
|
-
return false;
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
// src/builder/hooks/use-is-valid-connection.ts
|
|
584
|
-
function isLoopController(source) {
|
|
585
|
-
const type = source?.type?.toLowerCase();
|
|
586
|
-
const disabled = source?.data?.disabled === true || source !== void 0 && "disabled" in source && source.disabled === true;
|
|
587
|
-
return (type === "internal:loop" || type === "loop") && !disabled;
|
|
588
|
-
}
|
|
589
|
-
function isRecord2(value) {
|
|
590
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
591
|
-
}
|
|
592
|
-
function readRecord2(value) {
|
|
593
|
-
return isRecord2(value) ? value : void 0;
|
|
594
|
-
}
|
|
595
|
-
function loopBodyHandle(source) {
|
|
596
|
-
const node = readRecord2(source);
|
|
597
|
-
const data = readRecord2(node?.data);
|
|
598
|
-
const parameters = {
|
|
599
|
-
...data,
|
|
600
|
-
...readRecord2(node?.config),
|
|
601
|
-
...readRecord2(readRecord2(data?.args)?.state),
|
|
602
|
-
...readRecord2(readRecord2(node?.args)?.state)
|
|
603
|
-
};
|
|
604
|
-
return typeof parameters.loopHandle === "string" && parameters.loopHandle ? parameters.loopHandle : "loop";
|
|
605
|
-
}
|
|
606
|
-
function isLoopBodyEdge(edge, nodes) {
|
|
607
|
-
const source = nodes.find((node) => node.id === edge.source);
|
|
608
|
-
return source !== void 0 && isLoopController(source) && edge.sourceHandle === loopBodyHandle(source);
|
|
609
|
-
}
|
|
610
|
-
function adjacency(edges) {
|
|
611
|
-
const outgoing = /* @__PURE__ */ new Map();
|
|
612
|
-
for (const edge of edges) {
|
|
613
|
-
const targets = outgoing.get(edge.source) ?? /* @__PURE__ */ new Set();
|
|
614
|
-
targets.add(edge.target);
|
|
615
|
-
outgoing.set(edge.source, targets);
|
|
616
|
-
}
|
|
617
|
-
return outgoing;
|
|
618
|
-
}
|
|
619
|
-
function reachable(starts, outgoing, blocked = /* @__PURE__ */ new Set()) {
|
|
620
|
-
const pending = [...starts];
|
|
621
|
-
const visited = /* @__PURE__ */ new Set();
|
|
622
|
-
while (pending.length > 0) {
|
|
623
|
-
const current = pending.pop();
|
|
624
|
-
if (current === void 0 || visited.has(current) || blocked.has(current))
|
|
625
|
-
continue;
|
|
626
|
-
visited.add(current);
|
|
627
|
-
pending.push(...outgoing.get(current) ?? []);
|
|
628
|
-
}
|
|
629
|
-
return visited;
|
|
630
|
-
}
|
|
631
|
-
function controlledReturns(nodes, edges) {
|
|
632
|
-
const outgoing = adjacency(edges);
|
|
633
|
-
const incomingTargets = new Set(edges.map((edge) => edge.target));
|
|
634
|
-
const entries = nodes.filter((node) => !incomingTargets.has(node.id) || isNodeTrigger(node)).map((node) => node.id);
|
|
635
|
-
const returns = /* @__PURE__ */ new Set();
|
|
636
|
-
for (const controller of nodes.filter(isLoopController)) {
|
|
637
|
-
const bodyHandle = loopBodyHandle(controller);
|
|
638
|
-
const controllerEdges = edges.filter(
|
|
639
|
-
(edge) => edge.source === controller.id
|
|
640
|
-
);
|
|
641
|
-
const outside = reachable(
|
|
642
|
-
[
|
|
643
|
-
...entries,
|
|
644
|
-
...controllerEdges.filter((edge) => edge.sourceHandle !== bodyHandle).map((edge) => edge.target)
|
|
645
|
-
],
|
|
646
|
-
outgoing,
|
|
647
|
-
/* @__PURE__ */ new Set([controller.id])
|
|
648
|
-
);
|
|
649
|
-
const body = reachable(
|
|
650
|
-
controllerEdges.filter((edge) => edge.sourceHandle === bodyHandle).map((edge) => edge.target),
|
|
651
|
-
outgoing,
|
|
652
|
-
/* @__PURE__ */ new Set([controller.id, ...outside])
|
|
653
|
-
);
|
|
654
|
-
for (const edge of edges) {
|
|
655
|
-
if (edge.target === controller.id && body.has(edge.source))
|
|
656
|
-
returns.add(edge);
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
return returns;
|
|
660
|
-
}
|
|
661
|
-
function isValidWorkflowConnection(nodes, edges, connection) {
|
|
662
|
-
if (connection.target === connection.source) return false;
|
|
663
|
-
const candidates = [...edges, connection];
|
|
664
|
-
const previousReturns = controlledReturns(nodes, edges);
|
|
665
|
-
const nextReturns = controlledReturns(nodes, candidates);
|
|
666
|
-
const outgoing = adjacency(
|
|
667
|
-
candidates.filter((edge) => !nextReturns.has(edge))
|
|
668
|
-
);
|
|
669
|
-
const invalidated = [connection, ...previousReturns].filter(
|
|
670
|
-
(edge) => !nextReturns.has(edge)
|
|
671
|
-
);
|
|
672
|
-
return invalidated.every(
|
|
673
|
-
(edge) => !reachable([edge.target], outgoing).has(edge.source)
|
|
674
|
-
);
|
|
675
|
-
}
|
|
676
|
-
function useIsValidConnection(nodes, edges) {
|
|
677
|
-
return useCallback(
|
|
678
|
-
(connection) => isValidWorkflowConnection(nodes, edges, connection),
|
|
679
|
-
[nodes, edges]
|
|
680
|
-
);
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
// src/builder/stores/flow-store.ts
|
|
684
|
-
var HISTORY_LIMIT = 100;
|
|
685
|
-
var CLONE_OFFSET = 48;
|
|
686
|
-
function cloneValue(value) {
|
|
687
|
-
try {
|
|
688
|
-
return structuredClone(value);
|
|
689
|
-
} catch {
|
|
690
|
-
return JSON.parse(JSON.stringify(value));
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
var TAGS = [
|
|
694
|
-
{ value: "marketing", label: "Marketing", color: "var(--color-chart-5)" },
|
|
695
|
-
{ value: "support", label: "Support", color: "var(--color-chart-5)" },
|
|
696
|
-
{ value: "lead", label: "Lead", color: "var(--color-chart-4)" },
|
|
697
|
-
{ value: "new", label: "New", color: "var(--color-chart-7)" }
|
|
698
|
-
];
|
|
699
|
-
var INITIAL_EXECUTION = {
|
|
700
|
-
isExecuting: false,
|
|
701
|
-
executingNodeId: null,
|
|
702
|
-
currentRunId: null,
|
|
703
|
-
sourceRun: null,
|
|
704
|
-
stepPlan: null,
|
|
705
|
-
logs: [],
|
|
706
|
-
selectedLogId: null,
|
|
707
|
-
panelExpanded: false,
|
|
708
|
-
nodeStatuses: {},
|
|
709
|
-
nodeItemCounts: {},
|
|
710
|
-
followRequest: null
|
|
711
|
-
};
|
|
712
|
-
var INITIAL_HISTORY = { past: [], future: [] };
|
|
713
|
-
var useFlowStore = create()((set, get) => {
|
|
714
|
-
let lastCheckpointKind = null;
|
|
715
|
-
let lastCheckpointAt = 0;
|
|
716
|
-
function pushCheckpoint(kind, coalesce) {
|
|
717
|
-
const now = Date.now();
|
|
718
|
-
const isCoalesced = coalesce && kind === lastCheckpointKind && now - lastCheckpointAt < 800;
|
|
719
|
-
if (!isCoalesced) {
|
|
720
|
-
const state = get();
|
|
721
|
-
const snapshot = {
|
|
722
|
-
nodes: cloneValue(state.workflow.nodes),
|
|
723
|
-
edges: cloneValue(state.workflow.edges)
|
|
724
|
-
};
|
|
725
|
-
set((s) => ({
|
|
726
|
-
history: {
|
|
727
|
-
past: [...s.history.past, snapshot].slice(-HISTORY_LIMIT),
|
|
728
|
-
future: []
|
|
729
|
-
}
|
|
730
|
-
}));
|
|
731
|
-
} else if (get().history.future.length > 0) {
|
|
732
|
-
set((s) => ({ history: { ...s.history, future: [] } }));
|
|
733
|
-
}
|
|
734
|
-
lastCheckpointKind = kind;
|
|
735
|
-
lastCheckpointAt = now;
|
|
736
|
-
noteEdit();
|
|
737
|
-
}
|
|
738
|
-
function noteEdit() {
|
|
739
|
-
set((s) => ({ editRevision: s.editRevision + 1 }));
|
|
740
|
-
}
|
|
741
|
-
const REMOVAL_KINDS = /* @__PURE__ */ new Set(["nodes:remove", "edges:remove"]);
|
|
742
|
-
const SAME_ACTION_WINDOW_MS = 150;
|
|
743
|
-
function joinsPrecedingRemoval(kind) {
|
|
744
|
-
return lastCheckpointKind !== null && lastCheckpointKind !== kind && REMOVAL_KINDS.has(kind) && REMOVAL_KINDS.has(lastCheckpointKind) && Date.now() - lastCheckpointAt < SAME_ACTION_WINDOW_MS;
|
|
745
|
-
}
|
|
746
|
-
function resetCoalescing() {
|
|
747
|
-
lastCheckpointKind = null;
|
|
748
|
-
lastCheckpointAt = 0;
|
|
749
|
-
}
|
|
750
|
-
return {
|
|
751
|
-
tags: TAGS,
|
|
752
|
-
history: { ...INITIAL_HISTORY },
|
|
753
|
-
editRevision: 0,
|
|
754
|
-
loadGeneration: 0,
|
|
755
|
-
workflow: {
|
|
756
|
-
id: nanoid(),
|
|
757
|
-
workflowKey: "",
|
|
758
|
-
name: "",
|
|
759
|
-
version: "",
|
|
760
|
-
alias: "",
|
|
761
|
-
edges: [],
|
|
762
|
-
nodes: [],
|
|
763
|
-
ndv: null,
|
|
764
|
-
quickConfig: null,
|
|
765
|
-
pendingConnection: null,
|
|
766
|
-
renamingNodeId: null,
|
|
767
|
-
sidebar: {
|
|
768
|
-
active: "none",
|
|
769
|
-
panels: {
|
|
770
|
-
nodeProperties: {
|
|
771
|
-
selectedNode: null
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
},
|
|
776
|
-
execution: { ...INITIAL_EXECUTION },
|
|
777
|
-
actions: {
|
|
778
|
-
saveWorkflow: () => {
|
|
779
|
-
const { workflow } = get();
|
|
780
|
-
const { id, name, version, alias, dbId, status, nodes, edges } = workflow;
|
|
781
|
-
set({ workflow });
|
|
782
|
-
return { id, name, version, alias, dbId, status, nodes, edges };
|
|
783
|
-
},
|
|
784
|
-
setWorkflow: (workflow) => {
|
|
785
|
-
const current = get().workflow;
|
|
786
|
-
if (workflow.name !== void 0 && workflow.name !== current.name || workflow.alias !== void 0 && workflow.alias !== current.alias) {
|
|
787
|
-
noteEdit();
|
|
788
|
-
}
|
|
789
|
-
const nodes = workflow.nodes?.map(
|
|
790
|
-
(node) => node.data === void 0 || node.data === null ? { ...node, data: {} } : node
|
|
791
|
-
);
|
|
792
|
-
set((state) => ({
|
|
793
|
-
workflow: {
|
|
794
|
-
...state.workflow,
|
|
795
|
-
...workflow,
|
|
796
|
-
...nodes ? { nodes } : {}
|
|
797
|
-
}
|
|
798
|
-
}));
|
|
799
|
-
},
|
|
800
|
-
resetWorkflow: () => {
|
|
801
|
-
resetCoalescing();
|
|
802
|
-
set((s) => ({
|
|
803
|
-
loadGeneration: s.loadGeneration + 1,
|
|
804
|
-
workflow: {
|
|
805
|
-
id: nanoid(),
|
|
806
|
-
workflowKey: "",
|
|
807
|
-
name: "",
|
|
808
|
-
version: "",
|
|
809
|
-
alias: "",
|
|
810
|
-
dbId: void 0,
|
|
811
|
-
status: void 0,
|
|
812
|
-
codeBuildId: void 0,
|
|
813
|
-
edges: [],
|
|
814
|
-
nodes: [],
|
|
815
|
-
ndv: null,
|
|
816
|
-
quickConfig: null,
|
|
817
|
-
pendingConnection: null,
|
|
818
|
-
renamingNodeId: null,
|
|
819
|
-
sidebar: {
|
|
820
|
-
active: "none",
|
|
821
|
-
panels: {
|
|
822
|
-
nodeProperties: {
|
|
823
|
-
selectedNode: null
|
|
824
|
-
}
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
},
|
|
828
|
-
// Wipe run state too — resetWorkflow fires when the builder loads a
|
|
829
|
-
// (different) workflow, so the previous workflow's logs must not carry
|
|
830
|
-
// over into this one's Logs panel.
|
|
831
|
-
execution: { ...INITIAL_EXECUTION },
|
|
832
|
-
// A freshly loaded workflow must not be undo-able back to empty —
|
|
833
|
-
// undo/redo only ever applies within the currently open workflow.
|
|
834
|
-
history: { ...INITIAL_HISTORY }
|
|
835
|
-
}));
|
|
836
|
-
},
|
|
837
|
-
history: {
|
|
838
|
-
undo: () => {
|
|
839
|
-
const { past, future } = get().history;
|
|
840
|
-
const previous = past[past.length - 1];
|
|
841
|
-
if (!previous) return;
|
|
842
|
-
const { nodes, edges } = get().workflow;
|
|
843
|
-
const current = {
|
|
844
|
-
nodes: cloneValue(nodes),
|
|
845
|
-
edges: cloneValue(edges)
|
|
846
|
-
};
|
|
847
|
-
resetCoalescing();
|
|
848
|
-
noteEdit();
|
|
849
|
-
set((s) => ({
|
|
850
|
-
workflow: {
|
|
851
|
-
...s.workflow,
|
|
852
|
-
nodes: previous.nodes,
|
|
853
|
-
edges: previous.edges
|
|
854
|
-
},
|
|
855
|
-
history: {
|
|
856
|
-
past: past.slice(0, -1),
|
|
857
|
-
future: [current, ...future].slice(0, HISTORY_LIMIT)
|
|
858
|
-
}
|
|
859
|
-
}));
|
|
860
|
-
},
|
|
861
|
-
redo: () => {
|
|
862
|
-
const { past, future } = get().history;
|
|
863
|
-
const next = future[0];
|
|
864
|
-
if (!next) return;
|
|
865
|
-
const { nodes, edges } = get().workflow;
|
|
866
|
-
const current = {
|
|
867
|
-
nodes: cloneValue(nodes),
|
|
868
|
-
edges: cloneValue(edges)
|
|
869
|
-
};
|
|
870
|
-
resetCoalescing();
|
|
871
|
-
noteEdit();
|
|
872
|
-
set((s) => ({
|
|
873
|
-
workflow: {
|
|
874
|
-
...s.workflow,
|
|
875
|
-
nodes: next.nodes,
|
|
876
|
-
edges: next.edges
|
|
877
|
-
},
|
|
878
|
-
history: {
|
|
879
|
-
past: [...past, current].slice(-HISTORY_LIMIT),
|
|
880
|
-
future: future.slice(1)
|
|
881
|
-
}
|
|
882
|
-
}));
|
|
883
|
-
},
|
|
884
|
-
clear: () => {
|
|
885
|
-
resetCoalescing();
|
|
886
|
-
set({ history: { ...INITIAL_HISTORY } });
|
|
887
|
-
}
|
|
888
|
-
},
|
|
889
|
-
ndv: {
|
|
890
|
-
// Opening the full NDV supersedes the floating quick-config panel — the
|
|
891
|
-
// two edit the same node data, so only one should be visible at a time.
|
|
892
|
-
open: (node) => set((state) => ({
|
|
893
|
-
workflow: { ...state.workflow, ndv: node, quickConfig: null }
|
|
894
|
-
})),
|
|
895
|
-
close: () => set((state) => ({
|
|
896
|
-
workflow: { ...state.workflow, ndv: null }
|
|
897
|
-
}))
|
|
898
|
-
},
|
|
899
|
-
quickConfig: {
|
|
900
|
-
open: (node) => set((state) => ({
|
|
901
|
-
workflow: { ...state.workflow, quickConfig: node }
|
|
902
|
-
})),
|
|
903
|
-
close: () => set((state) => ({
|
|
904
|
-
workflow: { ...state.workflow, quickConfig: null }
|
|
905
|
-
}))
|
|
906
|
-
},
|
|
907
|
-
pendingConnection: {
|
|
908
|
-
start: (connection) => set((state) => ({
|
|
909
|
-
workflow: {
|
|
910
|
-
...state.workflow,
|
|
911
|
-
pendingConnection: connection,
|
|
912
|
-
sidebar: { ...state.workflow.sidebar, active: "store-browse" }
|
|
913
|
-
}
|
|
914
|
-
})),
|
|
915
|
-
clear: () => set((state) => ({
|
|
916
|
-
workflow: { ...state.workflow, pendingConnection: null }
|
|
917
|
-
}))
|
|
918
|
-
},
|
|
919
|
-
sidebar: {
|
|
920
|
-
// Leaving the store panel abandons any armed "+" attach mode — the
|
|
921
|
-
// pending handle would otherwise silently capture a later insert.
|
|
922
|
-
setActivePanel: (panel) => set((state) => ({
|
|
923
|
-
workflow: {
|
|
924
|
-
...state.workflow,
|
|
925
|
-
sidebar: { ...state.workflow.sidebar, active: panel },
|
|
926
|
-
...panel !== "store-browse" ? { pendingConnection: null } : {}
|
|
927
|
-
}
|
|
928
|
-
})),
|
|
929
|
-
showNodePropertiesOf: (node) => {
|
|
930
|
-
set((state) => ({
|
|
931
|
-
workflow: {
|
|
932
|
-
...state.workflow,
|
|
933
|
-
pendingConnection: null,
|
|
934
|
-
sidebar: {
|
|
935
|
-
...state.workflow.sidebar,
|
|
936
|
-
active: "node-properties",
|
|
937
|
-
panels: {
|
|
938
|
-
...state.workflow.sidebar.panels,
|
|
939
|
-
nodeProperties: {
|
|
940
|
-
...state.workflow.sidebar.panels.nodeProperties,
|
|
941
|
-
selectedNode: node
|
|
942
|
-
}
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
}
|
|
946
|
-
}));
|
|
947
|
-
},
|
|
948
|
-
panels: {
|
|
949
|
-
nodeProperties: {
|
|
950
|
-
setSelectedNode: (node) => set((state) => ({
|
|
951
|
-
workflow: {
|
|
952
|
-
...state.workflow,
|
|
953
|
-
sidebar: {
|
|
954
|
-
...state.workflow.sidebar,
|
|
955
|
-
panels: {
|
|
956
|
-
...state.workflow.sidebar.panels,
|
|
957
|
-
nodeProperties: {
|
|
958
|
-
...state.workflow.sidebar.panels.nodeProperties,
|
|
959
|
-
selectedNode: node
|
|
960
|
-
}
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
}))
|
|
965
|
-
},
|
|
966
|
-
tags: {
|
|
967
|
-
setTags: (tags) => set({ tags }),
|
|
968
|
-
createTag: (tag) => set((state) => ({
|
|
969
|
-
tags: [...state.tags, tag]
|
|
970
|
-
})),
|
|
971
|
-
updateTag: (tag, newTag) => set((state) => ({
|
|
972
|
-
tags: state.tags.map(
|
|
973
|
-
(f) => f.value === tag.value ? newTag : f
|
|
974
|
-
)
|
|
975
|
-
})),
|
|
976
|
-
deleteTag: (tag) => set((state) => ({
|
|
977
|
-
tags: state.tags.filter((f) => f.value !== tag.value)
|
|
978
|
-
}))
|
|
979
|
-
}
|
|
980
|
-
}
|
|
981
|
-
},
|
|
982
|
-
nodes: {
|
|
983
|
-
onNodesChange: (changes) => {
|
|
984
|
-
const removedIds = new Set(
|
|
985
|
-
changes.filter(
|
|
986
|
-
(c) => c.type === "remove"
|
|
987
|
-
).map((c) => c.id)
|
|
988
|
-
);
|
|
989
|
-
const addedCount = changes.filter((c) => c.type === "add").length;
|
|
990
|
-
if (removedIds.size > 0) {
|
|
991
|
-
const stillPresent = get().workflow.nodes.some(
|
|
992
|
-
(n) => removedIds.has(n.id)
|
|
993
|
-
);
|
|
994
|
-
if (stillPresent && !joinsPrecedingRemoval("nodes:remove")) {
|
|
995
|
-
pushCheckpoint("nodes:remove", false);
|
|
996
|
-
}
|
|
997
|
-
} else if (addedCount > 0) {
|
|
998
|
-
pushCheckpoint("nodes:add", false);
|
|
999
|
-
} else {
|
|
1000
|
-
const startsDrag = changes.some(
|
|
1001
|
-
(c) => c.type === "position" && c.dragging === true && !get().workflow.nodes.find((n) => n.id === c.id)?.dragging
|
|
1002
|
-
);
|
|
1003
|
-
if (startsDrag) noteEdit();
|
|
1004
|
-
const finishedDragIds = changes.filter(
|
|
1005
|
-
(c) => c.type === "position" && c.dragging === false
|
|
1006
|
-
);
|
|
1007
|
-
const actuallyMoved = finishedDragIds.some((c) => {
|
|
1008
|
-
const current = get().workflow.nodes.find((n) => n.id === c.id);
|
|
1009
|
-
return current && c.position && (current.position.x !== c.position.x || current.position.y !== c.position.y);
|
|
1010
|
-
});
|
|
1011
|
-
if (actuallyMoved) pushCheckpoint("nodes:move", false);
|
|
1012
|
-
}
|
|
1013
|
-
set(
|
|
1014
|
-
(state) => produce(state, (draft) => {
|
|
1015
|
-
const updatedNodes = applyNodeChanges(
|
|
1016
|
-
changes,
|
|
1017
|
-
draft.workflow.nodes
|
|
1018
|
-
);
|
|
1019
|
-
draft.workflow.nodes = updatedNodes;
|
|
1020
|
-
})
|
|
1021
|
-
);
|
|
1022
|
-
},
|
|
1023
|
-
setNodes: (nodes, opts) => {
|
|
1024
|
-
if (!opts?.skipHistory) {
|
|
1025
|
-
pushCheckpoint(
|
|
1026
|
-
opts?.historyKind ?? "nodes:set",
|
|
1027
|
-
!!opts?.historyKind
|
|
1028
|
-
);
|
|
1029
|
-
}
|
|
1030
|
-
set({ workflow: { ...get().workflow, nodes } });
|
|
1031
|
-
},
|
|
1032
|
-
deleteNode: (node) => {
|
|
1033
|
-
const exists = get().workflow.nodes.some((n) => n.id === node.id);
|
|
1034
|
-
if (exists) pushCheckpoint("nodes:delete", false);
|
|
1035
|
-
set((state) => ({
|
|
1036
|
-
workflow: {
|
|
1037
|
-
...state.workflow,
|
|
1038
|
-
nodes: state.workflow.nodes.filter((n) => n.id !== node.id),
|
|
1039
|
-
// Drop any UI state pointing at the removed node.
|
|
1040
|
-
...state.workflow.quickConfig?.nodeId === node.id ? { quickConfig: null } : {},
|
|
1041
|
-
...state.workflow.pendingConnection?.nodeId === node.id ? { pendingConnection: null } : {}
|
|
1042
|
-
}
|
|
1043
|
-
}));
|
|
1044
|
-
},
|
|
1045
|
-
deleteNodes: (nodes) => {
|
|
1046
|
-
const ids = new Set(nodes.map((n) => n.id));
|
|
1047
|
-
if (ids.size === 0) return;
|
|
1048
|
-
const anyExist = get().workflow.nodes.some((n) => ids.has(n.id));
|
|
1049
|
-
if (anyExist) pushCheckpoint("nodes:delete", false);
|
|
1050
|
-
set((state) => ({
|
|
1051
|
-
workflow: {
|
|
1052
|
-
...state.workflow,
|
|
1053
|
-
nodes: state.workflow.nodes.filter((n) => !ids.has(n.id)),
|
|
1054
|
-
edges: state.workflow.edges.filter(
|
|
1055
|
-
(e) => !ids.has(e.source) && !ids.has(e.target)
|
|
1056
|
-
),
|
|
1057
|
-
...state.workflow.quickConfig && ids.has(state.workflow.quickConfig.nodeId) ? { quickConfig: null } : {},
|
|
1058
|
-
...state.workflow.pendingConnection && ids.has(state.workflow.pendingConnection.nodeId) ? { pendingConnection: null } : {}
|
|
1059
|
-
}
|
|
1060
|
-
}));
|
|
1061
|
-
},
|
|
1062
|
-
duplicateNodes: (nodeIds) => {
|
|
1063
|
-
const { nodes, edges } = get().workflow;
|
|
1064
|
-
const idSet = new Set(nodeIds);
|
|
1065
|
-
const selected = nodes.filter((n) => idSet.has(n.id));
|
|
1066
|
-
if (selected.length === 0) return;
|
|
1067
|
-
pushCheckpoint("nodes:duplicate", false);
|
|
1068
|
-
const idMap = /* @__PURE__ */ new Map();
|
|
1069
|
-
const clones = selected.map((n) => {
|
|
1070
|
-
const newId = nanoid();
|
|
1071
|
-
idMap.set(n.id, newId);
|
|
1072
|
-
const cloned = cloneValue(n);
|
|
1073
|
-
return {
|
|
1074
|
-
...cloned,
|
|
1075
|
-
id: newId,
|
|
1076
|
-
position: {
|
|
1077
|
-
x: cloned.position.x + CLONE_OFFSET,
|
|
1078
|
-
y: cloned.position.y + CLONE_OFFSET
|
|
1079
|
-
},
|
|
1080
|
-
selected: true
|
|
1081
|
-
};
|
|
1082
|
-
});
|
|
1083
|
-
const clonedEdges = edges.filter((e) => idMap.has(e.source) && idMap.has(e.target)).map((e) => {
|
|
1084
|
-
const cloned = cloneValue(e);
|
|
1085
|
-
return {
|
|
1086
|
-
...cloned,
|
|
1087
|
-
id: nanoid(),
|
|
1088
|
-
source: idMap.get(e.source),
|
|
1089
|
-
target: idMap.get(e.target),
|
|
1090
|
-
selected: false
|
|
1091
|
-
};
|
|
1092
|
-
});
|
|
1093
|
-
set((state) => ({
|
|
1094
|
-
workflow: {
|
|
1095
|
-
...state.workflow,
|
|
1096
|
-
nodes: [
|
|
1097
|
-
...state.workflow.nodes.map(
|
|
1098
|
-
(n) => idSet.has(n.id) ? { ...n, selected: false } : n
|
|
1099
|
-
),
|
|
1100
|
-
...clones
|
|
1101
|
-
],
|
|
1102
|
-
edges: [...state.workflow.edges, ...clonedEdges]
|
|
1103
|
-
}
|
|
1104
|
-
}));
|
|
1105
|
-
},
|
|
1106
|
-
pasteNodes: (payload) => {
|
|
1107
|
-
const pasteNodesIn = payload.nodes ?? [];
|
|
1108
|
-
if (pasteNodesIn.length === 0) return;
|
|
1109
|
-
pushCheckpoint("nodes:paste", false);
|
|
1110
|
-
const idMap = /* @__PURE__ */ new Map();
|
|
1111
|
-
const clones = pasteNodesIn.map((n) => {
|
|
1112
|
-
const newId = nanoid();
|
|
1113
|
-
idMap.set(n.id, newId);
|
|
1114
|
-
const cloned = cloneValue(n);
|
|
1115
|
-
return {
|
|
1116
|
-
...cloned,
|
|
1117
|
-
id: newId,
|
|
1118
|
-
position: {
|
|
1119
|
-
x: (cloned.position?.x ?? 0) + CLONE_OFFSET,
|
|
1120
|
-
y: (cloned.position?.y ?? 0) + CLONE_OFFSET
|
|
1121
|
-
},
|
|
1122
|
-
selected: true
|
|
1123
|
-
};
|
|
1124
|
-
});
|
|
1125
|
-
const clonedEdges = (payload.edges ?? []).filter((e) => idMap.has(e.source) && idMap.has(e.target)).map((e) => {
|
|
1126
|
-
const cloned = cloneValue(e);
|
|
1127
|
-
return {
|
|
1128
|
-
...cloned,
|
|
1129
|
-
id: nanoid(),
|
|
1130
|
-
source: idMap.get(e.source),
|
|
1131
|
-
target: idMap.get(e.target),
|
|
1132
|
-
selected: false
|
|
1133
|
-
};
|
|
1134
|
-
});
|
|
1135
|
-
set((state) => ({
|
|
1136
|
-
workflow: {
|
|
1137
|
-
...state.workflow,
|
|
1138
|
-
nodes: [
|
|
1139
|
-
...state.workflow.nodes.map((n) => ({ ...n, selected: false })),
|
|
1140
|
-
...clones
|
|
1141
|
-
],
|
|
1142
|
-
edges: [...state.workflow.edges, ...clonedEdges]
|
|
1143
|
-
}
|
|
1144
|
-
}));
|
|
1145
|
-
},
|
|
1146
|
-
toggleDisabled: (nodeId) => {
|
|
1147
|
-
const { nodes, edges } = get().workflow;
|
|
1148
|
-
const updatedNodes = nodes.map((node) => {
|
|
1149
|
-
if (node.id !== nodeId) return node;
|
|
1150
|
-
const data = node.data ?? {};
|
|
1151
|
-
return {
|
|
1152
|
-
...node,
|
|
1153
|
-
data: { ...data, disabled: !(data.disabled === true) }
|
|
1154
|
-
};
|
|
1155
|
-
});
|
|
1156
|
-
const breaksLoop = edges.some(
|
|
1157
|
-
(edge) => edge.source === nodeId && isLoopBodyEdge(edge, nodes) && !isValidWorkflowConnection(updatedNodes, edges, edge)
|
|
1158
|
-
);
|
|
1159
|
-
if (breaksLoop) return false;
|
|
1160
|
-
pushCheckpoint("nodes:disable", false);
|
|
1161
|
-
set((state) => ({
|
|
1162
|
-
workflow: {
|
|
1163
|
-
...state.workflow,
|
|
1164
|
-
nodes: updatedNodes
|
|
1165
|
-
}
|
|
1166
|
-
}));
|
|
1167
|
-
return true;
|
|
1168
|
-
},
|
|
1169
|
-
renameNode: (nodeId, label) => {
|
|
1170
|
-
pushCheckpoint("nodes:rename", false);
|
|
1171
|
-
set((state) => ({
|
|
1172
|
-
workflow: {
|
|
1173
|
-
...state.workflow,
|
|
1174
|
-
nodes: state.workflow.nodes.map(
|
|
1175
|
-
(n) => n.id === nodeId ? { ...n, data: { ...n.data ?? {}, label } } : n
|
|
1176
|
-
),
|
|
1177
|
-
renamingNodeId: null
|
|
1178
|
-
}
|
|
1179
|
-
}));
|
|
1180
|
-
},
|
|
1181
|
-
startRename: (nodeId) => {
|
|
1182
|
-
set((state) => ({
|
|
1183
|
-
workflow: { ...state.workflow, renamingNodeId: nodeId }
|
|
1184
|
-
}));
|
|
1185
|
-
},
|
|
1186
|
-
endRename: () => {
|
|
1187
|
-
set((state) => ({
|
|
1188
|
-
workflow: { ...state.workflow, renamingNodeId: null }
|
|
1189
|
-
}));
|
|
1190
|
-
}
|
|
1191
|
-
},
|
|
1192
|
-
edges: {
|
|
1193
|
-
onEdgesChange: (changes) => {
|
|
1194
|
-
const removedIds = new Set(
|
|
1195
|
-
changes.filter(
|
|
1196
|
-
(c) => c.type === "remove"
|
|
1197
|
-
).map((c) => c.id)
|
|
1198
|
-
);
|
|
1199
|
-
if (removedIds.size > 0) {
|
|
1200
|
-
const stillPresent = get().workflow.edges.some(
|
|
1201
|
-
(e) => removedIds.has(e.id)
|
|
1202
|
-
);
|
|
1203
|
-
if (stillPresent && !joinsPrecedingRemoval("edges:remove")) {
|
|
1204
|
-
pushCheckpoint("edges:remove", false);
|
|
1205
|
-
}
|
|
1206
|
-
} else if (changes.some((c) => c.type === "add")) {
|
|
1207
|
-
pushCheckpoint("edges:add", false);
|
|
1208
|
-
}
|
|
1209
|
-
set(
|
|
1210
|
-
(state) => produce(state, (draft) => {
|
|
1211
|
-
const updatedEdges = applyEdgeChanges(
|
|
1212
|
-
changes,
|
|
1213
|
-
draft.workflow.edges
|
|
1214
|
-
);
|
|
1215
|
-
draft.workflow.edges = updatedEdges;
|
|
1216
|
-
})
|
|
1217
|
-
);
|
|
1218
|
-
},
|
|
1219
|
-
onConnect: (connection) => {
|
|
1220
|
-
pushCheckpoint("edges:connect", false);
|
|
1221
|
-
const edge = {
|
|
1222
|
-
...connection,
|
|
1223
|
-
id: nanoid(),
|
|
1224
|
-
type: "deletable"
|
|
1225
|
-
};
|
|
1226
|
-
set({
|
|
1227
|
-
workflow: {
|
|
1228
|
-
...get().workflow,
|
|
1229
|
-
edges: addEdge(edge, get().workflow.edges)
|
|
1230
|
-
}
|
|
1231
|
-
});
|
|
1232
|
-
},
|
|
1233
|
-
setEdges: (edges, opts) => {
|
|
1234
|
-
if (!opts?.skipHistory) {
|
|
1235
|
-
pushCheckpoint(
|
|
1236
|
-
opts?.historyKind ?? "edges:set",
|
|
1237
|
-
!!opts?.historyKind
|
|
1238
|
-
);
|
|
1239
|
-
}
|
|
1240
|
-
set({ workflow: { ...get().workflow, edges } });
|
|
1241
|
-
},
|
|
1242
|
-
deleteEdge: (edge) => {
|
|
1243
|
-
const exists = get().workflow.edges.some((e) => e.id === edge.id);
|
|
1244
|
-
if (exists) pushCheckpoint("edges:delete", false);
|
|
1245
|
-
set((state) => ({
|
|
1246
|
-
workflow: {
|
|
1247
|
-
...state.workflow,
|
|
1248
|
-
edges: state.workflow.edges.filter((e) => e.id !== edge.id)
|
|
1249
|
-
}
|
|
1250
|
-
}));
|
|
1251
|
-
}
|
|
1252
|
-
},
|
|
1253
|
-
execution: {
|
|
1254
|
-
startExecution: (nodeId, runId, metadata) => {
|
|
1255
|
-
set((state) => ({
|
|
1256
|
-
execution: {
|
|
1257
|
-
...state.execution,
|
|
1258
|
-
isExecuting: true,
|
|
1259
|
-
executingNodeId: nodeId,
|
|
1260
|
-
currentRunId: runId,
|
|
1261
|
-
sourceRun: metadata ? { runId, ...metadata } : { runId, workflowKey: "", version: "" },
|
|
1262
|
-
panelExpanded: true,
|
|
1263
|
-
nodeStatuses: {
|
|
1264
|
-
...state.execution.nodeStatuses,
|
|
1265
|
-
[nodeId]: "running"
|
|
1266
|
-
}
|
|
1267
|
-
}
|
|
1268
|
-
}));
|
|
1269
|
-
},
|
|
1270
|
-
setRunMetadata: (metadata) => {
|
|
1271
|
-
set((state) => {
|
|
1272
|
-
if (state.execution.currentRunId !== metadata.runId && state.execution.sourceRun?.runId !== metadata.runId) {
|
|
1273
|
-
return state;
|
|
1274
|
-
}
|
|
1275
|
-
return {
|
|
1276
|
-
execution: {
|
|
1277
|
-
...state.execution,
|
|
1278
|
-
currentRunId: metadata.runId,
|
|
1279
|
-
sourceRun: metadata
|
|
1280
|
-
}
|
|
1281
|
-
};
|
|
1282
|
-
});
|
|
1283
|
-
},
|
|
1284
|
-
setStepPlan: (plan) => {
|
|
1285
|
-
set((state) => ({
|
|
1286
|
-
execution: {
|
|
1287
|
-
...state.execution,
|
|
1288
|
-
stepPlan: plan
|
|
1289
|
-
}
|
|
1290
|
-
}));
|
|
1291
|
-
},
|
|
1292
|
-
addLog: (log) => {
|
|
1293
|
-
set((state) => ({
|
|
1294
|
-
execution: {
|
|
1295
|
-
...state.execution,
|
|
1296
|
-
logs: [...state.execution.logs, log],
|
|
1297
|
-
selectedLogId: log.id
|
|
1298
|
-
}
|
|
1299
|
-
}));
|
|
1300
|
-
},
|
|
1301
|
-
updateLog: (logId, updates) => {
|
|
1302
|
-
set((state) => ({
|
|
1303
|
-
execution: {
|
|
1304
|
-
...state.execution,
|
|
1305
|
-
logs: state.execution.logs.map(
|
|
1306
|
-
(log) => log.id === logId ? { ...log, ...updates } : log
|
|
1307
|
-
)
|
|
1308
|
-
}
|
|
1309
|
-
}));
|
|
1310
|
-
},
|
|
1311
|
-
setNodeStatus: (nodeId, status) => {
|
|
1312
|
-
set((state) => ({
|
|
1313
|
-
execution: {
|
|
1314
|
-
...state.execution,
|
|
1315
|
-
nodeStatuses: {
|
|
1316
|
-
...state.execution.nodeStatuses,
|
|
1317
|
-
[nodeId]: status
|
|
1318
|
-
}
|
|
1319
|
-
}
|
|
1320
|
-
}));
|
|
1321
|
-
},
|
|
1322
|
-
setNodeItemCount: (nodeId, count) => {
|
|
1323
|
-
set((state) => ({
|
|
1324
|
-
execution: {
|
|
1325
|
-
...state.execution,
|
|
1326
|
-
nodeItemCounts: {
|
|
1327
|
-
...state.execution.nodeItemCounts,
|
|
1328
|
-
[nodeId]: count
|
|
1329
|
-
}
|
|
1330
|
-
}
|
|
1331
|
-
}));
|
|
1332
|
-
},
|
|
1333
|
-
selectLog: (logId) => {
|
|
1334
|
-
set((state) => ({
|
|
1335
|
-
execution: {
|
|
1336
|
-
...state.execution,
|
|
1337
|
-
selectedLogId: logId
|
|
1338
|
-
}
|
|
1339
|
-
}));
|
|
1340
|
-
},
|
|
1341
|
-
togglePanel: () => {
|
|
1342
|
-
set((state) => ({
|
|
1343
|
-
execution: {
|
|
1344
|
-
...state.execution,
|
|
1345
|
-
panelExpanded: !state.execution.panelExpanded
|
|
1346
|
-
}
|
|
1347
|
-
}));
|
|
1348
|
-
},
|
|
1349
|
-
clearLogs: () => {
|
|
1350
|
-
set((state) => ({
|
|
1351
|
-
execution: {
|
|
1352
|
-
...state.execution,
|
|
1353
|
-
logs: [],
|
|
1354
|
-
stepPlan: null,
|
|
1355
|
-
currentRunId: null,
|
|
1356
|
-
sourceRun: null,
|
|
1357
|
-
selectedLogId: null,
|
|
1358
|
-
nodeStatuses: {},
|
|
1359
|
-
nodeItemCounts: {}
|
|
1360
|
-
}
|
|
1361
|
-
}));
|
|
1362
|
-
},
|
|
1363
|
-
completeExecution: () => {
|
|
1364
|
-
set((state) => ({
|
|
1365
|
-
execution: {
|
|
1366
|
-
...state.execution,
|
|
1367
|
-
isExecuting: false,
|
|
1368
|
-
executingNodeId: null
|
|
1369
|
-
}
|
|
1370
|
-
}));
|
|
1371
|
-
},
|
|
1372
|
-
requestFollowRun: (runId, triggerNodeId) => {
|
|
1373
|
-
set((state) => ({
|
|
1374
|
-
execution: {
|
|
1375
|
-
...state.execution,
|
|
1376
|
-
followRequest: { runId, triggerNodeId }
|
|
1377
|
-
}
|
|
1378
|
-
}));
|
|
1379
|
-
},
|
|
1380
|
-
clearFollowRequest: () => {
|
|
1381
|
-
set((state) => ({
|
|
1382
|
-
execution: { ...state.execution, followRequest: null }
|
|
1383
|
-
}));
|
|
1384
|
-
},
|
|
1385
|
-
loadDebugRun: (runId, logs, metadata) => {
|
|
1386
|
-
const nodeStatuses = {};
|
|
1387
|
-
for (const log of logs) {
|
|
1388
|
-
nodeStatuses[log.nodeId] = log.status === "completed" ? "success" : log.status === "failed" ? "error" : log.status === "running" ? "running" : "idle";
|
|
1389
|
-
}
|
|
1390
|
-
set(() => ({
|
|
1391
|
-
execution: {
|
|
1392
|
-
...INITIAL_EXECUTION,
|
|
1393
|
-
currentRunId: runId,
|
|
1394
|
-
sourceRun: metadata ? { runId, ...metadata } : { runId, workflowKey: "", version: "" },
|
|
1395
|
-
logs,
|
|
1396
|
-
nodeStatuses,
|
|
1397
|
-
panelExpanded: true
|
|
1398
|
-
}
|
|
1399
|
-
}));
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
};
|
|
1404
|
-
});
|
|
1405
|
-
if (typeof window !== "undefined" && import.meta.env?.DEV) {
|
|
1406
|
-
window.__fgFlowStore = useFlowStore;
|
|
1407
|
-
}
|
|
1408
512
|
function useDeleteNode() {
|
|
1409
513
|
const { getNode, getEdges, deleteElements } = useReactFlow();
|
|
1410
514
|
const deleteNodes = useFlowStore((state) => state.actions.nodes.deleteNodes);
|
|
@@ -1420,11 +524,6 @@ function useDeleteNode() {
|
|
|
1420
524
|
[deleteElements, getEdges, getNode, deleteNodes]
|
|
1421
525
|
);
|
|
1422
526
|
}
|
|
1423
|
-
|
|
1424
|
-
// src/builder/contants/symbols.ts
|
|
1425
|
-
var NODE_TYPE_DRAG_DATA_FORMAT = "application/flow-builder.node-type";
|
|
1426
|
-
var NODE_OPERATION_DRAG_DATA_FORMAT = "application/flow-builder.node-operation";
|
|
1427
|
-
var STICKY_NOTE_TYPE = "sticky-note";
|
|
1428
527
|
var STICKY_COLORS = {
|
|
1429
528
|
yellow: "var(--color-chart-4)",
|
|
1430
529
|
orange: "var(--color-status-warning-bg)",
|
|
@@ -1520,7 +619,7 @@ function StickyNoteNodeComponent({
|
|
|
1520
619
|
if (!source) return;
|
|
1521
620
|
const clone = {
|
|
1522
621
|
...source,
|
|
1523
|
-
id: nanoid
|
|
622
|
+
id: nanoid(),
|
|
1524
623
|
position: {
|
|
1525
624
|
x: source.position.x + 24,
|
|
1526
625
|
y: source.position.y + 24
|
|
@@ -1644,1158 +743,204 @@ function StickyNoteNodeComponent({
|
|
|
1644
743
|
/* @__PURE__ */ jsx(
|
|
1645
744
|
"div",
|
|
1646
745
|
{
|
|
1647
|
-
className: "flex h-full w-full flex-col overflow-hidden rounded-lg border",
|
|
1648
|
-
style: {
|
|
1649
|
-
backgroundColor: `${accent}1F`,
|
|
1650
|
-
// Same border whether selected or not — selection shows only via the
|
|
1651
|
-
// floating toolbar (no extra border/outline on click).
|
|
1652
|
-
borderColor: `${accent}59`
|
|
1653
|
-
},
|
|
1654
|
-
onDoubleClick: (e) => {
|
|
1655
|
-
e.stopPropagation();
|
|
1656
|
-
if (!readOnly) startEditing();
|
|
1657
|
-
},
|
|
1658
|
-
children: editing ? /* @__PURE__ */ jsx(
|
|
1659
|
-
"textarea",
|
|
1660
|
-
{
|
|
1661
|
-
ref: textareaRef,
|
|
1662
|
-
readOnly,
|
|
1663
|
-
value: draft,
|
|
1664
|
-
onChange: (e) => setDraft(e.target.value),
|
|
1665
|
-
onBlur: commitEdit,
|
|
1666
|
-
onKeyDown: (e) => {
|
|
1667
|
-
e.stopPropagation();
|
|
1668
|
-
if (e.key === "Escape") cancelEdit();
|
|
1669
|
-
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) commitEdit();
|
|
1670
|
-
},
|
|
1671
|
-
placeholder: tr(
|
|
1672
|
-
"fluidgrids.builder.stickyNote.editorPlaceholder",
|
|
1673
|
-
"# Note\nSupports **markdown** \u2014 headings, lists, links\u2026"
|
|
1674
|
-
),
|
|
1675
|
-
className: "nodrag nowheel h-full w-full resize-none bg-transparent p-3 font-mono text-xs leading-relaxed text-foreground outline-none placeholder:text-muted-foreground/60"
|
|
1676
|
-
}
|
|
1677
|
-
) : content.trim() ? /* @__PURE__ */ jsx(
|
|
1678
|
-
"div",
|
|
1679
|
-
{
|
|
1680
|
-
className: cn(
|
|
1681
|
-
"nowheel h-full w-full overflow-auto p-3 text-xs leading-relaxed text-foreground",
|
|
1682
|
-
// Compact markdown typography scoped to the note body.
|
|
1683
|
-
"[&_h1]:mb-1.5 [&_h1]:text-sm [&_h1]:font-bold",
|
|
1684
|
-
"[&_h2]:mb-1 [&_h2]:text-[13px] [&_h2]:font-bold",
|
|
1685
|
-
"[&_h3]:mb-1 [&_h3]:text-xs [&_h3]:font-semibold",
|
|
1686
|
-
"[&_p]:mb-1.5 [&_ul]:mb-1.5 [&_ul]:list-disc [&_ul]:pl-4",
|
|
1687
|
-
"[&_ol]:mb-1.5 [&_ol]:list-decimal [&_ol]:pl-4 [&_li]:mb-0.5",
|
|
1688
|
-
"[&_a]:underline [&_code]:rounded [&_code]:bg-muted [&_code]:px-1"
|
|
1689
|
-
),
|
|
1690
|
-
children: /* @__PURE__ */ jsx(ReactMarkdown, { children: content })
|
|
1691
|
-
}
|
|
1692
|
-
) : /* @__PURE__ */ jsx("div", { className: "flex h-full w-full items-center justify-center p-3 text-xs text-muted-foreground/70", children: tr(
|
|
1693
|
-
"fluidgrids.builder.stickyNote.emptyStateHint",
|
|
1694
|
-
"Double-click to edit"
|
|
1695
|
-
) })
|
|
1696
|
-
}
|
|
1697
|
-
)
|
|
1698
|
-
] })
|
|
1699
|
-
);
|
|
1700
|
-
}
|
|
1701
|
-
var StickyNoteNode = memo(StickyNoteNodeComponent);
|
|
1702
|
-
function buildStickyNode(position) {
|
|
1703
|
-
return {
|
|
1704
|
-
id: nanoid$1(),
|
|
1705
|
-
type: STICKY_NOTE_TYPE,
|
|
1706
|
-
position,
|
|
1707
|
-
width: STICKY_DEFAULT_SIZE.width,
|
|
1708
|
-
height: STICKY_DEFAULT_SIZE.height,
|
|
1709
|
-
// Render under regular nodes and edges — notes are a background layer.
|
|
1710
|
-
zIndex: -1,
|
|
1711
|
-
selected: true,
|
|
1712
|
-
data: { content: "", color: DEFAULT_STICKY_COLOR }
|
|
1713
|
-
};
|
|
1714
|
-
}
|
|
1715
|
-
|
|
1716
|
-
// src/modules/connections/utils/adapter-selection.ts
|
|
1717
|
-
var ANY_PROVIDER = "*";
|
|
1718
|
-
function isOptionalAdapter(adapter) {
|
|
1719
|
-
return adapter.required === false;
|
|
1720
|
-
}
|
|
1721
|
-
function newConnectionProviderKey(adapters) {
|
|
1722
|
-
if (adapters.length !== 1) return void 0;
|
|
1723
|
-
const provider = adapters[0]?.provider;
|
|
1724
|
-
return provider && provider !== ANY_PROVIDER ? provider : void 0;
|
|
1725
|
-
}
|
|
1726
|
-
function matchesAdapterProvider(adapter, providerKey) {
|
|
1727
|
-
const normalizedKey = providerKey.trim().toLowerCase();
|
|
1728
|
-
if (normalizedKey.length === 0) return false;
|
|
1729
|
-
if (adapter.provider.trim() === ANY_PROVIDER) return true;
|
|
1730
|
-
return adapter.provider.trim().toLowerCase() === normalizedKey || adapter.name.trim().toLowerCase() === normalizedKey;
|
|
1731
|
-
}
|
|
1732
|
-
function connectionsForAdapter(connections, adapterName) {
|
|
1733
|
-
return connections.filter(
|
|
1734
|
-
(connection) => connection.adapter.toLowerCase() === adapterName.toLowerCase()
|
|
1735
|
-
);
|
|
1736
|
-
}
|
|
1737
|
-
function replaceAdapterConnections(connections, adapterName, connectionIds = []) {
|
|
1738
|
-
const otherConnections = connections.filter(
|
|
1739
|
-
(connection) => connection.adapter.toLowerCase() !== adapterName.toLowerCase()
|
|
1740
|
-
);
|
|
1741
|
-
const uniqueIds = [...new Set(connectionIds.filter(Boolean))];
|
|
1742
|
-
return [
|
|
1743
|
-
...otherConnections,
|
|
1744
|
-
...uniqueIds.map((connectionId) => ({
|
|
1745
|
-
connectionId,
|
|
1746
|
-
adapter: adapterName
|
|
1747
|
-
}))
|
|
1748
|
-
];
|
|
1749
|
-
}
|
|
1750
|
-
function missingRequiredAdapters(adapters, selected) {
|
|
1751
|
-
return adapters.filter(
|
|
1752
|
-
(adapter) => !isOptionalAdapter(adapter) && !selected.some((connection) => connection.adapter === adapter.name)
|
|
1753
|
-
);
|
|
1754
|
-
}
|
|
1755
|
-
var NODE_DOCS_URL = gql`
|
|
1756
|
-
query NodeDocsUrlLookup($nodeType: String!, $nodeVersion: String!) {
|
|
1757
|
-
nodeEndpointConfig(nodeType: $nodeType, nodeVersion: $nodeVersion) {
|
|
1758
|
-
docsUrl
|
|
1759
|
-
}
|
|
1760
|
-
}
|
|
1761
|
-
`;
|
|
1762
|
-
var cache = /* @__PURE__ */ new Map();
|
|
1763
|
-
var inFlight = /* @__PURE__ */ new Map();
|
|
1764
|
-
function fetchDocsUrl(nodeType, nodeVersion) {
|
|
1765
|
-
const key = `${nodeType}@${nodeVersion}`;
|
|
1766
|
-
if (cache.has(key)) return Promise.resolve(cache.get(key));
|
|
1767
|
-
const existing = inFlight.get(key);
|
|
1768
|
-
if (existing) return existing;
|
|
1769
|
-
const client = getFluidGridsClientSafe();
|
|
1770
|
-
if (!client) {
|
|
1771
|
-
cache.set(key, void 0);
|
|
1772
|
-
return Promise.resolve(void 0);
|
|
1773
|
-
}
|
|
1774
|
-
const promise = client.query({
|
|
1775
|
-
query: NODE_DOCS_URL,
|
|
1776
|
-
variables: { nodeType, nodeVersion },
|
|
1777
|
-
fetchPolicy: "cache-first"
|
|
1778
|
-
}).then((result) => result.data?.nodeEndpointConfig?.docsUrl ?? void 0).catch(() => void 0).finally(() => inFlight.delete(key));
|
|
1779
|
-
inFlight.set(key, promise);
|
|
1780
|
-
return promise.then((url) => {
|
|
1781
|
-
cache.set(key, url);
|
|
1782
|
-
return url;
|
|
1783
|
-
});
|
|
1784
|
-
}
|
|
1785
|
-
function useNodeDocsUrl(nodeType, nodeVersion) {
|
|
1786
|
-
const [docsUrl, setDocsUrl] = useState(
|
|
1787
|
-
() => nodeType && nodeVersion ? cache.get(`${nodeType}@${nodeVersion}`) : void 0
|
|
1788
|
-
);
|
|
1789
|
-
useEffect(() => {
|
|
1790
|
-
if (!nodeType || !nodeVersion) {
|
|
1791
|
-
setDocsUrl(void 0);
|
|
1792
|
-
return;
|
|
1793
|
-
}
|
|
1794
|
-
let cancelled = false;
|
|
1795
|
-
fetchDocsUrl(nodeType, nodeVersion).then((url) => {
|
|
1796
|
-
if (!cancelled) setDocsUrl(url);
|
|
1797
|
-
});
|
|
1798
|
-
return () => {
|
|
1799
|
-
cancelled = true;
|
|
1800
|
-
};
|
|
1801
|
-
}, [nodeType, nodeVersion]);
|
|
1802
|
-
return docsUrl;
|
|
1803
|
-
}
|
|
1804
|
-
function isImageIcon(icon) {
|
|
1805
|
-
return !!icon && (/^https?:\/\//.test(icon) || icon.startsWith("data:"));
|
|
1806
|
-
}
|
|
1807
|
-
function NodeTypeIcon({
|
|
1808
|
-
icon,
|
|
1809
|
-
alt,
|
|
1810
|
-
className,
|
|
1811
|
-
fallbackIcon = "mynaui:puzzle"
|
|
1812
|
-
}) {
|
|
1813
|
-
if (isImageIcon(icon)) {
|
|
1814
|
-
return /* @__PURE__ */ jsx(
|
|
1815
|
-
"img",
|
|
1816
|
-
{
|
|
1817
|
-
src: icon,
|
|
1818
|
-
alt: alt ?? "",
|
|
1819
|
-
className: cn("object-contain", className)
|
|
1820
|
-
}
|
|
1821
|
-
);
|
|
1822
|
-
}
|
|
1823
|
-
return /* @__PURE__ */ jsx(Icon, { icon: icon || fallbackIcon, className });
|
|
1824
|
-
}
|
|
1825
|
-
var PROVIDER_ACCENTS = [
|
|
1826
|
-
[/gmail|google/, "var(--color-chart-5)"],
|
|
1827
|
-
[/slack/, "var(--color-chart-3)"],
|
|
1828
|
-
[/github|gitlab/, nodeCategoryColor("utility")],
|
|
1829
|
-
[/stripe/, "var(--color-chart-12)"],
|
|
1830
|
-
[/discord|telegram/, "var(--color-chart-1)"],
|
|
1831
|
-
[/notion/, "var(--color-text-primary)"],
|
|
1832
|
-
[/whatsapp|sheet|excel/, "var(--color-chart-7)"],
|
|
1833
|
-
[/openai|anthropic|claude/, nodeCategoryColor("ai")],
|
|
1834
|
-
[/twilio/, "var(--color-chart-10)"],
|
|
1835
|
-
[/http|api|webhook|rest/, nodeCategoryColor("integration")],
|
|
1836
|
-
[/db|sql|postgres|mysql|mongo/, nodeCategoryColor("data")]
|
|
1837
|
-
];
|
|
1838
|
-
function nodeAccent(key) {
|
|
1839
|
-
const k = (key || "").toLowerCase();
|
|
1840
|
-
for (const [re, color] of PROVIDER_ACCENTS) if (re.test(k)) return color;
|
|
1841
|
-
return chartSeriesColor(chartSeriesIndex(k));
|
|
1842
|
-
}
|
|
1843
|
-
function tint(color, pct = 14) {
|
|
1844
|
-
return `color-mix(in srgb, ${color} ${pct}%, transparent)`;
|
|
1845
|
-
}
|
|
1846
|
-
function InlineEditableLabel({
|
|
1847
|
-
value,
|
|
1848
|
-
placeholder,
|
|
1849
|
-
editing,
|
|
1850
|
-
onStartEdit,
|
|
1851
|
-
onCommit,
|
|
1852
|
-
onCancel,
|
|
1853
|
-
className,
|
|
1854
|
-
inputClassName
|
|
1855
|
-
}) {
|
|
1856
|
-
const tr = useTr();
|
|
1857
|
-
const [draft, setDraft] = React.useState(value);
|
|
1858
|
-
const inputRef = React.useRef(null);
|
|
1859
|
-
React.useEffect(() => {
|
|
1860
|
-
if (!editing) return;
|
|
1861
|
-
setDraft(value);
|
|
1862
|
-
const raf = requestAnimationFrame(() => {
|
|
1863
|
-
inputRef.current?.focus();
|
|
1864
|
-
inputRef.current?.select();
|
|
1865
|
-
});
|
|
1866
|
-
return () => cancelAnimationFrame(raf);
|
|
1867
|
-
}, [editing, value]);
|
|
1868
|
-
if (editing) {
|
|
1869
|
-
return /* @__PURE__ */ jsx(
|
|
1870
|
-
"input",
|
|
1871
|
-
{
|
|
1872
|
-
ref: inputRef,
|
|
1873
|
-
value: draft,
|
|
1874
|
-
onChange: (e) => setDraft(e.target.value),
|
|
1875
|
-
onClick: (e) => e.stopPropagation(),
|
|
1876
|
-
onDoubleClick: (e) => e.stopPropagation(),
|
|
1877
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
1878
|
-
onKeyDown: (e) => {
|
|
1879
|
-
e.stopPropagation();
|
|
1880
|
-
if (e.key === "Enter") {
|
|
1881
|
-
e.preventDefault();
|
|
1882
|
-
onCommit(draft.trim());
|
|
1883
|
-
} else if (e.key === "Escape") {
|
|
1884
|
-
e.preventDefault();
|
|
1885
|
-
onCancel();
|
|
1886
|
-
}
|
|
1887
|
-
},
|
|
1888
|
-
onBlur: () => onCommit(draft.trim()),
|
|
1889
|
-
className: cn(
|
|
1890
|
-
"min-w-0 flex-1 rounded border border-primary/50 bg-card px-1 text-inherit outline-none",
|
|
1891
|
-
inputClassName
|
|
1892
|
-
)
|
|
1893
|
-
}
|
|
1894
|
-
);
|
|
1895
|
-
}
|
|
1896
|
-
return /* @__PURE__ */ jsx(
|
|
1897
|
-
"span",
|
|
1898
|
-
{
|
|
1899
|
-
className: cn("cursor-text truncate", className),
|
|
1900
|
-
title: tr(
|
|
1901
|
-
"fluidgrids.builder.nodeCard.renameTooltip",
|
|
1902
|
-
"Double-click or press F2 to rename"
|
|
1903
|
-
),
|
|
1904
|
-
onDoubleClick: (e) => {
|
|
1905
|
-
e.stopPropagation();
|
|
1906
|
-
onStartEdit();
|
|
1907
|
-
},
|
|
1908
|
-
children: value || placeholder
|
|
1909
|
-
}
|
|
1910
|
-
);
|
|
1911
|
-
}
|
|
1912
|
-
var NodeCard = React.forwardRef(
|
|
1913
|
-
({
|
|
1914
|
-
className,
|
|
1915
|
-
selected = false,
|
|
1916
|
-
executionStatus = "idle",
|
|
1917
|
-
itemCount,
|
|
1918
|
-
isTrigger = false,
|
|
1919
|
-
accent = nodeCategoryColor("action"),
|
|
1920
|
-
onSettings,
|
|
1921
|
-
onExecute,
|
|
1922
|
-
onDelete,
|
|
1923
|
-
isExecuting = false,
|
|
1924
|
-
infoButton,
|
|
1925
|
-
disabled = false,
|
|
1926
|
-
onToggleDisabled,
|
|
1927
|
-
children,
|
|
1928
|
-
...props
|
|
1929
|
-
}, ref) => {
|
|
1930
|
-
const tr = useTr();
|
|
1931
|
-
const [hovered, setHovered] = React.useState(false);
|
|
1932
|
-
const statusRing = executionStatus === "running" ? "ring-2 ring-[var(--color-status-success-border)] animate-pulse-border" : executionStatus === "success" ? "ring-2 ring-[var(--color-status-success-border)]" : executionStatus === "error" ? "ring-2 ring-[var(--color-status-error-border)]" : "";
|
|
1933
|
-
return /* @__PURE__ */ jsxs(
|
|
1934
|
-
"div",
|
|
1935
|
-
{
|
|
1936
|
-
className: "group/node relative",
|
|
1937
|
-
onMouseEnter: () => setHovered(true),
|
|
1938
|
-
onMouseLeave: () => setHovered(false),
|
|
1939
|
-
children: [
|
|
1940
|
-
itemCount !== void 0 && itemCount > 0 && /* @__PURE__ */ jsx("div", { className: "absolute -top-7 left-1/2 -translate-x-1/2 z-10", children: /* @__PURE__ */ jsxs("div", { className: "rounded-full border border-border bg-card px-2 py-0.5 text-[10px] font-medium text-muted-foreground shadow-sm", children: [
|
|
1941
|
-
itemCount,
|
|
1942
|
-
" ",
|
|
1943
|
-
itemCount !== 1 ? tr("fluidgrids.builder.nodeCard.itemCountOther", "items") : tr("fluidgrids.builder.nodeCard.itemCountOne", "item")
|
|
1944
|
-
] }) }),
|
|
1945
|
-
(onSettings || onExecute || onDelete || onToggleDisabled || infoButton) && /* @__PURE__ */ jsxs(
|
|
1946
|
-
"div",
|
|
1947
|
-
{
|
|
1948
|
-
className: cn(
|
|
1949
|
-
"absolute right-1 z-20 flex items-center gap-0.5 rounded-lg border border-border bg-card p-0.5 shadow-md transition-all duration-150",
|
|
1950
|
-
hovered ? "pointer-events-auto opacity-100" : "pointer-events-none opacity-0"
|
|
1951
|
-
),
|
|
1952
|
-
style: {
|
|
1953
|
-
// Inline offset (not a `-top-*` class) so it survives the host
|
|
1954
|
-
// app's Tailwind scan of fe-sdk source, which drops some spacing
|
|
1955
|
-
// utilities. The toolbar is ~30px tall; top:-15px centers it on
|
|
1956
|
-
// the card's top edge (half outside, half over the card).
|
|
1957
|
-
top: -15,
|
|
1958
|
-
transform: hovered ? "translateY(0)" : "translateY(4px)"
|
|
1959
|
-
},
|
|
1960
|
-
onClick: (e) => e.stopPropagation(),
|
|
1961
|
-
onDoubleClick: (e) => e.stopPropagation(),
|
|
1962
|
-
children: [
|
|
1963
|
-
onSettings && /* @__PURE__ */ jsx(
|
|
1964
|
-
ToolbarButton2,
|
|
1965
|
-
{
|
|
1966
|
-
title: tr(
|
|
1967
|
-
"fluidgrids.builder.nodeCard.configureTooltip",
|
|
1968
|
-
"Configure"
|
|
1969
|
-
),
|
|
1970
|
-
onClick: onSettings,
|
|
1971
|
-
children: /* @__PURE__ */ jsx(Icon, { icon: "lucide:sliders-horizontal", className: "size-4" })
|
|
1972
|
-
}
|
|
1973
|
-
),
|
|
1974
|
-
onExecute && /* @__PURE__ */ jsx(
|
|
1975
|
-
ToolbarButton2,
|
|
1976
|
-
{
|
|
1977
|
-
"data-agent": "confirm",
|
|
1978
|
-
title: tr(
|
|
1979
|
-
"fluidgrids.builder.nodeCard.executeTooltip",
|
|
1980
|
-
"Execute step"
|
|
1981
|
-
),
|
|
1982
|
-
onClick: onExecute,
|
|
1983
|
-
disabled: isExecuting,
|
|
1984
|
-
children: isExecuting ? /* @__PURE__ */ jsx(
|
|
1985
|
-
Icon,
|
|
1986
|
-
{
|
|
1987
|
-
icon: "svg-spinners:ring-resize",
|
|
1988
|
-
className: "size-4 text-[var(--color-status-success-text)]"
|
|
1989
|
-
}
|
|
1990
|
-
) : /* @__PURE__ */ jsx(
|
|
1991
|
-
Icon,
|
|
1992
|
-
{
|
|
1993
|
-
icon: "mdi:play",
|
|
1994
|
-
className: "size-4 text-[var(--color-status-success-text)]"
|
|
1995
|
-
}
|
|
1996
|
-
)
|
|
1997
|
-
}
|
|
1998
|
-
),
|
|
1999
|
-
infoButton,
|
|
2000
|
-
onToggleDisabled && /* @__PURE__ */ jsx(
|
|
2001
|
-
ToolbarButton2,
|
|
2002
|
-
{
|
|
2003
|
-
title: disabled ? tr(
|
|
2004
|
-
"fluidgrids.builder.nodeCard.enableTooltip",
|
|
2005
|
-
"Enable node"
|
|
2006
|
-
) : tr(
|
|
2007
|
-
"fluidgrids.builder.nodeCard.disableTooltip",
|
|
2008
|
-
"Disable node (skip on run)"
|
|
2009
|
-
),
|
|
2010
|
-
onClick: onToggleDisabled,
|
|
2011
|
-
children: /* @__PURE__ */ jsx(
|
|
2012
|
-
Icon,
|
|
2013
|
-
{
|
|
2014
|
-
icon: disabled ? "mdi:power" : "mdi:power-off",
|
|
2015
|
-
className: cn(
|
|
2016
|
-
"size-4",
|
|
2017
|
-
disabled ? "text-[var(--color-status-warning-text)]" : "text-muted-foreground"
|
|
2018
|
-
)
|
|
2019
|
-
}
|
|
2020
|
-
)
|
|
2021
|
-
}
|
|
2022
|
-
),
|
|
2023
|
-
onDelete && /* @__PURE__ */ jsx(
|
|
2024
|
-
ToolbarButton2,
|
|
2025
|
-
{
|
|
2026
|
-
title: tr(
|
|
2027
|
-
"fluidgrids.builder.nodeCard.deleteTooltip",
|
|
2028
|
-
"Delete"
|
|
2029
|
-
),
|
|
2030
|
-
onClick: onDelete,
|
|
2031
|
-
children: /* @__PURE__ */ jsx(
|
|
2032
|
-
Icon,
|
|
2033
|
-
{
|
|
2034
|
-
icon: "mynaui:trash",
|
|
2035
|
-
className: "size-4 text-[var(--color-status-error-text)]"
|
|
2036
|
-
}
|
|
2037
|
-
)
|
|
2038
|
-
}
|
|
2039
|
-
)
|
|
2040
|
-
]
|
|
2041
|
-
}
|
|
2042
|
-
),
|
|
2043
|
-
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: [
|
|
2044
|
-
/* @__PURE__ */ jsx(Icon, { icon: "mdi:power-off", className: "size-2.5" }),
|
|
2045
|
-
tr("fluidgrids.builder.nodeCard.disabledBadge", "Disabled")
|
|
2046
|
-
] }) }),
|
|
2047
|
-
/* @__PURE__ */ jsxs(
|
|
2048
|
-
"div",
|
|
2049
|
-
{
|
|
2050
|
-
ref,
|
|
2051
|
-
"data-selected": selected,
|
|
2052
|
-
className: cn(
|
|
2053
|
-
"relative w-72 rounded-xl border border-border bg-card shadow-sm will-change-transform",
|
|
2054
|
-
statusRing,
|
|
2055
|
-
executionStatus === "success" && "animate-success-glow",
|
|
2056
|
-
disabled && "opacity-50 grayscale-[0.6]",
|
|
2057
|
-
className
|
|
2058
|
-
),
|
|
2059
|
-
style: {
|
|
2060
|
-
borderTop: `3px solid ${accent}`,
|
|
2061
|
-
transition: "transform 0.15s ease, box-shadow 0.15s ease",
|
|
2062
|
-
transform: hovered ? "translateY(-2px)" : "none",
|
|
2063
|
-
boxShadow: hovered ? "var(--shadow-float)" : void 0
|
|
2064
|
-
},
|
|
2065
|
-
...props,
|
|
2066
|
-
children: [
|
|
2067
|
-
/* @__PURE__ */ jsx(
|
|
2068
|
-
"div",
|
|
2069
|
-
{
|
|
2070
|
-
className: "pointer-events-none absolute -inset-0.5 transition-opacity duration-150",
|
|
2071
|
-
style: {
|
|
2072
|
-
borderRadius: 14,
|
|
2073
|
-
opacity: selected || hovered ? 1 : 0,
|
|
2074
|
-
boxShadow: selected ? `0 0 0 2px ${accent}, 0 0 0 5px ${tint(accent, 18)}` : `0 0 0 2px ${accent}`
|
|
2075
|
-
}
|
|
2076
|
-
}
|
|
2077
|
-
),
|
|
2078
|
-
isTrigger && /* @__PURE__ */ jsx(
|
|
2079
|
-
"div",
|
|
2080
|
-
{
|
|
2081
|
-
className: "absolute -top-2 -left-2 z-10 flex size-5 items-center justify-center rounded-full shadow-md ring-2 ring-card",
|
|
2082
|
-
style: { backgroundColor: "var(--color-status-success-text)" },
|
|
2083
|
-
children: /* @__PURE__ */ jsx(
|
|
2084
|
-
Icon,
|
|
2085
|
-
{
|
|
2086
|
-
icon: "mdi:lightning-bolt",
|
|
2087
|
-
className: "size-3",
|
|
2088
|
-
style: { color: "var(--color-status-success-text-inverse)" }
|
|
2089
|
-
}
|
|
2090
|
-
)
|
|
2091
|
-
}
|
|
2092
|
-
),
|
|
2093
|
-
children
|
|
2094
|
-
]
|
|
2095
|
-
}
|
|
2096
|
-
),
|
|
2097
|
-
executionStatus === "success" && /* @__PURE__ */ jsx(StatusCorner, { icon: "mdi:check", tone: "success" }),
|
|
2098
|
-
executionStatus === "error" && /* @__PURE__ */ jsx(StatusCorner, { icon: "mdi:close", tone: "error" }),
|
|
2099
|
-
executionStatus === "running" && /* @__PURE__ */ jsx(StatusCorner, { icon: "svg-spinners:ring-resize", tone: "success" })
|
|
2100
|
-
]
|
|
2101
|
-
}
|
|
2102
|
-
);
|
|
2103
|
-
}
|
|
2104
|
-
);
|
|
2105
|
-
NodeCard.displayName = "NodeCard";
|
|
2106
|
-
function ToolbarButton2({
|
|
2107
|
-
title,
|
|
2108
|
-
onClick,
|
|
2109
|
-
disabled,
|
|
2110
|
-
children,
|
|
2111
|
-
"data-agent": agent
|
|
2112
|
-
}) {
|
|
2113
|
-
return /* @__PURE__ */ jsx(
|
|
2114
|
-
"button",
|
|
2115
|
-
{
|
|
2116
|
-
type: "button",
|
|
2117
|
-
"data-agent": agent,
|
|
2118
|
-
title,
|
|
2119
|
-
disabled,
|
|
2120
|
-
onClick: (e) => {
|
|
2121
|
-
e.stopPropagation();
|
|
2122
|
-
onClick?.();
|
|
2123
|
-
},
|
|
2124
|
-
className: "flex size-6 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:opacity-50",
|
|
2125
|
-
children
|
|
2126
|
-
}
|
|
2127
|
-
);
|
|
2128
|
-
}
|
|
2129
|
-
function StatusCorner({
|
|
2130
|
-
icon,
|
|
2131
|
-
tone
|
|
2132
|
-
}) {
|
|
2133
|
-
const bg = tone === "success" ? "var(--color-status-success-bg)" : "var(--color-status-error-bg)";
|
|
2134
|
-
const fg = tone === "success" ? "var(--color-status-success-text-inverse)" : "var(--color-status-error-text-inverse)";
|
|
2135
|
-
return /* @__PURE__ */ jsx("div", { className: "absolute -bottom-1.5 -right-1.5 z-10", children: /* @__PURE__ */ jsx(
|
|
2136
|
-
"div",
|
|
2137
|
-
{
|
|
2138
|
-
className: "rounded-full p-0.5 shadow-md animate-in zoom-in duration-200",
|
|
2139
|
-
style: { backgroundColor: bg },
|
|
2140
|
-
children: /* @__PURE__ */ jsx(Icon, { icon, className: "size-3", style: { color: fg } })
|
|
2141
|
-
}
|
|
2142
|
-
) });
|
|
2143
|
-
}
|
|
2144
|
-
var NodeCardHeader = React.forwardRef(
|
|
2145
|
-
({
|
|
2146
|
-
icon,
|
|
2147
|
-
appName,
|
|
2148
|
-
accentKey,
|
|
2149
|
-
missingCredentials = false,
|
|
2150
|
-
label,
|
|
2151
|
-
isRenaming = false,
|
|
2152
|
-
onStartRename,
|
|
2153
|
-
onCommitRename,
|
|
2154
|
-
onCancelRename
|
|
2155
|
-
}, ref) => {
|
|
2156
|
-
const tr = useTr();
|
|
2157
|
-
const accent = nodeAccent(accentKey);
|
|
2158
|
-
return /* @__PURE__ */ jsxs("div", { ref, className: "flex items-center gap-2.5 px-3 pb-3 pt-4", children: [
|
|
2159
|
-
/* @__PURE__ */ jsx(
|
|
2160
|
-
"div",
|
|
2161
|
-
{
|
|
2162
|
-
className: "flex size-8 shrink-0 items-center justify-center rounded-lg",
|
|
2163
|
-
style: {
|
|
2164
|
-
backgroundColor: tint(accent, 13),
|
|
2165
|
-
color: accent,
|
|
2166
|
-
border: `1px solid ${tint(accent, 26)}`
|
|
2167
|
-
},
|
|
2168
|
-
children: /* @__PURE__ */ jsx(NodeTypeIcon, { icon, alt: appName, className: "size-[18px]" })
|
|
2169
|
-
}
|
|
2170
|
-
),
|
|
2171
|
-
onStartRename && onCommitRename && onCancelRename ? /* @__PURE__ */ jsx(
|
|
2172
|
-
InlineEditableLabel,
|
|
2173
|
-
{
|
|
2174
|
-
value: label ?? "",
|
|
2175
|
-
placeholder: appName,
|
|
2176
|
-
editing: isRenaming,
|
|
2177
|
-
onStartEdit: onStartRename,
|
|
2178
|
-
onCommit: onCommitRename,
|
|
2179
|
-
onCancel: onCancelRename,
|
|
2180
|
-
className: "min-w-0 flex-1 truncate text-[11px] font-semibold uppercase tracking-wide text-muted-foreground",
|
|
2181
|
-
inputClassName: "text-[11px] font-semibold uppercase tracking-wide"
|
|
2182
|
-
}
|
|
2183
|
-
) : /* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: label || appName }),
|
|
2184
|
-
missingCredentials && /* @__PURE__ */ jsx(
|
|
2185
|
-
"span",
|
|
2186
|
-
{
|
|
2187
|
-
title: tr(
|
|
2188
|
-
"fluidgrids.builder.nodeCard.missingCredentialsTooltip",
|
|
2189
|
-
"Credentials not configured"
|
|
2190
|
-
),
|
|
2191
|
-
className: "flex items-center text-[var(--color-status-warning-text)]",
|
|
2192
|
-
"aria-label": tr(
|
|
2193
|
-
"fluidgrids.builder.nodeCard.missingCredentialsAriaLabel",
|
|
2194
|
-
"Credentials not configured"
|
|
2195
|
-
),
|
|
2196
|
-
children: /* @__PURE__ */ jsx(Icon, { icon: "lucide:alert-triangle", className: "size-4" })
|
|
2197
|
-
}
|
|
2198
|
-
)
|
|
2199
|
-
] });
|
|
2200
|
-
}
|
|
2201
|
-
);
|
|
2202
|
-
NodeCardHeader.displayName = "NodeCardHeader";
|
|
2203
|
-
var NodeCardBody = React.forwardRef(
|
|
2204
|
-
({ operationName, description }, ref) => {
|
|
2205
|
-
const tr = useTr();
|
|
2206
|
-
return /* @__PURE__ */ jsxs(
|
|
2207
|
-
"div",
|
|
2208
|
-
{
|
|
2209
|
-
ref,
|
|
2210
|
-
className: "rounded-b-xl border-t border-border/60 px-3 pb-3 pt-2.5",
|
|
2211
|
-
children: [
|
|
2212
|
-
/* @__PURE__ */ jsx("div", { className: "text-[10px] font-semibold uppercase tracking-wider text-muted-foreground", children: tr("fluidgrids.builder.nodeCard.operationLabel", "Operation") }),
|
|
2213
|
-
/* @__PURE__ */ jsx("div", { className: "mt-0.5 truncate font-mono text-[13px] font-bold text-card-foreground", children: operationName }),
|
|
2214
|
-
description ? /* @__PURE__ */ jsx("p", { className: "mt-1 line-clamp-2 text-xs leading-snug text-muted-foreground", children: description }) : null
|
|
2215
|
-
]
|
|
2216
|
-
}
|
|
2217
|
-
);
|
|
2218
|
-
}
|
|
2219
|
-
);
|
|
2220
|
-
NodeCardBody.displayName = "NodeCardBody";
|
|
2221
|
-
function CustomHandle({
|
|
2222
|
-
className,
|
|
2223
|
-
isConnectable,
|
|
2224
|
-
accent,
|
|
2225
|
-
...props
|
|
2226
|
-
}) {
|
|
2227
|
-
const { nodeLookup, edges } = useStore(({ nodeLookup: nodeLookup2, edges: edges2 }) => ({
|
|
2228
|
-
nodeLookup: nodeLookup2,
|
|
2229
|
-
edges: edges2
|
|
2230
|
-
}));
|
|
2231
|
-
const nodeId = useNodeId();
|
|
2232
|
-
const isHandleConnectable = useMemo(() => {
|
|
2233
|
-
if (!nodeId) return false;
|
|
2234
|
-
const node = nodeLookup.get(nodeId);
|
|
2235
|
-
if (!node) return false;
|
|
2236
|
-
const connectedEdges = getConnectedEdges([node], edges);
|
|
2237
|
-
if (typeof isConnectable === "function")
|
|
2238
|
-
return isConnectable({ node, connectedEdges });
|
|
2239
|
-
if (typeof isConnectable === "number")
|
|
2240
|
-
return connectedEdges.length < isConnectable;
|
|
2241
|
-
return isConnectable;
|
|
2242
|
-
}, [edges, isConnectable, nodeId, nodeLookup]);
|
|
2243
|
-
return /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(
|
|
2244
|
-
Handle,
|
|
2245
|
-
{
|
|
2246
|
-
className: cn(
|
|
2247
|
-
"cursor-crosshair transition-transform hover:scale-110",
|
|
2248
|
-
!accent && "size-3 border-2 border-card-foreground/40 hover:border-primary/50",
|
|
2249
|
-
className
|
|
2250
|
-
),
|
|
2251
|
-
isConnectable: isHandleConnectable,
|
|
2252
|
-
style: accent ? {
|
|
2253
|
-
width: 14,
|
|
2254
|
-
height: 14,
|
|
2255
|
-
borderRadius: "50%",
|
|
2256
|
-
background: "var(--color-node-bg)",
|
|
2257
|
-
border: `2.5px solid ${accent}`,
|
|
2258
|
-
boxShadow: `0 0 0 3px color-mix(in srgb, ${accent} 12%, transparent)`
|
|
2259
|
-
} : void 0,
|
|
2260
|
-
...props
|
|
2261
|
-
}
|
|
2262
|
-
) });
|
|
2263
|
-
}
|
|
2264
|
-
|
|
2265
|
-
// src/builder/components/flow-builder/components/blocks/nodes/node/handle-spec.ts
|
|
2266
|
-
function isDynamicSpec(spec) {
|
|
2267
|
-
return !!spec && !Array.isArray(spec) && typeof spec.fromStateRecord === "string";
|
|
2268
|
-
}
|
|
2269
|
-
var DEFAULT_HANDLES = [{ id: "source", label: "" }];
|
|
2270
|
-
var BUILTIN_OUTPUT_HANDLES = {
|
|
2271
|
-
"internal:wait-for-signal": [
|
|
2272
|
-
{ id: "received", label: "Received", tone: "success" },
|
|
2273
|
-
{ id: "timedOut", label: "Timed out", tone: "warning" }
|
|
2274
|
-
]
|
|
2275
|
-
};
|
|
2276
|
-
function resolveOutputHandles(data, nodeType) {
|
|
2277
|
-
const nodeData = data?.nodeData;
|
|
2278
|
-
const operationsBlob = Array.isArray(nodeData?.operations) ? void 0 : nodeData?.operations;
|
|
2279
|
-
const operationList = Array.isArray(nodeData?.operations) ? nodeData.operations : operationsBlob?.operations ?? [];
|
|
2280
|
-
const operationName = typeof data?.operation_name === "string" ? data.operation_name : void 0;
|
|
2281
|
-
const operationSpec = operationName ? operationList.find((op) => op?.name === operationName)?.outputHandles : void 0;
|
|
2282
|
-
const spec = operationSpec ?? nodeData?.outputHandles ?? operationsBlob?.outputHandles;
|
|
2283
|
-
if (!spec)
|
|
2284
|
-
return nodeType && BUILTIN_OUTPUT_HANDLES[nodeType] || DEFAULT_HANDLES;
|
|
2285
|
-
if (isDynamicSpec(spec)) {
|
|
2286
|
-
const args = data?.args;
|
|
2287
|
-
const record2 = args?.state?.[spec.fromStateRecord] ?? data?.[spec.fromStateRecord] ?? {};
|
|
2288
|
-
const dynamic = Object.entries(record2).filter(([, handleId]) => typeof handleId === "string" && handleId).map(([label, handleId]) => ({ id: handleId, label }));
|
|
2289
|
-
return [...dynamic, ...spec.extra ?? []];
|
|
2290
|
-
}
|
|
2291
|
-
if (spec.length === 0) return DEFAULT_HANDLES;
|
|
2292
|
-
return spec;
|
|
2293
|
-
}
|
|
2294
|
-
var DEFAULT_INPUT_HANDLES = [{ id: "target", label: "" }];
|
|
2295
|
-
function resolveInputHandles(data) {
|
|
2296
|
-
const nodeData = data?.nodeData;
|
|
2297
|
-
const spec = nodeData?.inputHandles ?? nodeData?.operations?.inputHandles;
|
|
2298
|
-
if (!Array.isArray(spec) || spec.length === 0) return DEFAULT_INPUT_HANDLES;
|
|
2299
|
-
return spec;
|
|
2300
|
-
}
|
|
2301
|
-
function outputHandlesSpacerHeight(count) {
|
|
2302
|
-
return count > 2 ? (count - 2) * 26 : 0;
|
|
2303
|
-
}
|
|
2304
|
-
var TONE_COLORS = {
|
|
2305
|
-
success: "var(--color-status-success-text)",
|
|
2306
|
-
error: "var(--color-status-error-text)",
|
|
2307
|
-
warning: "var(--color-status-warning-text)",
|
|
2308
|
-
info: "var(--color-status-info-text)",
|
|
2309
|
-
neutral: "var(--color-text-muted)"
|
|
2310
|
-
};
|
|
2311
|
-
function HandlePlusStub({
|
|
2312
|
-
nodeId,
|
|
2313
|
-
handleId,
|
|
2314
|
-
color,
|
|
2315
|
-
isConnectable,
|
|
2316
|
-
isOnlyHandle,
|
|
2317
|
-
anchor
|
|
2318
|
-
}) {
|
|
2319
|
-
const tr = useTr();
|
|
2320
|
-
const startAttach = useFlowStore((s) => s.actions.pendingConnection.start);
|
|
2321
|
-
const isArmedHere = useFlowStore(
|
|
2322
|
-
(s) => s.workflow.pendingConnection?.nodeId === nodeId && s.workflow.pendingConnection?.handleId === handleId
|
|
2323
|
-
);
|
|
2324
|
-
const hasOutgoing = useStore(
|
|
2325
|
-
(s) => s.edges.some(
|
|
2326
|
-
(e) => e.source === nodeId && (e.sourceHandle === handleId || isOnlyHandle && (e.sourceHandle === null || e.sourceHandle === void 0))
|
|
2327
|
-
)
|
|
2328
|
-
);
|
|
2329
|
-
if (hasOutgoing || isConnectable === false) return null;
|
|
2330
|
-
const containerStyle = anchor === "card" ? {
|
|
2331
|
-
left: "100%",
|
|
2332
|
-
top: "50%",
|
|
2333
|
-
transform: "translateY(-50%)",
|
|
2334
|
-
marginLeft: 10
|
|
2335
|
-
} : { left: 10, top: 0, transform: "translateY(-50%)" };
|
|
2336
|
-
return /* @__PURE__ */ jsxs(
|
|
2337
|
-
"div",
|
|
2338
|
-
{
|
|
2339
|
-
className: "nodrag nopan absolute flex items-center",
|
|
2340
|
-
style: { ...containerStyle, pointerEvents: "none", zIndex: 5 },
|
|
2341
|
-
children: [
|
|
2342
|
-
/* @__PURE__ */ jsx(
|
|
2343
|
-
"div",
|
|
2344
|
-
{
|
|
2345
|
-
style: {
|
|
2346
|
-
width: 16,
|
|
2347
|
-
borderTop: `1.5px dashed ${color}`,
|
|
2348
|
-
opacity: 0.5
|
|
2349
|
-
}
|
|
2350
|
-
}
|
|
2351
|
-
),
|
|
2352
|
-
/* @__PURE__ */ jsx(
|
|
2353
|
-
"button",
|
|
2354
|
-
{
|
|
2355
|
-
type: "button",
|
|
2356
|
-
title: tr(
|
|
2357
|
-
"fluidgrids.builder.outputHandles.addNextNodeTooltip",
|
|
2358
|
-
"Add next node"
|
|
2359
|
-
),
|
|
2360
|
-
"aria-label": `Add next node from ${handleId}`,
|
|
2361
|
-
"data-testid": `handle-plus-${nodeId}-${handleId}`,
|
|
2362
|
-
onClick: (e) => {
|
|
2363
|
-
e.stopPropagation();
|
|
2364
|
-
startAttach({ nodeId, handleId });
|
|
2365
|
-
},
|
|
2366
|
-
onDoubleClick: (e) => e.stopPropagation(),
|
|
2367
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
2368
|
-
className: "cursor-pointer transition-transform hover:scale-110",
|
|
2369
|
-
style: {
|
|
2370
|
-
pointerEvents: "all",
|
|
2371
|
-
width: 16,
|
|
2372
|
-
height: 16,
|
|
2373
|
-
borderRadius: "50%",
|
|
2374
|
-
display: "flex",
|
|
2375
|
-
alignItems: "center",
|
|
2376
|
-
justifyContent: "center",
|
|
2377
|
-
border: `1.5px solid ${color}`,
|
|
2378
|
-
background: isArmedHere ? color : "var(--color-node-bg)",
|
|
2379
|
-
color: isArmedHere ? "var(--color-node-bg)" : color,
|
|
2380
|
-
boxShadow: isArmedHere ? `0 0 0 3px color-mix(in srgb, ${color} 22%, transparent)` : `0 0 0 2px color-mix(in srgb, ${color} 10%, transparent)`,
|
|
2381
|
-
transition: "transform .12s ease, background .12s ease, color .12s ease"
|
|
2382
|
-
},
|
|
2383
|
-
children: /* @__PURE__ */ jsx(Icon, { icon: "mdi:plus", className: "size-2.5" })
|
|
2384
|
-
}
|
|
2385
|
-
)
|
|
2386
|
-
]
|
|
2387
|
-
}
|
|
2388
|
-
);
|
|
2389
|
-
}
|
|
2390
|
-
function OutputHandles({
|
|
2391
|
-
nodeId,
|
|
2392
|
-
handles,
|
|
2393
|
-
accent,
|
|
2394
|
-
isConnectable
|
|
2395
|
-
}) {
|
|
2396
|
-
const updateNodeInternals = useUpdateNodeInternals();
|
|
2397
|
-
const signature = useMemo(
|
|
2398
|
-
() => handles.map((h) => h.id).join("|"),
|
|
2399
|
-
[handles]
|
|
2400
|
-
);
|
|
2401
|
-
useEffect(() => {
|
|
2402
|
-
updateNodeInternals(nodeId);
|
|
2403
|
-
}, [nodeId, signature, updateNodeInternals]);
|
|
2404
|
-
if (handles.length === 1) {
|
|
2405
|
-
const handle = handles[0];
|
|
2406
|
-
const color = handle.tone ? TONE_COLORS[handle.tone] : accent;
|
|
2407
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2408
|
-
/* @__PURE__ */ jsx(
|
|
2409
|
-
CustomHandle,
|
|
2410
|
-
{
|
|
2411
|
-
type: "source",
|
|
2412
|
-
id: handle.id,
|
|
2413
|
-
position: Position.Right,
|
|
2414
|
-
isConnectable,
|
|
2415
|
-
accent: color
|
|
2416
|
-
}
|
|
2417
|
-
),
|
|
2418
|
-
/* @__PURE__ */ jsx(
|
|
2419
|
-
HandlePlusStub,
|
|
2420
|
-
{
|
|
2421
|
-
nodeId,
|
|
2422
|
-
handleId: handle.id,
|
|
2423
|
-
color,
|
|
2424
|
-
isConnectable,
|
|
2425
|
-
isOnlyHandle: true,
|
|
2426
|
-
anchor: "card"
|
|
2427
|
-
}
|
|
2428
|
-
)
|
|
2429
|
-
] });
|
|
2430
|
-
}
|
|
2431
|
-
const total = handles.length;
|
|
2432
|
-
return /* @__PURE__ */ jsx(Fragment, { children: handles.map((handle, index) => {
|
|
2433
|
-
const top = `${(index + 1) / (total + 1) * 100}%`;
|
|
2434
|
-
const color = handle.tone ? TONE_COLORS[handle.tone] : accent;
|
|
2435
|
-
return /* @__PURE__ */ jsxs(
|
|
2436
|
-
"div",
|
|
2437
|
-
{
|
|
2438
|
-
className: "absolute right-0",
|
|
2439
|
-
style: { top, transform: "translateY(-50%)" },
|
|
2440
|
-
children: [
|
|
2441
|
-
/* @__PURE__ */ jsx(
|
|
2442
|
-
CustomHandle,
|
|
2443
|
-
{
|
|
2444
|
-
type: "source",
|
|
2445
|
-
id: handle.id,
|
|
2446
|
-
position: Position.Right,
|
|
2447
|
-
isConnectable,
|
|
2448
|
-
accent: color
|
|
2449
|
-
}
|
|
2450
|
-
),
|
|
2451
|
-
handle.label && /* @__PURE__ */ jsx(
|
|
2452
|
-
"span",
|
|
746
|
+
className: "flex h-full w-full flex-col overflow-hidden rounded-lg border",
|
|
747
|
+
style: {
|
|
748
|
+
backgroundColor: `${accent}1F`,
|
|
749
|
+
// Same border whether selected or not — selection shows only via the
|
|
750
|
+
// floating toolbar (no extra border/outline on click).
|
|
751
|
+
borderColor: `${accent}59`
|
|
752
|
+
},
|
|
753
|
+
onDoubleClick: (e) => {
|
|
754
|
+
e.stopPropagation();
|
|
755
|
+
if (!readOnly) startEditing();
|
|
756
|
+
},
|
|
757
|
+
children: editing ? /* @__PURE__ */ jsx(
|
|
758
|
+
"textarea",
|
|
2453
759
|
{
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
760
|
+
ref: textareaRef,
|
|
761
|
+
readOnly,
|
|
762
|
+
value: draft,
|
|
763
|
+
onChange: (e) => setDraft(e.target.value),
|
|
764
|
+
onBlur: commitEdit,
|
|
765
|
+
onKeyDown: (e) => {
|
|
766
|
+
e.stopPropagation();
|
|
767
|
+
if (e.key === "Escape") cancelEdit();
|
|
768
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) commitEdit();
|
|
769
|
+
},
|
|
770
|
+
placeholder: tr(
|
|
771
|
+
"fluidgrids.builder.stickyNote.editorPlaceholder",
|
|
772
|
+
"# Note\nSupports **markdown** \u2014 headings, lists, links\u2026"
|
|
773
|
+
),
|
|
774
|
+
className: "nodrag nowheel h-full w-full resize-none bg-transparent p-3 font-mono text-xs leading-relaxed text-foreground outline-none placeholder:text-muted-foreground/60"
|
|
2458
775
|
}
|
|
2459
|
-
)
|
|
2460
|
-
|
|
2461
|
-
HandlePlusStub,
|
|
776
|
+
) : content.trim() ? /* @__PURE__ */ jsx(
|
|
777
|
+
"div",
|
|
2462
778
|
{
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
779
|
+
className: cn(
|
|
780
|
+
"nowheel h-full w-full overflow-auto p-3 text-xs leading-relaxed text-foreground",
|
|
781
|
+
// Compact markdown typography scoped to the note body.
|
|
782
|
+
"[&_h1]:mb-1.5 [&_h1]:text-sm [&_h1]:font-bold",
|
|
783
|
+
"[&_h2]:mb-1 [&_h2]:text-[13px] [&_h2]:font-bold",
|
|
784
|
+
"[&_h3]:mb-1 [&_h3]:text-xs [&_h3]:font-semibold",
|
|
785
|
+
"[&_p]:mb-1.5 [&_ul]:mb-1.5 [&_ul]:list-disc [&_ul]:pl-4",
|
|
786
|
+
"[&_ol]:mb-1.5 [&_ol]:list-decimal [&_ol]:pl-4 [&_li]:mb-0.5",
|
|
787
|
+
"[&_a]:underline [&_code]:rounded [&_code]:bg-muted [&_code]:px-1"
|
|
788
|
+
),
|
|
789
|
+
children: /* @__PURE__ */ jsx(ReactMarkdown, { children: content })
|
|
2469
790
|
}
|
|
2470
|
-
)
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
}
|
|
2477
|
-
function InputHandles({
|
|
2478
|
-
nodeId,
|
|
2479
|
-
handles,
|
|
2480
|
-
accent,
|
|
2481
|
-
isConnectable
|
|
2482
|
-
}) {
|
|
2483
|
-
const updateNodeInternals = useUpdateNodeInternals();
|
|
2484
|
-
const signature = useMemo(
|
|
2485
|
-
() => handles.map((h) => h.id).join("|"),
|
|
2486
|
-
[handles]
|
|
791
|
+
) : /* @__PURE__ */ jsx("div", { className: "flex h-full w-full items-center justify-center p-3 text-xs text-muted-foreground/70", children: tr(
|
|
792
|
+
"fluidgrids.builder.stickyNote.emptyStateHint",
|
|
793
|
+
"Double-click to edit"
|
|
794
|
+
) })
|
|
795
|
+
}
|
|
796
|
+
)
|
|
797
|
+
] })
|
|
2487
798
|
);
|
|
2488
|
-
useEffect(() => {
|
|
2489
|
-
updateNodeInternals(nodeId);
|
|
2490
|
-
}, [nodeId, signature, updateNodeInternals]);
|
|
2491
|
-
if (handles.length === 1) {
|
|
2492
|
-
const handle = handles[0];
|
|
2493
|
-
return /* @__PURE__ */ jsx(
|
|
2494
|
-
CustomHandle,
|
|
2495
|
-
{
|
|
2496
|
-
type: "target",
|
|
2497
|
-
id: handle.id,
|
|
2498
|
-
position: Position.Left,
|
|
2499
|
-
isConnectable,
|
|
2500
|
-
accent: handle.tone ? TONE_COLORS[handle.tone] : accent
|
|
2501
|
-
}
|
|
2502
|
-
);
|
|
2503
|
-
}
|
|
2504
|
-
const total = handles.length;
|
|
2505
|
-
return /* @__PURE__ */ jsx(Fragment, { children: handles.map((handle, index) => {
|
|
2506
|
-
const top = `${(index + 1) / (total + 1) * 100}%`;
|
|
2507
|
-
const color = handle.tone ? TONE_COLORS[handle.tone] : accent;
|
|
2508
|
-
return /* @__PURE__ */ jsxs(
|
|
2509
|
-
"div",
|
|
2510
|
-
{
|
|
2511
|
-
className: "absolute left-0",
|
|
2512
|
-
style: { top, transform: "translateY(-50%)" },
|
|
2513
|
-
children: [
|
|
2514
|
-
/* @__PURE__ */ jsx(
|
|
2515
|
-
CustomHandle,
|
|
2516
|
-
{
|
|
2517
|
-
type: "target",
|
|
2518
|
-
id: handle.id,
|
|
2519
|
-
position: Position.Left,
|
|
2520
|
-
isConnectable,
|
|
2521
|
-
accent: color
|
|
2522
|
-
}
|
|
2523
|
-
),
|
|
2524
|
-
handle.label && /* @__PURE__ */ jsx(
|
|
2525
|
-
"span",
|
|
2526
|
-
{
|
|
2527
|
-
className: "pointer-events-none absolute whitespace-nowrap text-[10px] font-medium leading-none",
|
|
2528
|
-
style: {
|
|
2529
|
-
color,
|
|
2530
|
-
right: "100%",
|
|
2531
|
-
marginRight: 16,
|
|
2532
|
-
top: "50%",
|
|
2533
|
-
transform: "translateY(-50%)"
|
|
2534
|
-
},
|
|
2535
|
-
title: handle.label,
|
|
2536
|
-
children: handle.label
|
|
2537
|
-
}
|
|
2538
|
-
)
|
|
2539
|
-
]
|
|
2540
|
-
},
|
|
2541
|
-
handle.id
|
|
2542
|
-
);
|
|
2543
|
-
}) });
|
|
2544
799
|
}
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
isConnectable,
|
|
2559
|
-
onClick,
|
|
2560
|
-
onDoubleClick,
|
|
2561
|
-
onSettings,
|
|
2562
|
-
onExecute,
|
|
2563
|
-
onDelete,
|
|
2564
|
-
infoButton,
|
|
2565
|
-
disabled = false,
|
|
2566
|
-
onToggleDisabled,
|
|
2567
|
-
isRenaming = false,
|
|
2568
|
-
onStartRename,
|
|
2569
|
-
onCommitRename,
|
|
2570
|
-
onCancelRename
|
|
2571
|
-
}) {
|
|
2572
|
-
const minHeight = Math.max(
|
|
2573
|
-
64,
|
|
2574
|
-
Math.max(outputHandles.length, inputHandles.length) * 30 + 24
|
|
2575
|
-
);
|
|
2576
|
-
return /* @__PURE__ */ jsxs(
|
|
2577
|
-
NodeCard,
|
|
2578
|
-
{
|
|
2579
|
-
className: "w-48",
|
|
2580
|
-
"data-selected": selected,
|
|
2581
|
-
selected,
|
|
2582
|
-
onClick,
|
|
2583
|
-
onDoubleClick,
|
|
2584
|
-
executionStatus,
|
|
2585
|
-
itemCount,
|
|
2586
|
-
isTrigger,
|
|
2587
|
-
accent,
|
|
2588
|
-
isExecuting,
|
|
2589
|
-
onSettings,
|
|
2590
|
-
onExecute,
|
|
2591
|
-
onDelete,
|
|
2592
|
-
infoButton,
|
|
2593
|
-
disabled,
|
|
2594
|
-
onToggleDisabled,
|
|
2595
|
-
children: [
|
|
2596
|
-
/* @__PURE__ */ jsxs(
|
|
2597
|
-
"div",
|
|
2598
|
-
{
|
|
2599
|
-
className: "flex flex-col items-center justify-center gap-1 px-3 py-3 text-center",
|
|
2600
|
-
style: { minHeight },
|
|
2601
|
-
children: [
|
|
2602
|
-
/* @__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 } }) }),
|
|
2603
|
-
onStartRename && onCommitRename && onCancelRename ? /* @__PURE__ */ jsx(
|
|
2604
|
-
InlineEditableLabel,
|
|
2605
|
-
{
|
|
2606
|
-
value: title,
|
|
2607
|
-
placeholder: title,
|
|
2608
|
-
editing: isRenaming,
|
|
2609
|
-
onStartEdit: onStartRename,
|
|
2610
|
-
onCommit: onCommitRename,
|
|
2611
|
-
onCancel: onCancelRename,
|
|
2612
|
-
className: "max-w-full truncate text-sm font-semibold leading-tight",
|
|
2613
|
-
inputClassName: "text-sm font-semibold text-center"
|
|
2614
|
-
}
|
|
2615
|
-
) : /* @__PURE__ */ jsx("span", { className: "max-w-full truncate text-sm font-semibold leading-tight", children: title }),
|
|
2616
|
-
subtitle && /* @__PURE__ */ jsx(
|
|
2617
|
-
"span",
|
|
2618
|
-
{
|
|
2619
|
-
className: "max-w-full truncate font-mono text-[10px] text-muted-foreground",
|
|
2620
|
-
title: subtitle,
|
|
2621
|
-
children: subtitle
|
|
2622
|
-
}
|
|
2623
|
-
)
|
|
2624
|
-
]
|
|
2625
|
-
}
|
|
2626
|
-
),
|
|
2627
|
-
/* @__PURE__ */ jsx(
|
|
2628
|
-
InputHandles,
|
|
2629
|
-
{
|
|
2630
|
-
nodeId,
|
|
2631
|
-
handles: inputHandles,
|
|
2632
|
-
accent,
|
|
2633
|
-
isConnectable
|
|
2634
|
-
}
|
|
2635
|
-
),
|
|
2636
|
-
/* @__PURE__ */ jsx(
|
|
2637
|
-
OutputHandles,
|
|
2638
|
-
{
|
|
2639
|
-
nodeId,
|
|
2640
|
-
handles: outputHandles,
|
|
2641
|
-
accent,
|
|
2642
|
-
isConnectable
|
|
2643
|
-
}
|
|
2644
|
-
)
|
|
2645
|
-
]
|
|
2646
|
-
}
|
|
2647
|
-
);
|
|
800
|
+
var StickyNoteNode = memo(StickyNoteNodeComponent);
|
|
801
|
+
function buildStickyNode(position) {
|
|
802
|
+
return {
|
|
803
|
+
id: nanoid(),
|
|
804
|
+
type: STICKY_NOTE_TYPE,
|
|
805
|
+
position,
|
|
806
|
+
width: STICKY_DEFAULT_SIZE.width,
|
|
807
|
+
height: STICKY_DEFAULT_SIZE.height,
|
|
808
|
+
// Render under regular nodes and edges — notes are a background layer.
|
|
809
|
+
zIndex: -1,
|
|
810
|
+
selected: true,
|
|
811
|
+
data: { content: "", color: DEFAULT_STICKY_COLOR }
|
|
812
|
+
};
|
|
2648
813
|
}
|
|
2649
814
|
|
|
2650
|
-
// src/
|
|
2651
|
-
var
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2655
|
-
}
|
|
2656
|
-
function str(value) {
|
|
2657
|
-
return typeof value === "string" && value.trim() ? value : void 0;
|
|
815
|
+
// src/modules/connections/utils/adapter-selection.ts
|
|
816
|
+
var ANY_PROVIDER = "*";
|
|
817
|
+
function isOptionalAdapter(adapter) {
|
|
818
|
+
return adapter.required === false;
|
|
2658
819
|
}
|
|
2659
|
-
function
|
|
2660
|
-
|
|
2661
|
-
const
|
|
2662
|
-
|
|
2663
|
-
return {
|
|
2664
|
-
workflowFn: str(s.workflowFn),
|
|
2665
|
-
taskQueue: str(s.taskQueue) ?? "managed",
|
|
2666
|
-
waitForCompletion,
|
|
2667
|
-
parentClosePolicy: policy === "TERMINATE" || policy === "ABANDON" || policy === "REQUEST_CANCEL" ? policy : waitForCompletion ? "TERMINATE" : "ABANDON",
|
|
2668
|
-
timeout: typeof s.timeout === "number" && s.timeout > 0 ? s.timeout : 0
|
|
2669
|
-
};
|
|
820
|
+
function newConnectionProviderKey(adapters) {
|
|
821
|
+
if (adapters.length !== 1) return void 0;
|
|
822
|
+
const provider = adapters[0]?.provider;
|
|
823
|
+
return provider && provider !== ANY_PROVIDER ? provider : void 0;
|
|
2670
824
|
}
|
|
2671
|
-
function
|
|
2672
|
-
|
|
825
|
+
function matchesAdapterProvider(adapter, providerKey) {
|
|
826
|
+
const normalizedKey = providerKey.trim().toLowerCase();
|
|
827
|
+
if (normalizedKey.length === 0) return false;
|
|
828
|
+
if (adapter.provider.trim() === ANY_PROVIDER) return true;
|
|
829
|
+
return adapter.provider.trim().toLowerCase() === normalizedKey || adapter.name.trim().toLowerCase() === normalizedKey;
|
|
2673
830
|
}
|
|
2674
|
-
function
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
if (schema.type === "array") return `${typeLabel(schema.items)}[]`;
|
|
2679
|
-
return typeof schema.type === "string" ? schema.type : "any";
|
|
831
|
+
function connectionsForAdapter(connections, adapterName) {
|
|
832
|
+
return connections.filter(
|
|
833
|
+
(connection) => connection.adapter.toLowerCase() === adapterName.toLowerCase()
|
|
834
|
+
);
|
|
2680
835
|
}
|
|
2681
|
-
function
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
Array.isArray(schema.required) ? schema.required.map(String) : []
|
|
836
|
+
function replaceAdapterConnections(connections, adapterName, connectionIds = []) {
|
|
837
|
+
const otherConnections = connections.filter(
|
|
838
|
+
(connection) => connection.adapter.toLowerCase() !== adapterName.toLowerCase()
|
|
2685
839
|
);
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
840
|
+
const uniqueIds = [...new Set(connectionIds.filter(Boolean))];
|
|
841
|
+
return [
|
|
842
|
+
...otherConnections,
|
|
843
|
+
...uniqueIds.map((connectionId) => ({
|
|
844
|
+
connectionId,
|
|
845
|
+
adapter: adapterName
|
|
846
|
+
}))
|
|
847
|
+
];
|
|
2692
848
|
}
|
|
2693
|
-
function
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
queries: of("queries"),
|
|
2698
|
-
updates: of("updates")
|
|
2699
|
-
};
|
|
849
|
+
function missingRequiredAdapters(adapters, selected) {
|
|
850
|
+
return adapters.filter(
|
|
851
|
+
(adapter) => !isOptionalAdapter(adapter) && !selected.some((connection) => connection.adapter === adapter.name)
|
|
852
|
+
);
|
|
2700
853
|
}
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
const fromColumn = str(state.childRunId);
|
|
2706
|
-
if (fromColumn) return fromColumn;
|
|
2707
|
-
if (isRecord3(state.output)) {
|
|
2708
|
-
const fromOutput = str(state.output._childRunId);
|
|
2709
|
-
if (fromOutput) return fromOutput;
|
|
854
|
+
var NODE_DOCS_URL = gql`
|
|
855
|
+
query NodeDocsUrlLookup($nodeType: String!, $nodeVersion: String!) {
|
|
856
|
+
nodeEndpointConfig(nodeType: $nodeType, nodeVersion: $nodeVersion) {
|
|
857
|
+
docsUrl
|
|
2710
858
|
}
|
|
2711
859
|
}
|
|
2712
|
-
|
|
860
|
+
`;
|
|
861
|
+
var cache = /* @__PURE__ */ new Map();
|
|
862
|
+
var inFlight = /* @__PURE__ */ new Map();
|
|
863
|
+
function fetchDocsUrl(nodeType, nodeVersion) {
|
|
864
|
+
const key = `${nodeType}@${nodeVersion}`;
|
|
865
|
+
if (cache.has(key)) return Promise.resolve(cache.get(key));
|
|
866
|
+
const existing = inFlight.get(key);
|
|
867
|
+
if (existing) return existing;
|
|
868
|
+
const client = getFluidGridsClientSafe();
|
|
869
|
+
if (!client) {
|
|
870
|
+
cache.set(key, void 0);
|
|
871
|
+
return Promise.resolve(void 0);
|
|
872
|
+
}
|
|
873
|
+
const promise = client.query({
|
|
874
|
+
query: NODE_DOCS_URL,
|
|
875
|
+
variables: { nodeType, nodeVersion },
|
|
876
|
+
fetchPolicy: "cache-first"
|
|
877
|
+
}).then((result) => result.data?.nodeEndpointConfig?.docsUrl ?? void 0).catch(() => void 0).finally(() => inFlight.delete(key));
|
|
878
|
+
inFlight.set(key, promise);
|
|
879
|
+
return promise.then((url) => {
|
|
880
|
+
cache.set(key, url);
|
|
881
|
+
return url;
|
|
882
|
+
});
|
|
2713
883
|
}
|
|
2714
|
-
function
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
return files.some(
|
|
2727
|
-
(file) => file.path.startsWith("workflows/") && file.path.endsWith(".py")
|
|
2728
|
-
) ? "python" : "typescript";
|
|
2729
|
-
}
|
|
2730
|
-
function changedSourceFiles(loaded, current) {
|
|
2731
|
-
return loaded.filter((file) => {
|
|
2732
|
-
const now = current[file.path];
|
|
2733
|
-
return now !== void 0 && now !== file.content;
|
|
2734
|
-
}).map((file) => ({ path: file.path, content: current[file.path] })).sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
2735
|
-
}
|
|
2736
|
-
function defaultSourcePath(files, entry) {
|
|
2737
|
-
if (entry && files.some((file) => file.path === entry)) return entry;
|
|
2738
|
-
return files.find(
|
|
2739
|
-
(file) => file.path.startsWith("workflows/") && isEditableSourcePath(file.path)
|
|
2740
|
-
)?.path ?? files[0]?.path;
|
|
2741
|
-
}
|
|
2742
|
-
function diagnosticsByPath(diagnostics) {
|
|
2743
|
-
const result = /* @__PURE__ */ new Map();
|
|
2744
|
-
for (const diagnostic of diagnostics) {
|
|
2745
|
-
const path = diagnostic.path?.replace(/^\.\//, "") ?? "";
|
|
2746
|
-
const list = result.get(path) ?? [];
|
|
2747
|
-
list.push({
|
|
2748
|
-
line: diagnostic.line,
|
|
2749
|
-
column: diagnostic.column,
|
|
2750
|
-
severity: editorSeverity(diagnostic.severity),
|
|
2751
|
-
code: diagnostic.code,
|
|
2752
|
-
message: diagnostic.message
|
|
884
|
+
function useNodeDocsUrl(nodeType, nodeVersion) {
|
|
885
|
+
const [docsUrl, setDocsUrl] = useState(
|
|
886
|
+
() => nodeType && nodeVersion ? cache.get(`${nodeType}@${nodeVersion}`) : void 0
|
|
887
|
+
);
|
|
888
|
+
useEffect(() => {
|
|
889
|
+
if (!nodeType || !nodeVersion) {
|
|
890
|
+
setDocsUrl(void 0);
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
let cancelled = false;
|
|
894
|
+
fetchDocsUrl(nodeType, nodeVersion).then((url) => {
|
|
895
|
+
if (!cancelled) setDocsUrl(url);
|
|
2753
896
|
});
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
897
|
+
return () => {
|
|
898
|
+
cancelled = true;
|
|
899
|
+
};
|
|
900
|
+
}, [nodeType, nodeVersion]);
|
|
901
|
+
return docsUrl;
|
|
2757
902
|
}
|
|
2758
903
|
|
|
2759
904
|
// src/modules/executions/utils/signal-targets.ts
|
|
2760
|
-
function
|
|
905
|
+
function isRecord(value) {
|
|
2761
906
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2762
907
|
}
|
|
2763
|
-
function
|
|
908
|
+
function str(value) {
|
|
2764
909
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
2765
910
|
}
|
|
2766
911
|
function durableInterfaceOf(definitionJson, workflowFn) {
|
|
2767
|
-
if (!
|
|
912
|
+
if (!isRecord(definitionJson)) return void 0;
|
|
2768
913
|
const code = definitionJson.code;
|
|
2769
|
-
if (
|
|
914
|
+
if (isRecord(code) && isRecord(code.exports) && workflowFn) {
|
|
2770
915
|
const workflows = code.exports.workflows;
|
|
2771
|
-
if (
|
|
916
|
+
if (isRecord(workflows)) {
|
|
2772
917
|
const entry = workflows[workflowFn];
|
|
2773
|
-
if (
|
|
918
|
+
if (isRecord(entry) && isRecord(entry.interface)) return entry.interface;
|
|
2774
919
|
}
|
|
2775
920
|
}
|
|
2776
|
-
return
|
|
921
|
+
return isRecord(definitionJson.interface) ? definitionJson.interface : void 0;
|
|
2777
922
|
}
|
|
2778
923
|
function declaredSignals(iface) {
|
|
2779
924
|
if (!iface) return { targets: [], openNames: false };
|
|
2780
|
-
const signals =
|
|
925
|
+
const signals = isRecord(iface.signals) ? iface.signals : {};
|
|
2781
926
|
const targets = Object.keys(signals).sort().map((name) => {
|
|
2782
927
|
const entry = signals[name];
|
|
2783
|
-
const payload =
|
|
928
|
+
const payload = isRecord(entry) && isRecord(entry.payload) ? entry.payload : void 0;
|
|
2784
929
|
return payload ? { name, payloadSchema: payload } : { name };
|
|
2785
930
|
});
|
|
2786
|
-
const open =
|
|
931
|
+
const open = isRecord(iface.open) && iface.open.signals === true;
|
|
2787
932
|
return { targets, openNames: open };
|
|
2788
933
|
}
|
|
2789
934
|
function nodeStateArgs(node) {
|
|
2790
|
-
if (!
|
|
2791
|
-
const root =
|
|
2792
|
-
if (root &&
|
|
2793
|
-
const data =
|
|
2794
|
-
const mirror = data &&
|
|
2795
|
-
return mirror &&
|
|
935
|
+
if (!isRecord(node)) return void 0;
|
|
936
|
+
const root = isRecord(node.args) ? node.args : void 0;
|
|
937
|
+
if (root && isRecord(root.state)) return root.state;
|
|
938
|
+
const data = isRecord(node.data) ? node.data : void 0;
|
|
939
|
+
const mirror = data && isRecord(data.args) ? data.args : void 0;
|
|
940
|
+
return mirror && isRecord(mirror.state) ? mirror.state : void 0;
|
|
2796
941
|
}
|
|
2797
942
|
function definitionNodes(definitionJson) {
|
|
2798
|
-
if (!
|
|
943
|
+
if (!isRecord(definitionJson) || !isRecord(definitionJson.data)) return [];
|
|
2799
944
|
const nodes = definitionJson.data.nodes;
|
|
2800
945
|
return Array.isArray(nodes) ? nodes : [];
|
|
2801
946
|
}
|
|
@@ -2804,16 +949,16 @@ function parkedSignalTargets(nodeStates, definitionJson) {
|
|
|
2804
949
|
const result = [];
|
|
2805
950
|
const seen = /* @__PURE__ */ new Set();
|
|
2806
951
|
for (const state of nodeStates) {
|
|
2807
|
-
if (state.status !== "WAITING" || !
|
|
952
|
+
if (state.status !== "WAITING" || !isRecord(state.output)) continue;
|
|
2808
953
|
if (state.output._waiting !== "signal") continue;
|
|
2809
|
-
const name =
|
|
954
|
+
const name = str(state.output._signalName);
|
|
2810
955
|
if (!name || seen.has(`${state.nodeId}:${name}`)) continue;
|
|
2811
956
|
seen.add(`${state.nodeId}:${name}`);
|
|
2812
957
|
const node = nodes.find(
|
|
2813
|
-
(candidate) =>
|
|
958
|
+
(candidate) => isRecord(candidate) && candidate.id === state.nodeId
|
|
2814
959
|
);
|
|
2815
960
|
const args = nodeStateArgs(node);
|
|
2816
|
-
const schema = args &&
|
|
961
|
+
const schema = args && isRecord(args.payloadSchema) ? args.payloadSchema : void 0;
|
|
2817
962
|
result.push(
|
|
2818
963
|
schema ? { name, payloadSchema: schema, nodeId: state.nodeId } : { name, nodeId: state.nodeId }
|
|
2819
964
|
);
|
|
@@ -2836,9 +981,9 @@ function canSignalRun(targets) {
|
|
|
2836
981
|
return targets.targets.length > 0 || targets.openNames;
|
|
2837
982
|
}
|
|
2838
983
|
function fieldOf(name, schema, required) {
|
|
2839
|
-
if (!
|
|
2840
|
-
const title =
|
|
2841
|
-
const description =
|
|
984
|
+
if (!isRecord(schema)) return null;
|
|
985
|
+
const title = str(schema.title) ?? name;
|
|
986
|
+
const description = str(schema.description);
|
|
2842
987
|
if (Array.isArray(schema.enum)) {
|
|
2843
988
|
const choices = schema.enum.filter(
|
|
2844
989
|
(value) => typeof value === "string"
|
|
@@ -2853,7 +998,7 @@ function fieldOf(name, schema, required) {
|
|
|
2853
998
|
return null;
|
|
2854
999
|
}
|
|
2855
1000
|
function formFieldsOf(schema) {
|
|
2856
|
-
if (!schema || schema.type !== "object" || !
|
|
1001
|
+
if (!schema || schema.type !== "object" || !isRecord(schema.properties))
|
|
2857
1002
|
return null;
|
|
2858
1003
|
const required = new Set(
|
|
2859
1004
|
Array.isArray(schema.required) ? schema.required.filter(
|
|
@@ -3134,20 +1279,20 @@ function listCustomBlocks() {
|
|
|
3134
1279
|
// src/builder/components/lib/expression-preview.ts
|
|
3135
1280
|
var PURE_EXPRESSION_REGEX = /^\{\{(.*)\}\}$/s;
|
|
3136
1281
|
var PURE_LEGACY_REGEX = /^\$\{(.*)\}$/s;
|
|
3137
|
-
function containsExpressionSyntax(
|
|
3138
|
-
return typeof
|
|
1282
|
+
function containsExpressionSyntax(str2) {
|
|
1283
|
+
return typeof str2 === "string" && str2.includes("{{");
|
|
3139
1284
|
}
|
|
3140
|
-
function findEmbeddedExpressions(
|
|
1285
|
+
function findEmbeddedExpressions(str2) {
|
|
3141
1286
|
const matches2 = [];
|
|
3142
1287
|
let searchFrom = 0;
|
|
3143
|
-
while (searchFrom <
|
|
3144
|
-
const start =
|
|
1288
|
+
while (searchFrom < str2.length) {
|
|
1289
|
+
const start = str2.indexOf("{{", searchFrom);
|
|
3145
1290
|
if (start === -1) break;
|
|
3146
|
-
const end =
|
|
1291
|
+
const end = str2.indexOf("}}", start + 2);
|
|
3147
1292
|
if (end === -1) break;
|
|
3148
1293
|
matches2.push({
|
|
3149
|
-
full:
|
|
3150
|
-
expression:
|
|
1294
|
+
full: str2.slice(start, end + 2),
|
|
1295
|
+
expression: str2.slice(start + 2, end).trim()
|
|
3151
1296
|
});
|
|
3152
1297
|
searchFrom = end + 2;
|
|
3153
1298
|
}
|
|
@@ -3237,9 +1382,9 @@ function stringifyForInterpolation(value) {
|
|
|
3237
1382
|
if (typeof value === "object") return JSON.stringify(value);
|
|
3238
1383
|
return String(value);
|
|
3239
1384
|
}
|
|
3240
|
-
function previewNewSyntax(
|
|
1385
|
+
function previewNewSyntax(str2, scope) {
|
|
3241
1386
|
const sandbox = buildExpressionSandbox(scope);
|
|
3242
|
-
const pure = PURE_EXPRESSION_REGEX.exec(
|
|
1387
|
+
const pure = PURE_EXPRESSION_REGEX.exec(str2);
|
|
3243
1388
|
try {
|
|
3244
1389
|
if (pure) {
|
|
3245
1390
|
const expression = pure[1]?.trim();
|
|
@@ -3248,8 +1393,8 @@ function previewNewSyntax(str3, scope) {
|
|
|
3248
1393
|
}
|
|
3249
1394
|
return { isTemplate: true, value: evaluateBare(expression, sandbox) };
|
|
3250
1395
|
}
|
|
3251
|
-
let result =
|
|
3252
|
-
for (const match of findEmbeddedExpressions(
|
|
1396
|
+
let result = str2;
|
|
1397
|
+
for (const match of findEmbeddedExpressions(str2)) {
|
|
3253
1398
|
if (!match.expression) continue;
|
|
3254
1399
|
const value = evaluateBare(match.expression, sandbox);
|
|
3255
1400
|
result = result.replace(match.full, stringifyForInterpolation(value));
|
|
@@ -3262,7 +1407,7 @@ function previewNewSyntax(str3, scope) {
|
|
|
3262
1407
|
};
|
|
3263
1408
|
}
|
|
3264
1409
|
}
|
|
3265
|
-
function previewLegacySyntax(
|
|
1410
|
+
function previewLegacySyntax(str2, scope) {
|
|
3266
1411
|
const sandbox = {
|
|
3267
1412
|
...SAFE_GLOBALS,
|
|
3268
1413
|
output: scope.input,
|
|
@@ -3279,19 +1424,19 @@ function previewLegacySyntax(str3, scope) {
|
|
|
3279
1424
|
version: scope.version ?? "1.0.0"
|
|
3280
1425
|
}
|
|
3281
1426
|
};
|
|
3282
|
-
const pure = PURE_LEGACY_REGEX.exec(
|
|
1427
|
+
const pure = PURE_LEGACY_REGEX.exec(str2);
|
|
3283
1428
|
try {
|
|
3284
1429
|
if (pure) {
|
|
3285
1430
|
const expression = pure[1]?.trim();
|
|
3286
1431
|
if (!expression) return { isTemplate: true, error: "Empty expression" };
|
|
3287
1432
|
return { isTemplate: true, value: evaluateBare(expression, sandbox) };
|
|
3288
1433
|
}
|
|
3289
|
-
if (!
|
|
1434
|
+
if (!str2.includes("${")) {
|
|
3290
1435
|
return { isTemplate: false };
|
|
3291
1436
|
}
|
|
3292
|
-
let result =
|
|
1437
|
+
let result = str2;
|
|
3293
1438
|
const templateRegex = /\$\{([^}]+)\}/g;
|
|
3294
|
-
for (const match of
|
|
1439
|
+
for (const match of str2.matchAll(templateRegex)) {
|
|
3295
1440
|
const expression = match[1]?.trim();
|
|
3296
1441
|
if (!expression) continue;
|
|
3297
1442
|
const value = evaluateBare(expression, sandbox);
|
|
@@ -3305,14 +1450,14 @@ function previewLegacySyntax(str3, scope) {
|
|
|
3305
1450
|
};
|
|
3306
1451
|
}
|
|
3307
1452
|
}
|
|
3308
|
-
function evaluateExpressionPreview(
|
|
3309
|
-
if (typeof
|
|
1453
|
+
function evaluateExpressionPreview(str2, scope) {
|
|
1454
|
+
if (typeof str2 !== "string" || str2.trim() === "") {
|
|
3310
1455
|
return { isTemplate: false };
|
|
3311
1456
|
}
|
|
3312
|
-
if (containsExpressionSyntax(
|
|
3313
|
-
return previewNewSyntax(
|
|
1457
|
+
if (containsExpressionSyntax(str2)) {
|
|
1458
|
+
return previewNewSyntax(str2, scope);
|
|
3314
1459
|
}
|
|
3315
|
-
return previewLegacySyntax(
|
|
1460
|
+
return previewLegacySyntax(str2, scope);
|
|
3316
1461
|
}
|
|
3317
1462
|
var EXPRESSION_BUILTINS = [
|
|
3318
1463
|
{ insert: "$json", label: "$json", description: "Current item's data" },
|
|
@@ -4361,7 +2506,7 @@ var AdaptiveCardRenderer = forwardRef(function AdaptiveCardRenderer2({ cardData,
|
|
|
4361
2506
|
var components_default = AdaptiveCardRenderer;
|
|
4362
2507
|
|
|
4363
2508
|
// src/modules/ui-blocks/parse.ts
|
|
4364
|
-
function
|
|
2509
|
+
function isRecord2(value) {
|
|
4365
2510
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4366
2511
|
}
|
|
4367
2512
|
function humanizeFieldName(name) {
|
|
@@ -4372,7 +2517,7 @@ function synthesizeCardFromInputFields(inputFields) {
|
|
|
4372
2517
|
if (names.length === 0) return null;
|
|
4373
2518
|
const body = [];
|
|
4374
2519
|
for (const name of names) {
|
|
4375
|
-
const field =
|
|
2520
|
+
const field = isRecord2(inputFields[name]) ? inputFields[name] : {};
|
|
4376
2521
|
const description = typeof field.description === "string" ? field.description : void 0;
|
|
4377
2522
|
const required = field.required === true;
|
|
4378
2523
|
const secret = field.secret === true;
|
|
@@ -4403,9 +2548,9 @@ function synthesizeCardFromInputFields(inputFields) {
|
|
|
4403
2548
|
}
|
|
4404
2549
|
function secretFieldNames(inputFields) {
|
|
4405
2550
|
const names = /* @__PURE__ */ new Set();
|
|
4406
|
-
if (!
|
|
2551
|
+
if (!isRecord2(inputFields)) return names;
|
|
4407
2552
|
for (const [name, field] of Object.entries(inputFields)) {
|
|
4408
|
-
if (
|
|
2553
|
+
if (isRecord2(field) && field.secret === true) names.add(name);
|
|
4409
2554
|
}
|
|
4410
2555
|
return names;
|
|
4411
2556
|
}
|
|
@@ -4418,7 +2563,7 @@ function maskSecretInputs(card, secrets) {
|
|
|
4418
2563
|
if (secrets.size === 0) return card;
|
|
4419
2564
|
const visit = (value) => {
|
|
4420
2565
|
if (Array.isArray(value)) return value.map(visit);
|
|
4421
|
-
if (!
|
|
2566
|
+
if (!isRecord2(value)) return value;
|
|
4422
2567
|
const copy = {};
|
|
4423
2568
|
for (const [key, nested] of Object.entries(value))
|
|
4424
2569
|
copy[key] = visit(nested);
|
|
@@ -4432,7 +2577,7 @@ function maskSecretInputs(card, secrets) {
|
|
|
4432
2577
|
return visit(card);
|
|
4433
2578
|
}
|
|
4434
2579
|
function validateUiSpec(raw) {
|
|
4435
|
-
if (!
|
|
2580
|
+
if (!isRecord2(raw)) return "ui is not an object";
|
|
4436
2581
|
if (raw.version !== 1)
|
|
4437
2582
|
return `unsupported ui.version: ${String(raw.version)}`;
|
|
4438
2583
|
if (!Array.isArray(raw.blocks) || raw.blocks.length === 0) {
|
|
@@ -4441,7 +2586,7 @@ function validateUiSpec(raw) {
|
|
|
4441
2586
|
const seenIds = /* @__PURE__ */ new Set();
|
|
4442
2587
|
const blocks = [];
|
|
4443
2588
|
for (const [index, rawBlock] of raw.blocks.entries()) {
|
|
4444
|
-
if (!
|
|
2589
|
+
if (!isRecord2(rawBlock)) return `ui.blocks[${index}] is not an object`;
|
|
4445
2590
|
const id = rawBlock.id;
|
|
4446
2591
|
if (typeof id !== "string" || id.length === 0) {
|
|
4447
2592
|
return `ui.blocks[${index}] is missing a non-empty string id`;
|
|
@@ -4449,7 +2594,7 @@ function validateUiSpec(raw) {
|
|
|
4449
2594
|
if (seenIds.has(id)) return `ui.blocks has duplicate id "${id}"`;
|
|
4450
2595
|
seenIds.add(id);
|
|
4451
2596
|
if (rawBlock.type === "adaptive_card") {
|
|
4452
|
-
if (!
|
|
2597
|
+
if (!isRecord2(rawBlock.card)) {
|
|
4453
2598
|
return `ui.blocks[${index}] ("${id}") has no card object`;
|
|
4454
2599
|
}
|
|
4455
2600
|
blocks.push({ id, type: "adaptive_card", card: rawBlock.card });
|
|
@@ -4461,7 +2606,7 @@ function validateUiSpec(raw) {
|
|
|
4461
2606
|
id,
|
|
4462
2607
|
type: "custom",
|
|
4463
2608
|
component: rawBlock.component,
|
|
4464
|
-
props:
|
|
2609
|
+
props: isRecord2(rawBlock.props) ? rawBlock.props : void 0
|
|
4465
2610
|
});
|
|
4466
2611
|
} else {
|
|
4467
2612
|
return `ui.blocks[${index}] ("${id}") has unknown type "${String(rawBlock.type)}"`;
|
|
@@ -4488,7 +2633,7 @@ function resolveUiSpec(operation) {
|
|
|
4488
2633
|
`ui-blocks: invalid ui declaration on operation "${operation.name ?? "?"}" (${result}); falling back to adaptive_card`
|
|
4489
2634
|
);
|
|
4490
2635
|
}
|
|
4491
|
-
if (
|
|
2636
|
+
if (isRecord2(operation.adaptive_card)) {
|
|
4492
2637
|
return {
|
|
4493
2638
|
spec: {
|
|
4494
2639
|
version: 1,
|
|
@@ -4503,7 +2648,7 @@ function resolveUiSpec(operation) {
|
|
|
4503
2648
|
synthesized: true
|
|
4504
2649
|
};
|
|
4505
2650
|
}
|
|
4506
|
-
if (
|
|
2651
|
+
if (isRecord2(operation.input_fields)) {
|
|
4507
2652
|
const card = synthesizeCardFromInputFields(operation.input_fields);
|
|
4508
2653
|
if (card) {
|
|
4509
2654
|
return {
|
|
@@ -4518,17 +2663,17 @@ function resolveUiSpec(operation) {
|
|
|
4518
2663
|
return null;
|
|
4519
2664
|
}
|
|
4520
2665
|
function isSubmitAction(action) {
|
|
4521
|
-
return
|
|
2666
|
+
return isRecord2(action) && action.type === "Action.Submit";
|
|
4522
2667
|
}
|
|
4523
2668
|
function stripFromActions(actions) {
|
|
4524
2669
|
return actions.filter((action) => !isSubmitAction(action)).map(
|
|
4525
|
-
(action) =>
|
|
2670
|
+
(action) => isRecord2(action) && isRecord2(action.card) ? { ...action, card: stripSubmitActions(action.card) } : action
|
|
4526
2671
|
);
|
|
4527
2672
|
}
|
|
4528
2673
|
function stripFromElements(elements) {
|
|
4529
2674
|
const result = [];
|
|
4530
2675
|
for (const element of elements) {
|
|
4531
|
-
if (!
|
|
2676
|
+
if (!isRecord2(element)) {
|
|
4532
2677
|
result.push(element);
|
|
4533
2678
|
continue;
|
|
4534
2679
|
}
|
|
@@ -4543,7 +2688,7 @@ function stripFromElements(elements) {
|
|
|
4543
2688
|
}
|
|
4544
2689
|
if (Array.isArray(el.columns)) {
|
|
4545
2690
|
el.columns = el.columns.map(
|
|
4546
|
-
(column) =>
|
|
2691
|
+
(column) => isRecord2(column) && Array.isArray(column.items) ? { ...column, items: stripFromElements(column.items) } : column
|
|
4547
2692
|
);
|
|
4548
2693
|
}
|
|
4549
2694
|
result.push(el);
|
|
@@ -5854,23 +3999,6 @@ function AdapterConnectionSelector({
|
|
|
5854
3999
|
] });
|
|
5855
4000
|
}
|
|
5856
4001
|
|
|
5857
|
-
// src/builder/lib/sticky-notes.ts
|
|
5858
|
-
function isStickyNode(node) {
|
|
5859
|
-
return node?.type === STICKY_NOTE_TYPE;
|
|
5860
|
-
}
|
|
5861
|
-
function partitionStickyNotes(nodes) {
|
|
5862
|
-
return {
|
|
5863
|
-
nodes: nodes.filter((n) => !isStickyNode(n)),
|
|
5864
|
-
stickyNotes: nodes.filter((n) => isStickyNode(n))
|
|
5865
|
-
};
|
|
5866
|
-
}
|
|
5867
|
-
function mergeStickyNotes(def) {
|
|
5868
|
-
const nodes = Array.isArray(def.nodes) ? def.nodes : [];
|
|
5869
|
-
const stickies = Array.isArray(def.stickyNotes) ? def.stickyNotes : [];
|
|
5870
|
-
const seen = new Set(nodes.map((n) => n.id));
|
|
5871
|
-
return [...nodes, ...stickies.filter((s) => s?.id && !seen.has(s.id))];
|
|
5872
|
-
}
|
|
5873
|
-
|
|
5874
4002
|
// src/hooks/workflow-saved-events.ts
|
|
5875
4003
|
var listeners = /* @__PURE__ */ new Map();
|
|
5876
4004
|
function subscribeWorkflowSaved(workflowKey, listener) {
|
|
@@ -5887,11 +4015,11 @@ function notifyWorkflowSaved(workflowKey) {
|
|
|
5887
4015
|
}
|
|
5888
4016
|
|
|
5889
4017
|
// src/builder/lib/display-options.ts
|
|
5890
|
-
function
|
|
4018
|
+
function isRecord3(value) {
|
|
5891
4019
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5892
4020
|
}
|
|
5893
4021
|
function readRuleSet(value) {
|
|
5894
|
-
if (!
|
|
4022
|
+
if (!isRecord3(value)) return void 0;
|
|
5895
4023
|
const rules = {};
|
|
5896
4024
|
for (const [key, allowed] of Object.entries(value)) {
|
|
5897
4025
|
if (Array.isArray(allowed)) rules[key] = allowed;
|
|
@@ -5900,8 +4028,8 @@ function readRuleSet(value) {
|
|
|
5900
4028
|
return Object.keys(rules).length > 0 ? rules : void 0;
|
|
5901
4029
|
}
|
|
5902
4030
|
function readDisplayOptions(spec) {
|
|
5903
|
-
const raw =
|
|
5904
|
-
if (!
|
|
4031
|
+
const raw = isRecord3(spec) ? spec.displayOptions : void 0;
|
|
4032
|
+
if (!isRecord3(raw)) return void 0;
|
|
5905
4033
|
const show = readRuleSet(raw.show);
|
|
5906
4034
|
const hide = readRuleSet(raw.hide);
|
|
5907
4035
|
if (!show && !hide) return void 0;
|
|
@@ -5914,7 +4042,7 @@ function matches(current, allowed) {
|
|
|
5914
4042
|
);
|
|
5915
4043
|
}
|
|
5916
4044
|
function isParamVisible(spec, values, defaults = {}) {
|
|
5917
|
-
const options =
|
|
4045
|
+
const options = isRecord3(spec) ? readDisplayOptions(spec) ?? (isRecord3(spec.show) || isRecord3(spec.hide) ? readDisplayOptions({ displayOptions: spec }) : void 0) : void 0;
|
|
5918
4046
|
if (!options) return true;
|
|
5919
4047
|
const valueOf = (key) => values[key] === void 0 ? defaults[key] : values[key];
|
|
5920
4048
|
if (options.show) {
|
|
@@ -5934,7 +4062,7 @@ function isParamVisible(spec, values, defaults = {}) {
|
|
|
5934
4062
|
function defaultsOf(fields) {
|
|
5935
4063
|
const defaults = {};
|
|
5936
4064
|
for (const [name, spec] of Object.entries(fields)) {
|
|
5937
|
-
if (
|
|
4065
|
+
if (isRecord3(spec) && spec.default !== void 0)
|
|
5938
4066
|
defaults[name] = spec.default;
|
|
5939
4067
|
}
|
|
5940
4068
|
return defaults;
|
|
@@ -5945,17 +4073,17 @@ function dropHiddenParameters(state, fields, mappedFields = /* @__PURE__ */ new
|
|
|
5945
4073
|
let next;
|
|
5946
4074
|
const ensure = () => next ??= { ...state };
|
|
5947
4075
|
for (const [name, spec] of Object.entries(fields)) {
|
|
5948
|
-
if (!
|
|
4076
|
+
if (!isRecord3(spec)) continue;
|
|
5949
4077
|
if (!mappedFields.has(name) && Object.hasOwn(state, name) && !isParamVisible(spec, state, defaults)) {
|
|
5950
4078
|
delete ensure()[name];
|
|
5951
4079
|
continue;
|
|
5952
4080
|
}
|
|
5953
|
-
const rowFields =
|
|
4081
|
+
const rowFields = isRecord3(spec.fields) ? spec.fields : void 0;
|
|
5954
4082
|
const rows = state[name];
|
|
5955
4083
|
if (rowFields && Array.isArray(rows)) {
|
|
5956
4084
|
let changed = false;
|
|
5957
4085
|
const cleaned = rows.map((row) => {
|
|
5958
|
-
if (!
|
|
4086
|
+
if (!isRecord3(row)) return row;
|
|
5959
4087
|
const cleanedRow = dropHiddenParameters(row, rowFields);
|
|
5960
4088
|
if (cleanedRow !== row) changed = true;
|
|
5961
4089
|
return cleanedRow;
|
|
@@ -5967,7 +4095,7 @@ function dropHiddenParameters(state, fields, mappedFields = /* @__PURE__ */ new
|
|
|
5967
4095
|
}
|
|
5968
4096
|
|
|
5969
4097
|
// src/builder/lib/field-schema.ts
|
|
5970
|
-
function
|
|
4098
|
+
function isRecord4(value) {
|
|
5971
4099
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5972
4100
|
}
|
|
5973
4101
|
function isIdentifier(key) {
|
|
@@ -5986,11 +4114,11 @@ function pathToExpression(path) {
|
|
|
5986
4114
|
function mergeFieldSpecs(common, variant) {
|
|
5987
4115
|
const base = typeof common === "string" ? { type: common } : common;
|
|
5988
4116
|
const branch = typeof variant === "string" ? { type: variant } : variant;
|
|
5989
|
-
if (!
|
|
4117
|
+
if (!isRecord4(base) || !isRecord4(branch)) return branch;
|
|
5990
4118
|
const merged = { ...base, ...branch };
|
|
5991
4119
|
const commonProperties = base.properties;
|
|
5992
4120
|
const branchProperties = branch.properties;
|
|
5993
|
-
if (
|
|
4121
|
+
if (isRecord4(commonProperties) && isRecord4(branchProperties)) {
|
|
5994
4122
|
merged.properties = Object.fromEntries(
|
|
5995
4123
|
Object.entries({ ...commonProperties, ...branchProperties }).map(
|
|
5996
4124
|
([key, value]) => [
|
|
@@ -6009,14 +4137,14 @@ function fieldFromSpec(key, path, spec) {
|
|
|
6009
4137
|
if (typeof spec === "string") {
|
|
6010
4138
|
return { key, path, type: spec };
|
|
6011
4139
|
}
|
|
6012
|
-
if (
|
|
4140
|
+
if (isRecord4(spec)) {
|
|
6013
4141
|
const declaredType2 = typeof spec.type === "string" ? spec.type : void 0;
|
|
6014
4142
|
const description = typeof spec.description === "string" ? spec.description : void 0;
|
|
6015
4143
|
const required = spec.required === true;
|
|
6016
4144
|
const alternatives = ["oneOf", "anyOf"].flatMap((keyword) => {
|
|
6017
4145
|
const variants = spec[keyword];
|
|
6018
4146
|
return Array.isArray(variants) ? variants.flatMap(
|
|
6019
|
-
(variant, index) =>
|
|
4147
|
+
(variant, index) => isRecord4(variant) || typeof variant === "string" ? [{ keyword, index, variant }] : []
|
|
6020
4148
|
) : [];
|
|
6021
4149
|
});
|
|
6022
4150
|
if (alternatives.length > 0) {
|
|
@@ -6045,7 +4173,7 @@ function fieldFromSpec(key, path, spec) {
|
|
|
6045
4173
|
type: declaredType2 ?? [...new Set(children.map((field) => field.type))].join(" | ")
|
|
6046
4174
|
};
|
|
6047
4175
|
}
|
|
6048
|
-
if (
|
|
4176
|
+
if (isRecord4(spec.properties) && (!declaredType2 || declaredType2 === "object")) {
|
|
6049
4177
|
const children = Object.entries(spec.properties).map(
|
|
6050
4178
|
([childKey, childSpec]) => fieldFromSpec(childKey, joinPath(path, childKey), childSpec)
|
|
6051
4179
|
);
|
|
@@ -6067,7 +4195,7 @@ function fieldFromSpec(key, path, spec) {
|
|
|
6067
4195
|
return { key, path, type: "any" };
|
|
6068
4196
|
}
|
|
6069
4197
|
function fieldsFromIO(io, root = "") {
|
|
6070
|
-
if (!
|
|
4198
|
+
if (!isRecord4(io)) return [];
|
|
6071
4199
|
return Object.entries(io).map(
|
|
6072
4200
|
([key, spec]) => fieldFromSpec(key, joinPath(root, key), spec)
|
|
6073
4201
|
);
|
|
@@ -6086,7 +4214,7 @@ function fieldFromValue(key, path, value) {
|
|
|
6086
4214
|
const children = value.length > 0 ? [fieldFromValue("0", `${path}[0]`, value[0])] : void 0;
|
|
6087
4215
|
return { key, path, type: "array", children };
|
|
6088
4216
|
}
|
|
6089
|
-
if (
|
|
4217
|
+
if (isRecord4(value)) {
|
|
6090
4218
|
const children = Object.entries(value).map(
|
|
6091
4219
|
([k, v]) => fieldFromValue(k, joinPath(path, k), v)
|
|
6092
4220
|
);
|
|
@@ -6095,7 +4223,7 @@ function fieldFromValue(key, path, value) {
|
|
|
6095
4223
|
return { key, path, type: typeOfValue(value) };
|
|
6096
4224
|
}
|
|
6097
4225
|
function fieldsFromValue(value, root = "") {
|
|
6098
|
-
if (!
|
|
4226
|
+
if (!isRecord4(value)) return [];
|
|
6099
4227
|
return Object.entries(value).map(
|
|
6100
4228
|
([key, v]) => fieldFromValue(key, joinPath(root, key), v)
|
|
6101
4229
|
);
|
|
@@ -6111,13 +4239,13 @@ function declaredOutputFields(nodeType, op) {
|
|
|
6111
4239
|
}
|
|
6112
4240
|
function normalizeOperations(raw) {
|
|
6113
4241
|
if (Array.isArray(raw)) return raw;
|
|
6114
|
-
if (
|
|
4242
|
+
if (isRecord4(raw) && Array.isArray(raw.operations)) {
|
|
6115
4243
|
return raw.operations;
|
|
6116
4244
|
}
|
|
6117
4245
|
return [];
|
|
6118
4246
|
}
|
|
6119
4247
|
function resolveNodeOperation(data, fallbackOperations) {
|
|
6120
|
-
const nodeData =
|
|
4248
|
+
const nodeData = isRecord4(data?.nodeData) ? data?.nodeData : void 0;
|
|
6121
4249
|
let operations = normalizeOperations(nodeData?.operations);
|
|
6122
4250
|
if (operations.length === 0) {
|
|
6123
4251
|
operations = normalizeOperations(data?.operations);
|
|
@@ -6131,11 +4259,11 @@ function resolveNodeOperation(data, fallbackOperations) {
|
|
|
6131
4259
|
}
|
|
6132
4260
|
|
|
6133
4261
|
// src/builder/lib/parameter-values.ts
|
|
6134
|
-
function
|
|
4262
|
+
function isRecord5(value) {
|
|
6135
4263
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6136
4264
|
}
|
|
6137
4265
|
function record(value) {
|
|
6138
|
-
return
|
|
4266
|
+
return isRecord5(value) ? value : void 0;
|
|
6139
4267
|
}
|
|
6140
4268
|
function declaredType(schema) {
|
|
6141
4269
|
const type = typeof schema === "string" ? schema : record(schema)?.type;
|
|
@@ -8310,7 +6438,7 @@ function useNodeExecution() {
|
|
|
8310
6438
|
} catch (error) {
|
|
8311
6439
|
console.error("[useNodeExecution] Error executing step:", error);
|
|
8312
6440
|
const errorMessage = describeOperationError(error);
|
|
8313
|
-
const errorRunId = nanoid();
|
|
6441
|
+
const errorRunId = nanoid$1();
|
|
8314
6442
|
const errorLog = {
|
|
8315
6443
|
id: `${errorRunId}-${nodeId}`,
|
|
8316
6444
|
runId: errorRunId,
|
|
@@ -8423,7 +6551,7 @@ function useNodeExecution() {
|
|
|
8423
6551
|
surface: "builder-run"
|
|
8424
6552
|
});
|
|
8425
6553
|
const errorMessage = describeOperationError(error);
|
|
8426
|
-
const errorRunId = nanoid();
|
|
6554
|
+
const errorRunId = nanoid$1();
|
|
8427
6555
|
const errorLog = {
|
|
8428
6556
|
id: `${errorRunId}-${triggerNode.id}`,
|
|
8429
6557
|
runId: errorRunId,
|
|
@@ -9076,45 +7204,6 @@ function useInsertNode() {
|
|
|
9076
7204
|
[screenToFlowPosition, getNodes, addNodes, updateNode]
|
|
9077
7205
|
);
|
|
9078
7206
|
}
|
|
9079
|
-
|
|
9080
|
-
// src/builder/lib/node-operation-selection.ts
|
|
9081
|
-
function resolveOperationName(selectedOperation, fallback) {
|
|
9082
|
-
return typeof selectedOperation === "string" && selectedOperation.trim() ? selectedOperation : fallback;
|
|
9083
|
-
}
|
|
9084
|
-
function canRenderOperationPanel(selectedOperation, supportedOperations) {
|
|
9085
|
-
const operationName = resolveOperationName(selectedOperation, "");
|
|
9086
|
-
return operationName === "" || supportedOperations.includes(operationName);
|
|
9087
|
-
}
|
|
9088
|
-
function isRecord9(value) {
|
|
9089
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
9090
|
-
}
|
|
9091
|
-
function readRecord3(value) {
|
|
9092
|
-
return isRecord9(value) ? value : void 0;
|
|
9093
|
-
}
|
|
9094
|
-
function readOperations(value) {
|
|
9095
|
-
const operations = Array.isArray(value) ? value : readRecord3(value)?.operations;
|
|
9096
|
-
return Array.isArray(operations) ? operations : [];
|
|
9097
|
-
}
|
|
9098
|
-
function synchronizeOperationUpdate(currentData, updates, registeredOperations) {
|
|
9099
|
-
const operationName = resolveOperationName(updates.operation_name, "");
|
|
9100
|
-
if (!operationName || operationName === currentData.operation_name)
|
|
9101
|
-
return updates;
|
|
9102
|
-
const manifest = readRecord3(updates.nodeData ?? currentData.nodeData);
|
|
9103
|
-
const operations = [
|
|
9104
|
-
...readOperations(manifest?.operations),
|
|
9105
|
-
...readOperations(registeredOperations)
|
|
9106
|
-
];
|
|
9107
|
-
const selected = readRecord3(
|
|
9108
|
-
operations.find(
|
|
9109
|
-
(operation) => readRecord3(operation)?.name === operationName
|
|
9110
|
-
)
|
|
9111
|
-
);
|
|
9112
|
-
return {
|
|
9113
|
-
...updates,
|
|
9114
|
-
operation_type: typeof selected?.type === "string" ? selected.type : updates.operation_type,
|
|
9115
|
-
nodeData: { ...manifest, operations: selected ? [selected] : [] }
|
|
9116
|
-
};
|
|
9117
|
-
}
|
|
9118
7207
|
function isAutoManagedConnectionAdapter(nodeType, adapter) {
|
|
9119
7208
|
const isBigConsoleDataSinkAutoAdapter = nodeType === "store/bigconsole_datasink" && adapter.name === "bigconsole" && adapter.provider === "bigconsole";
|
|
9120
7209
|
return isBigConsoleDataSinkAutoAdapter || adapter.mode === "auto" || adapter.autoProvision === true || adapter.autoManaged === true || adapter.hidden === true;
|
|
@@ -10109,7 +8198,7 @@ function getNodeDetail(nodeType) {
|
|
|
10109
8198
|
}
|
|
10110
8199
|
function createNodeData(type, data) {
|
|
10111
8200
|
return {
|
|
10112
|
-
id: nanoid(),
|
|
8201
|
+
id: nanoid$1(),
|
|
10113
8202
|
type,
|
|
10114
8203
|
data
|
|
10115
8204
|
};
|
|
@@ -10119,4 +8208,4 @@ function createNodeWithDefaultData(type, data) {
|
|
|
10119
8208
|
return Object.assign(createNodeData(type, defaultData), data);
|
|
10120
8209
|
}
|
|
10121
8210
|
|
|
10122
|
-
export { AUTOSAVE_DEBOUNCE_MS, AUTOSAVE_RETRY_DELAYS_MS, AVAILABLE_NODES, BILLING_PLANS_PATH,
|
|
8211
|
+
export { AUTOSAVE_DEBOUNCE_MS, AUTOSAVE_RETRY_DELAYS_MS, AVAILABLE_NODES, BILLING_PLANS_PATH, ConnectionFormDialog, ConnectionSelector, DURABLE_FUNCTION_NODE_TYPES, EDIT_SESSION_ID, ExpressionEditor, FLUIDGRIDS_FLAGS, FLUIDGRIDS_FLAG_DEFAULTS, FluidGridsContext, FluidGridsProvider, NODES, NODES_METADATA, NODE_CONFIGS, NODE_TYPES, NodePropertyPanel, PHASE_C_FLAGS_OFF, RUNS_QUOTA_NAME, RUN_CONTROL_NODE_TYPES, WORKFLOWS_QUOTA_NAME, WORKFLOW_TEST_NODE_TYPES, autosaveAllowedFor, bannerOf, blankWorkflowCreateInput, buildOperationSeed, buildStickyNode, builderPathOf, canAutosave, canSignalRun, classifyCreateRefusal, clearCodeWorkflowDefinitionCache, codeBuildIdOf, components_default, createConfiguredNode, createThenOpen, declaredOutputFields, declaredSignals, departingSave, editStateFor, editingLeaseLocked, emitNodeInstalled, emitRunFailed, emitRunLimitHit, emitRunStarted, emitTemplateUsed, emitUpgradeClicked, emitWorkflowCreated, emitWorkflowLimitHit, emitWorkflowPublished, ensureNodeConfigsLoaded, fieldsFromIO, fieldsFromValue, filterPaletteNodes, findQuotaRefusal, findSaveConflict, forgetSessionForReload, formatParameterValue, getNodeDetail, getNodeMetadata, inAppLeaveTarget, isDurableFunctionNodeType, isFlowComplete, isLocked, isNodeConfigsInitialized, isNodeTypeHiddenFromPalette, isParamVisible, isQuotaExhaustedFailure, isRunControlNodeType, leaseCallQueue, leavingLosesChanges, listCustomBlocks, liveInternalOperations, loadDefinitionJson, nodesOf, onNodeTypesUpdate, openRunQuotaUpgradePrompt, parseParameterValue, parseRawSignalPayload, pathToExpression, payloadFromCardValues, phaseAfterAcquire, phaseAfterTakeOver, readDisplayOptions, refetchStoreNodes, registerCustomBlock, registerWorkflowNodeTypes, releasesOnClose, rememberOwnStatusChange, rememberRevision, rememberSessionForReload, resolveNodeOperation, resolvePhaseCFlags, resolveUiSpec, runSignalTargets, runTriggerFromMode, saveIndicatorOf, savedEverythingBeforeLeaving, sessionBeforeReload, shouldReleaseForIdle, signalPayloadCard, stripSubmitActions, structuredParameterType, subscribeWorkflowSaved, tickAction, touchesSavedFields, useAgentDefinitionList, useAgentDefinitions, useCodeWorkflowInterface, useConnection, useConnections, useConnectionsByProvider, useContinuousOptimisationEnabled, useCreateConnection, useDurableFunctionNodesEnabled, useDurableParityEnabled, useEditLeaseLocked, useEditLeaseStore, useFlowValidator, useFluidGridsAnalytics, useFluidGridsContext, useFluidGridsFlag, useGuardedNavigate, useInitiateOAuth, useInsertNode, useManualSave, useNodeExecution, useNodeRegistryRevision, usePaletteGates, usePhaseCFlags, useProviders, useRunGuard, useSaveStatusStore, useSaveWorkflow, useSelfHostedWorkersEnabled, useWorkflowTestsEnabled, watchLeavingLosesChanges, workflowFingerprint };
|