@checkstack/ui 1.9.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 (52) hide show
  1. package/CHANGELOG.md +417 -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/ListEmptyState.tsx +51 -0
  27. package/src/components/QueryErrorState.tsx +64 -0
  28. package/src/components/ResponsiveTable.tsx +92 -0
  29. package/src/components/Skeleton.tsx +39 -0
  30. package/src/components/TemplateInput.tsx +104 -0
  31. package/src/components/TemplateInputToggle.tsx +111 -0
  32. package/src/components/TemplateValueInput.test.ts +98 -0
  33. package/src/components/TemplateValueInput.tsx +470 -0
  34. package/src/components/VariablePicker.tsx +271 -0
  35. package/src/hooks/useInitOnceForKey.test.ts +27 -0
  36. package/src/hooks/useInitOnceForKey.ts +21 -18
  37. package/src/index.ts +10 -0
  38. package/src/utils/toastTemplates.test.ts +82 -0
  39. package/src/utils/toastTemplates.ts +47 -0
  40. package/stories/ActionCard.stories.tsx +62 -0
  41. package/stories/Alert.stories.tsx +5 -5
  42. package/stories/ListEmptyState.stories.tsx +48 -0
  43. package/stories/QueryErrorState.stories.tsx +40 -0
  44. package/stories/ResponsiveTable.stories.tsx +93 -0
  45. package/stories/Skeleton.stories.tsx +53 -0
  46. package/stories/TemplateInputToggle.stories.tsx +77 -0
  47. package/stories/TemplateValueInput.stories.tsx +65 -0
  48. package/stories/VariablePicker.stories.tsx +109 -0
  49. package/stories/toastTemplates.stories.tsx +60 -0
  50. package/src/components/CodeEditor/MonacoEditor.tsx +0 -616
  51. package/src/components/CodeEditor/monacoStdlib.ts +0 -62
  52. package/src/components/CodeEditor/monacoWorkers.ts +0 -118
@@ -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
+ };
@@ -1,13 +1,55 @@
1
- // Monaco-based CodeEditor
2
- // Re-export all from MonacoEditor as the new CodeEditor implementation
1
+ // Public `CodeEditor` component. Adapts the stable `CodeEditorProps` API to the
2
+ // `@typefox/monaco-editor-react`-backed `TypefoxEditor` (real VS Code language
3
+ // services in the browser). Consumers (DynamicForm, automation, healthcheck)
4
+ // import this and are unaffected by the underlying editor implementation.
5
+ import { TypefoxEditor } from "./TypefoxEditor";
6
+ import type { CodeEditorProps } from "./types";
3
7
 
4
- export {
5
- CodeEditor,
6
- type CodeEditorProps,
7
- type CodeEditorLanguage,
8
- type TemplateProperty,
9
- type ShellEnvVar,
10
- } from "./MonacoEditor";
8
+ /**
9
+ * Code editor with context-aware IntelliSense, template / shell completion, and
10
+ * structural validation. See `CodeEditorProps`.
11
+ */
12
+ export const CodeEditor = ({
13
+ id,
14
+ value,
15
+ onChange,
16
+ language = "typescript",
17
+ minHeight = "100px",
18
+ readOnly,
19
+ placeholder,
20
+ typeDefinitions,
21
+ templateProperties,
22
+ shellEnvVars,
23
+ markers,
24
+ }: CodeEditorProps) => {
25
+ // CodeEditorProps.minHeight is a CSS length string ("240px"); TypefoxEditor
26
+ // takes a pixel number.
27
+ const minHeightPx = Number.parseInt(minHeight, 10) || 100;
28
+
29
+ return (
30
+ <TypefoxEditor
31
+ id={id ?? "code-editor"}
32
+ value={value}
33
+ onChange={onChange}
34
+ language={language}
35
+ minHeight={minHeightPx}
36
+ readOnly={readOnly}
37
+ placeholder={placeholder}
38
+ typeDefinitions={typeDefinitions}
39
+ templateProperties={templateProperties}
40
+ shellEnvVars={shellEnvVars}
41
+ markers={markers}
42
+ />
43
+ );
44
+ };
45
+
46
+ export type {
47
+ CodeEditorProps,
48
+ CodeEditorLanguage,
49
+ TemplateProperty,
50
+ ShellEnvVar,
51
+ EditorMarker,
52
+ } from "./types";
11
53
 
12
54
  export {
13
55
  generateTypeDefinitions,