@tai42/studio-sdk 0.2.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/LICENSE +202 -0
- package/NOTICE +15 -0
- package/README.md +318 -0
- package/SECURITY.md +51 -0
- package/dist/components/badge.d.ts +13 -0
- package/dist/components/badge.d.ts.map +1 -0
- package/dist/components/badge.js +14 -0
- package/dist/components/badge.js.map +1 -0
- package/dist/components/checkbox.d.ts +24 -0
- package/dist/components/checkbox.d.ts.map +1 -0
- package/dist/components/checkbox.js +31 -0
- package/dist/components/checkbox.js.map +1 -0
- package/dist/components/code-block.d.ts +7 -0
- package/dist/components/code-block.d.ts.map +1 -0
- package/dist/components/code-block.js +23 -0
- package/dist/components/code-block.js.map +1 -0
- package/dist/components/completion-input.d.ts +31 -0
- package/dist/components/completion-input.d.ts.map +1 -0
- package/dist/components/completion-input.js +61 -0
- package/dist/components/completion-input.js.map +1 -0
- package/dist/components/components.css +2212 -0
- package/dist/components/confirm-dialog.d.ts +40 -0
- package/dist/components/confirm-dialog.d.ts.map +1 -0
- package/dist/components/confirm-dialog.js +11 -0
- package/dist/components/confirm-dialog.js.map +1 -0
- package/dist/components/control-styles.d.ts +12 -0
- package/dist/components/control-styles.d.ts.map +1 -0
- package/dist/components/control-styles.js +14 -0
- package/dist/components/control-styles.js.map +1 -0
- package/dist/components/copy-field.d.ts +8 -0
- package/dist/components/copy-field.d.ts.map +1 -0
- package/dist/components/copy-field.js +106 -0
- package/dist/components/copy-field.js.map +1 -0
- package/dist/components/dialog.d.ts +21 -0
- package/dist/components/dialog.d.ts.map +1 -0
- package/dist/components/dialog.js +25 -0
- package/dist/components/dialog.js.map +1 -0
- package/dist/components/drawer.d.ts +22 -0
- package/dist/components/drawer.d.ts.map +1 -0
- package/dist/components/drawer.js +32 -0
- package/dist/components/drawer.js.map +1 -0
- package/dist/components/error-boundary.d.ts +33 -0
- package/dist/components/error-boundary.d.ts.map +1 -0
- package/dist/components/error-boundary.js +36 -0
- package/dist/components/error-boundary.js.map +1 -0
- package/dist/components/extension-combo-builder.d.ts +70 -0
- package/dist/components/extension-combo-builder.d.ts.map +1 -0
- package/dist/components/extension-combo-builder.js +154 -0
- package/dist/components/extension-combo-builder.js.map +1 -0
- package/dist/components/extension-grouping.d.ts +65 -0
- package/dist/components/extension-grouping.d.ts.map +1 -0
- package/dist/components/extension-grouping.js +78 -0
- package/dist/components/extension-grouping.js.map +1 -0
- package/dist/components/extension-picker.d.ts +35 -0
- package/dist/components/extension-picker.d.ts.map +1 -0
- package/dist/components/extension-picker.js +31 -0
- package/dist/components/extension-picker.js.map +1 -0
- package/dist/components/external-link.d.ts +19 -0
- package/dist/components/external-link.d.ts.map +1 -0
- package/dist/components/external-link.js +12 -0
- package/dist/components/external-link.js.map +1 -0
- package/dist/components/field.d.ts +64 -0
- package/dist/components/field.d.ts.map +1 -0
- package/dist/components/field.js +56 -0
- package/dist/components/field.js.map +1 -0
- package/dist/components/fleet-report.d.ts +39 -0
- package/dist/components/fleet-report.d.ts.map +1 -0
- package/dist/components/fleet-report.js +50 -0
- package/dist/components/fleet-report.js.map +1 -0
- package/dist/components/fonts.css +22 -0
- package/dist/components/icons.d.ts +142 -0
- package/dist/components/icons.d.ts.map +1 -0
- package/dist/components/icons.js +139 -0
- package/dist/components/icons.js.map +1 -0
- package/dist/components/inputs.d.ts +52 -0
- package/dist/components/inputs.d.ts.map +1 -0
- package/dist/components/inputs.js +35 -0
- package/dist/components/inputs.js.map +1 -0
- package/dist/components/json-diff.d.ts +40 -0
- package/dist/components/json-diff.d.ts.map +1 -0
- package/dist/components/json-diff.js +119 -0
- package/dist/components/json-diff.js.map +1 -0
- package/dist/components/json-tree.d.ts +8 -0
- package/dist/components/json-tree.d.ts.map +1 -0
- package/dist/components/json-tree.js +70 -0
- package/dist/components/json-tree.js.map +1 -0
- package/dist/components/modal-focus.d.ts +15 -0
- package/dist/components/modal-focus.d.ts.map +1 -0
- package/dist/components/modal-focus.js +136 -0
- package/dist/components/modal-focus.js.map +1 -0
- package/dist/components/page-header.d.ts +56 -0
- package/dist/components/page-header.d.ts.map +1 -0
- package/dist/components/page-header.js +24 -0
- package/dist/components/page-header.js.map +1 -0
- package/dist/components/primitives.d.ts +186 -0
- package/dist/components/primitives.d.ts.map +1 -0
- package/dist/components/primitives.js +204 -0
- package/dist/components/primitives.js.map +1 -0
- package/dist/components/progress-bar.d.ts +29 -0
- package/dist/components/progress-bar.d.ts.map +1 -0
- package/dist/components/progress-bar.js +48 -0
- package/dist/components/progress-bar.js.map +1 -0
- package/dist/components/radio-group.d.ts +37 -0
- package/dist/components/radio-group.d.ts.map +1 -0
- package/dist/components/radio-group.js +56 -0
- package/dist/components/radio-group.js.map +1 -0
- package/dist/components/reveal-input.d.ts +13 -0
- package/dist/components/reveal-input.d.ts.map +1 -0
- package/dist/components/reveal-input.js +31 -0
- package/dist/components/reveal-input.js.map +1 -0
- package/dist/components/scroll-region.d.ts +85 -0
- package/dist/components/scroll-region.d.ts.map +1 -0
- package/dist/components/scroll-region.js +574 -0
- package/dist/components/scroll-region.js.map +1 -0
- package/dist/components/select.d.ts +53 -0
- package/dist/components/select.d.ts.map +1 -0
- package/dist/components/select.js +33 -0
- package/dist/components/select.js.map +1 -0
- package/dist/components/table.d.ts +59 -0
- package/dist/components/table.d.ts.map +1 -0
- package/dist/components/table.js +20 -0
- package/dist/components/table.js.map +1 -0
- package/dist/components/tabs.d.ts +15 -0
- package/dist/components/tabs.d.ts.map +1 -0
- package/dist/components/tabs.js +13 -0
- package/dist/components/tabs.js.map +1 -0
- package/dist/components/tags.d.ts +46 -0
- package/dist/components/tags.d.ts.map +1 -0
- package/dist/components/tags.js +68 -0
- package/dist/components/tags.js.map +1 -0
- package/dist/components/tokens.css +392 -0
- package/dist/components/tokens.d.ts +15 -0
- package/dist/components/tokens.d.ts.map +1 -0
- package/dist/components/tokens.js +101 -0
- package/dist/components/tokens.js.map +1 -0
- package/dist/components/tool-picker.d.ts +24 -0
- package/dist/components/tool-picker.d.ts.map +1 -0
- package/dist/components/tool-picker.js +97 -0
- package/dist/components/tool-picker.js.map +1 -0
- package/dist/components/tooltip.d.ts +17 -0
- package/dist/components/tooltip.d.ts.map +1 -0
- package/dist/components/tooltip.js +18 -0
- package/dist/components/tooltip.js.map +1 -0
- package/dist/components/version-history-panel.d.ts +71 -0
- package/dist/components/version-history-panel.d.ts.map +1 -0
- package/dist/components/version-history-panel.js +148 -0
- package/dist/components/version-history-panel.js.map +1 -0
- package/dist/download.d.ts +7 -0
- package/dist/download.d.ts.map +1 -0
- package/dist/download.js +18 -0
- package/dist/download.js.map +1 -0
- package/dist/element-slot.d.ts +4 -0
- package/dist/element-slot.d.ts.map +1 -0
- package/dist/element-slot.js +20 -0
- package/dist/element-slot.js.map +1 -0
- package/dist/elicitation/ElicitationForm.d.ts +34 -0
- package/dist/elicitation/ElicitationForm.d.ts.map +1 -0
- package/dist/elicitation/ElicitationForm.js +24 -0
- package/dist/elicitation/ElicitationForm.js.map +1 -0
- package/dist/errors.d.ts +9 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +15 -0
- package/dist/errors.js.map +1 -0
- package/dist/extension-combos.d.ts +13 -0
- package/dist/extension-combos.d.ts.map +1 -0
- package/dist/extension-combos.js +9 -0
- package/dist/extension-combos.js.map +1 -0
- package/dist/hooks/useApi.d.ts +1222 -0
- package/dist/hooks/useApi.d.ts.map +1 -0
- package/dist/hooks/useApi.js +22 -0
- package/dist/hooks/useApi.js.map +1 -0
- package/dist/hooks/useAuth.d.ts +13 -0
- package/dist/hooks/useAuth.d.ts.map +1 -0
- package/dist/hooks/useAuth.js +53 -0
- package/dist/hooks/useAuth.js.map +1 -0
- package/dist/hooks/useBreakpoint.d.ts +10 -0
- package/dist/hooks/useBreakpoint.d.ts.map +1 -0
- package/dist/hooks/useBreakpoint.js +66 -0
- package/dist/hooks/useBreakpoint.js.map +1 -0
- package/dist/hooks/useCapabilities.d.ts +88 -0
- package/dist/hooks/useCapabilities.d.ts.map +1 -0
- package/dist/hooks/useCapabilities.js +203 -0
- package/dist/hooks/useCapabilities.js.map +1 -0
- package/dist/hooks/useSse.d.ts +13 -0
- package/dist/hooks/useSse.d.ts.map +1 -0
- package/dist/hooks/useSse.js +298 -0
- package/dist/hooks/useSse.js.map +1 -0
- package/dist/hooks/useTheme.d.ts +20 -0
- package/dist/hooks/useTheme.d.ts.map +1 -0
- package/dist/hooks/useTheme.js +97 -0
- package/dist/hooks/useTheme.js.map +1 -0
- package/dist/hooks/useUnauthorized.d.ts +3 -0
- package/dist/hooks/useUnauthorized.d.ts.map +1 -0
- package/dist/hooks/useUnauthorized.js +18 -0
- package/dist/hooks/useUnauthorized.js.map +1 -0
- package/dist/host.d.ts +11 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +10 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +118 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +91 -0
- package/dist/index.js.map +1 -0
- package/dist/navigation/context.d.ts +25 -0
- package/dist/navigation/context.d.ts.map +1 -0
- package/dist/navigation/context.js +45 -0
- package/dist/navigation/context.js.map +1 -0
- package/dist/navigation/index.d.ts +4 -0
- package/dist/navigation/index.d.ts.map +1 -0
- package/dist/navigation/index.js +2 -0
- package/dist/navigation/index.js.map +1 -0
- package/dist/navigation/types.d.ts +97 -0
- package/dist/navigation/types.d.ts.map +1 -0
- package/dist/navigation/types.js +16 -0
- package/dist/navigation/types.js.map +1 -0
- package/dist/plugin/host-state.d.ts +45 -0
- package/dist/plugin/host-state.d.ts.map +1 -0
- package/dist/plugin/host-state.js +62 -0
- package/dist/plugin/host-state.js.map +1 -0
- package/dist/plugin/registry.d.ts +35 -0
- package/dist/plugin/registry.d.ts.map +1 -0
- package/dist/plugin/registry.js +129 -0
- package/dist/plugin/registry.js.map +1 -0
- package/dist/plugin/types.d.ts +165 -0
- package/dist/plugin/types.d.ts.map +1 -0
- package/dist/plugin/types.js +2 -0
- package/dist/plugin/types.js.map +1 -0
- package/dist/plugin/version.d.ts +34 -0
- package/dist/plugin/version.d.ts.map +1 -0
- package/dist/plugin/version.js +37 -0
- package/dist/plugin/version.js.map +1 -0
- package/dist/query-keys.d.ts +31 -0
- package/dist/query-keys.d.ts.map +1 -0
- package/dist/query-keys.js +31 -0
- package/dist/query-keys.js.map +1 -0
- package/dist/schema-editor/SchemaEditor.d.ts +43 -0
- package/dist/schema-editor/SchemaEditor.d.ts.map +1 -0
- package/dist/schema-editor/SchemaEditor.js +106 -0
- package/dist/schema-editor/SchemaEditor.js.map +1 -0
- package/dist/schema-editor/index.d.ts +10 -0
- package/dist/schema-editor/index.d.ts.map +1 -0
- package/dist/schema-editor/index.js +8 -0
- package/dist/schema-editor/index.js.map +1 -0
- package/dist/schema-editor/lint.d.ts +37 -0
- package/dist/schema-editor/lint.d.ts.map +1 -0
- package/dist/schema-editor/lint.js +49 -0
- package/dist/schema-editor/lint.js.map +1 -0
- package/dist/schema-form/SchemaForm.d.ts +70 -0
- package/dist/schema-form/SchemaForm.d.ts.map +1 -0
- package/dist/schema-form/SchemaForm.js +13 -0
- package/dist/schema-form/SchemaForm.js.map +1 -0
- package/dist/schema-form/array-field.d.ts +20 -0
- package/dist/schema-form/array-field.d.ts.map +1 -0
- package/dist/schema-form/array-field.js +39 -0
- package/dist/schema-form/array-field.js.map +1 -0
- package/dist/schema-form/classify.d.ts +87 -0
- package/dist/schema-form/classify.d.ts.map +1 -0
- package/dist/schema-form/classify.js +199 -0
- package/dist/schema-form/classify.js.map +1 -0
- package/dist/schema-form/context.d.ts +4 -0
- package/dist/schema-form/context.d.ts.map +1 -0
- package/dist/schema-form/context.js +14 -0
- package/dist/schema-form/context.js.map +1 -0
- package/dist/schema-form/default-value.d.ts +8 -0
- package/dist/schema-form/default-value.d.ts.map +1 -0
- package/dist/schema-form/default-value.js +64 -0
- package/dist/schema-form/default-value.js.map +1 -0
- package/dist/schema-form/enum-field.d.ts +19 -0
- package/dist/schema-form/enum-field.d.ts.map +1 -0
- package/dist/schema-form/enum-field.js +26 -0
- package/dist/schema-form/enum-field.js.map +1 -0
- package/dist/schema-form/field-group.d.ts +9 -0
- package/dist/schema-form/field-group.d.ts.map +1 -0
- package/dist/schema-form/field-group.js +32 -0
- package/dist/schema-form/field-group.js.map +1 -0
- package/dist/schema-form/field-node.d.ts +24 -0
- package/dist/schema-form/field-node.d.ts.map +1 -0
- package/dist/schema-form/field-node.js +51 -0
- package/dist/schema-form/field-node.js.map +1 -0
- package/dist/schema-form/index.d.ts +13 -0
- package/dist/schema-form/index.d.ts.map +1 -0
- package/dist/schema-form/index.js +11 -0
- package/dist/schema-form/index.js.map +1 -0
- package/dist/schema-form/media-field.d.ts +24 -0
- package/dist/schema-form/media-field.d.ts.map +1 -0
- package/dist/schema-form/media-field.js +169 -0
- package/dist/schema-form/media-field.js.map +1 -0
- package/dist/schema-form/media.d.ts +40 -0
- package/dist/schema-form/media.d.ts.map +1 -0
- package/dist/schema-form/media.js +65 -0
- package/dist/schema-form/media.js.map +1 -0
- package/dist/schema-form/object-fields.d.ts +20 -0
- package/dist/schema-form/object-fields.d.ts.map +1 -0
- package/dist/schema-form/object-fields.js +24 -0
- package/dist/schema-form/object-fields.js.map +1 -0
- package/dist/schema-form/resolve.d.ts +41 -0
- package/dist/schema-form/resolve.d.ts.map +1 -0
- package/dist/schema-form/resolve.js +102 -0
- package/dist/schema-form/resolve.js.map +1 -0
- package/dist/schema-form/string-field.d.ts +20 -0
- package/dist/schema-form/string-field.d.ts.map +1 -0
- package/dist/schema-form/string-field.js +68 -0
- package/dist/schema-form/string-field.js.map +1 -0
- package/dist/schema-form/styles.d.ts +18 -0
- package/dist/schema-form/styles.d.ts.map +1 -0
- package/dist/schema-form/styles.js +18 -0
- package/dist/schema-form/styles.js.map +1 -0
- package/dist/schema-form/types.d.ts +67 -0
- package/dist/schema-form/types.d.ts.map +1 -0
- package/dist/schema-form/types.js +10 -0
- package/dist/schema-form/types.js.map +1 -0
- package/dist/schema-form/union-field.d.ts +24 -0
- package/dist/schema-form/union-field.d.ts.map +1 -0
- package/dist/schema-form/union-field.js +55 -0
- package/dist/schema-form/union-field.js.map +1 -0
- package/dist/schema-form/union.d.ts +4 -0
- package/dist/schema-form/union.d.ts.map +1 -0
- package/dist/schema-form/union.js +68 -0
- package/dist/schema-form/union.js.map +1 -0
- package/dist/schema-form/unsupported-notice.d.ts +18 -0
- package/dist/schema-form/unsupported-notice.d.ts.map +1 -0
- package/dist/schema-form/unsupported-notice.js +8 -0
- package/dist/schema-form/unsupported-notice.js.map +1 -0
- package/dist/schema-form/validate.d.ts +18 -0
- package/dist/schema-form/validate.d.ts.map +1 -0
- package/dist/schema-form/validate.js +162 -0
- package/dist/schema-form/validate.js.map +1 -0
- package/dist/structured-output/StructuredOutput.d.ts +27 -0
- package/dist/structured-output/StructuredOutput.d.ts.map +1 -0
- package/dist/structured-output/StructuredOutput.js +41 -0
- package/dist/structured-output/StructuredOutput.js.map +1 -0
- package/dist/testing.d.ts +80 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +207 -0
- package/dist/testing.js.map +1 -0
- package/package.json +101 -0
- package/src/components/badge.tsx +31 -0
- package/src/components/checkbox.tsx +93 -0
- package/src/components/code-block.tsx +37 -0
- package/src/components/completion-input.tsx +137 -0
- package/src/components/components.css +2212 -0
- package/src/components/confirm-dialog.tsx +77 -0
- package/src/components/control-styles.ts +14 -0
- package/src/components/copy-field.tsx +178 -0
- package/src/components/dialog.tsx +76 -0
- package/src/components/drawer.tsx +83 -0
- package/src/components/error-boundary.tsx +56 -0
- package/src/components/extension-combo-builder.tsx +305 -0
- package/src/components/extension-grouping.ts +116 -0
- package/src/components/extension-picker.tsx +97 -0
- package/src/components/external-link.tsx +40 -0
- package/src/components/field.tsx +169 -0
- package/src/components/fleet-report.tsx +136 -0
- package/src/components/fonts.css +22 -0
- package/src/components/icons.tsx +504 -0
- package/src/components/inputs.tsx +125 -0
- package/src/components/json-diff.tsx +192 -0
- package/src/components/json-tree.tsx +129 -0
- package/src/components/modal-focus.ts +150 -0
- package/src/components/page-header.tsx +107 -0
- package/src/components/primitives.tsx +489 -0
- package/src/components/progress-bar.tsx +100 -0
- package/src/components/radio-group.tsx +160 -0
- package/src/components/reveal-input.tsx +87 -0
- package/src/components/scroll-region.tsx +703 -0
- package/src/components/select.tsx +149 -0
- package/src/components/table.tsx +94 -0
- package/src/components/tabs.tsx +51 -0
- package/src/components/tags.tsx +137 -0
- package/src/components/tokens.css +392 -0
- package/src/components/tokens.ts +102 -0
- package/src/components/tool-picker.tsx +175 -0
- package/src/components/tooltip.tsx +46 -0
- package/src/components/version-history-panel.tsx +407 -0
- package/src/css.d.ts +2 -0
- package/src/download.ts +17 -0
- package/src/element-slot.ts +22 -0
- package/src/elicitation/ElicitationForm.tsx +87 -0
- package/src/errors.ts +12 -0
- package/src/extension-combos.ts +18 -0
- package/src/hooks/useApi.ts +27 -0
- package/src/hooks/useAuth.ts +67 -0
- package/src/hooks/useBreakpoint.ts +78 -0
- package/src/hooks/useCapabilities.ts +242 -0
- package/src/hooks/useSse.ts +314 -0
- package/src/hooks/useTheme.ts +133 -0
- package/src/hooks/useUnauthorized.ts +20 -0
- package/src/host.ts +15 -0
- package/src/index.ts +267 -0
- package/src/navigation/context.tsx +90 -0
- package/src/navigation/index.ts +9 -0
- package/src/navigation/types.ts +90 -0
- package/src/plugin/host-state.ts +93 -0
- package/src/plugin/registry.ts +174 -0
- package/src/plugin/types.ts +178 -0
- package/src/plugin/version.ts +44 -0
- package/src/query-keys.ts +34 -0
- package/src/schema-editor/SchemaEditor.tsx +186 -0
- package/src/schema-editor/index.ts +9 -0
- package/src/schema-editor/lint.ts +70 -0
- package/src/schema-form/SchemaForm.tsx +107 -0
- package/src/schema-form/array-field.tsx +110 -0
- package/src/schema-form/classify.ts +302 -0
- package/src/schema-form/context.ts +17 -0
- package/src/schema-form/default-value.ts +65 -0
- package/src/schema-form/enum-field.tsx +65 -0
- package/src/schema-form/field-group.tsx +71 -0
- package/src/schema-form/field-node.tsx +161 -0
- package/src/schema-form/index.ts +12 -0
- package/src/schema-form/media-field.tsx +281 -0
- package/src/schema-form/media.ts +69 -0
- package/src/schema-form/object-fields.tsx +74 -0
- package/src/schema-form/resolve.ts +114 -0
- package/src/schema-form/string-field.tsx +161 -0
- package/src/schema-form/styles.ts +20 -0
- package/src/schema-form/types.ts +71 -0
- package/src/schema-form/union-field.tsx +122 -0
- package/src/schema-form/union.ts +78 -0
- package/src/schema-form/unsupported-notice.tsx +39 -0
- package/src/schema-form/validate.ts +183 -0
- package/src/structured-output/StructuredOutput.tsx +81 -0
- package/src/testing.ts +235 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* `ExtensionComboBuilder` — a controlled editor for a preset/tool's LIST OF
|
|
4
|
+
* extension combos. A combo is an ordered list of extension ELEMENTS, each a bare
|
|
5
|
+
* extension NAME or a `{ name, config }` mapping carrying author config; the value
|
|
6
|
+
* is the list of combos (`PresetExtensionElement[][]`), the SAME shape the
|
|
7
|
+
* preset/tool extensions wire carries. It is PRESENTATIONAL: the caller fetches the
|
|
8
|
+
* extension catalog (`available`) and owns the `value`; this component fetches nothing.
|
|
9
|
+
*
|
|
10
|
+
* The surface has two parts:
|
|
11
|
+
* - the current combos, each an ordered row of name `Badge`s with a per-combo Edit
|
|
12
|
+
* (pull it back into the draft) and Remove;
|
|
13
|
+
* - a combo UNDER CONSTRUCTION, authored with the shared `ExtensionPicker` (grouped
|
|
14
|
+
* by kind, single-select for the non-stackable `backend` kind). When the draft
|
|
15
|
+
* includes the `output_schema` extension, its config is authored inline with a
|
|
16
|
+
* `SchemaEditor` (no title required); an "Add combo" / "Update combo" action
|
|
17
|
+
* composes the elements — `output_schema` as `{ name, config: { schema } }`, every
|
|
18
|
+
* other extension as a bare name — and writes it into the value.
|
|
19
|
+
*
|
|
20
|
+
* The builder only blocks the client-trivial invalids: an EMPTY combo (Add is
|
|
21
|
+
* disabled until the draft has ≥1 member), a DUPLICATE of a combo already in the
|
|
22
|
+
* value (by name sequence; flagged inline, Add blocked), an INVALID `output_schema`
|
|
23
|
+
* config (the `SchemaEditor` shows the parse/lint error and Add is blocked), and an
|
|
24
|
+
* UNKNOWN extension name in an existing combo (a name absent from `available`, which
|
|
25
|
+
* happens when a plugin is removed after a preset was authored) — flagged inline on
|
|
26
|
+
* that combo row and reported through `onValidityChange` so the caller can block
|
|
27
|
+
* submit. Every deeper rule — the registry's one-per-non-stackable-kind constraint,
|
|
28
|
+
* meta-schema validity, kind/ordering — is SERVER-AUTHORITATIVE: the write route
|
|
29
|
+
* validates each combo and its 400 message is surfaced verbatim by the caller.
|
|
30
|
+
*
|
|
31
|
+
* Loading is signaled by `availableReady`: while the catalog is still loading the
|
|
32
|
+
* builder reports VALID and suppresses the unknown-name notes (no danger-note flash
|
|
33
|
+
* while submit stays enabled — the server backstops), so a stale-seeded combo does
|
|
34
|
+
* not flicker invalid before the catalog resolves.
|
|
35
|
+
*
|
|
36
|
+
* SAFETY: an extension name is server-supplied, so every name renders as TEXT through
|
|
37
|
+
* the DS `Badge`/`Checkbox` (React escapes it) — never an HTML sink.
|
|
38
|
+
*
|
|
39
|
+
* Geometry and ink come from the design-system classes: each committed combo is a
|
|
40
|
+
* `tai-card` row, the invalid notes are `tai-field-error` (icon + message, never
|
|
41
|
+
* color alone), and Remove is a labelled `Button` carrying `CloseIcon` beside the
|
|
42
|
+
* word, under an accessible name that names the combo it removes.
|
|
43
|
+
*/
|
|
44
|
+
import { Fragment, useEffect, useState } from 'react';
|
|
45
|
+
import { comboElementNames, extensionElementName } from '../extension-combos';
|
|
46
|
+
import { SchemaEditor } from '../schema-editor';
|
|
47
|
+
import { Badge } from './badge';
|
|
48
|
+
import { ExtensionPicker } from './extension-picker';
|
|
49
|
+
import { CloseIcon, XCircleIcon } from './icons';
|
|
50
|
+
import { Button } from './primitives';
|
|
51
|
+
/** The one config-taking extension this builder authors inline. */
|
|
52
|
+
const OUTPUT_SCHEMA = 'output_schema';
|
|
53
|
+
/** Two combos are equal when their NAME sequences match (config is not part of identity). */
|
|
54
|
+
function sameNames(a, b) {
|
|
55
|
+
return a.length === b.length && a.every((name, index) => name === b[index]);
|
|
56
|
+
}
|
|
57
|
+
/** The stored `output_schema` config schema for a combo, if it carries one. */
|
|
58
|
+
function outputSchemaConfig(combo) {
|
|
59
|
+
for (const element of combo) {
|
|
60
|
+
if (typeof element !== 'string' && element.name === OUTPUT_SCHEMA) {
|
|
61
|
+
const schema = element.config.schema;
|
|
62
|
+
return typeof schema === 'object' && schema !== null && !Array.isArray(schema)
|
|
63
|
+
? schema
|
|
64
|
+
: {};
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
/** The element names in a combo that are absent from the known catalog. */
|
|
70
|
+
function unknownNames(combo, availableNames) {
|
|
71
|
+
return comboElementNames(combo).filter((name) => !availableNames.has(name));
|
|
72
|
+
}
|
|
73
|
+
export function ExtensionComboBuilder({ available, value, onChange, disabled, idPrefix = 'extension-combo-builder', onValidityChange, availableReady = true, }) {
|
|
74
|
+
const [draft, setDraft] = useState([]);
|
|
75
|
+
const [draftConfig, setDraftConfig] = useState({ schema: null, valid: true });
|
|
76
|
+
// The index of the combo being edited (pulled into the draft), or `null` for a new one.
|
|
77
|
+
const [editing, setEditing] = useState(null);
|
|
78
|
+
const draftHasOutputSchema = draft.includes(OUTPUT_SCHEMA);
|
|
79
|
+
const isDuplicate = draft.length > 0 &&
|
|
80
|
+
value.some((combo, index) => index !== editing && sameNames(comboElementNames(combo), draft));
|
|
81
|
+
const configInvalid = draftHasOutputSchema && !draftConfig.valid;
|
|
82
|
+
const canAdd = !disabled && draft.length > 0 && !isDuplicate && !configInvalid;
|
|
83
|
+
// Unknown-name validation over the EXISTING combos. Until the catalog is ready the
|
|
84
|
+
// builder reports VALID and suppresses the notes (no flash on a stale-seeded combo).
|
|
85
|
+
const availableNames = new Set(available.map((extension) => extension.name));
|
|
86
|
+
const hasUnknownName = availableReady && value.some((combo) => unknownNames(combo, availableNames).length > 0);
|
|
87
|
+
const valid = !hasUnknownName;
|
|
88
|
+
useEffect(() => {
|
|
89
|
+
onValidityChange?.(valid);
|
|
90
|
+
}, [onValidityChange, valid]);
|
|
91
|
+
const resetDraft = () => {
|
|
92
|
+
setDraft([]);
|
|
93
|
+
setDraftConfig({ schema: null, valid: true });
|
|
94
|
+
setEditing(null);
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Compose the draft names into config-bearing elements. `output_schema` takes the
|
|
98
|
+
* inline-authored config; every other name keeps the edited combo's existing
|
|
99
|
+
* element verbatim when it survives — preserving any author `config` (e.g. an
|
|
100
|
+
* `ask_external` verifier) the builder does not itself author — and a newly-added
|
|
101
|
+
* name becomes a bare-name element.
|
|
102
|
+
*/
|
|
103
|
+
const composeCombo = () => {
|
|
104
|
+
const source = editing === null ? undefined : value[editing];
|
|
105
|
+
const byName = new Map();
|
|
106
|
+
if (source !== undefined) {
|
|
107
|
+
for (const element of source)
|
|
108
|
+
byName.set(extensionElementName(element), element);
|
|
109
|
+
}
|
|
110
|
+
return draft.map((name) => name === OUTPUT_SCHEMA
|
|
111
|
+
? { name, config: { schema: draftConfig.schema ?? {} } }
|
|
112
|
+
: (byName.get(name) ?? name));
|
|
113
|
+
};
|
|
114
|
+
const commitCombo = () => {
|
|
115
|
+
if (!canAdd)
|
|
116
|
+
return;
|
|
117
|
+
const composed = composeCombo();
|
|
118
|
+
if (editing === null) {
|
|
119
|
+
onChange([...value.map((combo) => [...combo]), composed]);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
onChange(value.map((combo, index) => (index === editing ? composed : [...combo])));
|
|
123
|
+
}
|
|
124
|
+
resetDraft();
|
|
125
|
+
};
|
|
126
|
+
const startEdit = (index) => {
|
|
127
|
+
const combo = value[index];
|
|
128
|
+
if (combo === undefined)
|
|
129
|
+
return;
|
|
130
|
+
setDraft(comboElementNames(combo));
|
|
131
|
+
setDraftConfig({ schema: outputSchemaConfig(combo), valid: true });
|
|
132
|
+
setEditing(index);
|
|
133
|
+
};
|
|
134
|
+
const removeCombo = (index) => {
|
|
135
|
+
onChange(value.filter((_, i) => i !== index).map((combo) => [...combo]));
|
|
136
|
+
// Removing the row under edit (or one before it) invalidates the draft target.
|
|
137
|
+
if (editing !== null && (editing === index || editing > index))
|
|
138
|
+
resetDraft();
|
|
139
|
+
};
|
|
140
|
+
return (_jsxs("div", { "data-testid": idPrefix, className: "tai-stack", children: [value.length > 0 ? (_jsx("ul", { className: "tai-stack tai-stack-2", children: value.map((combo, index) => {
|
|
141
|
+
const names = comboElementNames(combo);
|
|
142
|
+
const unknown = availableReady ? unknownNames(combo, availableNames) : [];
|
|
143
|
+
return (
|
|
144
|
+
// The index IS the identity here: the list mutates by append, in-place
|
|
145
|
+
// update, and remove-by-index (no reorder), and a combo has no stable id
|
|
146
|
+
// of its own — so an index key is stable and cannot collide.
|
|
147
|
+
_jsxs("li", { className: "tai-card tai-stack tai-stack-2", children: [_jsxs("div", { className: "tai-row", children: [_jsx("span", { className: "tai-row", children: names.map((name, position) => (_jsxs(Fragment, { children: [position > 0 ? (_jsx("span", { "aria-hidden": true, className: "tai-muted", children: "+" })) : null, _jsx(Badge, { variant: unknown.includes(name) ? 'danger' : 'primary', children: name })] }, `${name}-${String(position)}`))) }), _jsx(Button, { type: "button", "aria-label": `${editing === index ? 'Editing' : 'Edit'} combo ${names.join('+')}`, disabled: disabled === true || editing === index, onClick: () => {
|
|
148
|
+
startEdit(index);
|
|
149
|
+
}, children: editing === index ? 'Editing' : 'Edit' }), _jsxs(Button, { type: "button", "aria-label": `Remove combo ${names.join('+')}`, disabled: disabled, onClick: () => {
|
|
150
|
+
removeCombo(index);
|
|
151
|
+
}, children: [_jsx(CloseIcon, {}), "Remove"] })] }), unknown.length > 0 ? (_jsxs("p", { role: "alert", className: "tai-field-error", children: [_jsx(XCircleIcon, {}), unknown.length === 1 ? 'Unknown extension: ' : 'Unknown extensions: ', unknown.join(', '), "."] })) : null] }, index));
|
|
152
|
+
}) })) : (_jsx("p", { className: "tai-muted", children: "No extension combos." })), _jsxs("div", { className: "tai-stack tai-stack-2", children: [_jsx(ExtensionPicker, { available: available, value: draft, onChange: setDraft, disabled: disabled, idPrefix: `${idPrefix}-draft` }), draftHasOutputSchema ? (_jsx(SchemaEditor, { value: draftConfig.schema, onChange: setDraftConfig, requireTitle: false, label: "Output schema", description: "The JSON Schema the output_schema extension enforces on this combo's result.", disabled: disabled, idPrefix: `${idPrefix}-output-schema` }, editing === null ? 'new' : `edit-${String(editing)}`)) : null, isDuplicate ? (_jsxs("p", { role: "alert", className: "tai-field-error", children: [_jsx(XCircleIcon, {}), "This combo is already added."] })) : null, _jsxs("div", { className: "tai-row", children: [_jsx(Button, { type: "button", variant: "primary", onClick: commitCombo, disabled: !canAdd, children: editing === null ? 'Add combo' : 'Update combo' }), editing !== null ? (_jsx(Button, { type: "button", onClick: resetDraft, disabled: disabled, children: "Cancel edit" })) : null] })] })] }));
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=extension-combo-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension-combo-builder.js","sourceRoot":"","sources":["../../src/components/extension-combo-builder.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAkB,MAAM,OAAO,CAAC;AAItE,OAAO,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC9E,OAAO,EAAE,YAAY,EAA2B,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEtC,mEAAmE;AACnE,MAAM,aAAa,GAAG,eAAe,CAAC;AA2BtC,6FAA6F;AAC7F,SAAS,SAAS,CAAC,CAAoB,EAAE,CAAoB;IAC3D,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED,+EAA+E;AAC/E,SAAS,kBAAkB,CACzB,KAAwC;IAExC,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE,CAAC;QAC5B,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAClE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;YACrC,OAAO,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;gBAC5E,CAAC,CAAE,MAAkC;gBACrC,CAAC,CAAC,EAAE,CAAC;QACT,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,2EAA2E;AAC3E,SAAS,YAAY,CACnB,KAAwC,EACxC,cAAmC;IAEnC,OAAO,iBAAiB,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,EACpC,SAAS,EACT,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,QAAQ,GAAG,yBAAyB,EACpC,gBAAgB,EAChB,cAAc,GAAG,IAAI,GACM;IAC3B,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAW,EAAE,CAAC,CAAC;IACjD,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAqB,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClG,wFAAwF;IACxF,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAC;IAE5D,MAAM,oBAAoB,GAAG,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IAC3D,MAAM,WAAW,GACf,KAAK,CAAC,MAAM,GAAG,CAAC;QAChB,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,OAAO,IAAI,SAAS,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;IAChG,MAAM,aAAa,GAAG,oBAAoB,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;IACjE,MAAM,MAAM,GAAG,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,aAAa,CAAC;IAE/E,mFAAmF;IACnF,qFAAqF;IACrF,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7E,MAAM,cAAc,GAClB,cAAc,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC1F,MAAM,KAAK,GAAG,CAAC,cAAc,CAAC;IAE9B,SAAS,CAAC,GAAG,EAAE;QACb,gBAAgB,EAAE,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC,EAAE,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC,CAAC;IAE9B,MAAM,UAAU,GAAG,GAAS,EAAE;QAC5B,QAAQ,CAAC,EAAE,CAAC,CAAC;QACb,cAAc,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,UAAU,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC,CAAC;IAEF;;;;;;OAMG;IACH,MAAM,YAAY,GAAG,GAA6B,EAAE;QAClD,MAAM,MAAM,GAAG,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkC,CAAC;QACzD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,KAAK,MAAM,OAAO,IAAI,MAAM;gBAAE,MAAM,CAAC,GAAG,CAAC,oBAAoB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;QACnF,CAAC;QACD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACxB,IAAI,KAAK,aAAa;YACpB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,MAAM,IAAI,EAAE,EAAE,EAAE;YACxD,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAC/B,CAAC;IACJ,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,GAAS,EAAE;QAC7B,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,QAAQ,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;QAC5D,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACrF,CAAC;QACD,UAAU,EAAE,CAAC;IACf,CAAC,CAAC;IAEF,MAAM,SAAS,GAAG,CAAC,KAAa,EAAQ,EAAE;QACxC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QAC3B,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO;QAChC,QAAQ,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;QACnC,cAAc,CAAC,EAAE,MAAM,EAAE,kBAAkB,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACnE,UAAU,CAAC,KAAK,CAAC,CAAC;IACpB,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,CAAC,KAAa,EAAQ,EAAE;QAC1C,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACzE,+EAA+E;QAC/E,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK,IAAI,OAAO,GAAG,KAAK,CAAC;YAAE,UAAU,EAAE,CAAC;IAC/E,CAAC,CAAC;IAEF,OAAO,CACL,8BAAkB,QAAQ,EAAE,SAAS,EAAC,WAAW,aAC9C,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAClB,aAAI,SAAS,EAAC,uBAAuB,YAClC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;oBAC1B,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;oBACvC,MAAM,OAAO,GAAG,cAAc,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;oBAC1E,OAAO;oBACL,uEAAuE;oBACvE,yEAAyE;oBACzE,6DAA6D;oBAC7D,cAAgB,SAAS,EAAC,gCAAgC,aACxD,eAAK,SAAS,EAAC,SAAS,aACtB,eAAM,SAAS,EAAC,SAAS,YACtB,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAC7B,MAAC,QAAQ,eACN,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CACd,oCAAkB,SAAS,EAAC,WAAW,kBAEhC,CACR,CAAC,CAAC,CAAC,IAAI,EACR,KAAC,KAAK,IAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,YAC1D,IAAI,GACC,KARK,GAAG,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,EAAE,CASjC,CACZ,CAAC,GACG,EACP,KAAC,MAAM,IACL,IAAI,EAAC,QAAQ,gBAKD,GAAG,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,UAAU,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAChF,QAAQ,EAAE,QAAQ,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,EAChD,OAAO,EAAE,GAAG,EAAE;4CACZ,SAAS,CAAC,KAAK,CAAC,CAAC;wCACnB,CAAC,YAEA,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,GAChC,EACT,MAAC,MAAM,IACL,IAAI,EAAC,QAAQ,gBACD,gBAAgB,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAC7C,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,GAAG,EAAE;4CACZ,WAAW,CAAC,KAAK,CAAC,CAAC;wCACrB,CAAC,aAED,KAAC,SAAS,KAAG,cAEN,IACL,EACL,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CACpB,aAAG,IAAI,EAAC,OAAO,EAAC,SAAS,EAAC,iBAAiB,aACzC,KAAC,WAAW,KAAG,EACd,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,sBAAsB,EACrE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SACjB,CACL,CAAC,CAAC,CAAC,IAAI,KAhDD,KAAK,CAiDT,CACN,CAAC;gBACJ,CAAC,CAAC,GACC,CACN,CAAC,CAAC,CAAC,CACF,YAAG,SAAS,EAAC,WAAW,qCAAyB,CAClD,EAED,eAAK,SAAS,EAAC,uBAAuB,aACpC,KAAC,eAAe,IACd,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,GAAG,QAAQ,QAAQ,GAC7B,EAED,oBAAoB,CAAC,CAAC,CAAC,CACtB,KAAC,YAAY,IACX,KAAK,EAAE,WAAW,CAAC,MAAM,EACzB,QAAQ,EAAE,cAAc,EACxB,YAAY,EAAE,KAAK,EACnB,KAAK,EAAC,eAAe,EACrB,WAAW,EAAC,8EAA8E,EAC1F,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,GAAG,QAAQ,gBAAgB,IAGhC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,MAAM,CAAC,OAAO,CAAC,EAAE,CACzD,CACH,CAAC,CAAC,CAAC,IAAI,EAEP,WAAW,CAAC,CAAC,CAAC,CACb,aAAG,IAAI,EAAC,OAAO,EAAC,SAAS,EAAC,iBAAiB,aACzC,KAAC,WAAW,KAAG,oCAEb,CACL,CAAC,CAAC,CAAC,IAAI,EAER,eAAK,SAAS,EAAC,SAAS,aACtB,KAAC,MAAM,IAAC,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAC,SAAS,EAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,MAAM,YAC5E,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,cAAc,GACzC,EACR,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAClB,KAAC,MAAM,IAAC,IAAI,EAAC,QAAQ,EAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,4BAEpD,CACV,CAAC,CAAC,CAAC,IAAI,IACJ,IACF,IACF,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure catalog-shaping helpers for the extensions surface — the SHARED grouping
|
|
3
|
+
* source for both the read-only extensions catalog (`features/extensions`) and the
|
|
4
|
+
* `ExtensionPicker`. Kept free of React so the grouping logic is unit-tested
|
|
5
|
+
* directly.
|
|
6
|
+
*
|
|
7
|
+
* The `/api/extensions` catalog is a flat list of `{ name, kind }` entries. Two
|
|
8
|
+
* independent groupings live here:
|
|
9
|
+
* - `groupIntoFamilies` groups a tool's composed branch VARIANTS (which share a
|
|
10
|
+
* base tool name and append underscore suffixes — `tool`, `tool_a`, `tool_a_b`)
|
|
11
|
+
* back into one FAMILY keyed by that base name (the catalog view);
|
|
12
|
+
* - `groupByKind` groups the catalog by extension KIND (the picker view), where
|
|
13
|
+
* the `backend` kind is the single non-stackable one.
|
|
14
|
+
* `kindVariant` maps each serialized `kind` value to a design-system Badge variant.
|
|
15
|
+
*/
|
|
16
|
+
import type { Extension } from '@tai42/api-client';
|
|
17
|
+
import type { BadgeProps } from './badge';
|
|
18
|
+
/**
|
|
19
|
+
* The single non-stackable extension kind: at most one `backend` extension may
|
|
20
|
+
* appear in a combo (the `backend` kind is declared non-stackable, `multiple=False`).
|
|
21
|
+
* The `ExtensionPicker` enforces single-select for this kind.
|
|
22
|
+
*/
|
|
23
|
+
export declare const NON_STACKABLE_KIND = "backend";
|
|
24
|
+
/** One base tool and every extension entry that branches from it. */
|
|
25
|
+
export interface ExtensionFamily {
|
|
26
|
+
/** The base tool name (the segment before the first underscore). */
|
|
27
|
+
readonly base: string;
|
|
28
|
+
/** The family's entries, ordered by full name. */
|
|
29
|
+
readonly members: readonly Extension[];
|
|
30
|
+
}
|
|
31
|
+
/** One extension `kind` and every catalog entry of that kind. */
|
|
32
|
+
export interface ExtensionKindGroup {
|
|
33
|
+
/** The serialized kind value (`wrapper` / `transformer` / `backend`). */
|
|
34
|
+
readonly kind: string;
|
|
35
|
+
/** Whether this kind is non-stackable (single-select in the picker). */
|
|
36
|
+
readonly nonStackable: boolean;
|
|
37
|
+
/** The kind's entries, ordered by name. */
|
|
38
|
+
readonly members: readonly Extension[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The base tool name a variant belongs to: the substring before the first
|
|
42
|
+
* underscore, or the whole name when it has none. `tool`, `tool_a`, `tool_a_b`
|
|
43
|
+
* all resolve to `tool`; `x_chain` and `x_batch` both resolve to `x`.
|
|
44
|
+
*/
|
|
45
|
+
export declare function baseNameOf(name: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* Group a flat extension list into families keyed by base tool name. Families
|
|
48
|
+
* are ordered by base name and each family's members by full name, so the render
|
|
49
|
+
* order is stable regardless of the server's list order.
|
|
50
|
+
*/
|
|
51
|
+
export declare function groupIntoFamilies(extensions: readonly Extension[]): ExtensionFamily[];
|
|
52
|
+
/**
|
|
53
|
+
* Group a flat extension list by `kind`, for the picker. Groups are ordered by
|
|
54
|
+
* kind and each group's members by name, so the render order is stable regardless
|
|
55
|
+
* of the server's list order. The `backend` group is flagged non-stackable.
|
|
56
|
+
*/
|
|
57
|
+
export declare function groupByKind(extensions: readonly Extension[]): ExtensionKindGroup[];
|
|
58
|
+
/**
|
|
59
|
+
* Map a serialized extension `kind` to a Badge variant. Known skeleton kinds get
|
|
60
|
+
* a themed color; any unrecognized kind falls back to the neutral variant (the
|
|
61
|
+
* Badge itself also neutral-fallbacks, but choosing here keeps the mapping
|
|
62
|
+
* explicit and testable).
|
|
63
|
+
*/
|
|
64
|
+
export declare function kindVariant(kind: string): NonNullable<BadgeProps['variant']>;
|
|
65
|
+
//# sourceMappingURL=extension-grouping.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension-grouping.d.ts","sourceRoot":"","sources":["../../src/components/extension-grouping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAE5C,qEAAqE;AACrE,MAAM,WAAW,eAAe;IAC9B,oEAAoE;IACpE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,QAAQ,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;CACxC;AAED,iEAAiE;AACjE,MAAM,WAAW,kBAAkB;IACjC,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,EAAE,SAAS,SAAS,EAAE,CAAC;CACxC;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,GAAG,eAAe,EAAE,CAiBrF;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,GAAG,kBAAkB,EAAE,CAiBlF;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAO5E"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The single non-stackable extension kind: at most one `backend` extension may
|
|
3
|
+
* appear in a combo (the `backend` kind is declared non-stackable, `multiple=False`).
|
|
4
|
+
* The `ExtensionPicker` enforces single-select for this kind.
|
|
5
|
+
*/
|
|
6
|
+
export const NON_STACKABLE_KIND = 'backend';
|
|
7
|
+
/**
|
|
8
|
+
* The base tool name a variant belongs to: the substring before the first
|
|
9
|
+
* underscore, or the whole name when it has none. `tool`, `tool_a`, `tool_a_b`
|
|
10
|
+
* all resolve to `tool`; `x_chain` and `x_batch` both resolve to `x`.
|
|
11
|
+
*/
|
|
12
|
+
export function baseNameOf(name) {
|
|
13
|
+
const separator = name.indexOf('_');
|
|
14
|
+
return separator === -1 ? name : name.slice(0, separator);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Group a flat extension list into families keyed by base tool name. Families
|
|
18
|
+
* are ordered by base name and each family's members by full name, so the render
|
|
19
|
+
* order is stable regardless of the server's list order.
|
|
20
|
+
*/
|
|
21
|
+
export function groupIntoFamilies(extensions) {
|
|
22
|
+
const byBase = new Map();
|
|
23
|
+
for (const extension of extensions) {
|
|
24
|
+
const base = baseNameOf(extension.name);
|
|
25
|
+
const members = byBase.get(base);
|
|
26
|
+
if (members) {
|
|
27
|
+
members.push(extension);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
byBase.set(base, [extension]);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return [...byBase.entries()]
|
|
34
|
+
.map(([base, members]) => ({
|
|
35
|
+
base,
|
|
36
|
+
members: [...members].sort((a, b) => a.name.localeCompare(b.name)),
|
|
37
|
+
}))
|
|
38
|
+
.sort((a, b) => a.base.localeCompare(b.base));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Group a flat extension list by `kind`, for the picker. Groups are ordered by
|
|
42
|
+
* kind and each group's members by name, so the render order is stable regardless
|
|
43
|
+
* of the server's list order. The `backend` group is flagged non-stackable.
|
|
44
|
+
*/
|
|
45
|
+
export function groupByKind(extensions) {
|
|
46
|
+
const byKind = new Map();
|
|
47
|
+
for (const extension of extensions) {
|
|
48
|
+
const members = byKind.get(extension.kind);
|
|
49
|
+
if (members) {
|
|
50
|
+
members.push(extension);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
byKind.set(extension.kind, [extension]);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return [...byKind.entries()]
|
|
57
|
+
.map(([kind, members]) => ({
|
|
58
|
+
kind,
|
|
59
|
+
nonStackable: kind === NON_STACKABLE_KIND,
|
|
60
|
+
members: [...members].sort((a, b) => a.name.localeCompare(b.name)),
|
|
61
|
+
}))
|
|
62
|
+
.sort((a, b) => a.kind.localeCompare(b.kind));
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Map a serialized extension `kind` to a Badge variant. Known skeleton kinds get
|
|
66
|
+
* a themed color; any unrecognized kind falls back to the neutral variant (the
|
|
67
|
+
* Badge itself also neutral-fallbacks, but choosing here keeps the mapping
|
|
68
|
+
* explicit and testable).
|
|
69
|
+
*/
|
|
70
|
+
export function kindVariant(kind) {
|
|
71
|
+
const known = {
|
|
72
|
+
wrapper: 'primary',
|
|
73
|
+
transformer: 'success',
|
|
74
|
+
backend: 'warning',
|
|
75
|
+
};
|
|
76
|
+
return known[kind] ?? 'neutral';
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=extension-grouping.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension-grouping.js","sourceRoot":"","sources":["../../src/components/extension-grouping.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ExtensionPicker` — a controlled multi-select over the extension catalog
|
|
3
|
+
* (`GET /api/extensions`), authoring ONE extension combo (an ordered list of
|
|
4
|
+
* extension names). Built on the DS `Checkbox` so features share one picker
|
|
5
|
+
* instead of re-implementing a checklist (the same reason `SchemaForm`/`ToolPicker`
|
|
6
|
+
* live in the SDK). It is PRESENTATIONAL: the caller fetches `available` and owns
|
|
7
|
+
* the selected `value`; this component fetches nothing.
|
|
8
|
+
*
|
|
9
|
+
* The catalog is GROUPED by `kind`. The `backend` kind is the single NON-STACKABLE
|
|
10
|
+
* one (`multiple=False`), so it is SINGLE-SELECT — checking a backend
|
|
11
|
+
* extension replaces any other backend already in the combo; every other kind is
|
|
12
|
+
* freely multi-select. Selection order is preserved (the combo is ordered — the
|
|
13
|
+
* stacking order that produces the branch tool name), so a newly-checked extension
|
|
14
|
+
* appends to the end and unchecking removes in place.
|
|
15
|
+
*
|
|
16
|
+
* SAFETY: an extension name AND its kind are server-supplied, so every name/kind
|
|
17
|
+
* renders as TEXT through the DS `Checkbox`/`Badge` (React escapes it) — never an
|
|
18
|
+
* HTML sink. Pinned by a test.
|
|
19
|
+
*
|
|
20
|
+
* Geometry and ink come from the design-system layout classes (`tai-stack`,
|
|
21
|
+
* `tai-row`, `tai-muted`); the component carries no palette of its own.
|
|
22
|
+
*/
|
|
23
|
+
import type { Extension } from '@tai42/api-client';
|
|
24
|
+
export interface ExtensionPickerProps {
|
|
25
|
+
/** The extension catalog (`GET /api/extensions`) the checklist is drawn from. */
|
|
26
|
+
readonly available: readonly Extension[];
|
|
27
|
+
/** The currently-selected extension names, in combo (stacking) order. */
|
|
28
|
+
readonly value: readonly string[];
|
|
29
|
+
/** Fired with the next ordered selection whenever a box toggles. */
|
|
30
|
+
readonly onChange: (names: string[]) => void;
|
|
31
|
+
readonly disabled?: boolean;
|
|
32
|
+
readonly idPrefix?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function ExtensionPicker({ available, value, onChange, disabled, idPrefix, }: ExtensionPickerProps): import("react").JSX.Element;
|
|
35
|
+
//# sourceMappingURL=extension-picker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension-picker.d.ts","sourceRoot":"","sources":["../../src/components/extension-picker.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAMnD,MAAM,WAAW,oBAAoB;IACnC,iFAAiF;IACjF,QAAQ,CAAC,SAAS,EAAE,SAAS,SAAS,EAAE,CAAC;IACzC,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,QAA6B,GAC9B,EAAE,oBAAoB,+BAmDtB"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Badge } from './badge';
|
|
3
|
+
import { Checkbox } from './checkbox';
|
|
4
|
+
import { groupByKind, kindVariant } from './extension-grouping';
|
|
5
|
+
export function ExtensionPicker({ available, value, onChange, disabled, idPrefix = 'extension-picker', }) {
|
|
6
|
+
const groups = groupByKind(available);
|
|
7
|
+
const selected = new Set(value);
|
|
8
|
+
/**
|
|
9
|
+
* Toggle a single extension. For a NON-STACKABLE kind (`backend`), checking one
|
|
10
|
+
* first strips any other selected member of that kind before appending, so the
|
|
11
|
+
* combo carries at most one backend; unchecking just removes it. Order is
|
|
12
|
+
* preserved: a newly-checked name lands at the end.
|
|
13
|
+
*/
|
|
14
|
+
const toggle = (extension, nonStackable, checked) => {
|
|
15
|
+
if (!checked) {
|
|
16
|
+
onChange(value.filter((name) => name !== extension.name));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (selected.has(extension.name))
|
|
20
|
+
return;
|
|
21
|
+
const siblingNames = nonStackable
|
|
22
|
+
? new Set(available.filter((e) => e.kind === extension.kind).map((e) => e.name))
|
|
23
|
+
: undefined;
|
|
24
|
+
const kept = siblingNames === undefined ? [...value] : value.filter((name) => !siblingNames.has(name));
|
|
25
|
+
onChange([...kept, extension.name]);
|
|
26
|
+
};
|
|
27
|
+
return (_jsx("div", { "data-testid": idPrefix, className: "tai-stack", children: groups.map((group) => (_jsxs("div", { className: "tai-stack tai-stack-2", children: [_jsxs("div", { className: "tai-row", children: [_jsx(Badge, { variant: kindVariant(group.kind), children: group.kind }), group.nonStackable ? _jsx("span", { className: "tai-muted", children: "(single-select)" }) : null] }), _jsx("div", { className: "tai-row", children: group.members.map((extension) => (_jsx(Checkbox, { label: extension.name, checked: selected.has(extension.name), disabled: disabled, onCheckedChange: (checked) => {
|
|
28
|
+
toggle(extension, group.nonStackable, checked);
|
|
29
|
+
} }, extension.name))) })] }, group.kind))) }));
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=extension-picker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension-picker.js","sourceRoot":"","sources":["../../src/components/extension-picker.tsx"],"names":[],"mappings":";AAwBA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAahE,MAAM,UAAU,eAAe,CAAC,EAC9B,SAAS,EACT,KAAK,EACL,QAAQ,EACR,QAAQ,EACR,QAAQ,GAAG,kBAAkB,GACR;IACrB,MAAM,MAAM,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAEhC;;;;;OAKG;IACH,MAAM,MAAM,GAAG,CAAC,SAAoB,EAAE,YAAqB,EAAE,OAAgB,EAAQ,EAAE;QACrF,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YAC1D,OAAO;QACT,CAAC;QACD,IAAI,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC;YAAE,OAAO;QACzC,MAAM,YAAY,GAAG,YAAY;YAC/B,CAAC,CAAC,IAAI,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAChF,CAAC,CAAC,SAAS,CAAC;QACd,MAAM,IAAI,GACR,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;QAC5F,QAAQ,CAAC,CAAC,GAAG,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC,CAAC,CAAC;IAEF,OAAO,CACL,6BAAkB,QAAQ,EAAE,SAAS,EAAC,WAAW,YAC9C,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CACrB,eAAsB,SAAS,EAAC,uBAAuB,aAGrD,eAAK,SAAS,EAAC,SAAS,aACtB,KAAC,KAAK,IAAC,OAAO,EAAE,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,YAAG,KAAK,CAAC,IAAI,GAAS,EAC5D,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,eAAM,SAAS,EAAC,WAAW,gCAAuB,CAAC,CAAC,CAAC,IAAI,IAC3E,EACN,cAAK,SAAS,EAAC,SAAS,YACrB,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAChC,KAAC,QAAQ,IAEP,KAAK,EAAE,SAAS,CAAC,IAAI,EACrB,OAAO,EAAE,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,EACrC,QAAQ,EAAE,QAAQ,EAClB,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE;4BAC3B,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;wBACjD,CAAC,IANI,SAAS,CAAC,IAAI,CAOnB,CACH,CAAC,GACE,KAnBE,KAAK,CAAC,IAAI,CAoBd,CACP,CAAC,GACE,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `ExternalLinkButton` — an open-link action for a URL the Studio did not author
|
|
3
|
+
* (a registry homepage, an interaction payload's link). Only an ABSOLUTE
|
|
4
|
+
* `http(s)` URL is navigable here: every other spelling — another scheme, and a
|
|
5
|
+
* relative reference, which would be a same-origin in-app navigation the caller
|
|
6
|
+
* never intended — is NEUTRALIZED into plain text with no anchor and no href.
|
|
7
|
+
* This is an XSS pin.
|
|
8
|
+
*
|
|
9
|
+
* The check and the neutralized rendering are `Button`'s; this module chooses the
|
|
10
|
+
* stricter of the two link policies rather than re-implementing either.
|
|
11
|
+
*/
|
|
12
|
+
import type { ReactNode } from 'react';
|
|
13
|
+
export { isSafeHttpUrl } from './primitives';
|
|
14
|
+
export interface ExternalLinkButtonProps {
|
|
15
|
+
readonly url: string;
|
|
16
|
+
readonly children?: ReactNode;
|
|
17
|
+
}
|
|
18
|
+
export declare function ExternalLinkButton({ url, children }: ExternalLinkButtonProps): import("react").JSX.Element;
|
|
19
|
+
//# sourceMappingURL=external-link.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-link.d.ts","sourceRoot":"","sources":["../../src/components/external-link.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAUvC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,CAAC;CAC/B;AAED,wBAAgB,kBAAkB,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,uBAAuB,+BAW5E"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Button, buttonClass, DEFAULT_BUTTON_VARIANT, isSafeHttpUrl, NeutralizedLink, } from './primitives';
|
|
3
|
+
export { isSafeHttpUrl } from './primitives';
|
|
4
|
+
export function ExternalLinkButton({ url, children }) {
|
|
5
|
+
const label = children ?? url;
|
|
6
|
+
if (!isSafeHttpUrl(url)) {
|
|
7
|
+
// The same classes the navigable form wears, so the two never drift apart.
|
|
8
|
+
return (_jsx(NeutralizedLink, { className: buttonClass(DEFAULT_BUTTON_VARIANT, undefined), children: label }));
|
|
9
|
+
}
|
|
10
|
+
return _jsx(Button, { href: url, children: label });
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=external-link.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"external-link.js","sourceRoot":"","sources":["../../src/components/external-link.tsx"],"names":[],"mappings":";AAaA,OAAO,EACL,MAAM,EACN,WAAW,EACX,sBAAsB,EACtB,aAAa,EACb,eAAe,GAChB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAO7C,MAAM,UAAU,kBAAkB,CAAC,EAAE,GAAG,EAAE,QAAQ,EAA2B;IAC3E,MAAM,KAAK,GAAG,QAAQ,IAAI,GAAG,CAAC;IAC9B,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,2EAA2E;QAC3E,OAAO,CACL,KAAC,eAAe,IAAC,SAAS,EAAE,WAAW,CAAC,sBAAsB,EAAE,SAAS,CAAC,YACvE,KAAK,GACU,CACnB,CAAC;IACJ,CAAC;IACD,OAAO,KAAC,MAAM,IAAC,IAAI,EAAE,GAAG,YAAG,KAAK,GAAU,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
/** The a11y wiring a form control spreads onto its element. */
|
|
3
|
+
export interface FieldControlProps {
|
|
4
|
+
readonly id: string | undefined;
|
|
5
|
+
readonly 'aria-describedby': string | undefined;
|
|
6
|
+
readonly 'aria-invalid': true | undefined;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Read the enclosing Field's wiring.
|
|
10
|
+
*
|
|
11
|
+
* `id` and `aria-describedby` are `undefined` both when there is no Field AND
|
|
12
|
+
* inside a group `Field`: a group has no single element to carry them, and the
|
|
13
|
+
* group container itself already carries the name and the description. Only
|
|
14
|
+
* `aria-invalid` still crosses that boundary, because `role="group"` does not
|
|
15
|
+
* support it (ARIA 1.2), so the control is the sole place an errored group can
|
|
16
|
+
* expose its invalid state.
|
|
17
|
+
*/
|
|
18
|
+
export declare function useFieldControl(): FieldControlProps;
|
|
19
|
+
export interface FieldProps {
|
|
20
|
+
readonly label: string;
|
|
21
|
+
readonly description?: string;
|
|
22
|
+
readonly error?: string;
|
|
23
|
+
readonly children: ReactNode;
|
|
24
|
+
readonly style?: CSSProperties;
|
|
25
|
+
/** APPENDED to `tai-field` rather than replacing it, so the field keeps its paint. */
|
|
26
|
+
readonly className?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Set when the wrapped control is a GROUP rather than one labelable element —
|
|
29
|
+
* a `RadioGroup`, a set of checkboxes, any `role="radiogroup"`/`role="group"`
|
|
30
|
+
* panel.
|
|
31
|
+
*
|
|
32
|
+
* `<label for>` can only name a labelable element: pointed at a group it
|
|
33
|
+
* either dangles at an id no element carries or names an element the browser
|
|
34
|
+
* refuses to label, and it is inert either way. So a group Field wraps
|
|
35
|
+
* `children` in the group CONTAINER itself — a `<div role="group">` carrying
|
|
36
|
+
* `aria-labelledby` at the label and `aria-describedby` at the description and
|
|
37
|
+
* error — and the label becomes a `<span>`, because a `<label>` associated
|
|
38
|
+
* with nothing is a semantics lie.
|
|
39
|
+
*
|
|
40
|
+
* IT ALSO CHANGES WHAT A CHILD READS FROM {@link useFieldControl}. The
|
|
41
|
+
* container is what carries the name and the description, so the group Field
|
|
42
|
+
* publishes NEITHER `id` NOR `aria-describedby` — both are `undefined`, and a
|
|
43
|
+
* control that spread them would take the group's own name and description for
|
|
44
|
+
* itself. `aria-invalid` still crosses: `role="group"` does not support it
|
|
45
|
+
* (ARIA 1.2), so the control is the only place an errored group can expose its
|
|
46
|
+
* invalid state.
|
|
47
|
+
*
|
|
48
|
+
* Naming therefore happens BY CONSTRUCTION rather than by the call site
|
|
49
|
+
* remembering to read a hook. The cost is one extra container announcement
|
|
50
|
+
* where the child has a group role of its own; that is accepted deliberately,
|
|
51
|
+
* because the two failure directions are asymmetric — a redundant container is
|
|
52
|
+
* audible, an unnamed group is silent.
|
|
53
|
+
*
|
|
54
|
+
* A group child left UNMARKED is a build failure, not a runtime surprise:
|
|
55
|
+
* `components/field-group.test.ts` ("Field group contract" → "marks every
|
|
56
|
+
* Field whose child does not claim its control id") scans every Field call
|
|
57
|
+
* site in the repository, and a child outside its list of control-id-claiming
|
|
58
|
+
* components — `RadioGroup` among them — reddens until the site passes
|
|
59
|
+
* `group`.
|
|
60
|
+
*/
|
|
61
|
+
readonly group?: boolean;
|
|
62
|
+
}
|
|
63
|
+
export declare function Field({ label, description, error, children, style, className, group, }: FieldProps): import("react").JSX.Element;
|
|
64
|
+
//# sourceMappingURL=field.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field.d.ts","sourceRoot":"","sources":["../../src/components/field.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAYtD,+DAA+D;AAC/D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,cAAc,EAAE,IAAI,GAAG,SAAS,CAAC;CAC3C;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,IAAI,iBAAiB,CAUnD;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC;IAC/B,sFAAsF;IACtF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiCG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,KAAK,CAAC,EACpB,KAAK,EACL,WAAW,EACX,KAAK,EACL,QAAQ,EACR,KAAK,EACL,SAAS,EACT,KAAa,GACd,EAAE,UAAU,+BAiEZ"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* `Field` — the label + description + error wrapper every form control sits in.
|
|
4
|
+
* It owns one generated id and publishes it (plus the description/error ids and
|
|
5
|
+
* the invalid flag) through a context; a nested control reads them via
|
|
6
|
+
* `useFieldControl` and spreads them, so the label's `htmlFor`, the control's
|
|
7
|
+
* `aria-describedby`, and its `aria-invalid` stay wired without the caller
|
|
8
|
+
* threading ids by hand.
|
|
9
|
+
*/
|
|
10
|
+
import { createContext, useContext, useId } from 'react';
|
|
11
|
+
import { XCircleIcon } from './icons';
|
|
12
|
+
const FieldContext = createContext(null);
|
|
13
|
+
/**
|
|
14
|
+
* Read the enclosing Field's wiring.
|
|
15
|
+
*
|
|
16
|
+
* `id` and `aria-describedby` are `undefined` both when there is no Field AND
|
|
17
|
+
* inside a group `Field`: a group has no single element to carry them, and the
|
|
18
|
+
* group container itself already carries the name and the description. Only
|
|
19
|
+
* `aria-invalid` still crosses that boundary, because `role="group"` does not
|
|
20
|
+
* support it (ARIA 1.2), so the control is the sole place an errored group can
|
|
21
|
+
* expose its invalid state.
|
|
22
|
+
*/
|
|
23
|
+
export function useFieldControl() {
|
|
24
|
+
const ctx = useContext(FieldContext);
|
|
25
|
+
if (ctx === null) {
|
|
26
|
+
return { id: undefined, 'aria-describedby': undefined, 'aria-invalid': undefined };
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
id: ctx.controlId,
|
|
30
|
+
'aria-describedby': ctx.describedBy,
|
|
31
|
+
'aria-invalid': ctx.invalid ? true : undefined,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export function Field({ label, description, error, children, style, className, group = false, }) {
|
|
35
|
+
const controlId = useId();
|
|
36
|
+
const labelId = `${controlId}-label`;
|
|
37
|
+
const descriptionId = `${controlId}-desc`;
|
|
38
|
+
const errorId = `${controlId}-err`;
|
|
39
|
+
const describedByIds = [];
|
|
40
|
+
if (description !== undefined)
|
|
41
|
+
describedByIds.push(descriptionId);
|
|
42
|
+
if (error !== undefined)
|
|
43
|
+
describedByIds.push(errorId);
|
|
44
|
+
const describedBy = describedByIds.length > 0 ? describedByIds.join(' ') : undefined;
|
|
45
|
+
// A group withholds the ID and the DESCRIPTION — there is no single element to
|
|
46
|
+
// carry them, and a control that spread them inside a group would take the
|
|
47
|
+
// group's own name and description for itself — but it still publishes
|
|
48
|
+
// `invalid`. `aria-invalid` is not supported on `role="group"` (ARIA 1.2), so
|
|
49
|
+
// if the group Field withheld it too, a group Field carrying an `error` would
|
|
50
|
+
// expose its invalid state NOWHERE in the accessibility tree.
|
|
51
|
+
const value = group
|
|
52
|
+
? { controlId: undefined, describedBy: undefined, invalid: error !== undefined }
|
|
53
|
+
: { controlId, describedBy, invalid: error !== undefined };
|
|
54
|
+
return (_jsx(FieldContext.Provider, { value: value, children: _jsxs("div", { className: className === undefined ? 'tai-field' : `tai-field ${className}`, style: style, children: [group ? (_jsx("span", { id: labelId, className: "tai-field-label", children: label })) : (_jsx("label", { id: labelId, htmlFor: controlId, className: "tai-field-label", children: label })), group ? (_jsx("div", { role: "group", "aria-labelledby": labelId, "aria-describedby": describedBy, className: "tai-field-group", children: children })) : (children), description !== undefined ? (_jsx("p", { id: descriptionId, className: "tai-field-hint", style: { margin: 0 }, children: description })) : null, error !== undefined ? (_jsxs("p", { id: errorId, role: "alert", className: "tai-field-error", style: { margin: 0 }, children: [_jsx(XCircleIcon, {}), error] })) : null] }) }));
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=field.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field.js","sourceRoot":"","sources":["../../src/components/field.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `FleetReport` — the shared, loud rendering of a config mutation's fleet broadcast.
|
|
3
|
+
* Every mutation surface (connector, backup, mcp-config, env, extensions, single-MCP
|
|
4
|
+
* reload, fleet reload) computes a `FleetReportSummary` from its response through the
|
|
5
|
+
* api-client's shared handler and hands it here, so a FAILED propagation is never
|
|
6
|
+
* invisible.
|
|
7
|
+
*
|
|
8
|
+
* The `action` prop tunes the copy to the caller's framing: `'save'` (the default,
|
|
9
|
+
* used by every config-mutation surface) reports a saved change that did not fully
|
|
10
|
+
* propagate and points the operator at the System page to reload; `'reload'` (the
|
|
11
|
+
* System page's own fleet-reload action) drops the "Change saved" framing — nothing
|
|
12
|
+
* was saved, a reload was dispatched — and the self-referential System-page pointer.
|
|
13
|
+
*
|
|
14
|
+
* A `converged` summary (every origin applied, or a lone-worker local-only change)
|
|
15
|
+
* renders NOTHING — the calling surface shows its own success. A `degraded` summary
|
|
16
|
+
* (the bus was reached but a sibling did not confirm) or an `unreachable` summary (the
|
|
17
|
+
* bus itself failed) renders a loud `role="alert"` panel naming the honest per-origin
|
|
18
|
+
* outcomes: `failed` / `missing` / `departed` / `timed_out`, or the bus error. It
|
|
19
|
+
* never fakes success on a stranded origin. Every server-supplied string (an origin
|
|
20
|
+
* name, an error/detail message) renders as escaped React text, never an HTML sink.
|
|
21
|
+
*
|
|
22
|
+
* Every state — the headline and each origin's outcome — is a `tai-status` line: an
|
|
23
|
+
* icon MARK plus a word LABEL, with the tone color only reinforcing them, so the
|
|
24
|
+
* report is readable without color perception.
|
|
25
|
+
*/
|
|
26
|
+
import type { ReactNode } from 'react';
|
|
27
|
+
import type { FleetReportSummary } from '@tai42/api-client';
|
|
28
|
+
/**
|
|
29
|
+
* Render a fleet broadcast's failure state. Returns `null` for a converged/absent
|
|
30
|
+
* report (nothing to warn about) so callers can always mount it unconditionally
|
|
31
|
+
* beside their own success line.
|
|
32
|
+
*/
|
|
33
|
+
export interface FleetReportProps {
|
|
34
|
+
readonly summary: FleetReportSummary | null;
|
|
35
|
+
/** Whose framing the copy takes: a saved config change, or a dispatched reload. */
|
|
36
|
+
readonly action?: 'save' | 'reload';
|
|
37
|
+
}
|
|
38
|
+
export declare function FleetReport({ summary, action }: FleetReportProps): ReactNode;
|
|
39
|
+
//# sourceMappingURL=fleet-report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fleet-report.d.ts","sourceRoot":"","sources":["../../src/components/fleet-report.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,kBAAkB,EAAuB,MAAM,mBAAmB,CAAC;AAgCjF;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC5C,mFAAmF;IACnF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;CACrC;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,MAAe,EAAE,EAAE,gBAAgB,GAAG,SAAS,CAkErF"}
|