@checkstack/ui 1.10.0 → 1.11.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 (41) hide show
  1. package/CHANGELOG.md +384 -0
  2. package/package.json +15 -7
  3. package/scripts/generate-stdlib-types.ts +2 -2
  4. package/src/components/ActionCard.tsx +221 -0
  5. package/src/components/CodeEditor/CodeEditor.tsx +51 -9
  6. package/src/components/CodeEditor/TypefoxEditor.tsx +868 -0
  7. package/src/components/CodeEditor/bracketKeyGroups.test.ts +120 -0
  8. package/src/components/CodeEditor/bracketKeyGroups.ts +205 -0
  9. package/src/components/CodeEditor/generateTypeDefinitions.ts +4 -4
  10. package/src/components/CodeEditor/index.ts +2 -0
  11. package/src/components/CodeEditor/scriptContext.test.ts +41 -0
  12. package/src/components/CodeEditor/scriptContext.ts +76 -1
  13. package/src/components/CodeEditor/templateValidation.ts +51 -0
  14. package/src/components/CodeEditor/types.ts +109 -0
  15. package/src/components/CodeEditor/validateJsonTemplate.test.ts +61 -0
  16. package/src/components/CodeEditor/validateJsonTemplate.ts +26 -0
  17. package/src/components/CodeEditor/validateXmlTemplate.test.ts +34 -0
  18. package/src/components/CodeEditor/validateXmlTemplate.ts +35 -0
  19. package/src/components/CodeEditor/validateYamlTemplate.test.ts +39 -0
  20. package/src/components/CodeEditor/validateYamlTemplate.ts +28 -0
  21. package/src/components/DynamicForm/DynamicForm.tsx +2 -0
  22. package/src/components/DynamicForm/FormField.tsx +29 -9
  23. package/src/components/DynamicForm/KeyValueEditor.tsx +2 -169
  24. package/src/components/DynamicForm/MultiTypeEditorField.tsx +16 -7
  25. package/src/components/DynamicForm/types.ts +11 -0
  26. package/src/components/TemplateInput.tsx +104 -0
  27. package/src/components/TemplateInputToggle.tsx +111 -0
  28. package/src/components/TemplateValueInput.test.ts +98 -0
  29. package/src/components/TemplateValueInput.tsx +470 -0
  30. package/src/components/VariablePicker.tsx +271 -0
  31. package/src/hooks/useInitOnceForKey.test.ts +27 -0
  32. package/src/hooks/useInitOnceForKey.ts +21 -18
  33. package/src/index.ts +5 -0
  34. package/stories/ActionCard.stories.tsx +62 -0
  35. package/stories/Alert.stories.tsx +5 -5
  36. package/stories/TemplateInputToggle.stories.tsx +77 -0
  37. package/stories/TemplateValueInput.stories.tsx +65 -0
  38. package/stories/VariablePicker.stories.tsx +109 -0
  39. package/src/components/CodeEditor/MonacoEditor.tsx +0 -616
  40. package/src/components/CodeEditor/monacoStdlib.ts +0 -62
  41. package/src/components/CodeEditor/monacoWorkers.ts +0 -118
package/CHANGELOG.md CHANGED
@@ -1,5 +1,389 @@
1
1
  # @checkstack/ui
2
2
 
3
+ ## 1.11.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 41c77f4: feat(automation): deep + live definition validation surfaces invalid values, keys and ids — marked inline
8
+
9
+ Previously `validateDefinition` only checked the structural shape via
10
+ `AutomationDefinitionSchema`, where an action's `config` is typed as
11
+ `z.record(z.unknown())`. So a bad config value (e.g. `level:
12
+ debugthisiswrong` on `automation.log`) passed validation, and switching
13
+ to the visual editor just showed an empty dropdown with no explanation.
14
+
15
+ **Backend — deep validation.** New `collectDefinitionIssues` walker
16
+ validates the whole definition semantically, not just structurally:
17
+
18
+ - unknown trigger `event` / action `action` ids,
19
+ - each provider action's `config` against the registered action's own
20
+ schema (wrong enum value, missing required field, wrong type),
21
+ - each trigger's `config` against the trigger's `configSchema`,
22
+ - **unknown / typo'd config keys** — object configs are validated in
23
+ strict mode, so `levle: "info"` is reported rather than silently
24
+ stripped,
25
+ - recurses through `choose` / `parallel` / `repeat` / `sequence` so
26
+ nested action configs are covered too.
27
+
28
+ Issues come back with a dot-joinable `path` (e.g.
29
+ `actions.0.config.level`, `triggers.1.event`). The `validateDefinition`
30
+ RPC now returns these.
31
+
32
+ **Frontend — live + inline.** The automation editor re-validates on
33
+ every edit (debounced ~400ms) in BOTH tabs, and marks the offending
34
+ content in place rather than in a separate alert panel:
35
+
36
+ - **YAML tab** — issues (and YAML syntax errors) are squiggled at the
37
+ exact node. `@checkstack/ui`'s `CodeEditor` gained a `markers` prop;
38
+ the editor maps each issue's `path` onto the YAML document's node
39
+ range via a new `computeYamlMarkers` helper (walking up to the
40
+ nearest existing ancestor when a key is absent, e.g. a missing
41
+ required field).
42
+ - **Visual tab** — the specific card carrying an issue is marked: a
43
+ destructive border + warning icon + the field-level messages. A
44
+ `ValidationProvider` context partitions issues by owner (action card
45
+ / trigger card / condition / top-level) using the action-node path
46
+ grammar, so a nested action's config error attaches to the nested
47
+ card, and a `choose`'s own `when` error attaches to the choose card.
48
+ `ActionCard` gained an `errors` prop. So importing YAML with a bad
49
+ value (the empty-dropdown case) now visibly flags the card instead of
50
+ being silent.
51
+
52
+ The big error alert is gone; the only residual panel is a slim fallback
53
+ for the rare top-level issue that can't attach to any card.
54
+
55
+ Note: strict config validation means an action whose config schema
56
+ intentionally allowed extra keys would now flag them; action configs
57
+ across the platform declare all their fields, so this only catches
58
+ genuine typos.
59
+
60
+ - 41c77f4: fix(automation): editor UI fixes — action-config autocomplete, popup edge clamping + scroll, de-misleading action icon
61
+
62
+ Four fixes to the automation editor's visual mode:
63
+
64
+ - **Template autocomplete on action config fields.** A provider
65
+ action's config form (e.g. `automation.log`'s `message`) rendered
66
+ plain string fields with no `{{ … }}` autocomplete — only the
67
+ condition/expression fields had it. `DynamicForm` gains a
68
+ `templateCompletionProvider` prop; when supplied, default single-line
69
+ string fields render a `TemplateValueInput` wired to it instead of a
70
+ bare `Input`. The automation editor passes the staged template-mode
71
+ provider, so config fields now get the same field / comparator / value
72
+ / filter completion as conditions. Other `DynamicForm` consumers are
73
+ unaffected (the prop is opt-in; without it string fields stay plain).
74
+
75
+ - **Autocomplete popup no longer overflows the window.** The popup is
76
+ now edge-aware: it flips above the input when there isn't room below,
77
+ anchors to the input's right edge when a left-anchored popup would
78
+ spill past the right edge, and caps its height to the available space
79
+ (the list scrolls within it). The placement decision is extracted into
80
+ a pure, unit-tested `computePopupPlacement` helper.
81
+
82
+ - **Keyboard navigation scrolls the popup.** Arrowing through a list
83
+ taller than the popup now scrolls the highlighted row into view
84
+ (`scrollIntoView({ block: "nearest" })`) instead of leaving the
85
+ selection off-screen.
86
+
87
+ - **Action card icon no longer looks like a run button.** The "action"
88
+ kind used a `Play` triangle, which reads as a test/run control but
89
+ actually sits inside the card's expand toggle (so clicking it just
90
+ collapsed the card). Swapped to `Zap`, the conventional
91
+ automation-action glyph, which carries no "click to run" affordance.
92
+
93
+ - **Inline-script actions get their typed runtime context.** The Monaco
94
+ editor for `Run Script (TypeScript)` was falling back to an untyped
95
+ default context because the editor never received type definitions.
96
+ `useVariableScope` now also returns the `declare const context: …`
97
+ declarations from `generateAutomationContextTypes` (already built, but
98
+ never wired), and the provider action body forwards them to
99
+ `DynamicForm` so `context.trigger.payload` is typed as the discriminated
100
+ union over the automation's subscribed triggers, with
101
+ `context.artifacts` / `context.var` / `context.repeat` in scope at the
102
+ action's position. Shell scripts get their context the same way every
103
+ other config string does: `{{ … }}` templates are expanded by the
104
+ dispatch engine (`renderValue`) before the script runs, with the same
105
+ field autocomplete as other template fields.
106
+
107
+ - 41c77f4: feat(automation): native per-editor context for script actions (typed `context` for TS, `$ENV` for shell)
108
+
109
+ Script action editors had a confusing dual system: the TypeScript editor
110
+ type-checked `{{ }}` template text as code (so `{{ artifact.x }}` errored
111
+ with "Cannot find name"), and the runtime never actually populated the
112
+ `context` object. This standardises on a single, native context-access
113
+ mechanism per editor kind.
114
+
115
+ **Run scope reaches actions.** `ActionExecutionContext` gains a `scope`
116
+ (`{ trigger, artifacts, vars, repeat? }`), populated by the dispatch
117
+ engine from the same scope it already uses for `{{ }}` rendering. Actions
118
+ that need broad context (the script actions) read from it instead of
119
+ having to declare every artifact type in `consumes`. Additive and
120
+ optional, so existing actions are unaffected.
121
+
122
+ **TypeScript / JavaScript → typed `context`.** `run_script` now builds
123
+ `context` from the run scope, so `context.trigger.payload`,
124
+ `context.artifacts`, `context.var`, `context.repeat`, and
125
+ `context.automation` are populated at run time (previously
126
+ `context.trigger` was always empty). The editor types match via
127
+ `generateAutomationContextTypes`.
128
+
129
+ **Shell → `$CHECKSTACK_*` env vars.** `run_shell` flattens the run scope
130
+ into environment variables (e.g. `$CHECKSTACK_TRIGGER_PAYLOAD_TITLE`,
131
+ `$CHECKSTACK_ARTIFACT_INTEGRATION_JIRA_ISSUE_ISSUEKEY`). Arrays become a
132
+ single newline-separated var (iterate with `while IFS= read -r x; do …;
133
+ done <<< "$VAR"`). Every value is a plain string — no JSON blob, since
134
+ the container has no `jq` to parse one. A shared `toShellEnvKey`
135
+ helper (in `@checkstack/automation-common`) derives the names so the
136
+ shell editor's `$` autocomplete lists exactly what the runtime injects.
137
+
138
+ **One syntax per field kind (editor + runtime).** `MultiTypeEditorField`
139
+ no longer offers `{{ }}` autocomplete in `typescript` / `javascript` /
140
+ `shell` editors, and the dispatch engine no longer template-renders
141
+ native-code config fields (those whose `x-editor-types` is a code type) —
142
+ so `{{ }}` can't be used in a script by accident. Text / markup editors
143
+ (`raw`, `json`, `yaml`, `xml`, `markdown`, `formdata`) and plain string
144
+ fields keep `{{ }}` as before. Because both the automation and
145
+ health-check editors share `MultiTypeEditorField`, they behave
146
+ identically.
147
+
148
+ **Script-editor IntelliSense polish.** The code editors got a few
149
+ ergonomic fixes so the typed context is actually usable: the suggestion
150
+ **details panel auto-opens** (so long completion names are legible
151
+ on-focus, not hidden behind the chevron); word-based keyword noise is
152
+ disabled in favour of language-service + provider completions; and a
153
+ TS/JS completion provider makes `context.artifacts.` list the in-scope
154
+ artifact ids and **auto-convert the dot to bracket notation** —
155
+ `context.artifacts["integration-jira.issue"]` — since those ids aren't
156
+ valid identifiers. (Driven by a new opt-in `dottedKeyCompletions` prop on
157
+ the editor / `DynamicForm`.)
158
+
159
+ **BREAKING (beta):** `{{ }}` interpolation inside a script action's
160
+ `script` field (shell or TypeScript) is no longer expanded at run time —
161
+ read run data via the typed `context` object (TS) or `$CHECKSTACK_*` env
162
+ vars (shell) instead. Non-script config fields are unchanged.
163
+
164
+ Also fixes: switching a provider action in the visual editor now resets
165
+ its config, so the validator no longer reports the previous action's keys
166
+ as unrecognised.
167
+
168
+ - 41c77f4: feat(automation): Phase 11 — editor primitives + context type generation
169
+
170
+ Lays the UI + type-generation groundwork for Phase 12's visual automation
171
+ editor. Every primitive reuses the existing Monaco wrapper / template
172
+ engine / `jsonSchemaToTypeScript` helper rather than building parallel
173
+ infrastructure.
174
+
175
+ **`@checkstack/automation-common` — `resolveVariableScope`**
176
+
177
+ Pure walker that returns the in-scope `{{ … }}` paths at a given action
178
+ position. Conservative scoping rules: linear-upstream variables /
179
+ artifacts only (no leaking across `choose` / `parallel` / `repeat`
180
+ branches), `repeat.index` / `repeat.item` exposed only inside a `repeat`,
181
+ and trigger.payload modelled as a **discriminated union over
182
+ `trigger.event`** — every payload field surfaces; ones that come from a
183
+ subset of subscribed triggers carry a `conditionalOnTriggers` annotation
184
+ so the picker can render an "Only when …" hint. Earlier draft used
185
+ schema-intersection; switched to discriminated unions per review
186
+ feedback so Monaco can narrow correctly inside event-gated branches.
187
+
188
+ **Condition-aware narrowing.** When the path descends through a
189
+ `choose-when`, the resolver parses the branch's `when:` expression and
190
+ statically pins `trigger.event` to the set the condition allows —
191
+ patterns covered are `trigger.event == "X"` (either operand order),
192
+ `trigger.event != "X"`, `||`/`&&` of those, and `{ and: [...] }` /
193
+ `{ or: [...] }` combinators. So an action inside
194
+ `when: 'trigger.event == "incident.created"'` sees only the
195
+ `incident.created` variant in scope, the `conditionalOnTriggers`
196
+ annotation disappears, and other-trigger fields drop out entirely.
197
+ Nested choose branches compound (intersection). Anything outside the
198
+ covered patterns falls back to the full union — better to show every
199
+ field than guess wrong.
200
+
201
+ **`@checkstack/template-engine`**
202
+
203
+ The expression AST (`Expr`, `BinaryExpr`, `MemberExpr`, etc.) is now a
204
+ public export — the resolver's condition-narrowing walker needs to
205
+ inspect parsed condition trees. `ParsedCondition.root` is tightened
206
+ from `unknown` to `Expr` so consumers don't need to cast.
207
+
208
+ **`@checkstack/automation-frontend` — `generateAutomationContextTypes`**
209
+
210
+ Consumes `resolveVariableScope`'s output + the trigger / artifact
211
+ registries and emits the `declare const context: { … }` TS declaration
212
+ that `integration-script.run_script`'s Monaco editor injects via
213
+ `addExtraLib`. The emitted shape:
214
+
215
+ ```ts
216
+ type AutomationTrigger =
217
+ | { event: "incident.created"; payload: { … } }
218
+ | { event: "incident.resolved"; payload: { … } };
219
+
220
+ declare const context: {
221
+ trigger: AutomationTrigger;
222
+ artifacts: { "jira.issue"?: { key: string; … }; … };
223
+ var: { foo?: string; … };
224
+ repeat: { index: number; item: unknown }; // only when inside a repeat
225
+ };
226
+ ```
227
+
228
+ `jsonSchemaToTypeScript` from `@checkstack/ui` is reused via a deep
229
+ import (rather than the barrel) so the bun test runner doesn't try to
230
+ load Monaco's Vite-only `?worker` modules during unit tests.
231
+
232
+ **`@checkstack/ui` — new editor primitives**
233
+
234
+ - `TemplateValueInput` — single-line `{{ }}` autocomplete input.
235
+ Extracted from `DynamicForm/KeyValueEditor`'s previously-private
236
+ `TemplateInput` so other editor surfaces can share it without
237
+ rebuilding the picker UX. `KeyValueEditor` is now a one-line
238
+ delegation; `detectTemplateContext` is also exported.
239
+ - `VariablePicker` — hierarchical popover for the explicit "fx" /
240
+ "Insert variable" workflow. Renders a filterable tree of
241
+ `VariableNode`s with type chips and `Only when …` hints sourced from
242
+ the resolver's `conditionalOnTriggers`. Defaults to a small "fx" pill
243
+ trigger; callers can pass a custom one.
244
+ - `TemplateInput` — high-level mode switcher: `text` mode delegates to
245
+ `TemplateValueInput`, all other modes (`code` / `bash` / `json` /
246
+ `yaml`) delegate to `CodeEditor` with the matching language so the
247
+ action editor can swap widgets purely from the action's
248
+ `x-editor-types` annotation without touching the consuming code.
249
+ - `TemplateInputToggle` — the small "fx" pill that flips a typed input
250
+ (number / select / date / …) into template mode and back. Auto-infers
251
+ template mode when the saved value already starts with `{{`, so
252
+ round-tripping a previously-templated automation works out of the
253
+ box. Render-prop API for the typed editor so consumers keep control
254
+ over their own input shape.
255
+ - `ActionCard` — collapsible card that hosts a single action in the
256
+ visual editor. Decoupled from `DynamicForm` so container blocks
257
+ (`ChooseBlock` / `ParallelBlock` / `RepeatBlock` in Phase 12) can use
258
+ it as a structural shell over their own children. Toggle / delete /
259
+ drag handle are conditionally rendered on their callback's presence.
260
+
261
+ Storybook stories shipped for each of the new primitives.
262
+
263
+ **`@checkstack/integration-script-backend`**
264
+
265
+ `ScriptContext` docstring and the `scriptRunConfigSchema.script` field
266
+ description now point at `generateAutomationContextTypes` so the Phase
267
+ 12 editor wiring is unambiguous — the runtime payload type stays
268
+ `Record<string, unknown>` (the runner can't know the trigger schema),
269
+ but the **editor** narrows it per-automation from the subscribed
270
+ triggers' payload schemas.
271
+
272
+ - 4832e33: fix(automation): insert runtime-parseable `templateRef` from editor autocomplete + variable picker, with array indexing
273
+
274
+ The automation editor's `{{ }}` autocomplete and the `fx` variable picker
275
+ previously inserted the canonical dotted path (e.g.
276
+ `artifact.integration-jira.issue.issueKey`), which the template engine
277
+ cannot parse when an artifact id contains dots or hyphens, and which used
278
+ the singular `artifact`/`var` namespaces the runtime template context does
279
+ not expose. They now insert the runtime-parseable `templateRef` form -
280
+ plural top-level namespace (`artifacts`/`variables`) plus bracket notation
281
+ for non-identifier segments, e.g. `artifacts["integration-jira.issue"].issueKey`.
282
+
283
+ - `@checkstack/automation-common`: `VariableEntry` gains `templateRef`
284
+ (runtime-parseable insertion form) and `referenceable`, alongside the
285
+ unchanged canonical `path`. New exported helpers `isTemplateIdentifier`,
286
+ `appendTemplateSegment`, and `appendArrayIndex` build the form. Scope
287
+ derivation now descends into `array` schemas, offering both the whole
288
+ array and a representative element subtree (`tags[0]`, `comments[0].author`,
289
+ nested `matrix[0][0]`).
290
+ - `CompletionField` / `TemplateProperty` / `VariableNode` carry a
291
+ `templateRef` alongside the canonical `path`.
292
+ - The staged completion provider's field label, filter/match, insert text,
293
+ and value-stage field lookup all operate in `templateRef` space. The
294
+ expression tokenizer now emits bracket tokens and reconstructs the full
295
+ `foo["bar"].baz` / `foo["bar"].list[0]` access chain (normalising single
296
+ quotes to the stored double-quoted form, and supporting bare numeric array
297
+ indices) so value-stage enum suggestions resolve for bracket-notation and
298
+ indexed fields.
299
+ - `VariablePicker` and the `DynamicForm` template inserters write the
300
+ `templateRef` (falling back to `path` when absent).
301
+ - Shell-env (`$CHECKSTACK_*`) name derivation deliberately keeps using the
302
+ canonical dotted `path`, so the suggested env names stay byte-identical
303
+ to the backend's path-based injection. Script-context type generation is
304
+ unchanged.
305
+ - `@checkstack/integration-script-backend`: shell-script actions now also
306
+ expose array elements as indexed `$CHECKSTACK_*_<i>` env vars (and
307
+ `$CHECKSTACK_*_<i>_<field>` for object elements), alongside the existing
308
+ whole-array newline-joined var, so the runtime injects exactly the
309
+ array-element names the editor now suggests.
310
+
311
+ - 35bc682: feat(healthcheck): expose check + system run-context to script collectors
312
+
313
+ Script health checks can now read which check and system a run is for.
314
+ Previously shell scripts got only a curated env whitelist and inline
315
+ scripts only `context.config`, so a script had no built-in way to know
316
+ its own check name or the system it was checking.
317
+
318
+ - `@checkstack/backend-api`: new `CollectorRunContext` type
319
+ (`{ check: { id, name, intervalSeconds }, system: { id, name } }`) and
320
+ an optional `runContext` param on `CollectorStrategy.execute`. Optional,
321
+ so existing collector implementations are unaffected.
322
+ - Shell-script collector: injects reserved `CHECKSTACK_CHECK_ID`,
323
+ `CHECKSTACK_CHECK_NAME`, `CHECKSTACK_CHECK_INTERVAL_SECONDS`,
324
+ `CHECKSTACK_SYSTEM_ID`, `CHECKSTACK_SYSTEM_NAME` env vars (user-supplied
325
+ `env` still wins on collision).
326
+ - Inline-script collector: exposes `context.check` and `context.system`
327
+ alongside `context.config`; the inline-script editor now types them for
328
+ autocomplete.
329
+ - Shell editors (health-check collectors and automation shell actions) now
330
+ also suggest the user's own `env` (JSON) keys as `$NAME` completions, via
331
+ the new exported `customShellEnvVars` helper. Keys that aren't valid shell
332
+ identifiers are omitted.
333
+ - Fix: the Typefox `CodeEditor` captured a stale `onChange` at editor start,
334
+ so editing one `DynamicForm` field reverted sibling fields changed since
335
+ mount (e.g. typing in a shell `script` field wiped an unsaved `env` value,
336
+ or deleted a sibling automation action added after mount). The change
337
+ handler now routes through a ref to the current `onChange`.
338
+ - Fix: focusing a JSON editor threw "LanguageStatusService.addStatus is not
339
+ supported" because the standalone service set omitted `ILanguageStatusService`.
340
+ That one service is now registered via `serviceOverrides`.
341
+ - Fix: the automation trigger card nested a `<Badge>` (a `<div>`) inside a
342
+ `<p>`, producing a `validateDOMNesting` warning. Switched the wrapper to a
343
+ `<div>`.
344
+ - Local runs (`queue-executor`) and satellite runs both populate the
345
+ context. `SatelliteAssignment` (and the `getAssignmentsForSatellite`
346
+ RPC output) gained optional `configName` / `systemName` so the metadata
347
+ reaches satellite-side execution; `HealthCheckService` resolves the
348
+ system name via the catalog client.
349
+
350
+ BREAKING CHANGE: `createHealthCheckRouter` now requires a `catalogClient`
351
+ option (used to resolve system names for satellite assignments). Update
352
+ call sites to pass the catalog RPC client.
353
+
354
+ - c39ee69: Replace the Monaco-based `CodeEditor` with `@typefox/monaco-editor-react`, backed
355
+ by the standalone VS Code language services (no SharedArrayBuffer / cross-origin
356
+ isolation required). The `CodeEditor` public API is unchanged except for the
357
+ breaking note below; existing consumers keep working.
358
+
359
+ What this improves:
360
+
361
+ - Typed `context` IntelliSense is reliable (no more `addExtraLib` timing race).
362
+ - JSON / YAML / XML editors gain template-aware structural validation: the
363
+ content is validated as the JSON/YAML/XML it renders to, so `{{ }}` templates
364
+ are tolerated in any position (including unquoted, e.g. a numeric value) while
365
+ genuine structural errors are still flagged.
366
+ - JSON uses the real VS Code JSON language service (proper highlighting +
367
+ completion).
368
+ - Template `{{ }}` completion, shell `$env` completion, and external validation
369
+ markers are preserved.
370
+
371
+ > [!IMPORTANT]
372
+ > BREAKING (beta): the `dottedKeyCompletions` prop is removed from `CodeEditor`
373
+ > (and from `DynamicForm` / `FormField`). Bracket-notation completions for
374
+ > non-identifier object keys (e.g. `context.artifacts["integration-jira.issue"]`)
375
+ > are now derived automatically from the injected `typeDefinitions`, so the prop
376
+ > is no longer needed.
377
+
378
+ The `monaco-editor` and `@monaco-editor/react` dependencies are removed.
379
+
380
+ ### Patch Changes
381
+
382
+ - Updated dependencies [e2d6f25]
383
+ - Updated dependencies [6d52276]
384
+ - @checkstack/frontend-api@0.6.0
385
+ - @checkstack/common@0.12.0
386
+
3
387
  ## 1.10.0
4
388
 
5
389
  ### Minor Changes
package/package.json CHANGED
@@ -1,36 +1,44 @@
1
1
  {
2
2
  "name": "@checkstack/ui",
3
- "version": "1.10.0",
3
+ "version": "1.11.0",
4
4
  "license": "Elastic-2.0",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
7
7
  "dependencies": {
8
- "@checkstack/common": "0.10.0",
9
- "@checkstack/frontend-api": "0.5.1",
10
- "@monaco-editor/react": "^4.7.0",
8
+ "@checkstack/common": "0.11.0",
9
+ "@checkstack/frontend-api": "0.5.2",
10
+ "@codingame/monaco-vscode-editor-api": "25.1.2",
11
+ "@codingame/monaco-vscode-languages-service-override": "25.1.2",
12
+ "@codingame/monaco-vscode-standalone-json-language-features": "25.1.2",
13
+ "@codingame/monaco-vscode-standalone-languages": "25.1.2",
14
+ "@codingame/monaco-vscode-standalone-typescript-language-features": "25.1.2",
11
15
  "@radix-ui/react-accordion": "^1.2.12",
12
16
  "@radix-ui/react-dialog": "^1.1.15",
13
17
  "@radix-ui/react-popover": "^1.1.15",
14
18
  "@radix-ui/react-select": "^2.2.6",
15
19
  "@radix-ui/react-slider": "^1.2.1",
16
20
  "@radix-ui/react-slot": "^1.2.4",
21
+ "@typefox/monaco-editor-react": "7.7.0",
17
22
  "ajv": "^8.18.0",
18
23
  "ajv-formats": "^3.0.1",
19
24
  "class-variance-authority": "^0.7.1",
20
25
  "clsx": "^2.1.0",
21
26
  "date-fns": "^4.1.0",
27
+ "fast-xml-parser": "^5.8.0",
28
+ "jsonc-parser": "^3.3.1",
22
29
  "lucide-react": "0.562.0",
23
- "monaco-editor": "^0.55.1",
30
+ "monaco-languageclient": "10.7.0",
24
31
  "react": "^18.2.0",
25
32
  "react-day-picker": "^9.13.0",
26
33
  "react-dom": "^18.2.0",
27
34
  "react-markdown": "^10.1.0",
28
35
  "react-router-dom": "^6.20.0",
29
36
  "recharts": "^3.6.0",
30
- "tailwind-merge": "^2.2.0"
37
+ "tailwind-merge": "^2.2.0",
38
+ "yaml": "^2.9.0"
31
39
  },
32
40
  "devDependencies": {
33
- "@checkstack/scripts": "0.3.2",
41
+ "@checkstack/scripts": "0.3.3",
34
42
  "@checkstack/test-utils-frontend": "0.0.5",
35
43
  "@checkstack/tsconfig": "0.0.7",
36
44
  "@storybook/addon-a11y": "^10.3.6",
@@ -19,8 +19,8 @@
19
19
  *
20
20
  * Run with `bun run generate:monaco-types` from `core/ui`. The output JSON
21
21
  * lives at `src/components/CodeEditor/generated/stdlib-types.json` and is
22
- * lazy-imported by MonacoEditor (so the ~3 MB payload is code-split into
23
- * its own chunk and never blocks initial page load).
22
+ * lazy-imported by the editor (so the ~3 MB payload is code-split into its
23
+ * own chunk and never blocks initial page load).
24
24
  */
25
25
  import { createRequire } from "node:module";
26
26
  import { readdir, readFile, mkdir, writeFile } from "node:fs/promises";
@@ -0,0 +1,221 @@
1
+ import React from "react";
2
+ import {
3
+ ChevronDown,
4
+ ChevronRight,
5
+ GripVertical,
6
+ AlertTriangle,
7
+ Trash2,
8
+ } from "lucide-react";
9
+ import { Card, CardContent, CardHeader } from "./Card";
10
+ import { Button } from "./Button";
11
+ import { Toggle } from "./Toggle";
12
+ import { DynamicIcon, type LucideIconName } from "./DynamicIcon";
13
+ import { Badge, type BadgeProps } from "./Badge";
14
+ import { cn } from "../utils";
15
+
16
+ export interface ActionCardProps {
17
+ /** Stable identifier used for drag-reorder + React key. */
18
+ id: string;
19
+ /** Bold header label, e.g. "Notify User". */
20
+ title: string;
21
+ /** Operator-supplied description (the action's `id`/`description` field). */
22
+ description?: string;
23
+ /** Plugin/category label rendered as a subdued badge. */
24
+ category?: string;
25
+ /** Lucide icon (PascalCase) shown to the left of the title. */
26
+ icon?: LucideIconName;
27
+ /** Toggle for the action's `enabled` flag. Omit to hide the toggle. */
28
+ enabled?: boolean;
29
+ onEnabledChange?: (enabled: boolean) => void;
30
+ /** Removes the card from its container. Omit to hide the delete button. */
31
+ onDelete?: () => void;
32
+ /** Drag handle shown on the left; integrators wire it up via `dnd-kit`. */
33
+ dragHandleProps?: React.HTMLAttributes<HTMLButtonElement>;
34
+ /** Initial expanded state when uncontrolled. */
35
+ defaultExpanded?: boolean;
36
+ /** Controlled expanded state. */
37
+ expanded?: boolean;
38
+ onExpandedChange?: (expanded: boolean) => void;
39
+ /** Extra badges (e.g. produces / consumes hints). */
40
+ badges?: Array<{
41
+ label: string;
42
+ variant?: BadgeProps["variant"];
43
+ className?: string;
44
+ }>;
45
+ /** Card body — the action's config form. */
46
+ children?: React.ReactNode;
47
+ /** Optional class override on the outer Card. */
48
+ className?: string;
49
+ /**
50
+ * Validation messages attached to this card. When non-empty the card
51
+ * is marked with a destructive border + warning icon and the messages
52
+ * are listed in the header, so the operator sees *which* card (and
53
+ * field) is wrong without a separate panel.
54
+ */
55
+ errors?: string[];
56
+ }
57
+
58
+ /**
59
+ * Collapsible card that wraps a single automation action in the visual
60
+ * editor.
61
+ *
62
+ * Mirrors the visual layout of `StrategyConfigCard` but stays decoupled
63
+ * from `DynamicForm` so containers (`ChooseBlock`, `ParallelBlock`,
64
+ * `RepeatBlock`) can supply their own children — typically nested lists
65
+ * of `ActionCard`s rather than a flat config schema.
66
+ *
67
+ * Composition pattern (consumed by automation-frontend's editor):
68
+ *
69
+ * ```tsx
70
+ * <ActionCard
71
+ * id={action.id}
72
+ * title={action.action}
73
+ * enabled={action.enabled ?? true}
74
+ * onEnabledChange={(next) => onActionChange({ ...action, enabled: next })}
75
+ * onDelete={() => onDelete(action.id)}
76
+ * >
77
+ * <DynamicForm
78
+ * schema={registeredAction.configJsonSchema}
79
+ * value={action.config}
80
+ * onChange={(config) => onActionChange({ ...action, config })}
81
+ * />
82
+ * </ActionCard>
83
+ * ```
84
+ *
85
+ * The toggle, delete, and drag handle each gate on their respective
86
+ * callback being supplied — pass `onDelete` to render the trash button,
87
+ * `onEnabledChange` to render the enable toggle, `dragHandleProps` to
88
+ * render the grip. Containers that don't want any of those (e.g. a
89
+ * disabled preview) just omit them.
90
+ */
91
+ export const ActionCard: React.FC<ActionCardProps> = ({
92
+ id,
93
+ title,
94
+ description,
95
+ category,
96
+ icon,
97
+ enabled,
98
+ onEnabledChange,
99
+ onDelete,
100
+ dragHandleProps,
101
+ defaultExpanded = true,
102
+ expanded,
103
+ onExpandedChange,
104
+ badges,
105
+ children,
106
+ className,
107
+ errors,
108
+ }) => {
109
+ const [internalExpanded, setInternalExpanded] =
110
+ React.useState(defaultExpanded);
111
+ const isExpanded = expanded ?? internalExpanded;
112
+ const toggleExpanded = () => {
113
+ const next = !isExpanded;
114
+ if (expanded === undefined) setInternalExpanded(next);
115
+ onExpandedChange?.(next);
116
+ };
117
+ const hasErrors = errors !== undefined && errors.length > 0;
118
+
119
+ return (
120
+ <Card
121
+ data-action-id={id}
122
+ className={cn(
123
+ "transition-opacity",
124
+ enabled === false && "opacity-60",
125
+ hasErrors && "border-destructive/60 ring-1 ring-destructive/30",
126
+ className,
127
+ )}
128
+ >
129
+ <CardHeader className="flex flex-row items-center gap-2 p-3 space-y-0">
130
+ {dragHandleProps && (
131
+ <button
132
+ type="button"
133
+ className="cursor-grab text-muted-foreground hover:text-foreground"
134
+ aria-label="Drag to reorder"
135
+ {...dragHandleProps}
136
+ >
137
+ <GripVertical className="w-4 h-4" />
138
+ </button>
139
+ )}
140
+ <button
141
+ type="button"
142
+ onClick={toggleExpanded}
143
+ className="flex items-center flex-1 gap-2 text-left"
144
+ aria-expanded={isExpanded}
145
+ aria-controls={`${id}-body`}
146
+ >
147
+ {isExpanded ? (
148
+ <ChevronDown className="w-4 h-4 shrink-0 text-muted-foreground" />
149
+ ) : (
150
+ <ChevronRight className="w-4 h-4 shrink-0 text-muted-foreground" />
151
+ )}
152
+ {hasErrors ? (
153
+ <AlertTriangle className="w-4 h-4 shrink-0 text-destructive" />
154
+ ) : (
155
+ icon && <DynamicIcon name={icon} className="w-4 h-4 shrink-0" />
156
+ )}
157
+ <div className="flex-1 min-w-0">
158
+ <div className="flex items-center gap-2">
159
+ <span className="text-sm font-semibold truncate">{title}</span>
160
+ {category && (
161
+ <Badge variant="outline" className="shrink-0 text-[10px]">
162
+ {category}
163
+ </Badge>
164
+ )}
165
+ {badges?.map((badge) => (
166
+ <Badge
167
+ key={badge.label}
168
+ variant={badge.variant ?? "outline"}
169
+ className={cn("shrink-0 text-[10px]", badge.className)}
170
+ >
171
+ {badge.label}
172
+ </Badge>
173
+ ))}
174
+ </div>
175
+ {description && (
176
+ <p className="text-xs truncate text-muted-foreground">
177
+ {description}
178
+ </p>
179
+ )}
180
+ {hasErrors && (
181
+ <ul className="mt-0.5 space-y-0.5">
182
+ {errors!.map((error, index) => (
183
+ <li
184
+ key={index}
185
+ className="text-[11px] font-mono text-destructive"
186
+ >
187
+ {error}
188
+ </li>
189
+ ))}
190
+ </ul>
191
+ )}
192
+ </div>
193
+ </button>
194
+ {onEnabledChange && (
195
+ <Toggle
196
+ checked={enabled ?? true}
197
+ onCheckedChange={onEnabledChange}
198
+ aria-label={enabled ? "Disable action" : "Enable action"}
199
+ />
200
+ )}
201
+ {onDelete && (
202
+ <Button
203
+ type="button"
204
+ variant="ghost"
205
+ size="icon"
206
+ onClick={onDelete}
207
+ className="w-8 h-8 text-destructive hover:text-destructive/90 hover:bg-destructive/10 shrink-0"
208
+ aria-label="Delete action"
209
+ >
210
+ <Trash2 className="w-4 h-4" />
211
+ </Button>
212
+ )}
213
+ </CardHeader>
214
+ {isExpanded && children && (
215
+ <CardContent id={`${id}-body`} className="p-3 border-t border-border">
216
+ {children}
217
+ </CardContent>
218
+ )}
219
+ </Card>
220
+ );
221
+ };