@uipath/apollo-react 6.79.0 → 7.0.0

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 (52) hide show
  1. package/dist/canvas/components/Guardrails/guardrail-builder.cjs +5 -5
  2. package/dist/canvas/components/Guardrails/guardrail-builder.d.ts.map +1 -1
  3. package/dist/canvas/components/Guardrails/guardrail-builder.js +6 -6
  4. package/dist/canvas/components/Guardrails/index.cjs +7 -7
  5. package/dist/canvas/components/Guardrails/index.d.ts +2 -2
  6. package/dist/canvas/components/Guardrails/index.d.ts.map +1 -1
  7. package/dist/canvas/components/Guardrails/index.js +2 -2
  8. package/dist/canvas/components/Guardrails/types.d.ts +1 -1
  9. package/dist/canvas/components/Guardrails/types.d.ts.map +1 -1
  10. package/dist/canvas/components/Guardrails/utils.cjs +9 -9
  11. package/dist/canvas/components/Guardrails/utils.d.ts +3 -3
  12. package/dist/canvas/components/Guardrails/utils.d.ts.map +1 -1
  13. package/dist/canvas/components/Guardrails/utils.js +4 -4
  14. package/dist/canvas/components/JsonTree/index.cjs +4 -0
  15. package/dist/canvas/components/JsonTree/index.d.ts +1 -1
  16. package/dist/canvas/components/JsonTree/index.d.ts.map +1 -1
  17. package/dist/canvas/components/JsonTree/index.js +2 -2
  18. package/dist/canvas/components/NodeIOView/NodeIOView.cjs +10 -12
  19. package/dist/canvas/components/NodeIOView/NodeIOView.d.ts +1 -1
  20. package/dist/canvas/components/NodeIOView/NodeIOView.d.ts.map +1 -1
  21. package/dist/canvas/components/NodeIOView/NodeIOView.js +12 -14
  22. package/dist/canvas/components/NodeIOView/NodeIOView.types.d.ts +2 -0
  23. package/dist/canvas/components/NodeIOView/NodeIOView.types.d.ts.map +1 -1
  24. package/dist/canvas/components/NodePropertyPanel/NodePropertyPanel.cjs +6 -6
  25. package/dist/canvas/components/NodePropertyPanel/NodePropertyPanel.d.ts.map +1 -1
  26. package/dist/canvas/components/NodePropertyPanel/NodePropertyPanel.js +6 -6
  27. package/dist/canvas/components/NodeVariablesPanel/NodeVariableEditDialog.cjs +405 -0
  28. package/dist/canvas/components/NodeVariablesPanel/NodeVariableEditDialog.d.ts +10 -0
  29. package/dist/canvas/components/NodeVariablesPanel/NodeVariableEditDialog.d.ts.map +1 -0
  30. package/dist/canvas/components/NodeVariablesPanel/NodeVariableEditDialog.js +371 -0
  31. package/dist/canvas/components/NodeVariablesPanel/NodeVariablesPanel.cjs +726 -0
  32. package/dist/canvas/components/NodeVariablesPanel/NodeVariablesPanel.d.ts +3 -0
  33. package/dist/canvas/components/NodeVariablesPanel/NodeVariablesPanel.d.ts.map +1 -0
  34. package/dist/canvas/components/NodeVariablesPanel/NodeVariablesPanel.js +692 -0
  35. package/dist/canvas/components/NodeVariablesPanel/NodeVariablesPanel.types.cjs +18 -0
  36. package/dist/canvas/components/NodeVariablesPanel/NodeVariablesPanel.types.d.ts +65 -0
  37. package/dist/canvas/components/NodeVariablesPanel/NodeVariablesPanel.types.d.ts.map +1 -0
  38. package/dist/canvas/components/NodeVariablesPanel/NodeVariablesPanel.types.js +0 -0
  39. package/dist/canvas/components/NodeVariablesPanel/index.cjs +36 -0
  40. package/dist/canvas/components/NodeVariablesPanel/index.d.ts +3 -0
  41. package/dist/canvas/components/NodeVariablesPanel/index.d.ts.map +1 -0
  42. package/dist/canvas/components/NodeVariablesPanel/index.js +2 -0
  43. package/dist/canvas/components/index.cjs +23 -16
  44. package/dist/canvas/components/index.d.ts +1 -0
  45. package/dist/canvas/components/index.d.ts.map +1 -1
  46. package/dist/canvas/components/index.js +1 -0
  47. package/dist/canvas/locales/en.cjs +1 -1
  48. package/dist/canvas/locales/en.d.ts.map +1 -1
  49. package/dist/canvas/locales/en.js +1 -1
  50. package/dist/canvas/styles/tailwind.canvas.css +1 -1
  51. package/dist/chat/styles/tailwind.chat.css +1 -1
  52. package/package.json +3 -3
@@ -0,0 +1,692 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Button, Collapsible, CollapsibleContent, CollapsibleTrigger, cn } from "@uipath/apollo-wind";
3
+ import { ArrowDown, ArrowUp, ChevronDown, MousePointerClick, Pencil, Plus, SquareStack, Trash2, Variable } from "lucide-react";
4
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
5
+ import { useSafeLingui } from "../../../i18n/index.js";
6
+ import { CanvasTooltip } from "../CanvasTooltip.js";
7
+ import { JsonTreeToolbar, JsonTreeView, appendPathSegment, buildJsonTree, collectContainerPaths, flattenJsonTree, isArrayItemTemplateRoot, isPathCollapsed, schemaDisplayType } from "../JsonTree/index.js";
8
+ import { NodeVariableEditDialog } from "./NodeVariableEditDialog.js";
9
+ const SECTIONS = [
10
+ 'inputs',
11
+ 'outputs',
12
+ 'variables',
13
+ 'nodes'
14
+ ];
15
+ const isSourceSection = (section)=>'inputs' === section || 'nodes' === section;
16
+ const SECTION_ICONS = {
17
+ inputs: {
18
+ Icon: ArrowDown,
19
+ className: 'text-info'
20
+ },
21
+ outputs: {
22
+ Icon: ArrowUp,
23
+ className: 'text-success'
24
+ },
25
+ variables: {
26
+ Icon: Variable,
27
+ className: 'text-chart-purple'
28
+ },
29
+ nodes: {
30
+ Icon: SquareStack,
31
+ className: 'text-chart-pink'
32
+ }
33
+ };
34
+ const COUNT_CLASS = 'ml-auto shrink-0 font-mono text-[10px] text-foreground-muted';
35
+ const EMPTY_MESSAGE_CLASS = 'px-3 py-6 text-center text-xs text-foreground-muted';
36
+ const countEntries = (nodes)=>nodes?.filter((node)=>!isArrayItemTemplateRoot(node)).length ?? 0;
37
+ const VIRTUALIZE_THRESHOLD = 500;
38
+ function exceedsVirtualizeThreshold(nodes) {
39
+ let count = 0;
40
+ const stack = [
41
+ ...nodes.slice(0, VIRTUALIZE_THRESHOLD + 1)
42
+ ];
43
+ while(stack.length > 0){
44
+ const node = stack.pop();
45
+ count += 1;
46
+ if (count > VIRTUALIZE_THRESHOLD) return true;
47
+ for (const child of node.children ?? []){
48
+ stack.push(child);
49
+ if (stack.length + count > VIRTUALIZE_THRESHOLD) return true;
50
+ }
51
+ }
52
+ return false;
53
+ }
54
+ function objectPaths(nodes) {
55
+ const paths = [];
56
+ const stack = [];
57
+ for(let index = nodes.length - 1; index >= 0; index -= 1)stack.push(nodes[index]);
58
+ while(stack.length > 0){
59
+ const node = stack.pop();
60
+ if ('object' !== node.type || !node.children || 'number' == typeof node.segments[0]) continue;
61
+ paths.push(node.path);
62
+ for(let index = node.children.length - 1; index >= 0; index -= 1)stack.push(node.children[index]);
63
+ }
64
+ return paths;
65
+ }
66
+ function emptyValueFor(schema) {
67
+ const type = schemaDisplayType(schema);
68
+ if ('object' === type) return {};
69
+ if ('array' === type) return [];
70
+ return 'null' === type ? null : void 0;
71
+ }
72
+ function buildSourceTree(sources) {
73
+ const properties = Object.fromEntries(sources.map((source)=>[
74
+ source.id,
75
+ source.schema ?? {}
76
+ ]));
77
+ const value = Object.fromEntries(sources.flatMap((source)=>{
78
+ const entry = source.value ?? emptyValueFor(source.schema);
79
+ return void 0 === entry ? [] : [
80
+ [
81
+ source.id,
82
+ entry
83
+ ]
84
+ ];
85
+ }));
86
+ return buildJsonTree({
87
+ schema: {
88
+ type: 'object',
89
+ properties
90
+ },
91
+ value
92
+ });
93
+ }
94
+ function useScrollEdges() {
95
+ const ref = useRef(null);
96
+ const contentRef = useRef(null);
97
+ const [edges, setEdges] = useState({
98
+ top: false,
99
+ bottom: false
100
+ });
101
+ const update = useCallback(()=>{
102
+ const element = ref.current;
103
+ if (!element) return;
104
+ const top = element.scrollTop > 0;
105
+ const bottom = element.scrollTop + element.clientHeight < element.scrollHeight - 1;
106
+ setEdges((current)=>current.top === top && current.bottom === bottom ? current : {
107
+ top,
108
+ bottom
109
+ });
110
+ }, []);
111
+ useEffect(()=>{
112
+ const element = ref.current;
113
+ if (!element) return;
114
+ update();
115
+ if ("u" < typeof ResizeObserver) return;
116
+ const observer = new ResizeObserver(update);
117
+ observer.observe(element);
118
+ if (contentRef.current) observer.observe(contentRef.current);
119
+ return ()=>observer.disconnect();
120
+ }, [
121
+ update
122
+ ]);
123
+ return {
124
+ ref,
125
+ contentRef,
126
+ edges,
127
+ onScroll: update
128
+ };
129
+ }
130
+ function variableTypeOf(schema, value) {
131
+ const declared = schemaDisplayType(schema);
132
+ const type = declared && 'null' !== declared ? declared : Array.isArray(value) ? 'array' : null === value ? 'string' : typeof value;
133
+ return 'number' === type || 'boolean' === type || 'object' === type || 'array' === type ? type : 'string';
134
+ }
135
+ function rowFor(section, node) {
136
+ return isSourceSection(section) ? {
137
+ section,
138
+ nodeId: String(node.segments[0]),
139
+ node
140
+ } : {
141
+ section,
142
+ node
143
+ };
144
+ }
145
+ const isTopLevelVariable = ({ section, node })=>('outputs' === section || 'variables' === section) && 1 === node.segments.length && 'string' == typeof node.segments[0];
146
+ function siblingKeys(tree, targetPath) {
147
+ const keysOf = (nodes)=>new Set(nodes.map((node)=>node.key));
148
+ if (tree.some((node)=>node.path === targetPath)) return keysOf(tree);
149
+ const stack = [
150
+ ...tree
151
+ ];
152
+ while(stack.length > 0){
153
+ const node = stack.pop();
154
+ if (!node.children) continue;
155
+ if (node.children.some((child)=>child.path === targetPath)) return keysOf(node.children);
156
+ for (const child of node.children)stack.push(child);
157
+ }
158
+ return new Set();
159
+ }
160
+ function NodeVariablesPanel({ inputs = [], outputs, variables, nodes = [], outputsBasePath, variablesBasePath, referencePrefix = '$vars', pathForCopy, defaultExpandedSections = [
161
+ 'nodes'
162
+ ], filters, activeFilterId: activeFilterIdProp, defaultActiveFilterId = null, onActiveFilterChange, onFocusNode, onAdd, isVariableRow = isTopLevelVariable, onEditVariable, onRequestEditVariable, onDeleteVariable, onCopy, leading, rowWrapper, deriveTypeIcon, children, className }) {
163
+ const { _ } = useSafeLingui();
164
+ const trees = useMemo(()=>({
165
+ inputs: buildSourceTree(inputs),
166
+ outputs: buildJsonTree({
167
+ schema: outputs?.schema,
168
+ value: outputs?.value,
169
+ basePath: outputsBasePath
170
+ }),
171
+ variables: buildJsonTree({
172
+ schema: variables?.schema,
173
+ value: variables?.value,
174
+ basePath: variablesBasePath
175
+ }),
176
+ nodes: buildSourceTree(nodes)
177
+ }), [
178
+ inputs,
179
+ outputs,
180
+ outputsBasePath,
181
+ variables,
182
+ variablesBasePath,
183
+ nodes
184
+ ]);
185
+ const sourcesById = useMemo(()=>({
186
+ inputs: new Map(inputs.map((source)=>[
187
+ source.id,
188
+ source
189
+ ])),
190
+ nodes: new Map(nodes.map((source)=>[
191
+ source.id,
192
+ source
193
+ ]))
194
+ }), [
195
+ inputs,
196
+ nodes
197
+ ]);
198
+ const [openSections, setOpenSections] = useState(()=>new Set(defaultExpandedSections));
199
+ const [openPaths, setOpenPaths] = useState({
200
+ inputs: {},
201
+ outputs: {},
202
+ variables: {},
203
+ nodes: {}
204
+ });
205
+ const collapsed = useMemo(()=>Object.fromEntries(SECTIONS.map((section)=>[
206
+ section,
207
+ Object.fromEntries(collectContainerPaths(trees[section]).map(({ path })=>[
208
+ path,
209
+ !isPathCollapsed(openPaths[section], path)
210
+ ]))
211
+ ])), [
212
+ trees,
213
+ openPaths
214
+ ]);
215
+ const virtualize = useMemo(()=>Object.fromEntries(SECTIONS.map((section)=>[
216
+ section,
217
+ exceedsVirtualizeThreshold(trees[section])
218
+ ])), [
219
+ trees
220
+ ]);
221
+ const [scroller, setScroller] = useState(null);
222
+ const [query, setQuery] = useState('');
223
+ const [uncontrolledFilterId, setUncontrolledFilterId] = useState(defaultActiveFilterId);
224
+ const activeFilterId = void 0 !== activeFilterIdProp ? activeFilterIdProp : uncontrolledFilterId;
225
+ const changeFilter = (id)=>{
226
+ if (void 0 === activeFilterIdProp) setUncontrolledFilterId(id);
227
+ onActiveFilterChange?.(id);
228
+ };
229
+ const [editing, setEditing] = useState(null);
230
+ const referenceFor = useCallback((path, segments)=>{
231
+ const prefixed = referencePrefix && path ? `${referencePrefix}${path.startsWith('[') ? '' : '.'}${path}` : path || referencePrefix;
232
+ return pathForCopy ? pathForCopy(prefixed, segments) : prefixed;
233
+ }, [
234
+ referencePrefix,
235
+ pathForCopy
236
+ ]);
237
+ const search = query.trim();
238
+ const activeFilter = filters?.find((filter)=>filter.id === activeFilterId);
239
+ const narrowing = !!search || !!activeFilter;
240
+ const toolbarFilters = useMemo(()=>filters?.map(({ id, label })=>({
241
+ id,
242
+ label,
243
+ predicate: ()=>true
244
+ })), [
245
+ filters
246
+ ]);
247
+ const filterPredicates = useMemo(()=>activeFilter ? Object.fromEntries(SECTIONS.map((section)=>[
248
+ section,
249
+ (node)=>activeFilter.predicate(rowFor(section, node))
250
+ ])) : void 0, [
251
+ activeFilter
252
+ ]);
253
+ const decorateSource = useMemo(()=>{
254
+ const decorate = (section)=>(node)=>{
255
+ if (1 !== node.segments.length) return;
256
+ const source = sourcesById[section].get(String(node.segments[0]));
257
+ if (!source) return;
258
+ const count = source.outputCount ?? countEntries(node.children);
259
+ const countLabel = _({
260
+ id: 'canvas.node_variables_panel.node_output_count',
261
+ message: '{count, plural, one {# output} other {# outputs}}',
262
+ values: {
263
+ count
264
+ }
265
+ });
266
+ return {
267
+ label: source.label,
268
+ sublabel: source.id,
269
+ sublabelOnHover: true,
270
+ badge: {
271
+ icon: source.icon
272
+ },
273
+ hideCount: true,
274
+ hideValue: true,
275
+ meta: /*#__PURE__*/ jsx(CanvasTooltip, {
276
+ content: countLabel,
277
+ placement: "top",
278
+ delay: true,
279
+ children: /*#__PURE__*/ jsxs("span", {
280
+ role: "img",
281
+ "aria-label": countLabel,
282
+ className: COUNT_CLASS,
283
+ children: [
284
+ "(",
285
+ count,
286
+ ")"
287
+ ]
288
+ })
289
+ })
290
+ };
291
+ };
292
+ return {
293
+ inputs: decorate('inputs'),
294
+ nodes: decorate('nodes')
295
+ };
296
+ }, [
297
+ sourcesById,
298
+ _
299
+ ]);
300
+ const visibleCount = useMemo(()=>Object.fromEntries(SECTIONS.map((section)=>[
301
+ section,
302
+ narrowing ? flattenJsonTree(trees[section], {
303
+ collapsed: {},
304
+ query: search,
305
+ filterPredicate: filterPredicates?.[section],
306
+ displayTexts: isSourceSection(section) ? decorateSource[section] : void 0
307
+ }).length : 1
308
+ ])), [
309
+ narrowing,
310
+ trees,
311
+ search,
312
+ filterPredicates,
313
+ decorateSource
314
+ ]);
315
+ const totalCount = {
316
+ inputs: inputs.length,
317
+ outputs: countEntries(trees.outputs),
318
+ variables: countEntries(trees.variables),
319
+ nodes: nodes.length
320
+ };
321
+ const sectionOpen = (section)=>narrowing || openSections.has(section);
322
+ const setSectionOpen = (section, open)=>setOpenSections((current)=>{
323
+ const next = new Set(current);
324
+ if (open) next.add(section);
325
+ else next.delete(section);
326
+ return next;
327
+ });
328
+ const toggleCollapsed = (section)=>(path)=>setOpenPaths((current)=>({
329
+ ...current,
330
+ [section]: {
331
+ ...current[section],
332
+ [path]: isPathCollapsed(collapsed[section], path)
333
+ }
334
+ }));
335
+ const expandableSections = SECTIONS.filter((section)=>totalCount[section] > 0);
336
+ const expandablePaths = useMemo(()=>Object.fromEntries(SECTIONS.map((section)=>[
337
+ section,
338
+ objectPaths(trees[section])
339
+ ])), [
340
+ trees
341
+ ]);
342
+ const allExpanded = expandableSections.length > 0 && expandableSections.every((section)=>openSections.has(section)) && SECTIONS.every((section)=>expandablePaths[section].every((path)=>!isPathCollapsed(collapsed[section], path)));
343
+ const toggleAll = ()=>{
344
+ const open = !allExpanded;
345
+ setOpenSections(open ? new Set(expandableSections) : new Set());
346
+ setOpenPaths((current)=>Object.fromEntries(SECTIONS.map((section)=>[
347
+ section,
348
+ {
349
+ ...current[section],
350
+ ...Object.fromEntries(expandablePaths[section].map((path)=>[
351
+ path,
352
+ open
353
+ ]))
354
+ }
355
+ ])));
356
+ };
357
+ const sourceActions = (section)=>(node, ctx)=>{
358
+ if (1 !== node.segments.length) return ctx.defaultActions;
359
+ const source = sourcesById[section].get(String(node.segments[0]));
360
+ const label = source?.label ?? node.key;
361
+ const actions = [];
362
+ if (onAdd && source?.addable !== false) actions.push({
363
+ id: 'add-to-node',
364
+ icon: /*#__PURE__*/ jsx(Plus, {}),
365
+ label: _({
366
+ id: 'canvas.node_variables_panel.add_to_node_label',
367
+ message: 'Add from {label}',
368
+ values: {
369
+ label
370
+ }
371
+ }),
372
+ tooltip: _({
373
+ id: 'canvas.node_variables_panel.add_to_node',
374
+ message: 'Add'
375
+ }),
376
+ persistent: true,
377
+ onSelect: ()=>onAdd(section, node.key)
378
+ });
379
+ if (onFocusNode) actions.unshift({
380
+ id: 'focus-node',
381
+ icon: /*#__PURE__*/ jsx(MousePointerClick, {}),
382
+ label: _({
383
+ id: 'canvas.node_variables_panel.focus_node_label',
384
+ message: 'Focus on {label}',
385
+ values: {
386
+ label
387
+ }
388
+ }),
389
+ tooltip: _({
390
+ id: 'canvas.node_variables_panel.focus_node',
391
+ message: 'Focus on node'
392
+ }),
393
+ persistent: true,
394
+ placement: 'start',
395
+ onSelect: ()=>onFocusNode(node.key)
396
+ });
397
+ return actions;
398
+ };
399
+ const openEditDialog = (row)=>{
400
+ const { schema, value } = row.node;
401
+ setEditing({
402
+ row,
403
+ details: {
404
+ id: row.node.key,
405
+ type: variableTypeOf(schema, value),
406
+ description: schema?.description,
407
+ defaultValue: schema && Object.hasOwn(schema, 'default') ? schema.default : value
408
+ }
409
+ });
410
+ };
411
+ const variableActions = (row, ctx)=>{
412
+ const { node } = row;
413
+ const actions = [
414
+ ...ctx.defaultActions
415
+ ];
416
+ if (onRequestEditVariable || onEditVariable) actions.push({
417
+ id: 'edit-variable',
418
+ icon: /*#__PURE__*/ jsx(Pencil, {}),
419
+ label: _({
420
+ id: 'canvas.node_variables_panel.edit_variable',
421
+ message: 'Edit {name}',
422
+ values: {
423
+ name: node.key
424
+ }
425
+ }),
426
+ onSelect: ()=>onRequestEditVariable ? onRequestEditVariable(row) : openEditDialog(row)
427
+ });
428
+ if (onDeleteVariable) actions.push({
429
+ id: 'delete-variable',
430
+ icon: /*#__PURE__*/ jsx(Trash2, {}),
431
+ label: _({
432
+ id: 'canvas.node_variables_panel.delete_variable',
433
+ message: 'Delete {name}',
434
+ values: {
435
+ name: node.key
436
+ }
437
+ }),
438
+ tone: 'error',
439
+ onSelect: ()=>onDeleteVariable(row)
440
+ });
441
+ return actions;
442
+ };
443
+ const actionsFor = (section)=>(node, ctx)=>{
444
+ if (isSourceSection(section) && 1 === node.segments.length) return sourceActions(section)(node, ctx);
445
+ const row = rowFor(section, node);
446
+ return !node.isArrayItemTemplate && isVariableRow(row) ? variableActions(row, ctx) : ctx.defaultActions;
447
+ };
448
+ const renamedReference = ({ section, node })=>(id)=>{
449
+ const basePath = 'outputs' === section ? outputsBasePath ?? '' : 'variables' === section ? variablesBasePath ?? '' : '';
450
+ const parentSegments = node.segments.slice(0, -1);
451
+ const path = [
452
+ ...parentSegments,
453
+ id
454
+ ].reduce(appendPathSegment, basePath);
455
+ return referenceFor(path, [
456
+ ...parentSegments,
457
+ id
458
+ ]);
459
+ };
460
+ const sectionName = {
461
+ inputs: _({
462
+ id: 'canvas.node_variables_panel.section_inputs',
463
+ message: 'Inputs'
464
+ }),
465
+ outputs: _({
466
+ id: 'canvas.node_variables_panel.section_outputs',
467
+ message: 'Outputs'
468
+ }),
469
+ variables: _({
470
+ id: 'canvas.node_variables_panel.section_variables',
471
+ message: 'Variables'
472
+ }),
473
+ nodes: _({
474
+ id: 'canvas.node_variables_panel.section_nodes',
475
+ message: 'Nodes'
476
+ })
477
+ };
478
+ const sectionCountLabel = (section, count)=>({
479
+ inputs: _({
480
+ id: 'canvas.node_variables_panel.count_inputs',
481
+ message: '{count, plural, one {# input} other {# inputs}}',
482
+ values: {
483
+ count
484
+ }
485
+ }),
486
+ outputs: _({
487
+ id: 'canvas.node_variables_panel.count_outputs',
488
+ message: '{count, plural, one {# output} other {# outputs}}',
489
+ values: {
490
+ count
491
+ }
492
+ }),
493
+ variables: _({
494
+ id: 'canvas.node_variables_panel.count_variables',
495
+ message: '{count, plural, one {# variable} other {# variables}}',
496
+ values: {
497
+ count
498
+ }
499
+ }),
500
+ nodes: _({
501
+ id: 'canvas.node_variables_panel.count_nodes',
502
+ message: '{count, plural, one {# node} other {# nodes}}',
503
+ values: {
504
+ count
505
+ }
506
+ })
507
+ })[section];
508
+ const addLabel = (section)=>({
509
+ outputs: _({
510
+ id: 'canvas.node_variables_panel.add_outputs',
511
+ message: 'Add outputs'
512
+ }),
513
+ variables: _({
514
+ id: 'canvas.node_variables_panel.add_variables',
515
+ message: 'Add variables'
516
+ })
517
+ })[section];
518
+ const renderTree = (section)=>/*#__PURE__*/ jsx(JsonTreeView, {
519
+ nodes: trees[section],
520
+ collapsed: search ? {} : collapsed[section],
521
+ onToggleCollapsed: search ? void 0 : toggleCollapsed(section),
522
+ query: search,
523
+ filterPredicate: filterPredicates?.[section],
524
+ readOnly: true,
525
+ decorateNode: isSourceSection(section) ? decorateSource[section] : void 0,
526
+ deriveTypeIcon: deriveTypeIcon,
527
+ rowWrapper: rowWrapper,
528
+ nodeActions: actionsFor(section),
529
+ maxInlineActions: 4,
530
+ pathForCopy: referenceFor,
531
+ onCopy: onCopy,
532
+ virtualized: virtualize[section],
533
+ scrollElement: virtualize[section] ? scroller : void 0,
534
+ className: "h-auto py-1"
535
+ });
536
+ const renderSection = (section)=>{
537
+ if (narrowing && 0 === visibleCount[section]) return null;
538
+ const open = sectionOpen(section);
539
+ const name = sectionName[section];
540
+ const count = totalCount[section];
541
+ const { Icon, className: iconClassName } = SECTION_ICONS[section];
542
+ const addable = ('outputs' === section || 'variables' === section) && onAdd ? section : null;
543
+ return /*#__PURE__*/ jsx(Collapsible, {
544
+ open: open,
545
+ onOpenChange: (next)=>setSectionOpen(section, next),
546
+ disabled: narrowing,
547
+ asChild: true,
548
+ children: /*#__PURE__*/ jsxs("section", {
549
+ "aria-label": name,
550
+ className: "mb-2 overflow-hidden rounded-lg border border-surface-overlay bg-surface-overlay/40",
551
+ children: [
552
+ /*#__PURE__*/ jsxs("div", {
553
+ className: cn('flex h-9 items-center gap-2 pr-1 pl-2', open && trees[section].length > 0 && 'border-b border-surface-overlay/80'),
554
+ children: [
555
+ /*#__PURE__*/ jsxs(CollapsibleTrigger, {
556
+ className: "flex min-w-0 flex-1 cursor-pointer items-center gap-2 text-left disabled:cursor-default",
557
+ children: [
558
+ /*#__PURE__*/ jsx(ChevronDown, {
559
+ size: 10,
560
+ className: cn('shrink-0 text-foreground-subtle transition-transform', !open && '-rotate-90')
561
+ }),
562
+ /*#__PURE__*/ jsx("span", {
563
+ className: cn('grid size-4.5 shrink-0 place-items-center', iconClassName),
564
+ "aria-hidden": "true",
565
+ children: /*#__PURE__*/ jsx(Icon, {
566
+ size: 14
567
+ })
568
+ }),
569
+ /*#__PURE__*/ jsx("span", {
570
+ className: "truncate text-xs font-semibold tracking-[0.02em] text-foreground",
571
+ children: name
572
+ })
573
+ ]
574
+ }),
575
+ /*#__PURE__*/ jsx(CanvasTooltip, {
576
+ content: sectionCountLabel(section, count),
577
+ placement: "top",
578
+ delay: true,
579
+ children: /*#__PURE__*/ jsxs("span", {
580
+ role: "img",
581
+ "aria-label": sectionCountLabel(section, count),
582
+ className: COUNT_CLASS,
583
+ children: [
584
+ "(",
585
+ count,
586
+ ")"
587
+ ]
588
+ })
589
+ }),
590
+ addable && /*#__PURE__*/ jsx(Button, {
591
+ variant: "ghost",
592
+ size: "4xs",
593
+ icon: true,
594
+ "aria-label": addLabel(addable),
595
+ onClick: ()=>onAdd?.(addable),
596
+ className: "shrink-0 rounded text-foreground-subtle hover:bg-surface-raised hover:text-foreground [&_svg]:size-2.75",
597
+ children: /*#__PURE__*/ jsx(Plus, {})
598
+ }),
599
+ onAdd && !addable && /*#__PURE__*/ jsx("span", {
600
+ "aria-hidden": "true",
601
+ className: "size-5 shrink-0"
602
+ })
603
+ ]
604
+ }),
605
+ /*#__PURE__*/ jsx(CollapsibleContent, {
606
+ className: "bg-surface/30",
607
+ children: trees[section].length > 0 && renderTree(section)
608
+ })
609
+ ]
610
+ })
611
+ }, section);
612
+ };
613
+ const { ref: scrollRef, contentRef, edges, onScroll } = useScrollEdges();
614
+ const setScrollRef = useCallback((element)=>{
615
+ scrollRef.current = element;
616
+ setScroller(element);
617
+ }, [
618
+ scrollRef
619
+ ]);
620
+ const nothingVisible = narrowing && SECTIONS.every((section)=>0 === visibleCount[section]);
621
+ return /*#__PURE__*/ jsxs("div", {
622
+ className: cn('flex min-h-0 flex-1 flex-col', className),
623
+ children: [
624
+ /*#__PURE__*/ jsx(JsonTreeToolbar, {
625
+ query: query,
626
+ onQueryChange: setQuery,
627
+ searchPlaceholder: _({
628
+ id: 'canvas.node_variables_panel.search_placeholder',
629
+ message: 'Search variables'
630
+ }),
631
+ filters: toolbarFilters,
632
+ activeFilterId: activeFilter ? activeFilterId : null,
633
+ onFilterChange: changeFilter,
634
+ allCollapsed: !allExpanded,
635
+ onToggleAll: search ? void 0 : toggleAll,
636
+ leading: leading,
637
+ className: "shrink-0 pt-4 pb-2 [padding-inline:var(--mf-content-inset,1rem)]"
638
+ }),
639
+ /*#__PURE__*/ jsx("div", {
640
+ className: "min-h-0 flex-1 overflow-hidden text-foreground",
641
+ children: /*#__PURE__*/ jsxs("div", {
642
+ className: "relative mt-1 mb-4 h-[calc(100%-1.25rem)] min-h-0 [margin-inline:var(--mf-content-inset,1rem)]",
643
+ children: [
644
+ edges.top && /*#__PURE__*/ jsx("div", {
645
+ "aria-hidden": "true",
646
+ "data-edge": "top",
647
+ className: "pointer-events-none absolute inset-x-0 top-0 z-10 h-2 rounded-t-lg border-t border-surface-overlay"
648
+ }),
649
+ edges.bottom && /*#__PURE__*/ jsx("div", {
650
+ "aria-hidden": "true",
651
+ "data-edge": "bottom",
652
+ className: "pointer-events-none absolute inset-x-0 bottom-0 z-10 h-2 rounded-b-lg border-b border-surface-overlay"
653
+ }),
654
+ /*#__PURE__*/ jsx("div", {
655
+ ref: setScrollRef,
656
+ onScroll: onScroll,
657
+ className: "h-full min-h-0 overflow-y-auto rounded-lg pb-1",
658
+ children: /*#__PURE__*/ jsxs("div", {
659
+ ref: contentRef,
660
+ children: [
661
+ SECTIONS.map(renderSection),
662
+ nothingVisible && /*#__PURE__*/ jsx("p", {
663
+ className: EMPTY_MESSAGE_CLASS,
664
+ children: search ? _({
665
+ id: 'canvas.node_variables_panel.no_matches',
666
+ message: 'No variables match your search.'
667
+ }) : activeFilter?.emptyMessage ?? _({
668
+ id: 'canvas.node_variables_panel.filter_empty',
669
+ message: 'No variables match this filter.'
670
+ })
671
+ }),
672
+ children
673
+ ]
674
+ })
675
+ })
676
+ ]
677
+ })
678
+ }),
679
+ editing && onEditVariable && /*#__PURE__*/ jsx(NodeVariableEditDialog, {
680
+ variable: editing.details,
681
+ takenNames: siblingKeys(trees[editing.row.section], editing.row.node.path),
682
+ referenceFor: renamedReference(editing.row),
683
+ onSave: (next)=>{
684
+ onEditVariable(editing.row, next);
685
+ setEditing(null);
686
+ },
687
+ onClose: ()=>setEditing(null)
688
+ }, editing.row.node.path)
689
+ ]
690
+ });
691
+ }
692
+ export { NodeVariablesPanel };