@tduniec/plugin-template-designer-foundation 0.1.1

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 (78) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +13 -0
  3. package/dist/api/useScaffolderActions.esm.js +59 -0
  4. package/dist/api/useScaffolderActions.esm.js.map +1 -0
  5. package/dist/components/FieldEditorDialog.esm.js +55 -0
  6. package/dist/components/FieldEditorDialog.esm.js.map +1 -0
  7. package/dist/components/Nodes/ActionNode.esm.js +613 -0
  8. package/dist/components/Nodes/ActionNode.esm.js.map +1 -0
  9. package/dist/components/Nodes/OutputNode.esm.js +373 -0
  10. package/dist/components/Nodes/OutputNode.esm.js.map +1 -0
  11. package/dist/components/Nodes/ParameterInputNode.esm.js +320 -0
  12. package/dist/components/Nodes/ParameterInputNode.esm.js.map +1 -0
  13. package/dist/components/Nodes/ParameterTitlesNode.esm.js +251 -0
  14. package/dist/components/Nodes/ParameterTitlesNode.esm.js.map +1 -0
  15. package/dist/components/Nodes/ParametersNode.esm.js +147 -0
  16. package/dist/components/Nodes/ParametersNode.esm.js.map +1 -0
  17. package/dist/components/Nodes/action/schema.esm.js +68 -0
  18. package/dist/components/Nodes/action/schema.esm.js.map +1 -0
  19. package/dist/components/Nodes/action/useActionInputs.esm.js +71 -0
  20. package/dist/components/Nodes/action/useActionInputs.esm.js.map +1 -0
  21. package/dist/components/Nodes/common/AutoWidthPopper.esm.js +11 -0
  22. package/dist/components/Nodes/common/AutoWidthPopper.esm.js.map +1 -0
  23. package/dist/components/Nodes/common/nodeInteraction.esm.js +20 -0
  24. package/dist/components/Nodes/common/nodeInteraction.esm.js.map +1 -0
  25. package/dist/components/Nodes/output/useOutputController.esm.js +125 -0
  26. package/dist/components/Nodes/output/useOutputController.esm.js.map +1 -0
  27. package/dist/components/TemplateDesigner/TemplateLanding.esm.js +157 -0
  28. package/dist/components/TemplateDesigner/TemplateLanding.esm.js.map +1 -0
  29. package/dist/components/TemplateDesigner/TemplateWorkspace.esm.js +416 -0
  30. package/dist/components/TemplateDesigner/TemplateWorkspace.esm.js.map +1 -0
  31. package/dist/components/TemplateDesigner/codemirrorTheme.esm.js +30 -0
  32. package/dist/components/TemplateDesigner/codemirrorTheme.esm.js.map +1 -0
  33. package/dist/components/TemplateDesigner/useFieldEditor.esm.js +95 -0
  34. package/dist/components/TemplateDesigner/useFieldEditor.esm.js.map +1 -0
  35. package/dist/components/TemplateDesignerIcon.esm.js +33 -0
  36. package/dist/components/TemplateDesignerIcon.esm.js.map +1 -0
  37. package/dist/components/designerFlowConfig.esm.js +13 -0
  38. package/dist/components/designerFlowConfig.esm.js.map +1 -0
  39. package/dist/designerFlow/DesignerFlow.esm.js +828 -0
  40. package/dist/designerFlow/DesignerFlow.esm.js.map +1 -0
  41. package/dist/designerFlow/handlers.esm.js +317 -0
  42. package/dist/designerFlow/handlers.esm.js.map +1 -0
  43. package/dist/designerFlow/model.esm.js +166 -0
  44. package/dist/designerFlow/model.esm.js.map +1 -0
  45. package/dist/designerFlow/nodeLayout.esm.js +108 -0
  46. package/dist/designerFlow/nodeLayout.esm.js.map +1 -0
  47. package/dist/designerFlow/parameterTransforms.esm.js +124 -0
  48. package/dist/designerFlow/parameterTransforms.esm.js.map +1 -0
  49. package/dist/designerFlow/utils/stableComparators.esm.js +69 -0
  50. package/dist/designerFlow/utils/stableComparators.esm.js.map +1 -0
  51. package/dist/foundation/actionNodeCustomization.esm.js +20 -0
  52. package/dist/foundation/actionNodeCustomization.esm.js.map +1 -0
  53. package/dist/foundation/actionNodeRegistry.esm.js +30 -0
  54. package/dist/foundation/actionNodeRegistry.esm.js.map +1 -0
  55. package/dist/foundation/featureFlags.esm.js +6 -0
  56. package/dist/foundation/featureFlags.esm.js.map +1 -0
  57. package/dist/foundation/templateSources.esm.js +16 -0
  58. package/dist/foundation/templateSources.esm.js.map +1 -0
  59. package/dist/index.d.ts +382 -0
  60. package/dist/index.esm.js +25 -0
  61. package/dist/index.esm.js.map +1 -0
  62. package/dist/state/templateUtils.esm.js +46 -0
  63. package/dist/state/templateUtils.esm.js.map +1 -0
  64. package/dist/state/useParameterSections.esm.js +162 -0
  65. package/dist/state/useParameterSections.esm.js.map +1 -0
  66. package/dist/state/useTemplateState.esm.js +627 -0
  67. package/dist/state/useTemplateState.esm.js.map +1 -0
  68. package/dist/types/flowNodes.esm.js +8 -0
  69. package/dist/types/flowNodes.esm.js.map +1 -0
  70. package/dist/utils/createSequentialEdges.esm.js +15 -0
  71. package/dist/utils/createSequentialEdges.esm.js.map +1 -0
  72. package/dist/utils/mocks/mocks.esm.js +120 -0
  73. package/dist/utils/mocks/mocks.esm.js.map +1 -0
  74. package/dist/utils/sampleTemplate.esm.js +40 -0
  75. package/dist/utils/sampleTemplate.esm.js.map +1 -0
  76. package/dist/utils/yamlJsonConversion.esm.js +47 -0
  77. package/dist/utils/yamlJsonConversion.esm.js.map +1 -0
  78. package/package.json +103 -0
@@ -0,0 +1,613 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { memo, useState, useRef, useEffect } from 'react';
3
+ import { NodeToolbar, Position, Handle } from '@xyflow/react';
4
+ import { styled, useTheme } from '@material-ui/core/styles';
5
+ import { Box, Typography, IconButton, TextField, Button, Divider, Chip } from '@material-ui/core';
6
+ import DeleteOutlineIcon from '@material-ui/icons/DeleteOutline';
7
+ import AddIcon from '@material-ui/icons/Add';
8
+ import Autocomplete from '@material-ui/lab/Autocomplete';
9
+ import { normalizeSchemaType, buildTypeLabel, extractEnumOptions, stringifyValueForDisplay, coerceValueForType } from './action/schema.esm.js';
10
+ import { useActionInputs } from './action/useActionInputs.esm.js';
11
+ import { createStopNodeInteraction } from './common/nodeInteraction.esm.js';
12
+ import { AutoWidthPopper } from './common/AutoWidthPopper.esm.js';
13
+
14
+ const Card = styled(Box)(({ theme }) => ({
15
+ background: theme.palette.background.paper,
16
+ border: `1px solid ${theme.palette.divider}`,
17
+ borderRadius: 12,
18
+ width: 760,
19
+ // card width
20
+ padding: theme.spacing(1.5),
21
+ boxShadow: theme.shadows[2],
22
+ color: theme.palette.text.primary
23
+ }));
24
+ const Header = styled(Box)(({ theme }) => ({
25
+ display: "grid",
26
+ gridTemplateColumns: "1fr",
27
+ gap: theme.spacing(1),
28
+ marginBottom: theme.spacing(1)
29
+ }));
30
+ const Grid = styled(Box)(({ theme }) => ({
31
+ display: "grid",
32
+ gridTemplateColumns: "88px 1fr",
33
+ gap: theme.spacing(1),
34
+ alignItems: "center"
35
+ }));
36
+ const KvRow = styled(Box)(({ theme }) => ({
37
+ display: "grid",
38
+ gridTemplateColumns: "200px 140px 1fr auto",
39
+ gap: theme.spacing(1),
40
+ alignItems: "center"
41
+ }));
42
+ const DEFAULT_ACTION_OPTIONS = [
43
+ "fetch:template"
44
+ // TODO to be fixed later to not uses default actions
45
+ ];
46
+ const ActionNodeComponent = ({ data }) => {
47
+ const { rfId, step } = data;
48
+ if (process.env.NODE_ENV === "development") {
49
+ console.debug("[DesignerFlow] render ActionNode", rfId);
50
+ }
51
+ const [newKey, setNewKey] = useState("");
52
+ const [newVal, setNewVal] = useState("");
53
+ const stepOutputReferences = data.stepOutputReferences ?? [];
54
+ const [isConfirmingDelete, setIsConfirmingDelete] = useState(false);
55
+ const deleteConfirmationTimeoutRef = useRef(null);
56
+ const theme = useTheme();
57
+ const actionOptions = (data.scaffolderActionIds?.length ?? 0) > 0 ? data.scaffolderActionIds ?? [] : DEFAULT_ACTION_OPTIONS;
58
+ const handleTop = (field) => (e) => data.onUpdateField?.(rfId, field, e.target.value);
59
+ const actionId = typeof step?.action === "string" ? step.action : "";
60
+ const [actionInputValue, setActionInputValue] = useState(actionId);
61
+ useEffect(() => {
62
+ setActionInputValue(actionId);
63
+ }, [actionId]);
64
+ const {
65
+ actionInputSchema,
66
+ inputEntries,
67
+ usedInputKeys,
68
+ missingRequiredInputKeys,
69
+ availableInputOptions,
70
+ trimmedNewKey,
71
+ selectedNewKeyOption,
72
+ newKeyNormalizedType,
73
+ newKeyTypeLabel,
74
+ newKeyEnumOptions
75
+ } = useActionInputs({ data, step, actionId, newKey });
76
+ const displayedNewKeyTypeLabel = newKeyTypeLabel || "Any";
77
+ const hasMissingRequiredInputs = missingRequiredInputKeys.length > 0;
78
+ const isAddDisabled = !trimmedNewKey || usedInputKeys.has(trimmedNewKey);
79
+ const newValueOptions = Array.from(
80
+ /* @__PURE__ */ new Set([
81
+ ...newKeyNormalizedType === "boolean" ? ["true", "false"] : [],
82
+ ...newKeyEnumOptions,
83
+ ...stepOutputReferences
84
+ ])
85
+ );
86
+ const paletteMode = theme.palette.mode ?? theme.palette.type ?? "light";
87
+ const requiredInputsBackground = paletteMode === "dark" ? "rgba(244, 67, 54, 0.2)" : "rgba(244, 67, 54, 0.08)";
88
+ const addPair = () => {
89
+ const k = trimmedNewKey;
90
+ if (!k || usedInputKeys.has(k)) return;
91
+ const schema = selectedNewKeyOption?.schema ?? actionInputSchema?.[k];
92
+ const normalizedType = normalizeSchemaType(schema);
93
+ const parsedValue = coerceValueForType(newVal, normalizedType);
94
+ data.onUpdateInput?.(rfId, k, parsedValue);
95
+ setNewKey("");
96
+ setNewVal("");
97
+ };
98
+ const stopAll = createStopNodeInteraction();
99
+ useEffect(() => {
100
+ if (!isConfirmingDelete) {
101
+ if (deleteConfirmationTimeoutRef.current) {
102
+ clearTimeout(deleteConfirmationTimeoutRef.current);
103
+ deleteConfirmationTimeoutRef.current = null;
104
+ }
105
+ return void 0;
106
+ }
107
+ deleteConfirmationTimeoutRef.current = setTimeout(() => {
108
+ setIsConfirmingDelete(false);
109
+ deleteConfirmationTimeoutRef.current = null;
110
+ }, 3500);
111
+ return () => {
112
+ if (deleteConfirmationTimeoutRef.current) {
113
+ clearTimeout(deleteConfirmationTimeoutRef.current);
114
+ deleteConfirmationTimeoutRef.current = null;
115
+ }
116
+ };
117
+ }, [isConfirmingDelete]);
118
+ const handleDeleteNode = () => {
119
+ if (!data.onRemoveNode) {
120
+ return;
121
+ }
122
+ if (!isConfirmingDelete) {
123
+ setIsConfirmingDelete(true);
124
+ return;
125
+ }
126
+ data.onRemoveNode(rfId);
127
+ setIsConfirmingDelete(false);
128
+ };
129
+ return /* @__PURE__ */ jsxs(Card, { children: [
130
+ /* @__PURE__ */ jsxs(Header, { title: step?.name || "Unnamed Step", children: [
131
+ /* @__PURE__ */ jsxs(
132
+ Box,
133
+ {
134
+ style: {
135
+ display: "flex",
136
+ alignItems: "center",
137
+ justifyContent: "space-between",
138
+ gap: theme.spacing(1)
139
+ },
140
+ children: [
141
+ /* @__PURE__ */ jsx(Typography, { variant: "subtitle2", noWrap: true, children: step?.name || "Unnamed Step" }),
142
+ data.onRemoveNode && /* @__PURE__ */ jsxs(
143
+ Box,
144
+ {
145
+ style: {
146
+ display: "flex",
147
+ alignItems: "center",
148
+ gap: theme.spacing(0.5),
149
+ color: theme.palette.text.secondary
150
+ },
151
+ children: [
152
+ isConfirmingDelete && /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "error", children: "Click again to delete" }),
153
+ /* @__PURE__ */ jsx(
154
+ IconButton,
155
+ {
156
+ size: "small",
157
+ onClick: handleDeleteNode,
158
+ onPointerDown: (e) => e.stopPropagation(),
159
+ "aria-label": "Remove action",
160
+ color: isConfirmingDelete ? "secondary" : "default",
161
+ className: "nodrag nowheel",
162
+ children: /* @__PURE__ */ jsx(DeleteOutlineIcon, { fontSize: "small" })
163
+ }
164
+ )
165
+ ]
166
+ }
167
+ )
168
+ ]
169
+ }
170
+ ),
171
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", children: "Action" }),
172
+ /* @__PURE__ */ jsx(
173
+ Autocomplete,
174
+ {
175
+ size: "small",
176
+ options: actionOptions,
177
+ PopperComponent: AutoWidthPopper,
178
+ freeSolo: true,
179
+ autoHighlight: true,
180
+ value: actionId,
181
+ inputValue: actionInputValue,
182
+ filterOptions: (options) => {
183
+ const needle = actionInputValue.trim().toLowerCase();
184
+ if (!needle) {
185
+ return options;
186
+ }
187
+ return options.filter((opt) => opt.toLowerCase().includes(needle));
188
+ },
189
+ onChange: (_, newValue) => {
190
+ const nextValue = newValue ?? "";
191
+ setActionInputValue(nextValue);
192
+ data.onUpdateField?.(rfId, "action", nextValue);
193
+ },
194
+ onInputChange: (_, newInputValue, reason) => {
195
+ if (reason === "reset") {
196
+ return;
197
+ }
198
+ const nextValue = newInputValue ?? "";
199
+ setActionInputValue(nextValue);
200
+ data.onUpdateField?.(rfId, "action", nextValue);
201
+ },
202
+ onPointerDown: stopAll.onPointerDown,
203
+ onKeyDown: stopAll.onKeyDown,
204
+ className: stopAll.className,
205
+ fullWidth: true,
206
+ renderInput: (params) => /* @__PURE__ */ jsx(
207
+ TextField,
208
+ {
209
+ ...params,
210
+ size: "small",
211
+ placeholder: "e.g. fetch:template",
212
+ fullWidth: true,
213
+ inputProps: {
214
+ ...params.inputProps,
215
+ ...stopAll.inputProps
216
+ }
217
+ }
218
+ )
219
+ }
220
+ )
221
+ ] }),
222
+ /* @__PURE__ */ jsx(NodeToolbar, { position: Position.Bottom, children: /* @__PURE__ */ jsx(
223
+ Button,
224
+ {
225
+ variant: "outlined",
226
+ size: "small",
227
+ startIcon: /* @__PURE__ */ jsx(AddIcon, { fontSize: "small" }),
228
+ onClick: () => data.onAddNode?.({
229
+ afterRfId: rfId,
230
+ type: "actionNode"
231
+ }),
232
+ onPointerDown: (e) => e.stopPropagation(),
233
+ className: "nodrag nowheel",
234
+ children: "Add Action"
235
+ }
236
+ ) }),
237
+ /* @__PURE__ */ jsx(Divider, {}),
238
+ /* @__PURE__ */ jsx(Box, { sx: { mb: 1 }, children: /* @__PURE__ */ jsxs(Grid, { children: [
239
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", children: "ID" }),
240
+ /* @__PURE__ */ jsx(
241
+ TextField,
242
+ {
243
+ size: "small",
244
+ placeholder: "string id",
245
+ value: String(step?.id ?? ""),
246
+ onChange: handleTop("id"),
247
+ fullWidth: true,
248
+ ...stopAll
249
+ }
250
+ ),
251
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", children: "Name" }),
252
+ /* @__PURE__ */ jsx(
253
+ TextField,
254
+ {
255
+ size: "small",
256
+ placeholder: "Step name",
257
+ value: String(step?.name ?? ""),
258
+ onChange: handleTop("name"),
259
+ fullWidth: true,
260
+ ...stopAll
261
+ }
262
+ )
263
+ ] }) }),
264
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", children: "Inputs" }),
265
+ /* @__PURE__ */ jsxs(Box, { sx: { display: "grid", mt: 0.5 }, children: [
266
+ inputEntries.length === 0 && /* @__PURE__ */ jsx(
267
+ Box,
268
+ {
269
+ sx: {
270
+ fontSize: 12,
271
+ color: theme.palette.text.secondary,
272
+ border: `1px dashed ${theme.palette.divider}`,
273
+ borderRadius: 1,
274
+ p: 1,
275
+ textAlign: "center"
276
+ },
277
+ children: "No inputs yet"
278
+ }
279
+ ),
280
+ /* @__PURE__ */ jsxs(
281
+ KvRow,
282
+ {
283
+ sx: {
284
+ mt: inputEntries.length === 0 ? 1.5 : 0.5,
285
+ color: theme.palette.text.secondary
286
+ },
287
+ children: [
288
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", children: "Key" }),
289
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", children: "Type" }),
290
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "textSecondary", children: "Value" }),
291
+ /* @__PURE__ */ jsx(Box, {})
292
+ ]
293
+ }
294
+ ),
295
+ inputEntries.map(([k, v]) => {
296
+ const schema = actionInputSchema?.[k];
297
+ const normalizedType = normalizeSchemaType(schema, v);
298
+ const fallbackTypeLabel = normalizedType === "unknown" ? "Unknown" : normalizedType[0].toUpperCase() + normalizedType.slice(1);
299
+ const typeLabel = buildTypeLabel(schema) || fallbackTypeLabel;
300
+ const enumOptions = extractEnumOptions(schema);
301
+ const baseOptions = normalizedType === "boolean" ? ["true", "false"] : [];
302
+ const options = Array.from(
303
+ /* @__PURE__ */ new Set([...baseOptions, ...enumOptions, ...stepOutputReferences])
304
+ );
305
+ const displayValue = stringifyValueForDisplay(v, normalizedType);
306
+ const handleStringChange = (nextValue) => {
307
+ const parsed = coerceValueForType(nextValue, normalizedType);
308
+ data.onUpdateInput?.(rfId, k, parsed);
309
+ };
310
+ return /* @__PURE__ */ jsxs(KvRow, { children: [
311
+ /* @__PURE__ */ jsx(
312
+ Typography,
313
+ {
314
+ variant: "caption",
315
+ noWrap: true,
316
+ title: k,
317
+ color: "textSecondary",
318
+ children: k
319
+ }
320
+ ),
321
+ /* @__PURE__ */ jsx(Box, { display: "flex", children: /* @__PURE__ */ jsx(Chip, { size: "small", variant: "outlined", label: typeLabel }) }),
322
+ (normalizedType === "array" || normalizedType === "object") && /* @__PURE__ */ jsx(
323
+ TextField,
324
+ {
325
+ size: "small",
326
+ value: displayValue,
327
+ onChange: (event) => handleStringChange(event.target.value),
328
+ placeholder: "JSON value",
329
+ fullWidth: true,
330
+ multiline: true,
331
+ minRows: 2,
332
+ inputProps: {
333
+ ...stopAll.inputProps
334
+ },
335
+ onPointerDown: stopAll.onPointerDown,
336
+ onKeyDown: stopAll.onKeyDown,
337
+ className: stopAll.className
338
+ }
339
+ ),
340
+ (normalizedType === "number" || normalizedType === "integer") && /* @__PURE__ */ jsx(
341
+ TextField,
342
+ {
343
+ size: "small",
344
+ value: displayValue,
345
+ onChange: (event) => handleStringChange(event.target.value),
346
+ placeholder: "Number",
347
+ fullWidth: true,
348
+ inputProps: {
349
+ ...stopAll.inputProps,
350
+ inputMode: "decimal"
351
+ },
352
+ onPointerDown: stopAll.onPointerDown,
353
+ onKeyDown: stopAll.onKeyDown,
354
+ className: stopAll.className
355
+ }
356
+ ),
357
+ normalizedType !== "array" && normalizedType !== "object" && normalizedType !== "number" && normalizedType !== "integer" && /* @__PURE__ */ jsx(
358
+ Autocomplete,
359
+ {
360
+ size: "small",
361
+ freeSolo: true,
362
+ options,
363
+ PopperComponent: AutoWidthPopper,
364
+ value: displayValue,
365
+ inputValue: displayValue,
366
+ fullWidth: true,
367
+ onChange: (_, value) => handleStringChange(value ?? ""),
368
+ onInputChange: (_, value, reason) => {
369
+ if (reason === "reset") {
370
+ return;
371
+ }
372
+ handleStringChange(value ?? "");
373
+ },
374
+ onPointerDown: stopAll.onPointerDown,
375
+ onKeyDown: stopAll.onKeyDown,
376
+ className: stopAll.className,
377
+ renderInput: (params) => /* @__PURE__ */ jsx(
378
+ TextField,
379
+ {
380
+ ...params,
381
+ size: "small",
382
+ placeholder: "value",
383
+ inputProps: {
384
+ ...params.inputProps,
385
+ ...stopAll.inputProps
386
+ }
387
+ }
388
+ )
389
+ }
390
+ ),
391
+ /* @__PURE__ */ jsx(
392
+ IconButton,
393
+ {
394
+ size: "small",
395
+ onClick: () => data.onRemoveInputKey?.(rfId, k),
396
+ onPointerDown: (e) => e.stopPropagation(),
397
+ "aria-label": `Remove ${k}`,
398
+ className: "nodrag nowheel",
399
+ children: /* @__PURE__ */ jsx(DeleteOutlineIcon, { fontSize: "small" })
400
+ }
401
+ )
402
+ ] }, k);
403
+ }),
404
+ /* @__PURE__ */ jsxs(KvRow, { children: [
405
+ /* @__PURE__ */ jsx(
406
+ Autocomplete,
407
+ {
408
+ size: "small",
409
+ freeSolo: true,
410
+ options: availableInputOptions,
411
+ PopperComponent: AutoWidthPopper,
412
+ value: selectedNewKeyOption,
413
+ inputValue: newKey,
414
+ filterOptions: (options) => {
415
+ const needle = newKey.trim().toLowerCase();
416
+ if (!needle) {
417
+ return options;
418
+ }
419
+ return options.filter(
420
+ (option) => (typeof option === "string" ? option : option.label).toLowerCase().includes(needle)
421
+ );
422
+ },
423
+ onChange: (_, value) => {
424
+ if (!value) {
425
+ setNewKey("");
426
+ return;
427
+ }
428
+ if (typeof value === "string") {
429
+ setNewKey(value);
430
+ return;
431
+ }
432
+ setNewKey(value.key);
433
+ },
434
+ onInputChange: (_, value, reason) => {
435
+ if (reason === "reset") {
436
+ return;
437
+ }
438
+ setNewKey(value ?? "");
439
+ },
440
+ onPointerDown: stopAll.onPointerDown,
441
+ onKeyDown: stopAll.onKeyDown,
442
+ className: stopAll.className,
443
+ getOptionSelected: (option, value) => option.key === value?.key,
444
+ getOptionLabel: (option) => typeof option === "string" ? option : option.label,
445
+ renderInput: (params) => /* @__PURE__ */ jsx(
446
+ TextField,
447
+ {
448
+ ...params,
449
+ size: "small",
450
+ placeholder: "new key",
451
+ inputProps: {
452
+ ...params.inputProps,
453
+ ...stopAll.inputProps
454
+ }
455
+ }
456
+ )
457
+ }
458
+ ),
459
+ /* @__PURE__ */ jsx(Box, { display: "flex", children: /* @__PURE__ */ jsx(
460
+ Chip,
461
+ {
462
+ size: "small",
463
+ variant: "outlined",
464
+ label: displayedNewKeyTypeLabel
465
+ }
466
+ ) }),
467
+ (newKeyNormalizedType === "array" || newKeyNormalizedType === "object") && /* @__PURE__ */ jsx(
468
+ TextField,
469
+ {
470
+ size: "small",
471
+ value: newVal,
472
+ onChange: (event) => setNewVal(event.target.value),
473
+ placeholder: "JSON value",
474
+ fullWidth: true,
475
+ multiline: true,
476
+ minRows: 2,
477
+ inputProps: {
478
+ ...stopAll.inputProps
479
+ },
480
+ onPointerDown: stopAll.onPointerDown,
481
+ onKeyDown: stopAll.onKeyDown,
482
+ className: stopAll.className
483
+ }
484
+ ),
485
+ (newKeyNormalizedType === "number" || newKeyNormalizedType === "integer") && /* @__PURE__ */ jsx(
486
+ TextField,
487
+ {
488
+ size: "small",
489
+ value: newVal,
490
+ onChange: (event) => setNewVal(event.target.value),
491
+ placeholder: "Number",
492
+ fullWidth: true,
493
+ inputProps: {
494
+ ...stopAll.inputProps,
495
+ inputMode: "decimal"
496
+ },
497
+ onPointerDown: stopAll.onPointerDown,
498
+ onKeyDown: stopAll.onKeyDown,
499
+ className: stopAll.className
500
+ }
501
+ ),
502
+ newKeyNormalizedType !== "array" && newKeyNormalizedType !== "object" && newKeyNormalizedType !== "number" && newKeyNormalizedType !== "integer" && /* @__PURE__ */ jsx(
503
+ Autocomplete,
504
+ {
505
+ size: "small",
506
+ freeSolo: true,
507
+ options: newValueOptions,
508
+ PopperComponent: AutoWidthPopper,
509
+ value: newVal,
510
+ inputValue: newVal,
511
+ fullWidth: true,
512
+ filterOptions: (options) => {
513
+ const needle = newVal.trim().toLowerCase();
514
+ if (!needle) {
515
+ return options;
516
+ }
517
+ return options.filter((option) => {
518
+ const raw = String(option);
519
+ const normalized = raw.replace(/^\s*\$\{\{\s*/, "").replace(/\s*\}\}\s*$/, "");
520
+ const haystacks = [
521
+ raw.toLowerCase(),
522
+ normalized.toLowerCase()
523
+ ];
524
+ return haystacks.some(
525
+ (haystack) => haystack.includes(needle)
526
+ );
527
+ });
528
+ },
529
+ onChange: (_, value) => setNewVal(value ?? ""),
530
+ onInputChange: (_, value, reason) => {
531
+ if (reason === "reset") {
532
+ return;
533
+ }
534
+ setNewVal(value ?? "");
535
+ },
536
+ onPointerDown: stopAll.onPointerDown,
537
+ onKeyDown: stopAll.onKeyDown,
538
+ className: stopAll.className,
539
+ renderInput: (params) => /* @__PURE__ */ jsx(
540
+ TextField,
541
+ {
542
+ ...params,
543
+ size: "small",
544
+ placeholder: "new value",
545
+ inputProps: {
546
+ ...params.inputProps,
547
+ ...stopAll.inputProps
548
+ }
549
+ }
550
+ )
551
+ }
552
+ ),
553
+ /* @__PURE__ */ jsx(
554
+ Button,
555
+ {
556
+ size: "small",
557
+ variant: "contained",
558
+ onClick: addPair,
559
+ onPointerDown: (e) => e.stopPropagation(),
560
+ disabled: isAddDisabled,
561
+ className: "nodrag nowheel",
562
+ children: "Add"
563
+ }
564
+ )
565
+ ] })
566
+ ] }),
567
+ hasMissingRequiredInputs && /* @__PURE__ */ jsxs(
568
+ Box,
569
+ {
570
+ sx: {
571
+ mt: 1.5,
572
+ p: 1,
573
+ borderRadius: 1,
574
+ border: `1px solid ${theme.palette.error.main}`
575
+ },
576
+ style: { backgroundColor: requiredInputsBackground },
577
+ children: [
578
+ /* @__PURE__ */ jsx(Typography, { variant: "caption", color: "error", children: "Missing required inputs" }),
579
+ /* @__PURE__ */ jsx(
580
+ Box,
581
+ {
582
+ sx: {
583
+ display: "flex",
584
+ flexWrap: "wrap",
585
+ mt: 0.75
586
+ },
587
+ style: { gap: theme.spacing(0.5) },
588
+ children: missingRequiredInputKeys.map((key) => /* @__PURE__ */ jsx(
589
+ Chip,
590
+ {
591
+ size: "small",
592
+ variant: "outlined",
593
+ label: key,
594
+ style: {
595
+ borderColor: theme.palette.error.main,
596
+ color: theme.palette.error.main
597
+ }
598
+ },
599
+ key
600
+ ))
601
+ }
602
+ )
603
+ ]
604
+ }
605
+ ),
606
+ /* @__PURE__ */ jsx(Handle, { type: "target", position: Position.Top }),
607
+ /* @__PURE__ */ jsx(Handle, { type: "source", position: Position.Bottom })
608
+ ] });
609
+ };
610
+ const ActionNode = memo(ActionNodeComponent);
611
+
612
+ export { ActionNode };
613
+ //# sourceMappingURL=ActionNode.esm.js.map