@burdenoff/fluidgrids-fe-sdk 2026.1109.9 → 2026.1110.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/{ExecutionDetailPage-2ORSV3YN.js → ExecutionDetailPage-UXQFBLF3.js} +14 -14
  2. package/dist/{ExecutionsListPage-MY45NECW.js → ExecutionsListPage-A4GCUNFR.js} +11 -11
  3. package/dist/{WorkflowBuilder-MWC2BCTQ.js → WorkflowBuilder-ZLVMV2UA.js} +21 -15
  4. package/dist/{WorkflowsList-6AG7CFZM.js → WorkflowsList-XPNGNR4A.js} +8 -8
  5. package/dist/{agentTools-5O2KPQYJ.js → agentTools-V26FOMTS.js} +5 -7
  6. package/dist/{chunk-ACME5GOU.js → chunk-2DBAQR6F.js} +2 -2
  7. package/dist/{chunk-MYE6CMGK.js → chunk-2H4XAES7.js} +3 -3
  8. package/dist/{chunk-IZSWG5G3.js → chunk-3F4DIVKT.js} +1 -1
  9. package/dist/chunk-3JGAI5YC.js +1437 -0
  10. package/dist/{chunk-MSNCU6US.js → chunk-5TGPH3CX.js} +4 -4
  11. package/dist/{chunk-U52PO4QQ.js → chunk-5V7PMLQN.js} +1320 -58
  12. package/dist/{chunk-TKSVFP36.js → chunk-5ZAOXCIQ.js} +6 -6
  13. package/dist/{chunk-POCNG3PM.js → chunk-6CPQVLHT.js} +15 -16
  14. package/dist/{chunk-2LERIIZM.js → chunk-7UFE2CHD.js} +308 -1026
  15. package/dist/{chunk-VAWYR6P4.js → chunk-A6Q4FWB6.js} +9 -1
  16. package/dist/{chunk-G4NAU6FF.js → chunk-CBX2CXGH.js} +8 -8
  17. package/dist/{chunk-5UA262ZO.js → chunk-CKF2FBUP.js} +1 -1
  18. package/dist/{chunk-5YLS3WH5.js → chunk-D4L5BN64.js} +1 -1
  19. package/dist/{chunk-VYXTP6YF.js → chunk-DDINUPO3.js} +2185 -5390
  20. package/dist/{chunk-DFFQYK2X.js → chunk-DIIGFBYT.js} +1 -1
  21. package/dist/{chunk-3T3C3475.js → chunk-G7BT24PD.js} +550 -3
  22. package/dist/chunk-HORSE7WX.js +54 -0
  23. package/dist/{chunk-7ADEPA4W.js → chunk-I3DBTNWQ.js} +6 -6
  24. package/dist/{chunk-HZ7FQCFU.js → chunk-JNSHR2J2.js} +1 -1
  25. package/dist/{chunk-ZXLXZFWO.js → chunk-K22NDWSD.js} +2 -2
  26. package/dist/{chunk-JXCJRBWD.js → chunk-K2X63CR2.js} +1 -5
  27. package/dist/{chunk-Q526TUOC.js → chunk-L5MZ74DA.js} +1 -1
  28. package/dist/{chunk-WKF72AS2.js → chunk-OVZA4IM7.js} +4 -4
  29. package/dist/{chunk-GR3QNLFS.js → chunk-OZNFRJKC.js} +5 -5
  30. package/dist/{chunk-NEB4Y7AX.js → chunk-PI4AW4T2.js} +241 -34
  31. package/dist/{chunk-TNMXKPJX.js → chunk-PICOXEUO.js} +4 -4
  32. package/dist/{chunk-QWDF72GZ.js → chunk-QGRVYPQC.js} +2 -2
  33. package/dist/{chunk-THIMC2ZD.js → chunk-WGUHISC2.js} +29 -11
  34. package/dist/{chunk-B3USL2JQ.js → chunk-X7XVRJK2.js} +2 -2
  35. package/dist/{chunk-4EZFAL24.js → chunk-XLU63IUB.js} +6 -6
  36. package/dist/{chunk-CX3LABFK.js → chunk-Z6D6YL7C.js} +1 -1
  37. package/dist/{chunk-NCXK2AO6.js → chunk-ZQTANHKA.js} +2 -2
  38. package/dist/chunk-ZZBZPBO5.js +1644 -0
  39. package/dist/executions.js +15 -15
  40. package/dist/history.js +7 -9
  41. package/dist/index.d.ts +367 -159
  42. package/dist/index.js +592 -68
  43. package/dist/{node-detail-view-ZFGS3FWU.js → node-detail-view-2AFXRNX6.js} +19 -864
  44. package/dist/nodes.js +2 -2
  45. package/dist/observability.js +7 -7
  46. package/dist/{quick-config-panel-ZDGYZR7Y.js → quick-config-panel-U4AELSCT.js} +12 -54
  47. package/dist/settings.js +9 -9
  48. package/dist/templates.js +21 -14
  49. package/dist/workflow-builder.js +22 -16
  50. package/dist/workflow-preview.js +2 -2
  51. package/dist/workflows-list.js +8 -8
  52. package/package.json +1 -1
  53. package/dist/chunk-GTEBQQ7J.js +0 -24
  54. package/dist/chunk-O2OFNGAF.js +0 -338
  55. package/dist/chunk-QTOPG7SR.js +0 -501
  56. package/dist/chunk-U7UNWR3D.js +0 -260
@@ -1,28 +1,32 @@
1
- import { computeAttachPosition, firstInputHandleId } from './chunk-HZ7FQCFU.js';
1
+ import { computeAttachPosition, firstInputHandleId } from './chunk-JNSHR2J2.js';
2
2
  import { deepClone, applyTemplateInputs } from './chunk-GEMNVFPK.js';
3
3
  import { templatePreview } from './chunk-B6CCE2RW.js';
4
4
  import { Input } from './chunk-IEVSFCFS.js';
5
5
  import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter as DialogFooter$1 } from './chunk-YXMFRQYV.js';
6
6
  import { Badge as Badge$1 } from './chunk-TFCIZFDM.js';
7
- import { LogsPanel } from './chunk-O2OFNGAF.js';
8
- import { CreateWorkflowRefusalDialog, WorkflowShareDialog, useWorkflowCodeExport, orderedExportFiles, fileBaseName, downloadWorkflowCodeExport, isLosslessReport, sortFidelityItems, isLossyFidelityItem, lineOfNode } from './chunk-QWDF72GZ.js';
9
- import { emptyTestCaseDraft, EntityTagPicker, useWorkflowProposal, WorkflowProposalCard, useWorkflowTests, pinnedOutputsFromCanvas, enabledCaseIds, isTestRunOpen, MAX_TEST_CASES, draftFromTestCase, testRunSummaryText, testStatusLabel, TEST_STATUS_TONE_CLASS, testStatusTone, MAX_CASE_NAME, nextSortOrder, draftToInput } from './chunk-MYE6CMGK.js';
10
- import { buildNodeDisplayMap } from './chunk-DFFQYK2X.js';
7
+ import { LogsPanel, SCHEDULE_NODE_TYPE, TabButton, NodeSettingsPanel, SchedulePanel } from './chunk-3JGAI5YC.js';
8
+ import { NodeInputFields } from './chunk-HORSE7WX.js';
9
+ import { useGlobalStoreClient, ReadOnlyFieldset, NodeParamsForm, NodeExecutionActions } from './chunk-5V7PMLQN.js';
10
+ import { useNodeConfig, nodeSubtitle, nodeTitle } from './chunk-PI4AW4T2.js';
11
+ import { CreateWorkflowRefusalDialog, WorkflowShareDialog, useWorkflowCodeExport, orderedExportFiles, fileBaseName, downloadWorkflowCodeExport, isLosslessReport, sortFidelityItems, isLossyFidelityItem, lineOfNode } from './chunk-QGRVYPQC.js';
12
+ import { emptyTestCaseDraft, EntityTagPicker, useWorkflowProposal, WorkflowProposalCard, useWorkflowTests, pinnedOutputsFromCanvas, enabledCaseIds, isTestRunOpen, MAX_TEST_CASES, draftFromTestCase, testRunSummaryText, testStatusLabel, TEST_STATUS_TONE_CLASS, testStatusTone, MAX_CASE_NAME, nextSortOrder, draftToInput } from './chunk-2H4XAES7.js';
13
+ import { buildNodeDisplayMap } from './chunk-DIIGFBYT.js';
11
14
  import { AiCreditBalanceSlot } from './chunk-Y53CVZVV.js';
12
- import { countLifecycle, VersionLifecycleBar, VersionDiffDialog } from './chunk-B3USL2JQ.js';
13
- import { useRestoreWorkflowVersion, useWorkflowVersions, useActivateWorkflow, useDeleteWorkflow, useDeactivateWorkflow } from './chunk-ZXLXZFWO.js';
15
+ import { countLifecycle, VersionLifecycleBar, VersionDiffDialog } from './chunk-X7XVRJK2.js';
16
+ import { useRestoreWorkflowVersion, useWorkflowVersions, useActivateWorkflow, useDeleteWorkflow, useDeactivateWorkflow } from './chunk-K22NDWSD.js';
14
17
  import { PublishCustomNodeAction } from './chunk-XRGAH6IQ.js';
15
18
  import { Button } from './chunk-QJAZXCFQ.js';
16
19
  import { useRequestedProposal } from './chunk-GLYINMOR.js';
20
+ import { useConnections, ConnectionFormDialog } from './chunk-ZZBZPBO5.js';
17
21
  import { FluidGridsDocsLink } from './chunk-4VJ3MDOV.js';
18
- import { leaseCallQueue, RUNS_QUOTA_NAME, BILLING_PLANS_PATH, emitUpgradeClicked, FluidGridsContext, emitWorkflowCreated, emitTemplateUsed, ensureNodeConfigsLoaded, NODE_CONFIGS, useEditLeaseStore, useEditLeaseLocked, registerWorkflowNodeTypes, emitNodeInstalled, useNodeExecution, usePaletteGates, onNodeTypesUpdate, NODE_TYPES, getNodeMetadata, refetchStoreNodes, AVAILABLE_NODES, EDIT_SESSION_ID, useInsertNode, useSaveStatusStore, useManualSave, useDurableFunctionNodesEnabled, bannerOf, editStateFor, useSaveWorkflow, filterPaletteNodes, useFluidGridsAnalytics, useGuardedNavigate, sessionBeforeReload, forgetSessionForReload, releasesOnClose, touchesSavedFields, isLocked, watchLeavingLosesChanges, workflowFingerprint, savedEverythingBeforeLeaving, refusalOfQuota, buildStickyNode, NODES_METADATA, shouldReleaseForIdle, tickAction, rememberSessionForReload, leavingLosesChanges, buildOperationSeed, useDurableParityEnabled, useConnections, ConnectionFormDialog, useWorkflowTestsEnabled, useFluidGridsFlag, FLUIDGRIDS_FLAGS, useFlowValidator, saveIndicatorOf, departingSave, inAppLeaveTarget, isNodeConfigsInitialized, phaseAfterAcquire, rememberOwnStatusChange, useRunGuard, saveFailureActionOf, getNodeDetail, NODES, NodePropertyPanel, loadDefinitionJson, canAutosave, isNodeTypeHiddenFromPalette, ConnectionSelector, AUTOSAVE_RETRY_DELAYS_MS, AUTOSAVE_DEBOUNCE_MS, editingLeaseLocked, autosaveAllowedFor, isFlowComplete, rememberRevision, phaseAfterTakeOver } from './chunk-VYXTP6YF.js';
19
22
  import { SdkPermissionButton, FLUIDGRIDS_PERMISSIONS, useFluidGridsPermission, SdkPermissionGate } from './chunk-ERT444RG.js';
23
+ import { leaseCallQueue, RUNS_QUOTA_NAME, BILLING_PLANS_PATH, emitUpgradeClicked, FluidGridsContext, emitWorkflowCreated, emitTemplateUsed, ensureNodeConfigsLoaded, NODE_CONFIGS, useEditLeaseStore, useEditLeaseLocked, registerWorkflowNodeTypes, emitNodeInstalled, useNodeExecution, usePaletteGates, onNodeTypesUpdate, NODE_TYPES, getNodeMetadata, refetchStoreNodes, AVAILABLE_NODES, EDIT_SESSION_ID, useInsertNode, useSaveStatusStore, useManualSave, useDurableFunctionNodesEnabled, bannerOf, editStateFor, useSaveWorkflow, filterPaletteNodes, useFluidGridsAnalytics, useGuardedNavigate, sessionBeforeReload, forgetSessionForReload, releasesOnClose, touchesSavedFields, isLocked, watchLeavingLosesChanges, workflowFingerprint, savedEverythingBeforeLeaving, refusalOfQuota, buildStickyNode, NODES_METADATA, shouldReleaseForIdle, tickAction, rememberSessionForReload, leavingLosesChanges, buildOperationSeed, useDurableParityEnabled, useWorkflowTestsEnabled, useFluidGridsFlag, FLUIDGRIDS_FLAGS, useFlowValidator, saveIndicatorOf, departingSave, inAppLeaveTarget, isNodeConfigsInitialized, phaseAfterAcquire, rememberOwnStatusChange, useRunGuard, saveFailureActionOf, getNodeDetail, loadDefinitionJson, canAutosave, isNodeTypeHiddenFromPalette, usePhaseCFlags, AUTOSAVE_RETRY_DELAYS_MS, AUTOSAVE_DEBOUNCE_MS, editingLeaseLocked, autosaveAllowedFor, isFlowComplete, rememberRevision, phaseAfterTakeOver } from './chunk-DDINUPO3.js';
20
24
  import { BuilderReadOnlyProvider, useBuilderReadOnly } from './chunk-SDZEAIIE.js';
21
- import { useFlowStore, useIsValidConnection, NODE_TYPE_DRAG_DATA_FORMAT, NODE_OPERATION_DRAG_DATA_FORMAT, CODE_WORKFLOW_NODE_TYPE, STICKY_NOTE_TYPE, NodeTypeIcon, isImageIcon, synchronizeOperationUpdate, isTriggerOperation, canRenderOperationPanel, resolveOperationName } from './chunk-JXCJRBWD.js';
25
+ import { useFlowStore, useIsValidConnection, NODE_TYPE_DRAG_DATA_FORMAT, NODE_OPERATION_DRAG_DATA_FORMAT, CODE_WORKFLOW_NODE_TYPE, STICKY_NOTE_TYPE, NodeTypeIcon, isImageIcon, isTriggerOperation, nodeAccent } from './chunk-K2X63CR2.js';
22
26
  import { getGlobalStoreClient } from './chunk-TYI2XOSI.js';
23
27
  import { GetMyNodeInstallationsDocument, BrowseWorkflowTemplatesDocument, InstallWorkflowNodeDocument, SubmitWorkflowTemplateDocument, MyWorkflowTemplateSubmissionsDocument, WithdrawWorkflowTemplateSubmissionDocument, InstallPurchasedNodeDocument, BrowseWorkflowNodesDocument, UninstallWorkflowNodeDocument, CreateStoreOrderDocument, GetNodeInstallableVersionsDocument, OrganizationPrivateNodesDocument, InstallOrganizationPrivateNodeDocument, UninstallOrganizationPrivateNodeDocument } from './chunk-G77IGC3Y.js';
24
- import { WorkspaceRunsQuotaDocument, WorkflowGenerationTemplatesDocument, ReleaseWorkflowEditLeaseDocument, NodeSchemaIntrospectionDocument, AcquireWorkflowEditLeaseDocument, WorkflowEnvironmentsDocument, WorkflowPromotionRequestsDocument, DeployWorkflowVersionToDevDocument, RequestWorkflowPromotionDocument, ApproveWorkflowPromotionDocument, RejectWorkflowPromotionDocument, CancelWorkflowPromotionDocument, UpdateWorkflowEnvironmentPolicyDocument, WorkflowGitRepositoryDocument, WorkflowGitPushesDocument, WorkflowGitCommitsDocument, LinkWorkflowGitRepositoryDocument, UnlinkWorkflowGitRepositoryDocument, PushWorkflowToGitDocument, WorkflowGitDiffDocument, RestoreWorkflowFromGitDocument, WorkflowAuthoringDocument, WorkflowEditLeaseDocument, WorkflowVersioningDocument, WorkflowVersionDrainageDocument, ActivateWorkflowVersionCheckedDocument, WorkflowDefinitionDocument, NodeUsageStatusDocument, RemoveNodeFromWorkflowsDocument, SetWorkflowRolloutDocument, DeleteWorkflowRolloutDocument, TakeOverWorkflowEditLeaseDocument } from './chunk-VAWYR6P4.js';
25
28
  import { cn } from './chunk-JL7CASN5.js';
29
+ import { WorkspaceRunsQuotaDocument, WorkflowGenerationTemplatesDocument, ReleaseWorkflowEditLeaseDocument, NodeSchemaIntrospectionDocument, AcquireWorkflowEditLeaseDocument, WorkflowEnvironmentsDocument, WorkflowPromotionRequestsDocument, DeployWorkflowVersionToDevDocument, RequestWorkflowPromotionDocument, ApproveWorkflowPromotionDocument, RejectWorkflowPromotionDocument, CancelWorkflowPromotionDocument, UpdateWorkflowEnvironmentPolicyDocument, WorkflowGitRepositoryDocument, WorkflowGitPushesDocument, WorkflowGitCommitsDocument, LinkWorkflowGitRepositoryDocument, UnlinkWorkflowGitRepositoryDocument, PushWorkflowToGitDocument, WorkflowGitDiffDocument, RestoreWorkflowFromGitDocument, WorkflowAuthoringDocument, WorkflowEditLeaseDocument, WorkflowVersioningDocument, WorkflowVersionDrainageDocument, ActivateWorkflowVersionCheckedDocument, WorkflowDefinitionDocument, NodeUsageStatusDocument, RemoveNodeFromWorkflowsDocument, SetWorkflowRolloutDocument, DeleteWorkflowRolloutDocument, TakeOverWorkflowEditLeaseDocument } from './chunk-A6Q4FWB6.js';
26
30
  import { useTr } from './chunk-UULVIT25.js';
27
31
  import { waitForFluidGridsClient, getFluidGridsClient } from './chunk-PDODDDHY.js';
28
32
  import { throwIfResultError, describeOperationError, emitFluidGridsEvent } from './chunk-JKLZ6YZ3.js';
@@ -44,7 +48,6 @@ import { useShallow, shallow } from 'zustand/shallow';
44
48
  import { produce } from 'immer';
45
49
  import { Card as Card$1, Badge, CardContent as CardContent$1, Button as Button$1, Popover, PopoverTrigger, PopoverContent, AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle, AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, Toaster, Tabs, TabsList, TabsTrigger, TabsContent, CardHeader as CardHeader$1, CardTitle as CardTitle$1, CardDescription as CardDescription$1, ScrollArea, Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription, Label, Textarea, Select, SelectTrigger, SelectValue, SelectContent, SelectItem, AlertDialogAction, TooltipProvider, Switch, Input as Input$1, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem, Tooltip, TooltipTrigger, TooltipContent, Dialog as Dialog$1, DialogContent as DialogContent$1, DialogHeader as DialogHeader$1, DialogTitle as DialogTitle$1, DialogDescription as DialogDescription$1, DialogFooter, DropdownMenuLabel, DropdownMenuSeparator } from '@burdenoff/fe-libs/ui';
46
50
  import { isEmpty } from 'radash';
47
- import { gql as gql$1 } from '@apollo/client';
48
51
  import ReactMarkdown from 'react-markdown';
49
52
  import { animate, easeOut } from 'popmotion';
50
53
  import { createPortal } from 'react-dom';
@@ -296,21 +299,6 @@ function RunsUsageMeter({
296
299
  if (!quota) return null;
297
300
  return /* @__PURE__ */ jsx(RunsUsageMeterView, { quota, className, variant });
298
301
  }
299
- function useGlobalStoreClient() {
300
- const context = useContext(FluidGridsContext);
301
- if (context?.globalClient) {
302
- return context.globalClient;
303
- }
304
- const singletonClient = getGlobalStoreClient();
305
- if (singletonClient) {
306
- return singletonClient;
307
- }
308
- throw new Error(
309
- "useGlobalStoreClient: No global client available. Either wrap your component tree with <FluidGridsProvider globalClient={...}> or call setGlobalStoreClient(client) before rendering."
310
- );
311
- }
312
-
313
- // src/hooks/store/useInstalledNodes.ts
314
302
  function useInstalledNodes() {
315
303
  const client = useGlobalStoreClient();
316
304
  const context = useContext(FluidGridsContext);
@@ -2248,23 +2236,6 @@ function SidebarPanelWrapper({
2248
2236
  }
2249
2237
  );
2250
2238
  }
2251
- function SidebarPanelHeading({
2252
- children,
2253
- className,
2254
- ...props
2255
- }) {
2256
- return /* @__PURE__ */ jsx(
2257
- "div",
2258
- {
2259
- className: cn$1(
2260
- "flex items-center text-sm h-10 leading-none px-4 border-b border-t select-none shrink-0 border-card-foreground/10 bg-card/80 text-center text-card-foreground/60 gap-x-2 font-semibold",
2261
- className
2262
- ),
2263
- ...props,
2264
- children
2265
- }
2266
- );
2267
- }
2268
2239
  var HeaderWithIcon = ({ icon, title }) => {
2269
2240
  return /* @__PURE__ */ jsxs("div", { className: "flex items-center", children: [
2270
2241
  /* @__PURE__ */ jsx(Icon, { icon, className: `size-4` }),
@@ -2302,984 +2273,287 @@ function NodeListItem({
2302
2273
  }
2303
2274
  );
2304
2275
  }
2305
- function UnavailableNodePropertyPanel() {
2276
+ function IntroductionPropertyPanel() {
2277
+ const tr = useTr();
2306
2278
  return /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col items-center justify-center p-4 text-center", children: [
2307
- /* @__PURE__ */ jsx("div", { className: "size-12 flex items-center justify-center rounded-full bg-card", children: /* @__PURE__ */ jsx(
2279
+ /* @__PURE__ */ jsx("div", { className: "size-12 flex items-center justify-center rounded-full bg-primary", children: /* @__PURE__ */ jsx(
2308
2280
  Icon,
2309
2281
  {
2310
- icon: "mynaui:info-triangle",
2311
- className: "size-6 text-status-warning-text"
2282
+ icon: "mynaui:cog-one",
2283
+ className: "size-6 text-primary-foreground"
2312
2284
  }
2313
2285
  ) }),
2314
- /* @__PURE__ */ jsx("div", { className: "mt-4 text-balance font-medium", children: "Unavailable Properties" }),
2315
- /* @__PURE__ */ jsx("div", { className: "mt-1 text-xs text-card-foreground/40 font-medium leading-normal", children: "Either no properties are available for this node or the node is not selected." }),
2316
- /* @__PURE__ */ jsx("div", { className: "mt-8 w-full text-xs text-card-foreground/40 font-medium italic", children: "Select another node to view its properties." })
2286
+ /* @__PURE__ */ jsx("div", { className: "mt-4 text-balance font-medium", children: tr(
2287
+ "fluidgrids.builder.introductionPropertyPanel.title",
2288
+ "Node Properties"
2289
+ ) }),
2290
+ /* @__PURE__ */ jsx("div", { className: "mt-1 w-2.5/3 text-xs text-card/40 font-medium leading-normal", children: tr(
2291
+ "fluidgrids.builder.introductionPropertyPanel.description",
2292
+ "Here you can view and edit the properties of the selected node."
2293
+ ) }),
2294
+ /* @__PURE__ */ jsx("div", { className: "mt-8 w-full text-xs text-card/40 font-medium italic", children: tr(
2295
+ "fluidgrids.builder.introductionPropertyPanel.hint",
2296
+ "Select a node from the list on the top to view its properties."
2297
+ ) })
2317
2298
  ] });
2318
2299
  }
2319
- var CHANNEL_SUMMARY_FIELDS = gql$1`
2320
- fragment ChannelSummaryFields on Channel {
2321
- id
2322
- name
2323
- platform
2324
- channelType
2325
- status
2326
- connectionHealth
2327
- isConnected
2328
- description
2329
- adapterType
2330
- createdAt
2331
- }
2332
- `;
2333
- var CHANNEL_DETAIL_FIELDS = gql$1`
2334
- fragment ChannelDetailFields on Channel {
2335
- id
2336
- name
2337
- platform
2338
- channelType
2339
- status
2340
- connectionHealth
2341
- isConnected
2342
- description
2343
- adapterType
2344
- messageCount24h
2345
- config {
2346
- enableThreading
2347
- enableReactions
2348
- enablePresence
2349
- rateLimitPerMinute
2350
- }
2351
- createdAt
2352
- updatedAt
2353
- }
2354
- `;
2355
- var GET_CHANNELS = gql$1`
2356
- ${CHANNEL_SUMMARY_FIELDS}
2357
- query GetChannels(
2358
- $filter: ChannelFilterInput
2359
- $pagination: ChannelPaginationInput
2360
- ) {
2361
- getChannels(filter: $filter, pagination: $pagination) {
2362
- items {
2363
- ...ChannelSummaryFields
2364
- }
2365
- total
2366
- hasMore
2367
- }
2368
- }
2369
- `;
2370
- var GET_CHANNEL = gql$1`
2371
- ${CHANNEL_DETAIL_FIELDS}
2372
- query GetChannel($id: ID!) {
2373
- getChannel(id: $id) {
2374
- ...ChannelDetailFields
2375
- }
2376
- }
2377
- `;
2378
- var PLATFORM_TO_PROVIDER_KEY = {
2379
- SLACK: "slack",
2380
- TEAMS: "microsoft-teams",
2381
- DISCORD: "discord",
2382
- EMAIL: "email",
2383
- WHATSAPP: "whatsapp",
2384
- WEBCHAT: "webchat",
2385
- WEBHOOK: "webhook",
2386
- SMS: "sms",
2387
- PUSH: "push"
2388
- };
2389
- var PLATFORM_ICONS = {
2390
- SLACK: "mdi:slack",
2391
- TEAMS: "mdi:microsoft-teams",
2392
- DISCORD: "mdi:discord",
2393
- EMAIL: "mdi:email",
2394
- SMS: "mdi:message-text",
2395
- PUSH: "mdi:bell-ring",
2396
- WEBCHAT: "mdi:chat",
2397
- WEBHOOK: "mdi:webhook",
2398
- WHATSAPP: "mdi:whatsapp"
2399
- };
2400
- var STATUS_COLORS = {
2401
- ACTIVE: "text-[var(--color-status-success-text)]",
2402
- INACTIVE: "text-muted-foreground",
2403
- ERROR: "text-[var(--color-status-error-text)]",
2404
- ARCHIVED: "text-muted-foreground",
2405
- SUSPENDED: "text-[var(--color-status-warning-text)]"
2406
- };
2407
- var HEALTH_COLORS = {
2408
- HEALTHY: "text-[var(--color-status-success-text)]",
2409
- DEGRADED: "text-[var(--color-status-warning-text)]",
2410
- UNHEALTHY: "text-[var(--color-status-error-text)]",
2411
- UNKNOWN: "text-muted-foreground"
2412
- };
2413
- var HEALTH_ICONS = {
2414
- HEALTHY: "mdi:check-circle",
2415
- DEGRADED: "mdi:alert-circle",
2416
- UNHEALTHY: "mdi:close-circle",
2417
- UNKNOWN: "mdi:help-circle"
2418
- };
2419
- function useChannels(filter) {
2420
- const apolloClient = useGlobalStoreClient();
2421
- const [channels, setChannels] = useState([]);
2422
- const [total, setTotal] = useState(0);
2423
- const [hasMore, setHasMore] = useState(false);
2424
- const [loading, setLoading] = useState(true);
2425
- const [error, setError] = useState(null);
2426
- const filterKey = JSON.stringify(filter);
2427
- const fetchData = useCallback(async () => {
2428
- setLoading(true);
2429
- setError(null);
2430
- try {
2431
- const parsedFilter = filterKey ? JSON.parse(filterKey) : void 0;
2432
- const PAGE_SIZE = 100;
2433
- let offset = 0;
2434
- let allItems = [];
2435
- let totalCount = 0;
2436
- let more = true;
2437
- while (more) {
2438
- const result = await apolloClient.query({
2439
- query: GET_CHANNELS,
2440
- variables: {
2441
- filter: parsedFilter,
2442
- pagination: { limit: PAGE_SIZE, offset }
2443
- },
2444
- fetchPolicy: "network-only"
2445
- });
2446
- const page = result.data?.getChannels;
2447
- const pageItems = page?.items ?? [];
2448
- totalCount = page?.total ?? totalCount;
2449
- allItems = allItems.concat(pageItems);
2450
- more = (page?.hasMore ?? false) && pageItems.length === PAGE_SIZE;
2451
- offset += PAGE_SIZE;
2452
- }
2453
- setChannels(allItems);
2454
- setTotal(totalCount);
2455
- setHasMore(false);
2456
- } catch (err) {
2457
- setError(err);
2458
- } finally {
2459
- setLoading(false);
2460
- }
2461
- }, [apolloClient, filterKey]);
2462
- useEffect(() => {
2463
- fetchData();
2464
- }, [fetchData]);
2465
- return {
2466
- channels,
2467
- total,
2468
- hasMore,
2469
- loading,
2470
- error,
2471
- refetch: fetchData
2472
- };
2473
- }
2474
- function useChannel(channelId) {
2475
- const apolloClient = useGlobalStoreClient();
2476
- const [channel, setChannel] = useState(null);
2477
- const [loading, setLoading] = useState(true);
2478
- const [error, setError] = useState(null);
2479
- const fetchData = useCallback(
2480
- async (policy = "cache-first") => {
2481
- if (!channelId) return void 0;
2482
- try {
2483
- return await apolloClient.query({
2484
- query: GET_CHANNEL,
2485
- variables: { id: channelId },
2486
- fetchPolicy: policy
2487
- });
2488
- } catch (err) {
2489
- return err;
2490
- }
2491
- },
2492
- [apolloClient, channelId]
2493
- );
2494
- const applyResult = useCallback(
2495
- (result) => {
2496
- if (result instanceof Error) {
2497
- setError(result);
2498
- } else if (result) {
2499
- setChannel(result.data?.getChannel ?? null);
2500
- } else {
2501
- setChannel(null);
2502
- }
2503
- setLoading(false);
2504
- },
2505
- []
2506
- );
2507
- useEffect(() => {
2508
- let cancelled = false;
2509
- setLoading(true);
2510
- setError(null);
2511
- fetchData().then((result) => {
2512
- if (cancelled) return;
2513
- applyResult(result);
2514
- });
2515
- return () => {
2516
- cancelled = true;
2517
- };
2518
- }, [fetchData, applyResult]);
2519
- const refetch = useCallback(async () => {
2520
- setLoading(true);
2521
- setError(null);
2522
- const result = await fetchData("network-only");
2523
- applyResult(result);
2524
- }, [fetchData, applyResult]);
2525
- return {
2526
- channel,
2527
- loading,
2528
- error,
2529
- refetch
2530
- };
2300
+ function SidebarNodeEditor({
2301
+ nodeId,
2302
+ type
2303
+ }) {
2304
+ return /* @__PURE__ */ jsx(SidebarNodeEditorInner, { nodeId, type }, nodeId);
2531
2305
  }
2532
- function ChannelSelector({
2533
- selectedChannelId,
2534
- onSelect,
2535
- platformFilter
2306
+ function SidebarNodeEditorInner({
2307
+ nodeId,
2308
+ type
2536
2309
  }) {
2537
- const tr = useTr();
2538
- const [isOpen, setIsOpen] = useState(false);
2539
- const { channels, loading, error } = useChannels(
2540
- platformFilter ? { platform: platformFilter, channelType: "COMMUNICATION" } : { channelType: "COMMUNICATION" }
2310
+ const config = useNodeConfig({ nodeId, type }, { webhookEnabled: true });
2311
+ const { node, nodes } = config;
2312
+ const setSelectedNode = useFlowStore(
2313
+ (s) => s.actions.sidebar.panels.nodeProperties.setSelectedNode
2541
2314
  );
2542
- const selectedChannel = channels.find((c) => c.id === selectedChannelId);
2543
- return /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
2544
- /* @__PURE__ */ jsx("div", { className: "text-xs text-card-foreground/60 font-semibold", children: tr("fluidgrids.builder.channelSelector.fieldLabel", "Channel") }),
2545
- /* @__PURE__ */ jsxs(DropdownMenu, { open: isOpen, onOpenChange: setIsOpen, children: [
2546
- /* @__PURE__ */ jsx(DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
2547
- Button$1,
2548
- {
2549
- variant: "outline",
2550
- size: "sm",
2551
- className: "w-full justify-between",
2552
- children: [
2553
- selectedChannel ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 truncate", children: [
2554
- /* @__PURE__ */ jsx(
2555
- Icon,
2556
- {
2557
- icon: PLATFORM_ICONS[selectedChannel.platform] || "mdi:antenna",
2558
- className: "w-4 h-4 shrink-0"
2559
- }
2560
- ),
2561
- /* @__PURE__ */ jsx("span", { className: "truncate", children: selectedChannel.name }),
2562
- /* @__PURE__ */ jsx(
2563
- Icon,
2564
- {
2565
- icon: HEALTH_ICONS[selectedChannel.connectionHealth],
2566
- className: `w-3.5 h-3.5 shrink-0 ${HEALTH_COLORS[selectedChannel.connectionHealth]}`
2567
- }
2568
- )
2569
- ] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2 text-muted-foreground", children: [
2570
- /* @__PURE__ */ jsx(Icon, { icon: "mdi:antenna", className: "w-4 h-4" }),
2571
- tr(
2572
- "fluidgrids.builder.channelSelector.selectPlaceholder",
2573
- "Select channel"
2574
- )
2575
- ] }),
2576
- /* @__PURE__ */ jsx(
2577
- Icon,
2578
- {
2579
- icon: "mdi:chevron-down",
2580
- className: "w-4 h-4 text-muted-foreground shrink-0"
2581
- }
2582
- )
2583
- ]
2584
- }
2585
- ) }),
2586
- /* @__PURE__ */ jsx(
2587
- DropdownMenuContent,
2588
- {
2589
- align: "start",
2590
- className: "w-[260px] max-h-[350px] overflow-y-auto",
2591
- children: loading ? /* @__PURE__ */ jsxs("div", { className: "p-4 text-center text-sm text-muted-foreground", children: [
2592
- /* @__PURE__ */ jsx(
2593
- Icon,
2594
- {
2595
- icon: "mdi:loading",
2596
- className: "w-5 h-5 mx-auto mb-2 animate-spin"
2597
- }
2598
- ),
2599
- /* @__PURE__ */ jsx("p", { children: tr(
2600
- "fluidgrids.builder.channelSelector.loading",
2601
- "Loading channels..."
2602
- ) })
2603
- ] }) : error ? /* @__PURE__ */ jsxs("div", { className: "p-4 text-center text-sm text-muted-foreground", children: [
2604
- /* @__PURE__ */ jsx(
2605
- Icon,
2606
- {
2607
- icon: "mdi:alert-circle",
2608
- className: "w-5 h-5 mx-auto mb-2 text-[var(--color-status-error-text)]"
2609
- }
2610
- ),
2611
- /* @__PURE__ */ jsx("p", { children: tr(
2612
- "fluidgrids.builder.channelSelector.loadError",
2613
- "Failed to load channels"
2614
- ) }),
2615
- /* @__PURE__ */ jsx("p", { className: "text-xs mt-1", children: error.message })
2616
- ] }) : channels.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "p-4 text-center text-sm text-muted-foreground", children: [
2617
- /* @__PURE__ */ jsx(
2618
- Icon,
2619
- {
2620
- icon: "mdi:antenna-off",
2621
- className: "w-6 h-6 mx-auto mb-2 opacity-50"
2622
- }
2623
- ),
2624
- /* @__PURE__ */ jsx("p", { children: tr(
2625
- "fluidgrids.builder.channelSelector.emptyTitle",
2626
- "No channels found"
2627
- ) }),
2628
- /* @__PURE__ */ jsx("p", { className: "text-xs mt-1", children: tr(
2629
- "fluidgrids.builder.channelSelector.emptyHint",
2630
- "Create one in the Channels settings"
2631
- ) })
2632
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2633
- /* @__PURE__ */ jsx(DropdownMenuLabel, { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: tr(
2634
- "fluidgrids.builder.channelSelector.availableChannelsHeading",
2635
- "Available Channels"
2636
- ) }),
2637
- /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
2638
- channels.map((channel) => {
2639
- const isSelected = channel.id === selectedChannelId;
2640
- return /* @__PURE__ */ jsxs(
2641
- DropdownMenuItem,
2642
- {
2643
- onClick: () => {
2644
- onSelect(channel);
2645
- setIsOpen(false);
2646
- },
2647
- className: `flex items-center justify-between cursor-pointer ${isSelected ? "bg-primary/10" : ""}`,
2648
- children: [
2649
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
2650
- /* @__PURE__ */ jsx(
2651
- Icon,
2652
- {
2653
- icon: PLATFORM_ICONS[channel.platform] || "mdi:antenna",
2654
- className: "w-4 h-4 shrink-0"
2655
- }
2656
- ),
2657
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0", children: [
2658
- /* @__PURE__ */ jsx("span", { className: "font-medium truncate text-sm", children: channel.name }),
2659
- /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground flex items-center gap-1", children: [
2660
- /* @__PURE__ */ jsx("span", { className: STATUS_COLORS[channel.status], children: channel.status.toLowerCase() }),
2661
- /* @__PURE__ */ jsx("span", { children: "\xB7" }),
2662
- /* @__PURE__ */ jsx("span", { children: channel.platform.toLowerCase() })
2663
- ] })
2664
- ] })
2665
- ] }),
2666
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 shrink-0", children: [
2667
- /* @__PURE__ */ jsx(
2668
- Icon,
2669
- {
2670
- icon: HEALTH_ICONS[channel.connectionHealth],
2671
- className: `w-3.5 h-3.5 ${HEALTH_COLORS[channel.connectionHealth]}`
2672
- }
2673
- ),
2674
- isSelected && /* @__PURE__ */ jsx(
2675
- Icon,
2676
- {
2677
- icon: "mdi:check",
2678
- className: "w-4 h-4 text-primary"
2679
- }
2680
- )
2681
- ] })
2682
- ]
2683
- },
2684
- channel.id
2685
- );
2686
- })
2687
- ] })
2688
- }
2689
- )
2690
- ] })
2691
- ] });
2692
- }
2693
- function ChannelDetails({ channelId }) {
2694
- const { channel, loading, error } = useChannel(channelId);
2695
- if (loading) {
2696
- return /* @__PURE__ */ jsx("div", { className: "p-3 rounded-md border border-card-foreground/10 bg-card/30", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [
2697
- /* @__PURE__ */ jsx(Icon, { icon: "mdi:loading", className: "w-4 h-4 animate-spin" }),
2698
- "Loading channel details..."
2699
- ] }) });
2700
- }
2701
- if (error || !channel) {
2702
- return /* @__PURE__ */ jsx("div", { className: "p-3 rounded-md border border-[var(--color-status-error-border)] bg-[var(--color-status-error-bg-subtle)]", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-xs text-[var(--color-status-error-text)]", children: [
2703
- /* @__PURE__ */ jsx(Icon, { icon: "mdi:alert-circle", className: "w-4 h-4" }),
2704
- error ? error.message : "Channel not found"
2705
- ] }) });
2706
- }
2707
- return /* @__PURE__ */ jsxs("div", { className: "p-3 rounded-md border border-card-foreground/10 bg-card/30 space-y-2.5", children: [
2708
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
2709
- /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center w-8 h-8 rounded-md bg-primary/10", children: /* @__PURE__ */ jsx(
2710
- Icon,
2711
- {
2712
- icon: PLATFORM_ICONS[channel.platform] || "mdi:antenna",
2713
- className: "w-5 h-5 text-primary"
2714
- }
2715
- ) }),
2716
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0", children: [
2717
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium truncate", children: channel.name }),
2718
- /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
2719
- channel.platform.toLowerCase(),
2720
- " \xB7",
2721
- " ",
2722
- channel.channelType.toLowerCase()
2723
- ] })
2724
- ] })
2725
- ] }),
2726
- /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-2", children: [
2727
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
2728
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground uppercase tracking-wide", children: "Status" }),
2315
+ const { schedulePolicies } = usePhaseCFlags();
2316
+ const isSchedule = schedulePolicies && node?.type === SCHEDULE_NODE_TYPE;
2317
+ const [tab, setTab] = useState("parameters");
2318
+ const [showInput, setShowInput] = useState(false);
2319
+ useEffect(() => {
2320
+ if (!nodes.some((n) => n.id === nodeId)) setSelectedNode(null);
2321
+ }, [nodes, nodeId, setSelectedNode]);
2322
+ if (!node) return null;
2323
+ const activeTab = tab === "schedule" && !isSchedule ? "parameters" : tab;
2324
+ return /* @__PURE__ */ jsxs(
2325
+ "div",
2326
+ {
2327
+ className: "flex min-h-0 flex-1 flex-col",
2328
+ "data-testid": "sidebar-node-editor",
2329
+ children: [
2729
2330
  /* @__PURE__ */ jsx(
2730
- "span",
2331
+ EditorHeader,
2731
2332
  {
2732
- className: `text-xs font-medium ${STATUS_COLORS[channel.status]}`,
2733
- children: channel.status.toLowerCase()
2333
+ config,
2334
+ nodeId,
2335
+ type,
2336
+ showInput,
2337
+ onToggleInput: () => setShowInput((v) => !v)
2734
2338
  }
2735
- )
2736
- ] }),
2737
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
2738
- /* @__PURE__ */ jsx("span", { className: "text-[10px] text-muted-foreground uppercase tracking-wide", children: "Health" }),
2739
- /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1", children: [
2740
- /* @__PURE__ */ jsx(
2741
- Icon,
2339
+ ),
2340
+ /* @__PURE__ */ jsx(
2341
+ EditorTabs,
2342
+ {
2343
+ active: activeTab,
2344
+ onChange: setTab,
2345
+ isSchedule
2346
+ }
2347
+ ),
2348
+ /* @__PURE__ */ jsxs("div", { className: "min-h-0 flex-1 overflow-auto", children: [
2349
+ showInput && /* @__PURE__ */ jsx(
2350
+ "div",
2742
2351
  {
2743
- icon: HEALTH_ICONS[channel.connectionHealth],
2744
- className: `w-3.5 h-3.5 ${HEALTH_COLORS[channel.connectionHealth]}`
2352
+ className: "m-3 flex max-h-64 flex-col overflow-hidden rounded-lg border border-border bg-card",
2353
+ "data-testid": "sp-input-fields",
2354
+ children: /* @__PURE__ */ jsx(NodeInputFields, { config, testIdPrefix: "sp" })
2745
2355
  }
2746
2356
  ),
2747
- /* @__PURE__ */ jsx(
2748
- "span",
2749
- {
2750
- className: `text-xs font-medium ${HEALTH_COLORS[channel.connectionHealth]}`,
2751
- children: channel.connectionHealth.toLowerCase()
2752
- }
2753
- )
2754
- ] })
2755
- ] })
2756
- ] }),
2757
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 pt-1 border-t border-card-foreground/5", children: [
2758
- channel.isConnected ? /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs text-[var(--color-status-success-text)]", children: [
2759
- /* @__PURE__ */ jsx(Icon, { icon: "mdi:link", className: "w-3.5 h-3.5" }),
2760
- "Connected"
2761
- ] }) : /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
2762
- /* @__PURE__ */ jsx(Icon, { icon: "mdi:link-off", className: "w-3.5 h-3.5" }),
2763
- "Not connected"
2764
- ] }),
2765
- channel.messageCount24h !== void 0 && /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
2766
- /* @__PURE__ */ jsx(Icon, { icon: "mdi:message-text", className: "w-3.5 h-3.5" }),
2767
- channel.messageCount24h,
2768
- " msgs/24h"
2769
- ] })
2770
- ] }),
2771
- channel.description && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground pt-1 border-t border-card-foreground/5", children: channel.description })
2772
- ] });
2357
+ /* @__PURE__ */ jsx(EditorBody, { tab: activeTab, config, nodeId })
2358
+ ] }),
2359
+ /* @__PURE__ */ jsx(EditorRunActions, { nodeId })
2360
+ ]
2361
+ }
2362
+ );
2773
2363
  }
2774
- function ChannelAuth({
2775
- platform,
2776
- integrationId,
2777
- onIntegrationIdChange,
2778
- currentPath,
2779
- nodeId
2364
+ function EditorHeader({
2365
+ config,
2366
+ nodeId,
2367
+ type,
2368
+ showInput,
2369
+ onToggleInput
2780
2370
  }) {
2781
2371
  const tr = useTr();
2782
- const [localValue, setLocalValue] = useState(integrationId || "");
2783
- useEffect(() => {
2784
- setLocalValue(integrationId || "");
2785
- }, [integrationId]);
2786
- const providerKey = PLATFORM_TO_PROVIDER_KEY[platform] || platform.toLowerCase();
2787
- const platformIcon = PLATFORM_ICONS[platform] || "mdi:key";
2788
- const platformLabel = platform.charAt(0) + platform.slice(1).toLowerCase();
2789
- const handleAuthClick = () => {
2790
- const returnTo = currentPath || window.location.pathname;
2791
- const params = new URLSearchParams({
2792
- providerKey,
2793
- returnTo,
2794
- channelNodeId: nodeId
2795
- });
2796
- const integrationsUrl = `/integrations/connections/add?${params.toString()}`;
2797
- window.open(integrationsUrl, "_blank", "noopener,noreferrer");
2798
- };
2799
- const handleInputChange = (e) => {
2800
- const value = e.target.value;
2801
- setLocalValue(value);
2802
- onIntegrationIdChange(value);
2803
- };
2804
- const handlePaste = (e) => {
2805
- setTimeout(() => {
2806
- const value = e.target.value;
2807
- setLocalValue(value);
2808
- onIntegrationIdChange(value);
2809
- }, 0);
2810
- };
2811
- return /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
2812
- /* @__PURE__ */ jsx("div", { className: "text-xs text-card-foreground/60 font-semibold", children: tr("fluidgrids.builder.channelAuth.sectionHeading", "Authentication") }),
2813
- /* @__PURE__ */ jsxs(
2814
- Button$1,
2815
- {
2816
- variant: "outline",
2817
- size: "sm",
2818
- className: "w-full justify-start gap-2",
2819
- onClick: handleAuthClick,
2820
- children: [
2821
- /* @__PURE__ */ jsx(Icon, { icon: platformIcon, className: "w-4 h-4" }),
2822
- /* @__PURE__ */ jsxs("span", { children: [
2823
- tr(
2824
- "fluidgrids.builder.channelAuth.authenticateWithPrefix",
2825
- "Authenticate with"
2826
- ),
2827
- " ",
2828
- platformLabel
2829
- ] }),
2830
- /* @__PURE__ */ jsx(
2831
- Icon,
2832
- {
2833
- icon: "mdi:open-in-new",
2834
- className: "w-3.5 h-3.5 ml-auto text-muted-foreground"
2835
- }
2836
- )
2837
- ]
2838
- }
2839
- ),
2840
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
2841
- /* @__PURE__ */ jsx("label", { className: "text-[11px] text-muted-foreground", children: tr(
2842
- "fluidgrids.builder.channelAuth.integrationIdLabel",
2843
- "Integration Connection ID"
2844
- ) }),
2845
- /* @__PURE__ */ jsxs("div", { className: "relative", children: [
2372
+ const openNdv = useFlowStore((s) => s.actions.ndv.open);
2373
+ const meta = getNodeDetail(config.node?.type);
2374
+ const accent = nodeAccent(config.node?.type || meta.title);
2375
+ const subtitle = nodeSubtitle(config.node);
2376
+ return /* @__PURE__ */ jsxs(
2377
+ "div",
2378
+ {
2379
+ className: "flex shrink-0 items-center gap-2.5 border-b border-border px-3 py-2.5",
2380
+ style: { borderTop: `3px solid ${accent}` },
2381
+ children: [
2846
2382
  /* @__PURE__ */ jsx(
2847
- Input$1,
2383
+ "div",
2848
2384
  {
2849
- type: "text",
2850
- placeholder: tr(
2851
- "fluidgrids.builder.channelAuth.integrationIdPlaceholder",
2852
- "Paste integration ID here..."
2853
- ),
2854
- value: localValue,
2855
- onChange: handleInputChange,
2856
- onPaste: handlePaste,
2857
- className: "text-xs pr-8"
2385
+ className: "flex size-7 shrink-0 items-center justify-center rounded-lg",
2386
+ style: {
2387
+ backgroundColor: `color-mix(in srgb, ${accent} 13%, transparent)`,
2388
+ color: accent,
2389
+ border: `1px solid color-mix(in srgb, ${accent} 26%, transparent)`
2390
+ },
2391
+ children: /* @__PURE__ */ jsx(NodeTypeIcon, { icon: meta.icon, className: "size-4" })
2858
2392
  }
2859
2393
  ),
2860
- localValue && /* @__PURE__ */ jsx("div", { className: "absolute right-2 top-1/2 -translate-y-1/2", children: /* @__PURE__ */ jsx(
2861
- Icon,
2862
- {
2863
- icon: "mdi:check-circle",
2864
- className: "w-4 h-4 text-[var(--color-status-success-text)]"
2865
- }
2866
- ) })
2867
- ] }),
2868
- /* @__PURE__ */ jsx("p", { className: "text-[10px] text-muted-foreground", children: tr(
2869
- "fluidgrids.builder.channelAuth.integrationIdHelpText",
2870
- "Complete the OAuth flow above, then paste the connection ID here."
2871
- ) })
2872
- ] })
2873
- ] });
2874
- }
2875
- var LINK_INTEGRATION_MUTATION = gql$1`
2876
- mutation LinkIntegrationConnection(
2877
- $integrationConnectionId: ID!
2878
- $channelId: ID!
2879
- ) {
2880
- linkIntegrationConnection(
2881
- integrationConnectionId: $integrationConnectionId
2882
- channelId: $channelId
2883
- ) {
2884
- id
2885
- }
2886
- }
2887
- `;
2888
- function ChannelNodePropertyPanel({
2889
- id,
2890
- type,
2891
- data,
2892
- updateData
2893
- }) {
2894
- const [edges] = useFlowStore(useShallow((s) => [s.workflow.edges]));
2895
- const autoIsTrigger = !edges.some((e) => e.target === id);
2896
- const explicitRole = data?.args?.state?.role;
2897
- const fallbackIsTrigger = explicitRole !== void 0 ? explicitRole === "trigger" : autoIsTrigger;
2898
- const isTrigger = resolveOperationName(
2899
- data?.operation_name,
2900
- fallbackIsTrigger ? "onChannelMessageReceived" : "sendChannelMessage"
2901
- ) === "onChannelMessageReceived";
2902
- const [connectLoading, setConnectLoading] = useState(false);
2903
- const [connectStatus, setConnectStatus] = useState("idle");
2904
- const [connectError, setConnectError] = useState(null);
2905
- const globalClient = useGlobalStoreClient();
2906
- useEffect(() => {
2907
- if (explicitRole !== void 0) return;
2908
- const opName = resolveOperationName(
2909
- data?.operation_name,
2910
- autoIsTrigger ? "onChannelMessageReceived" : "sendChannelMessage"
2911
- );
2912
- if (data?.operation_name !== opName) {
2913
- updateData({ operation_name: opName });
2914
- }
2915
- }, [autoIsTrigger, id, explicitRole, data?.operation_name, updateData]);
2916
- const channelId = data?.args?.state?.channelId;
2917
- const integrationId = data?.args?.state?.integrationId;
2918
- const selectedPlatform = data?.args?.state?.platform;
2919
- const operationsArray = useMemo(() => {
2920
- const nodeDataOps = data?.nodeData?.operations;
2921
- if (nodeDataOps) {
2922
- const ops = Array.isArray(nodeDataOps) ? nodeDataOps : nodeDataOps.operations;
2923
- if (ops && ops.length > 0) return ops;
2924
- }
2925
- const nodeConfig = NODE_CONFIGS.find((c) => c.type === type);
2926
- if (nodeConfig?.operations) {
2927
- return nodeConfig.operations;
2928
- }
2929
- return [];
2930
- }, [data?.nodeData?.operations, type]);
2931
- const currentOperation = operationsArray.find(
2932
- (op) => op.name === data?.operation_name
2933
- );
2934
- const connectionAdapters = currentOperation?.connectionAdapters || currentOperation?.credentialAdapters || data?.nodeData?.connectionAdapters || data?.nodeData?.credentialAdapters || [];
2935
- const selectedConnections = useMemo(() => {
2936
- if (data?.args?.connections && data.args.connections.length > 0) {
2937
- return data.args.connections.map((conn) => ({
2938
- connectionId: conn.connectionId,
2939
- adapter: conn.adapter
2940
- }));
2941
- }
2942
- if (data?.args?.credentials && data.args.credentials.length > 0) {
2943
- return data.args.credentials.map((cred) => ({
2944
- connectionId: cred.id,
2945
- adapter: cred.adapter
2946
- }));
2947
- }
2948
- return [];
2949
- }, [data?.args?.connections, data?.args?.credentials]);
2950
- const handleRoleChange = useCallback(
2951
- (role) => {
2952
- const opName = role === "trigger" ? "onChannelMessageReceived" : "sendChannelMessage";
2953
- const currentState = data?.args?.state ?? {};
2954
- updateData({
2955
- operation_name: opName,
2956
- args: {
2957
- ...data?.args ?? {},
2958
- state: { ...currentState, role }
2959
- }
2960
- });
2961
- },
2962
- [data, updateData]
2963
- );
2964
- const updateState = useCallback(
2965
- (updates) => {
2966
- const currentState = data?.args?.state ?? {};
2967
- updateData({
2968
- args: {
2969
- ...data?.args ?? {},
2970
- state: { ...currentState, ...updates }
2971
- }
2972
- });
2973
- },
2974
- [data, updateData]
2975
- );
2976
- const handleChannelSelect = useCallback(
2977
- (channel) => {
2978
- updateState({
2979
- channelId: channel.id,
2980
- platform: channel.platform,
2981
- channelName: channel.name
2982
- });
2983
- },
2984
- [updateState]
2985
- );
2986
- const handleIntegrationIdChange = useCallback(
2987
- (newIntegrationId) => {
2988
- updateState({ integrationId: newIntegrationId });
2989
- },
2990
- [updateState]
2991
- );
2992
- const handleConnectionsChange = useCallback(
2993
- (connections) => {
2994
- const currentArgs = data?.args ?? {};
2995
- const { credentials: _legacy, ...restArgs } = currentArgs;
2996
- updateData({
2997
- args: {
2998
- ...restArgs,
2999
- connections: connections.map((conn) => ({
3000
- connectionId: conn.connectionId,
3001
- adapter: conn.adapter
3002
- }))
3003
- }
3004
- });
3005
- },
3006
- [data, updateData]
3007
- );
3008
- const handleConnect = useCallback(async () => {
3009
- if (!channelId || !integrationId) return;
3010
- setConnectLoading(true);
3011
- setConnectStatus("idle");
3012
- setConnectError(null);
3013
- try {
3014
- throwIfResultError(
3015
- await globalClient.mutate({
3016
- mutation: LINK_INTEGRATION_MUTATION,
3017
- variables: { integrationConnectionId: integrationId, channelId },
3018
- refetchQueries: [
3019
- { query: GET_CHANNEL, variables: { id: channelId } }
3020
- ],
3021
- awaitRefetchQueries: true
3022
- })
3023
- );
3024
- setConnectStatus("success");
3025
- updateState({ integrationId });
3026
- } catch (err) {
3027
- setConnectStatus("error");
3028
- setConnectError(err instanceof Error ? err.message : "Connection failed");
3029
- } finally {
3030
- setConnectLoading(false);
3031
- }
3032
- }, [channelId, integrationId, globalClient, updateState]);
3033
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 p-4", children: [
3034
- /* @__PURE__ */ jsx("div", { className: "text-xs text-card-foreground/20 self-end", children: id }),
3035
- /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
3036
- /* @__PURE__ */ jsx("div", { className: "text-xs text-card-foreground/60 font-semibold", children: "Operation" }),
3037
- /* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
3038
- /* @__PURE__ */ jsxs(
2394
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
2395
+ /* @__PURE__ */ jsx("p", { className: "truncate text-sm font-semibold leading-tight text-foreground", children: nodeTitle(config.node) }),
2396
+ subtitle && /* @__PURE__ */ jsx("p", { className: "truncate font-mono text-[11px] leading-tight text-muted-foreground", children: subtitle })
2397
+ ] }),
2398
+ /* @__PURE__ */ jsx(
3039
2399
  "button",
3040
2400
  {
3041
2401
  type: "button",
3042
- onClick: () => handleRoleChange("trigger"),
3043
- className: [
3044
- "flex-1 flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs transition-colors",
3045
- isTrigger ? "border-primary/60 bg-primary/10 text-primary font-semibold" : "border-card-foreground/10 text-card-foreground/40 hover:border-card-foreground/30 hover:text-card-foreground/70"
3046
- ].join(" "),
3047
- children: [
3048
- /* @__PURE__ */ jsx(Icon, { icon: "mdi:lightning-bolt", className: "w-3.5 h-3.5 shrink-0" }),
3049
- "Receive Messages"
3050
- ]
2402
+ title: showInput ? tr(
2403
+ "fluidgrids.builder.quickConfigPanel.hideInputDataTooltip",
2404
+ "Hide input data"
2405
+ ) : tr(
2406
+ "fluidgrids.builder.quickConfigPanel.mapInputDataTooltip",
2407
+ "Map data from input"
2408
+ ),
2409
+ "aria-label": tr(
2410
+ "fluidgrids.builder.quickConfigPanel.toggleMapperAriaLabel",
2411
+ "Toggle input mapper"
2412
+ ),
2413
+ "aria-pressed": showInput,
2414
+ onClick: onToggleInput,
2415
+ className: cn$1(
2416
+ "rounded-md p-1.5 transition-colors hover:bg-muted hover:text-foreground",
2417
+ showInput ? "text-primary" : "text-muted-foreground"
2418
+ ),
2419
+ "data-testid": "sp-toggle-mapper",
2420
+ children: /* @__PURE__ */ jsx(Icon, { icon: "mdi:tray-arrow-down", className: "size-4" })
3051
2421
  }
3052
2422
  ),
3053
- /* @__PURE__ */ jsxs(
2423
+ /* @__PURE__ */ jsx(
3054
2424
  "button",
3055
2425
  {
3056
2426
  type: "button",
3057
- onClick: () => handleRoleChange("action"),
3058
- className: [
3059
- "flex-1 flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs transition-colors",
3060
- !isTrigger ? "border-primary/60 bg-primary/10 text-primary font-semibold" : "border-card-foreground/10 text-card-foreground/40 hover:border-card-foreground/30 hover:text-card-foreground/70"
3061
- ].join(" "),
3062
- children: [
3063
- /* @__PURE__ */ jsx(Icon, { icon: "mdi:send", className: "w-3.5 h-3.5 shrink-0" }),
3064
- "Send Message"
3065
- ]
2427
+ title: tr(
2428
+ "fluidgrids.builder.quickConfigPanel.openFullEditorTooltip",
2429
+ "Open full editor"
2430
+ ),
2431
+ "aria-label": tr(
2432
+ "fluidgrids.builder.quickConfigPanel.openFullEditorAriaLabel",
2433
+ "Open full editor"
2434
+ ),
2435
+ onClick: () => openNdv({ nodeId, type }),
2436
+ className: "rounded-md p-1.5 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground",
2437
+ "data-testid": "sp-expand",
2438
+ children: /* @__PURE__ */ jsx(Icon, { icon: "mdi:arrow-expand", className: "size-4" })
3066
2439
  }
3067
2440
  )
3068
- ] }),
3069
- explicitRole === void 0 && !data?.operation_name && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-card-foreground/30", children: "Auto-detected from graph position. Click to override." })
3070
- ] }),
3071
- /* @__PURE__ */ jsx("div", { className: "h-px bg-card-foreground/10" }),
2441
+ ]
2442
+ }
2443
+ );
2444
+ }
2445
+ function EditorTabs({
2446
+ active,
2447
+ onChange,
2448
+ isSchedule
2449
+ }) {
2450
+ const tr = useTr();
2451
+ return /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-4 border-b border-border px-3", children: [
3072
2452
  /* @__PURE__ */ jsx(
3073
- ChannelSelector,
2453
+ TabButton,
3074
2454
  {
3075
- selectedChannelId: channelId,
3076
- onSelect: handleChannelSelect
2455
+ active: active === "parameters",
2456
+ onClick: () => onChange("parameters"),
2457
+ testId: "sp-tab-parameters",
2458
+ children: tr("fluidgrids.builder.nodeDetailView.tabParameters", "Parameters")
3077
2459
  }
3078
2460
  ),
3079
- channelId && /* @__PURE__ */ jsx(ChannelDetails, { channelId }),
3080
- channelId && /* @__PURE__ */ jsx("div", { className: "h-px bg-card-foreground/10" }),
3081
- channelId && selectedPlatform && /* @__PURE__ */ jsx(
3082
- ChannelAuth,
2461
+ isSchedule && /* @__PURE__ */ jsx(
2462
+ TabButton,
3083
2463
  {
3084
- platform: selectedPlatform,
3085
- integrationId,
3086
- onIntegrationIdChange: handleIntegrationIdChange,
3087
- nodeId: id
2464
+ active: active === "schedule",
2465
+ onClick: () => onChange("schedule"),
2466
+ testId: "sp-tab-schedule",
2467
+ children: tr("fluidgrids.builder.nodeDetailView.tabSchedule", "Schedule")
3088
2468
  }
3089
2469
  ),
3090
- channelId && /* @__PURE__ */ jsxs(Fragment, { children: [
3091
- /* @__PURE__ */ jsx("div", { className: "h-px bg-card-foreground/10" }),
3092
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
3093
- /* @__PURE__ */ jsxs(
3094
- Button$1,
3095
- {
3096
- variant: "default",
3097
- size: "sm",
3098
- className: "w-full gap-2",
3099
- onClick: handleConnect,
3100
- disabled: connectLoading || !integrationId,
3101
- title: !integrationId ? "Paste an Integration Connection ID first" : void 0,
3102
- children: [
3103
- connectLoading ? /* @__PURE__ */ jsx(Icon, { icon: "mdi:loading", className: "w-4 h-4 animate-spin" }) : connectStatus === "success" ? /* @__PURE__ */ jsx(Icon, { icon: "mdi:check-circle", className: "w-4 h-4" }) : /* @__PURE__ */ jsx(Icon, { icon: "mdi:link-variant", className: "w-4 h-4" }),
3104
- /* @__PURE__ */ jsx("span", { children: connectLoading ? "Connecting\u2026" : connectStatus === "success" ? "Connected!" : "Connect" })
3105
- ]
3106
- }
3107
- ),
3108
- connectStatus === "error" && connectError && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-destructive", children: connectError }),
3109
- connectStatus === "success" && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-[var(--color-status-success-text)]", children: "Channel linked \u2014 welcome message sent." })
3110
- ] })
3111
- ] }),
3112
- !isTrigger && /* @__PURE__ */ jsxs(Fragment, { children: [
3113
- /* @__PURE__ */ jsx("div", { className: "h-px bg-card-foreground/10" }),
3114
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
3115
- /* @__PURE__ */ jsx("div", { className: "text-xs text-card-foreground/60 font-semibold", children: "Message Text" }),
3116
- /* @__PURE__ */ jsx(
3117
- "textarea",
3118
- {
3119
- className: "w-full text-xs px-3 py-2 rounded-md border border-card-foreground/10 bg-transparent text-card-foreground/70 placeholder:text-card-foreground/30 resize-none focus:outline-none focus:border-primary/50",
3120
- rows: 3,
3121
- placeholder: "e.g. ${prev.response}",
3122
- value: data?.args?.state?.messageText ?? "",
3123
- onChange: (e) => updateState({ messageText: e.target.value })
3124
- }
3125
- )
3126
- ] })
3127
- ] }),
3128
- connectionAdapters.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
3129
- /* @__PURE__ */ jsx("div", { className: "h-px bg-card-foreground/10" }),
3130
- /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
3131
- /* @__PURE__ */ jsx("div", { className: "text-xs text-card-foreground/60 font-semibold", children: "Connections" }),
3132
- /* @__PURE__ */ jsx(
3133
- ConnectionSelector,
3134
- {
3135
- adapters: connectionAdapters,
3136
- selectedConnections,
3137
- onChange: handleConnectionsChange,
3138
- compact: true
3139
- }
3140
- )
3141
- ] })
3142
- ] })
2470
+ /* @__PURE__ */ jsx(
2471
+ TabButton,
2472
+ {
2473
+ active: active === "settings",
2474
+ onClick: () => onChange("settings"),
2475
+ testId: "sp-tab-settings",
2476
+ children: tr("fluidgrids.builder.nodeDetailView.tabSettings", "Settings")
2477
+ }
2478
+ )
3143
2479
  ] });
3144
2480
  }
3145
- function ConversationNodePropertyPanel({
3146
- id,
3147
- data,
3148
- updateData
2481
+ function EditorBody({
2482
+ tab,
2483
+ config,
2484
+ nodeId
3149
2485
  }) {
3150
- useEffect(() => {
3151
- const operationName = resolveOperationName(
3152
- data?.operation_name,
3153
- "storeAndForward"
3154
- );
3155
- if (data?.operation_name !== operationName) {
3156
- updateData({ operation_name: operationName });
3157
- }
3158
- }, [data?.operation_name, id, updateData]);
3159
- return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4 p-4", children: [
3160
- /* @__PURE__ */ jsx("div", { className: "text-xs text-card-foreground/20 self-end", children: id }),
3161
- /* @__PURE__ */ jsx("div", { className: "text-xs text-card-foreground/60 font-semibold", children: "Store & Forward" }),
3162
- /* @__PURE__ */ jsx("div", { className: "h-px bg-card-foreground/10" }),
3163
- /* @__PURE__ */ jsx("p", { className: "text-xs text-card-foreground/50 leading-relaxed", children: "Stores incoming messages and passes the stored record to the next node. All input comes automatically from the previous node \u2014 no configuration required." })
3164
- ] });
3165
- }
3166
- var CUSTOM_DYNAMIC_PANELS = {
3167
- "integration/channel": {
3168
- component: ChannelNodePropertyPanel,
3169
- operations: ["onChannelMessageReceived", "sendChannelMessage"]
3170
- },
3171
- channel_node: {
3172
- component: ChannelNodePropertyPanel,
3173
- operations: ["onChannelMessageReceived", "sendChannelMessage"]
3174
- },
3175
- "store/conversation": {
3176
- component: ConversationNodePropertyPanel,
3177
- operations: ["storeAndForward"]
2486
+ if (tab === "schedule") {
2487
+ return /* @__PURE__ */ jsx(EditorSchedule, { config, nodeId });
3178
2488
  }
3179
- };
3180
- function getCustomPanel(type, operationName) {
3181
- const panel = CUSTOM_DYNAMIC_PANELS[type] ?? Object.entries(CUSTOM_DYNAMIC_PANELS).find(
3182
- ([pattern]) => type.includes(pattern)
3183
- )?.[1];
3184
- return panel && canRenderOperationPanel(operationName, panel.operations) ? panel.component : null;
3185
- }
3186
- function NodePropertyPanel2({ id, type, data }) {
3187
- const [nodesLoaded, setNodesLoaded] = useState(isNodeConfigsInitialized());
3188
- useEffect(() => {
3189
- if (!nodesLoaded) {
3190
- ensureNodeConfigsLoaded().then(() => {
3191
- setNodesLoaded(true);
3192
- });
3193
- }
3194
- }, [nodesLoaded]);
3195
- const nodeConfig = NODES.find((n) => n.type === type);
3196
- const PanelComponent = nodeConfig?.propertyPanel;
3197
- const { setNodes } = useReactFlow();
3198
- const zustandSetNodes = useFlowStore((s) => s.actions.nodes.setNodes);
3199
- const nodeData = produce(data, () => {
3200
- });
3201
- const updateData = useCallback(
3202
- (newData) => {
3203
- setNodes((nds) => {
3204
- const updatedNodes = produce(nds, (draft) => {
3205
- const node = draft.find((n) => n.id === id);
3206
- if (node) {
3207
- node.data = {
3208
- ...node.data,
3209
- ...synchronizeOperationUpdate(
3210
- node.data,
3211
- newData,
3212
- NODE_CONFIGS.find((config) => config.type === type)?.operations
3213
- )
3214
- };
3215
- }
3216
- });
3217
- zustandSetNodes(updatedNodes);
3218
- return updatedNodes;
3219
- });
3220
- },
3221
- [id, type, setNodes, zustandSetNodes]
3222
- );
3223
- const CustomPanel = getCustomPanel(type, nodeData?.operation_name);
3224
- if (CustomPanel && nodeData) {
3225
- return /* @__PURE__ */ jsx(
3226
- CustomPanel,
3227
- {
3228
- id,
3229
- type,
3230
- data: nodeData,
3231
- updateData
3232
- }
3233
- );
2489
+ if (tab === "settings") {
2490
+ return /* @__PURE__ */ jsx("div", { className: "p-3", "data-testid": "sp-settings", children: /* @__PURE__ */ jsx(ReadOnlyFieldset, { children: /* @__PURE__ */ jsx(NodeSettingsPanel, { config }) }) });
3234
2491
  }
3235
- if (!PanelComponent) {
3236
- if (nodeData && data?.nodeData) {
3237
- return /* @__PURE__ */ jsx(
3238
- NodePropertyPanel,
3239
- {
3240
- id,
3241
- type,
3242
- data: nodeData,
3243
- updateData
3244
- }
3245
- );
2492
+ return /* @__PURE__ */ jsx("div", { className: "space-y-4 p-3", "data-testid": "sp-params", children: /* @__PURE__ */ jsx(ReadOnlyFieldset, { className: "space-y-4", children: /* @__PURE__ */ jsx(
2493
+ NodeParamsForm,
2494
+ {
2495
+ config,
2496
+ nodeType: config.node?.type,
2497
+ testIdPrefix: "sp"
3246
2498
  }
3247
- return /* @__PURE__ */ jsx(UnavailableNodePropertyPanel, {});
3248
- }
3249
- return nodeData ? /* @__PURE__ */ jsx(
3250
- PanelComponent,
2499
+ ) }) });
2500
+ }
2501
+ function EditorSchedule({
2502
+ config,
2503
+ nodeId
2504
+ }) {
2505
+ const workflowKey = useFlowStore((s) => s.workflow.workflowKey);
2506
+ const workflowDbId = useFlowStore((s) => s.workflow.dbId);
2507
+ const { allowed: canExecute } = useFluidGridsPermission(
2508
+ FLUIDGRIDS_PERMISSIONS.WORKFLOW_RUN_EXECUTE
2509
+ );
2510
+ const { allowed: canUpdate } = useFluidGridsPermission(
2511
+ FLUIDGRIDS_PERMISSIONS.WORKFLOW_UPDATE
2512
+ );
2513
+ return /* @__PURE__ */ jsx("div", { "data-testid": "sp-schedule", children: /* @__PURE__ */ jsx(
2514
+ SchedulePanel,
3251
2515
  {
3252
- id,
3253
- type,
3254
- data: nodeData,
3255
- updateData
2516
+ state: config.argsState,
2517
+ writeField: config.writeFixed,
2518
+ workflowKey: workflowDbId && workflowKey ? workflowKey : null,
2519
+ triggerNodeId: nodeId,
2520
+ canExecute,
2521
+ canUpdate
3256
2522
  }
3257
- ) : /* @__PURE__ */ jsx(UnavailableNodePropertyPanel, {});
2523
+ ) });
3258
2524
  }
3259
- function IntroductionPropertyPanel() {
3260
- const tr = useTr();
3261
- return /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col items-center justify-center p-4 text-center", children: [
3262
- /* @__PURE__ */ jsx("div", { className: "size-12 flex items-center justify-center rounded-full bg-primary", children: /* @__PURE__ */ jsx(
3263
- Icon,
3264
- {
3265
- icon: "mynaui:cog-one",
3266
- className: "size-6 text-primary-foreground"
3267
- }
3268
- ) }),
3269
- /* @__PURE__ */ jsx("div", { className: "mt-4 text-balance font-medium", children: tr(
3270
- "fluidgrids.builder.introductionPropertyPanel.title",
3271
- "Node Properties"
3272
- ) }),
3273
- /* @__PURE__ */ jsx("div", { className: "mt-1 w-2.5/3 text-xs text-card/40 font-medium leading-normal", children: tr(
3274
- "fluidgrids.builder.introductionPropertyPanel.description",
3275
- "Here you can view and edit the properties of the selected node."
3276
- ) }),
3277
- /* @__PURE__ */ jsx("div", { className: "mt-8 w-full text-xs text-card/40 font-medium italic", children: tr(
3278
- "fluidgrids.builder.introductionPropertyPanel.hint",
3279
- "Select a node from the list on the top to view its properties."
3280
- ) })
3281
- ] });
2525
+ function EditorRunActions({ nodeId }) {
2526
+ const nodes = useFlowStore((s) => s.workflow.nodes);
2527
+ const edges = useFlowStore((s) => s.workflow.edges);
2528
+ const workflowKey = useFlowStore((s) => s.workflow.workflowKey);
2529
+ const workflowId = useFlowStore((s) => s.workflow.id);
2530
+ const workflowVersion = useFlowStore((s) => s.workflow.version);
2531
+ const logs = useFlowStore((s) => s.execution.logs);
2532
+ const sourceRun = useFlowStore((s) => s.execution.sourceRun);
2533
+ const isExecuting = useFlowStore((s) => s.execution.isExecuting);
2534
+ const { executeStep, executeFromNode } = useNodeExecution();
2535
+ return /* @__PURE__ */ jsx(
2536
+ NodeExecutionActions,
2537
+ {
2538
+ targetNodeId: nodeId,
2539
+ nodes,
2540
+ edges,
2541
+ logs,
2542
+ workflowKey: workflowKey || workflowId,
2543
+ workflowVersion: workflowVersion || "1.0.0",
2544
+ sourceRun,
2545
+ isExecuting,
2546
+ onExecuteStep: async (targetId) => {
2547
+ await executeStep(targetId);
2548
+ },
2549
+ onContinueFromNode: async (sourceRunId, targetId) => {
2550
+ await executeFromNode(sourceRunId, targetId);
2551
+ },
2552
+ testIdPrefix: "sp"
2553
+ }
2554
+ );
3282
2555
  }
2556
+ var NODE_PANEL_WIDTH = 384;
3283
2557
  function NodePropertiesPanel() {
3284
2558
  const tr = useTr();
3285
2559
  const selectedNode = useFlowStore(
@@ -3291,6 +2565,7 @@ function NodePropertiesPanel() {
3291
2565
  const nodes = useNodes();
3292
2566
  const nodeList = useNodeList(nodes);
3293
2567
  const { setNodes } = useReactFlow();
2568
+ const [listOpen, setListOpen] = useState(!selectedNode);
3294
2569
  const onNodeClick = (id) => {
3295
2570
  setNodes(
3296
2571
  (nds) => produce(nds, (draft) => {
@@ -3304,57 +2579,64 @@ function NodePropertiesPanel() {
3304
2579
  type: nodeList.find((n) => n.id === id)?.type
3305
2580
  });
3306
2581
  };
3307
- const selectedNodeData = useMemo(() => {
3308
- const data = nodes.find((n) => n.id === selectedNode?.id)?.data;
3309
- return data;
3310
- }, [nodes, selectedNode?.id]);
3311
- return /* @__PURE__ */ jsxs(SidebarPanelWrapper, { children: [
3312
- /* @__PURE__ */ jsxs("div", { className: "h-80 w-80 flex flex-col", children: [
3313
- /* @__PURE__ */ jsx(SidebarPanelHeading, { className: "shrink-0", children: /* @__PURE__ */ jsx(
3314
- HeaderWithIcon,
3315
- {
3316
- icon: "mynaui:layers-three",
3317
- title: tr(
3318
- "fluidgrids.builder.nodePropertiesPanel.nodesInFlowHeading",
3319
- "Nodes in Flow"
3320
- )
3321
- }
3322
- ) }),
3323
- /* @__PURE__ */ jsx("div", { className: "flex w-full flex-col gap-1 p-1.5 overflow-y-auto", children: nodeList.map((node) => /* @__PURE__ */ jsx(
3324
- NodeListItem,
3325
- {
3326
- id: node.id,
3327
- title: node.detail.title,
3328
- icon: node.detail.icon,
3329
- selected: selectedNode?.id === node.id,
3330
- pseudoSelected: !!node.selected,
3331
- onClick: () => {
3332
- onNodeClick(node.id);
3333
- }
3334
- },
3335
- node.id
3336
- )) })
3337
- ] }),
3338
- /* @__PURE__ */ jsxs("div", { className: "w-80 max-h-[360px] 2xl:max-h-[594px] flex flex-col", children: [
3339
- /* @__PURE__ */ jsx(SidebarPanelHeading, { className: "shrink-0", children: /* @__PURE__ */ jsx(
3340
- HeaderWithIcon,
2582
+ return /* @__PURE__ */ jsxs(SidebarPanelWrapper, { style: { width: NODE_PANEL_WIDTH, maxWidth: "100%" }, children: [
2583
+ /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 flex-col border-b border-card-foreground/10", children: [
2584
+ /* @__PURE__ */ jsxs(
2585
+ "button",
3341
2586
  {
3342
- icon: "mynaui:cog",
3343
- title: tr(
3344
- "fluidgrids.builder.nodePropertiesPanel.nodePropertiesHeading",
3345
- "Node Properties"
3346
- )
2587
+ type: "button",
2588
+ onClick: () => setListOpen((open) => !open),
2589
+ "aria-expanded": listOpen,
2590
+ className: "flex h-10 w-full shrink-0 items-center gap-x-2 bg-card/80 px-4 text-sm font-semibold text-card-foreground/60 select-none hover:text-card-foreground",
2591
+ "data-testid": "sp-node-list-toggle",
2592
+ children: [
2593
+ /* @__PURE__ */ jsx(
2594
+ HeaderWithIcon,
2595
+ {
2596
+ icon: "mynaui:layers-three",
2597
+ title: tr(
2598
+ "fluidgrids.builder.nodePropertiesPanel.nodesInFlowHeading",
2599
+ "Nodes in Flow"
2600
+ )
2601
+ }
2602
+ ),
2603
+ /* @__PURE__ */ jsx("span", { className: "ml-auto text-xs font-medium tabular-nums", children: nodeList.length }),
2604
+ /* @__PURE__ */ jsx(
2605
+ Icon,
2606
+ {
2607
+ icon: "mdi:chevron-down",
2608
+ className: cn$1(
2609
+ "size-4 shrink-0 transition-transform",
2610
+ listOpen && "rotate-180"
2611
+ )
2612
+ }
2613
+ )
2614
+ ]
3347
2615
  }
3348
- ) }),
3349
- /* @__PURE__ */ jsx("div", { className: "flex w-full flex-col overflow-y-auto", children: selectedNode ? /* @__PURE__ */ jsx(
3350
- NodePropertyPanel2,
2616
+ ),
2617
+ listOpen && /* @__PURE__ */ jsx(
2618
+ "div",
3351
2619
  {
3352
- id: selectedNode.id,
3353
- type: selectedNode.type,
3354
- data: selectedNodeData
2620
+ className: "flex max-h-56 w-full flex-col gap-1 overflow-y-auto p-1.5",
2621
+ "data-testid": "sp-node-list",
2622
+ children: nodeList.map((node) => /* @__PURE__ */ jsx(
2623
+ NodeListItem,
2624
+ {
2625
+ id: node.id,
2626
+ title: node.detail.title,
2627
+ icon: node.detail.icon,
2628
+ selected: selectedNode?.id === node.id,
2629
+ pseudoSelected: !!node.selected,
2630
+ onClick: () => {
2631
+ onNodeClick(node.id);
2632
+ }
2633
+ },
2634
+ node.id
2635
+ ))
3355
2636
  }
3356
- ) : /* @__PURE__ */ jsx(IntroductionPropertyPanel, {}) })
3357
- ] })
2637
+ )
2638
+ ] }),
2639
+ selectedNode ? /* @__PURE__ */ jsx(SidebarNodeEditor, { nodeId: selectedNode.id, type: selectedNode.type }) : /* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col overflow-y-auto", children: /* @__PURE__ */ jsx(IntroductionPropertyPanel, {}) })
3358
2640
  ] });
3359
2641
  }
3360
2642
 
@@ -5615,8 +4897,8 @@ function DesktopSidebarFragment({
5615
4897
  }
5616
4898
  const { getFluidGridsClient: getFluidGridsClient2 } = await import('./client-62VHXHKN.js');
5617
4899
  const { getFluidGridsConfig: getFluidGridsConfig2 } = await import('./config-66FUPSG5.js');
5618
- const { gql: gql5 } = await import('@apollo/client/core');
5619
- const IMPORT_MUTATION = gql5`
4900
+ const { gql: gql3 } = await import('@apollo/client/core');
4901
+ const IMPORT_MUTATION = gql3`
5620
4902
  mutation ImportWorkflowTemplate(
5621
4903
  $input: ImportWorkflowTemplateInput!
5622
4904
  ) {
@@ -5772,8 +5054,8 @@ function DesktopSidebarFragment({
5772
5054
  { id: "template-load" }
5773
5055
  );
5774
5056
  const { getGlobalStoreClient: getGlobalStoreClient2 } = await import('./global-client-PJ5LANJA.js');
5775
- const { gql: gql5 } = await import('@apollo/client/core');
5776
- const GET_TEMPLATE_DETAIL = gql5`
5057
+ const { gql: gql3 } = await import('@apollo/client/core');
5058
+ const GET_TEMPLATE_DETAIL = gql3`
5777
5059
  query GetWorkflowTemplateDetail($id: ID!) {
5778
5060
  product(id: $id) {
5779
5061
  id
@@ -5925,7 +5207,7 @@ function DesktopSidebarFragment({
5925
5207
  },
5926
5208
  [configTemplate, configContent, configNodeCheck, performImport]
5927
5209
  );
5928
- return /* @__PURE__ */ jsxs("div", { className: "relative w-fit flex shrink-0 divide-x divide-card-foreground/10 rounded-xl border border-card-foreground/10 md:overflow-hidden md:max-w-sm", children: [
5210
+ return /* @__PURE__ */ jsxs("div", { className: "relative w-fit flex shrink-0 divide-x divide-card-foreground/10 rounded-xl border border-card-foreground/10 md:overflow-hidden md:max-w-md", children: [
5929
5211
  activePanel !== "none" && /* @__PURE__ */ jsx("div", { className: "absolute inset-y-0 right-full z-20 w-[78vw] overflow-hidden rounded-l-xl border-y border-l border-card-foreground/10 bg-card md:static md:z-auto md:w-auto md:grow md:min-w-xs md:rounded-none md:border-0", children: /* @__PURE__ */ jsx(SwitchSidebarPanel, { active: activePanel }) }),
5930
5212
  /* @__PURE__ */ jsx("div", { className: "shrink-0 bg-card p-1.5", children: /* @__PURE__ */ jsxs("div", { className: "h-full flex flex-col gap-2", children: [
5931
5213
  /* @__PURE__ */ jsx(
@@ -21244,12 +20526,12 @@ function EditLeaseBanner() {
21244
20526
  );
21245
20527
  }
21246
20528
  var LazyNodeDetailView = lazy(
21247
- () => import('./node-detail-view-ZFGS3FWU.js').then((m) => ({
20529
+ () => import('./node-detail-view-2AFXRNX6.js').then((m) => ({
21248
20530
  default: m.NodeDetailView
21249
20531
  }))
21250
20532
  );
21251
20533
  var LazyQuickConfigPanel = lazy(
21252
- () => import('./quick-config-panel-ZDGYZR7Y.js').then((m) => ({
20534
+ () => import('./quick-config-panel-U4AELSCT.js').then((m) => ({
21253
20535
  default: m.QuickConfigPanel
21254
20536
  }))
21255
20537
  );
@@ -21311,7 +20593,7 @@ var FlowBuilder = ({ readOnly = false }) => {
21311
20593
  );
21312
20594
  useEffect(() => {
21313
20595
  let cancelled = false;
21314
- void import('./agentTools-5O2KPQYJ.js').then(({ createBuilderAgentTools }) => {
20596
+ void import('./agentTools-V26FOMTS.js').then(({ createBuilderAgentTools }) => {
21315
20597
  if (cancelled) return;
21316
20598
  setAgentTools(
21317
20599
  createBuilderAgentTools({