@checkstack/ui 1.11.0 → 1.13.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.
- package/.storybook/main.ts +43 -0
- package/CHANGELOG.md +326 -0
- package/package.json +23 -18
- package/scripts/generate-stdlib-types.ts +23 -0
- package/src/components/Accordion.tsx +17 -9
- package/src/components/ActionCard.tsx +99 -11
- package/src/components/BrandIcon.tsx +57 -0
- package/src/components/CodeEditor/CodeEditor.tsx +159 -14
- package/src/components/CodeEditor/TypefoxEditor.tsx +537 -168
- package/src/components/CodeEditor/editorTheme.test.ts +41 -0
- package/src/components/CodeEditor/editorTheme.ts +26 -0
- package/src/components/CodeEditor/generated/builtin-modules.json +1 -0
- package/src/components/CodeEditor/importSpecifiers.test.ts +286 -0
- package/src/components/CodeEditor/importSpecifiers.ts +267 -0
- package/src/components/CodeEditor/index.ts +26 -0
- package/src/components/CodeEditor/monacoGuard.ts +76 -0
- package/src/components/CodeEditor/monacoTsService.ts +185 -0
- package/src/components/CodeEditor/popoutTitle.test.ts +37 -0
- package/src/components/CodeEditor/popoutTitle.ts +31 -0
- package/src/components/CodeEditor/scriptContext.test.ts +15 -7
- package/src/components/CodeEditor/scriptContext.ts +12 -18
- package/src/components/CodeEditor/scriptDiagnostics.test.ts +135 -0
- package/src/components/CodeEditor/scriptDiagnostics.ts +172 -0
- package/src/components/CodeEditor/types.ts +79 -0
- package/src/components/CodeEditor/validateScripts.ts +172 -0
- package/src/components/CodeEditor/vscodeServicesSignal.ts +72 -0
- package/src/components/ConfirmationModal.tsx +7 -1
- package/src/components/Dialog.tsx +32 -11
- package/src/components/DurationInput.tsx +121 -0
- package/src/components/DynamicForm/DynamicForm.tsx +119 -47
- package/src/components/DynamicForm/DynamicOptionsField.tsx +19 -14
- package/src/components/DynamicForm/FormField.tsx +183 -15
- package/src/components/DynamicForm/MultiTypeEditorField.tsx +78 -2
- package/src/components/DynamicForm/SecretEnvEditor.tsx +315 -0
- package/src/components/DynamicForm/index.ts +20 -0
- package/src/components/DynamicForm/secretEnv.logic.test.ts +126 -0
- package/src/components/DynamicForm/secretEnv.logic.ts +87 -0
- package/src/components/DynamicForm/types.ts +134 -1
- package/src/components/DynamicForm/utils.test.ts +38 -0
- package/src/components/DynamicForm/utils.ts +54 -0
- package/src/components/DynamicForm/validation.logic.test.ts +255 -0
- package/src/components/DynamicForm/validation.logic.ts +210 -0
- package/src/components/DynamicIcon.tsx +39 -17
- package/src/components/Markdown.tsx +68 -2
- package/src/components/Popover.tsx +6 -1
- package/src/components/ScriptTestPanel.logic.test.ts +139 -0
- package/src/components/ScriptTestPanel.logic.ts +137 -0
- package/src/components/ScriptTestPanel.tsx +394 -0
- package/src/components/Sheet.tsx +21 -6
- package/src/components/Spinner.tsx +56 -0
- package/src/components/StatusBadge.tsx +78 -0
- package/src/components/StrategyConfigCard.tsx +3 -3
- package/src/components/Tabs.tsx +7 -1
- package/src/components/TimeOfDayInput.tsx +116 -0
- package/src/components/UserMenu.logic.test.ts +37 -0
- package/src/components/UserMenu.logic.ts +30 -0
- package/src/components/UserMenu.tsx +40 -12
- package/src/components/comboboxInteraction.ts +39 -0
- package/src/components/iconRegistry.tsx +27 -0
- package/src/components/portalContainer.ts +24 -0
- package/src/index.ts +7 -0
- package/stories/ActionCard.stories.tsx +60 -0
- package/stories/CodeEditor.stories.tsx +47 -2
- package/stories/DurationInput.stories.tsx +59 -0
- package/stories/Introduction.mdx +1 -1
- package/stories/Markdown.stories.tsx +56 -0
- package/stories/ScriptTestPanel.stories.tsx +106 -0
- package/stories/SecretEnvEditor.stories.tsx +80 -0
- package/stories/Spinner.stories.tsx +90 -0
- package/stories/TimeOfDayInput.stories.tsx +34 -0
- package/tsconfig.json +4 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
2
|
import { Plus, Trash2 } from "lucide-react";
|
|
3
|
+
import { renderTemplatePreview } from "@checkstack/template-engine";
|
|
3
4
|
|
|
4
5
|
import {
|
|
5
6
|
Input,
|
|
@@ -14,13 +15,21 @@ import {
|
|
|
14
15
|
Toggle,
|
|
15
16
|
ColorPicker,
|
|
16
17
|
TemplateValueInput,
|
|
18
|
+
DurationInput,
|
|
19
|
+
type DurationValue,
|
|
17
20
|
} from "../../index";
|
|
18
21
|
|
|
19
22
|
import type { FormFieldProps, JsonSchemaProperty } from "./types";
|
|
20
|
-
import {
|
|
23
|
+
import {
|
|
24
|
+
getCleanDescription,
|
|
25
|
+
NONE_SENTINEL,
|
|
26
|
+
findSecretEnvSibling,
|
|
27
|
+
nestedChildrenRequired,
|
|
28
|
+
} from "./utils";
|
|
21
29
|
import { DynamicOptionsField } from "./DynamicOptionsField";
|
|
22
30
|
import { JsonField } from "./JsonField";
|
|
23
31
|
import { MultiTypeEditorField } from "./MultiTypeEditorField";
|
|
32
|
+
import { SecretEnvEditor } from "./SecretEnvEditor";
|
|
24
33
|
|
|
25
34
|
/**
|
|
26
35
|
* Recursive field renderer that handles all supported JSON Schema types.
|
|
@@ -38,6 +47,15 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
38
47
|
typeDefinitions,
|
|
39
48
|
shellEnvVars,
|
|
40
49
|
starterTemplates,
|
|
50
|
+
scriptTestRenderer,
|
|
51
|
+
secretNames,
|
|
52
|
+
acquireTypes,
|
|
53
|
+
acquireResetKey,
|
|
54
|
+
sdkTypes,
|
|
55
|
+
sdkTypesResetKey,
|
|
56
|
+
importablePackages,
|
|
57
|
+
templatePreviewContext,
|
|
58
|
+
siblingSecretEnv,
|
|
41
59
|
onChange,
|
|
42
60
|
}) => {
|
|
43
61
|
const description = propSchema.description || "";
|
|
@@ -74,6 +92,34 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
74
92
|
return <></>;
|
|
75
93
|
}
|
|
76
94
|
|
|
95
|
+
// Duration field — render the DurationInput (single-unit duration
|
|
96
|
+
// object). Marked via `x-duration: true` or `format: "duration"`. This
|
|
97
|
+
// branch is intentionally additive and sits before the generic union /
|
|
98
|
+
// object handlers so a `for:` / threshold-window config renders the
|
|
99
|
+
// widget rather than the raw oneOf discriminator picker.
|
|
100
|
+
const isDuration =
|
|
101
|
+
propSchema["x-duration"] === true || propSchema.format === "duration";
|
|
102
|
+
if (isDuration) {
|
|
103
|
+
const cleanDesc = getCleanDescription(description);
|
|
104
|
+
return (
|
|
105
|
+
<div className="space-y-2">
|
|
106
|
+
<div>
|
|
107
|
+
<Label htmlFor={id}>
|
|
108
|
+
{label} {isRequired && "*"}
|
|
109
|
+
</Label>
|
|
110
|
+
{cleanDesc && (
|
|
111
|
+
<p className="text-sm text-muted-foreground mt-0.5">{cleanDesc}</p>
|
|
112
|
+
)}
|
|
113
|
+
</div>
|
|
114
|
+
<DurationInput
|
|
115
|
+
id={id}
|
|
116
|
+
value={value as DurationValue | undefined}
|
|
117
|
+
onChange={(next) => onChange(next)}
|
|
118
|
+
/>
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
77
123
|
// Enum handling
|
|
78
124
|
if (propSchema.enum) {
|
|
79
125
|
const cleanDesc = getCleanDescription(description);
|
|
@@ -126,19 +172,39 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
126
172
|
const editorTypes = propSchema["x-editor-types"];
|
|
127
173
|
if (editorTypes && editorTypes.length > 0) {
|
|
128
174
|
return (
|
|
129
|
-
<
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
175
|
+
<div className="space-y-2">
|
|
176
|
+
<MultiTypeEditorField
|
|
177
|
+
id={id}
|
|
178
|
+
label={label}
|
|
179
|
+
description={cleanDesc}
|
|
180
|
+
value={value as string | undefined}
|
|
181
|
+
isRequired={isRequired}
|
|
182
|
+
editorTypes={editorTypes}
|
|
183
|
+
templateProperties={templateProperties}
|
|
184
|
+
typeDefinitions={typeDefinitions}
|
|
185
|
+
shellEnvVars={shellEnvVars}
|
|
186
|
+
starterTemplates={starterTemplates}
|
|
187
|
+
scriptTestRenderer={
|
|
188
|
+
propSchema["x-script-testable"] === true
|
|
189
|
+
? scriptTestRenderer
|
|
190
|
+
: undefined
|
|
191
|
+
}
|
|
192
|
+
acquireTypes={acquireTypes}
|
|
193
|
+
acquireResetKey={acquireResetKey}
|
|
194
|
+
sdkTypes={sdkTypes}
|
|
195
|
+
sdkTypesResetKey={sdkTypesResetKey}
|
|
196
|
+
importablePackages={importablePackages}
|
|
197
|
+
fieldId={id}
|
|
198
|
+
siblingSecretEnv={siblingSecretEnv}
|
|
199
|
+
onChange={onChange as (val: string | undefined) => void}
|
|
200
|
+
/>
|
|
201
|
+
{propSchema["x-templatable"] && templatePreviewContext && (
|
|
202
|
+
<TemplatePreviewLine
|
|
203
|
+
value={(value as string) || ""}
|
|
204
|
+
context={templatePreviewContext}
|
|
205
|
+
/>
|
|
206
|
+
)}
|
|
207
|
+
</div>
|
|
142
208
|
);
|
|
143
209
|
}
|
|
144
210
|
|
|
@@ -268,6 +334,12 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
268
334
|
placeholder={placeholder}
|
|
269
335
|
/>
|
|
270
336
|
)}
|
|
337
|
+
{propSchema["x-templatable"] && templatePreviewContext && (
|
|
338
|
+
<TemplatePreviewLine
|
|
339
|
+
value={(value as string) || ""}
|
|
340
|
+
context={templatePreviewContext}
|
|
341
|
+
/>
|
|
342
|
+
)}
|
|
271
343
|
</div>
|
|
272
344
|
);
|
|
273
345
|
}
|
|
@@ -331,6 +403,34 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
331
403
|
}
|
|
332
404
|
|
|
333
405
|
// Dictionary/Record (headers)
|
|
406
|
+
// Secret -> env mapping: a dedicated editor (env name + secret-name
|
|
407
|
+
// picker) instead of the raw JSON record fallback.
|
|
408
|
+
if (
|
|
409
|
+
propSchema.type === "object" &&
|
|
410
|
+
propSchema.additionalProperties &&
|
|
411
|
+
propSchema["x-secret-env"]
|
|
412
|
+
) {
|
|
413
|
+
const cleanDesc = getCleanDescription(description);
|
|
414
|
+
return (
|
|
415
|
+
<div className="space-y-2">
|
|
416
|
+
<div>
|
|
417
|
+
<Label htmlFor={id}>
|
|
418
|
+
{label} {isRequired && "*"}
|
|
419
|
+
</Label>
|
|
420
|
+
{cleanDesc && (
|
|
421
|
+
<p className="text-sm text-muted-foreground mt-0.5">{cleanDesc}</p>
|
|
422
|
+
)}
|
|
423
|
+
</div>
|
|
424
|
+
<SecretEnvEditor
|
|
425
|
+
id={id}
|
|
426
|
+
value={(value as Record<string, string> | undefined) ?? {}}
|
|
427
|
+
secretNames={secretNames}
|
|
428
|
+
onChange={(next) => onChange(next)}
|
|
429
|
+
/>
|
|
430
|
+
</div>
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
|
|
334
434
|
if (propSchema.type === "object" && propSchema.additionalProperties) {
|
|
335
435
|
const cleanDesc = getCleanDescription(description);
|
|
336
436
|
return (
|
|
@@ -355,6 +455,20 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
355
455
|
|
|
356
456
|
// Object (Nested Form)
|
|
357
457
|
if (propSchema.type === "object" && propSchema.properties) {
|
|
458
|
+
// Resolve the secret→env sibling within THIS object so a nested
|
|
459
|
+
// testable script field forwards the right mapping to the test panel.
|
|
460
|
+
const nestedSecretEnv = findSecretEnvSibling({
|
|
461
|
+
properties: propSchema.properties,
|
|
462
|
+
values: value as Record<string, unknown> | undefined,
|
|
463
|
+
});
|
|
464
|
+
// An OPTIONAL nested object (e.g. an opt-in spend cap) only marks its
|
|
465
|
+
// schema-required children with `*` once the operator starts providing the
|
|
466
|
+
// object; while empty, supplying it is optional. A required object always
|
|
467
|
+
// marks them. (See nestedChildrenRequired.)
|
|
468
|
+
const childrenRequired = nestedChildrenRequired({
|
|
469
|
+
objectRequired: isRequired ?? false,
|
|
470
|
+
objectValue: value,
|
|
471
|
+
});
|
|
358
472
|
return (
|
|
359
473
|
<div className="space-y-4 p-4 border rounded-lg bg-muted/30">
|
|
360
474
|
<p className="text-sm font-semibold">{label}</p>
|
|
@@ -365,7 +479,7 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
365
479
|
label={key.charAt(0).toUpperCase() + key.slice(1)}
|
|
366
480
|
propSchema={subSchema}
|
|
367
481
|
value={(value as Record<string, unknown>)?.[key]}
|
|
368
|
-
isRequired={propSchema.required?.includes(key)}
|
|
482
|
+
isRequired={childrenRequired && (propSchema.required?.includes(key) ?? false)}
|
|
369
483
|
formValues={formValues}
|
|
370
484
|
optionsResolvers={optionsResolvers}
|
|
371
485
|
templateProperties={templateProperties}
|
|
@@ -373,6 +487,15 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
373
487
|
typeDefinitions={typeDefinitions}
|
|
374
488
|
shellEnvVars={shellEnvVars}
|
|
375
489
|
starterTemplates={starterTemplates}
|
|
490
|
+
scriptTestRenderer={scriptTestRenderer}
|
|
491
|
+
secretNames={secretNames}
|
|
492
|
+
acquireTypes={acquireTypes}
|
|
493
|
+
acquireResetKey={acquireResetKey}
|
|
494
|
+
sdkTypes={sdkTypes}
|
|
495
|
+
sdkTypesResetKey={sdkTypesResetKey}
|
|
496
|
+
importablePackages={importablePackages}
|
|
497
|
+
templatePreviewContext={templatePreviewContext}
|
|
498
|
+
siblingSecretEnv={nestedSecretEnv}
|
|
376
499
|
onChange={(val) =>
|
|
377
500
|
onChange({ ...(value as Record<string, unknown>), [key]: val })
|
|
378
501
|
}
|
|
@@ -485,6 +608,14 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
485
608
|
typeDefinitions={typeDefinitions}
|
|
486
609
|
shellEnvVars={shellEnvVars}
|
|
487
610
|
starterTemplates={starterTemplates}
|
|
611
|
+
scriptTestRenderer={scriptTestRenderer}
|
|
612
|
+
secretNames={secretNames}
|
|
613
|
+
acquireTypes={acquireTypes}
|
|
614
|
+
acquireResetKey={acquireResetKey}
|
|
615
|
+
sdkTypes={sdkTypes}
|
|
616
|
+
sdkTypesResetKey={sdkTypesResetKey}
|
|
617
|
+
importablePackages={importablePackages}
|
|
618
|
+
templatePreviewContext={templatePreviewContext}
|
|
488
619
|
onChange={(val) => {
|
|
489
620
|
const next = [...(items as unknown[])];
|
|
490
621
|
next[index] = val;
|
|
@@ -543,6 +674,12 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
543
674
|
const displayDiscriminatorField =
|
|
544
675
|
discriminatorField.charAt(0).toUpperCase() + discriminatorField.slice(1);
|
|
545
676
|
|
|
677
|
+
// Secret→env sibling within the selected variant's object.
|
|
678
|
+
const variantSecretEnv = findSecretEnvSibling({
|
|
679
|
+
properties: selectedVariant.properties,
|
|
680
|
+
values: currentValue,
|
|
681
|
+
});
|
|
682
|
+
|
|
546
683
|
return (
|
|
547
684
|
<div className="space-y-3 p-3 border rounded-lg bg-background">
|
|
548
685
|
{/* Discriminator selector */}
|
|
@@ -617,6 +754,15 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
617
754
|
typeDefinitions={typeDefinitions}
|
|
618
755
|
shellEnvVars={shellEnvVars}
|
|
619
756
|
starterTemplates={starterTemplates}
|
|
757
|
+
scriptTestRenderer={scriptTestRenderer}
|
|
758
|
+
secretNames={secretNames}
|
|
759
|
+
acquireTypes={acquireTypes}
|
|
760
|
+
acquireResetKey={acquireResetKey}
|
|
761
|
+
sdkTypes={sdkTypes}
|
|
762
|
+
sdkTypesResetKey={sdkTypesResetKey}
|
|
763
|
+
importablePackages={importablePackages}
|
|
764
|
+
templatePreviewContext={templatePreviewContext}
|
|
765
|
+
siblingSecretEnv={variantSecretEnv}
|
|
620
766
|
onChange={(val) => onChange({ ...currentValue, [key]: val })}
|
|
621
767
|
/>
|
|
622
768
|
))}
|
|
@@ -627,6 +773,28 @@ export const FormField: React.FC<FormFieldProps> = ({
|
|
|
627
773
|
return <></>;
|
|
628
774
|
};
|
|
629
775
|
|
|
776
|
+
/**
|
|
777
|
+
* Inline preview of a templatable field's rendered output against a sample
|
|
778
|
+
* context. Shown below `x-templatable` string fields when the owning form
|
|
779
|
+
* supplies a `templatePreviewContext`. Pure render (no DOM/Monaco), so it
|
|
780
|
+
* matches the run-time `x-templatable` pass exactly.
|
|
781
|
+
*/
|
|
782
|
+
const TemplatePreviewLine: React.FC<{
|
|
783
|
+
value: string;
|
|
784
|
+
context: Record<string, unknown>;
|
|
785
|
+
}> = ({ value, context }) => {
|
|
786
|
+
if (!value || !value.includes("{{")) return null;
|
|
787
|
+
const rendered = renderTemplatePreview({ value, context });
|
|
788
|
+
return (
|
|
789
|
+
<p className="text-xs text-muted-foreground">
|
|
790
|
+
Preview:{" "}
|
|
791
|
+
<span className="font-mono break-all text-foreground">
|
|
792
|
+
{rendered || "(empty)"}
|
|
793
|
+
</span>
|
|
794
|
+
</p>
|
|
795
|
+
);
|
|
796
|
+
};
|
|
797
|
+
|
|
630
798
|
/**
|
|
631
799
|
* Shared visibility toggle button for secret fields.
|
|
632
800
|
*/
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Label } from "../Label";
|
|
3
3
|
import { Textarea } from "../Textarea";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
CodeEditor,
|
|
6
|
+
type TemplateProperty,
|
|
7
|
+
type AcquireTypes,
|
|
8
|
+
type AcquiredTypeFile,
|
|
9
|
+
} from "../CodeEditor";
|
|
5
10
|
import {
|
|
6
11
|
Select,
|
|
7
12
|
SelectContent,
|
|
@@ -17,7 +22,11 @@ import {
|
|
|
17
22
|
parseFormData,
|
|
18
23
|
EDITOR_TYPE_LABELS,
|
|
19
24
|
} from "./utils";
|
|
20
|
-
import type {
|
|
25
|
+
import type {
|
|
26
|
+
EditorStarterTemplates,
|
|
27
|
+
ScriptTestRenderer,
|
|
28
|
+
ShellEnvVar,
|
|
29
|
+
} from "./types";
|
|
21
30
|
import { pickStarterForEmptyField } from "./starterTemplateSelector";
|
|
22
31
|
|
|
23
32
|
export interface MultiTypeEditorFieldProps {
|
|
@@ -54,6 +63,38 @@ export interface MultiTypeEditorFieldProps {
|
|
|
54
63
|
* working example instead of a blank canvas.
|
|
55
64
|
*/
|
|
56
65
|
starterTemplates?: EditorStarterTemplates;
|
|
66
|
+
/**
|
|
67
|
+
* Optional renderer for the inline script-test panel. When supplied (the
|
|
68
|
+
* field is `x-script-testable`), it is rendered beneath the editor for
|
|
69
|
+
* `typescript` / `shell` modes, with the currently-selected language as
|
|
70
|
+
* `kind`. The owning page wires it to the `testScript` RPC.
|
|
71
|
+
*/
|
|
72
|
+
scriptTestRenderer?: ScriptTestRenderer;
|
|
73
|
+
/**
|
|
74
|
+
* Optional lazy type-acquisition resolver, forwarded to the TS/JS
|
|
75
|
+
* `CodeEditor` so imported npm packages autocomplete (lazy ATA).
|
|
76
|
+
*/
|
|
77
|
+
acquireTypes?: AcquireTypes;
|
|
78
|
+
/** Install identity (lockfile hash); resets acquired types on a new install. */
|
|
79
|
+
acquireResetKey?: string;
|
|
80
|
+
/** The running release's `@checkstack/sdk` editor bundle (helpers + client). */
|
|
81
|
+
sdkTypes?: ReadonlyArray<AcquiredTypeFile>;
|
|
82
|
+
/** Release version; resets the mounted SDK libs on a deployment upgrade. */
|
|
83
|
+
sdkTypesResetKey?: string;
|
|
84
|
+
/**
|
|
85
|
+
* Importable installed package names (`@types/*`-free), forwarded to the
|
|
86
|
+
* TS/JS `CodeEditor` so the import specifier itself autocompletes.
|
|
87
|
+
*/
|
|
88
|
+
importablePackages?: string[];
|
|
89
|
+
/** Form key of this field, forwarded to {@link scriptTestRenderer}. */
|
|
90
|
+
fieldId?: string;
|
|
91
|
+
/**
|
|
92
|
+
* Current value of the sibling `x-secret-env` mapping (located by
|
|
93
|
+
* annotation in the parent config object), forwarded to
|
|
94
|
+
* {@link scriptTestRenderer} so the test panel injects placeholders /
|
|
95
|
+
* overrides for the same secrets the action declares.
|
|
96
|
+
*/
|
|
97
|
+
siblingSecretEnv?: Record<string, string>;
|
|
57
98
|
/** Callback when value changes */
|
|
58
99
|
onChange: (value: string | undefined) => void;
|
|
59
100
|
}
|
|
@@ -74,6 +115,14 @@ export const MultiTypeEditorField: React.FC<MultiTypeEditorFieldProps> = ({
|
|
|
74
115
|
typeDefinitions,
|
|
75
116
|
shellEnvVars,
|
|
76
117
|
starterTemplates,
|
|
118
|
+
scriptTestRenderer,
|
|
119
|
+
acquireTypes,
|
|
120
|
+
acquireResetKey,
|
|
121
|
+
sdkTypes,
|
|
122
|
+
sdkTypesResetKey,
|
|
123
|
+
importablePackages,
|
|
124
|
+
fieldId,
|
|
125
|
+
siblingSecretEnv,
|
|
77
126
|
onChange,
|
|
78
127
|
}) => {
|
|
79
128
|
// Detect initial editor type from value
|
|
@@ -352,6 +401,11 @@ export const MultiTypeEditorField: React.FC<MultiTypeEditorFieldProps> = ({
|
|
|
352
401
|
language="javascript"
|
|
353
402
|
minHeight="150px"
|
|
354
403
|
typeDefinitions={typeDefinitions}
|
|
404
|
+
acquireTypes={acquireTypes}
|
|
405
|
+
acquireResetKey={acquireResetKey}
|
|
406
|
+
sdkTypes={sdkTypes}
|
|
407
|
+
sdkTypesResetKey={sdkTypesResetKey}
|
|
408
|
+
importablePackages={importablePackages}
|
|
355
409
|
/>
|
|
356
410
|
)}
|
|
357
411
|
|
|
@@ -363,6 +417,11 @@ export const MultiTypeEditorField: React.FC<MultiTypeEditorFieldProps> = ({
|
|
|
363
417
|
language="typescript"
|
|
364
418
|
minHeight="150px"
|
|
365
419
|
typeDefinitions={typeDefinitions}
|
|
420
|
+
acquireTypes={acquireTypes}
|
|
421
|
+
acquireResetKey={acquireResetKey}
|
|
422
|
+
sdkTypes={sdkTypes}
|
|
423
|
+
sdkTypesResetKey={sdkTypesResetKey}
|
|
424
|
+
importablePackages={importablePackages}
|
|
366
425
|
/>
|
|
367
426
|
)}
|
|
368
427
|
|
|
@@ -376,6 +435,23 @@ export const MultiTypeEditorField: React.FC<MultiTypeEditorFieldProps> = ({
|
|
|
376
435
|
shellEnvVars={shellEnvVars}
|
|
377
436
|
/>
|
|
378
437
|
)}
|
|
438
|
+
|
|
439
|
+
{/* Inline script-test panel for testable code fields. Shell maps to
|
|
440
|
+
the `shell` test kind; both typescript and javascript map to the
|
|
441
|
+
`typescript` runner kind (the ESM runner handles both). */}
|
|
442
|
+
{scriptTestRenderer !== undefined &&
|
|
443
|
+
(selectedType === "typescript" ||
|
|
444
|
+
selectedType === "javascript" ||
|
|
445
|
+
selectedType === "shell") &&
|
|
446
|
+
scriptTestRenderer({
|
|
447
|
+
fieldId: fieldId ?? id,
|
|
448
|
+
kind: selectedType === "shell" ? "shell" : "typescript",
|
|
449
|
+
script: value ?? "",
|
|
450
|
+
secretEnv:
|
|
451
|
+
siblingSecretEnv && Object.keys(siblingSecretEnv).length > 0
|
|
452
|
+
? siblingSecretEnv
|
|
453
|
+
: undefined,
|
|
454
|
+
})}
|
|
379
455
|
</div>
|
|
380
456
|
);
|
|
381
457
|
};
|