@tai42/studio-sdk 16.0.0 → 17.0.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/dist/components/code-block.js +1 -1
- package/dist/components/code-block.js.map +1 -1
- package/dist/components/confirm-dialog.js +1 -1
- package/dist/components/confirm-dialog.js.map +1 -1
- package/dist/components/copy-field.js +1 -1
- package/dist/components/copy-field.js.map +1 -1
- package/dist/components/date-range-picker.d.ts.map +1 -1
- package/dist/components/date-range-picker.js.map +1 -1
- package/dist/components/dialog.d.ts.map +1 -1
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/dirty-guard.d.ts.map +1 -1
- package/dist/components/dirty-guard.js +1 -1
- package/dist/components/dirty-guard.js.map +1 -1
- package/dist/components/explorer-body.d.ts +49 -0
- package/dist/components/explorer-body.d.ts.map +1 -0
- package/dist/components/explorer-body.js +67 -0
- package/dist/components/explorer-body.js.map +1 -0
- package/dist/components/explorer-page-size.d.ts +4 -0
- package/dist/components/explorer-page-size.d.ts.map +1 -0
- package/dist/components/explorer-page-size.js +36 -0
- package/dist/components/explorer-page-size.js.map +1 -0
- package/dist/components/explorer-tag-filter.d.ts +17 -0
- package/dist/components/explorer-tag-filter.d.ts.map +1 -0
- package/dist/components/explorer-tag-filter.js +29 -0
- package/dist/components/explorer-tag-filter.js.map +1 -0
- package/dist/components/explorer-tags.d.ts +22 -0
- package/dist/components/explorer-tags.d.ts.map +1 -0
- package/dist/components/explorer-tags.js +51 -0
- package/dist/components/explorer-tags.js.map +1 -0
- package/dist/components/explorer-view.d.ts +3 -17
- package/dist/components/explorer-view.d.ts.map +1 -1
- package/dist/components/explorer-view.js +53 -170
- package/dist/components/explorer-view.js.map +1 -1
- package/dist/components/extension-combo-builder.d.ts +1 -6
- package/dist/components/extension-combo-builder.d.ts.map +1 -1
- package/dist/components/extension-combo-builder.js +4 -79
- package/dist/components/extension-combo-builder.js.map +1 -1
- package/dist/components/extension-combo-parts.d.ts +44 -0
- package/dist/components/extension-combo-parts.d.ts.map +1 -0
- package/dist/components/extension-combo-parts.js +52 -0
- package/dist/components/extension-combo-parts.js.map +1 -0
- package/dist/components/field.d.ts +8 -0
- package/dist/components/field.d.ts.map +1 -1
- package/dist/components/field.js +0 -8
- package/dist/components/field.js.map +1 -1
- package/dist/components/fleet-report.d.ts +1 -1
- package/dist/components/fleet-report.d.ts.map +1 -1
- package/dist/components/fleet-report.js +51 -37
- package/dist/components/fleet-report.js.map +1 -1
- package/dist/components/folder-nav.d.ts.map +1 -1
- package/dist/components/folder-nav.js +1 -1
- package/dist/components/folder-nav.js.map +1 -1
- package/dist/components/form-dialog.d.ts.map +1 -1
- package/dist/components/form-dialog.js +1 -1
- package/dist/components/form-dialog.js.map +1 -1
- package/dist/components/icons/chrome-marks.d.ts +50 -0
- package/dist/components/icons/chrome-marks.d.ts.map +1 -0
- package/dist/components/icons/chrome-marks.js +51 -0
- package/dist/components/icons/chrome-marks.js.map +1 -0
- package/dist/components/icons/icon-frame.d.ts +29 -0
- package/dist/components/icons/icon-frame.d.ts.map +1 -0
- package/dist/components/icons/icon-frame.js +19 -0
- package/dist/components/icons/icon-frame.js.map +1 -0
- package/dist/components/icons/index.d.ts +40 -0
- package/dist/components/icons/index.d.ts.map +1 -0
- package/dist/components/icons/index.js +39 -0
- package/dist/components/icons/index.js.map +1 -0
- package/dist/components/icons/nav-map.d.ts +14 -0
- package/dist/components/icons/nav-map.d.ts.map +1 -0
- package/dist/components/icons/nav-map.js +28 -0
- package/dist/components/icons/nav-map.js.map +1 -0
- package/dist/components/icons/nav-marks.d.ts +44 -0
- package/dist/components/icons/nav-marks.d.ts.map +1 -0
- package/dist/components/icons/nav-marks.js +45 -0
- package/dist/components/icons/nav-marks.js.map +1 -0
- package/dist/components/icons/status-marks.d.ts +21 -0
- package/dist/components/icons/status-marks.d.ts.map +1 -0
- package/dist/components/icons/status-marks.js +22 -0
- package/dist/components/icons/status-marks.js.map +1 -0
- package/dist/components/icons/theme-marks.d.ts +9 -0
- package/dist/components/icons/theme-marks.d.ts.map +1 -0
- package/dist/components/icons/theme-marks.js +10 -0
- package/dist/components/icons/theme-marks.js.map +1 -0
- package/dist/components/inputs.js.map +1 -1
- package/dist/components/json-diff.d.ts.map +1 -1
- package/dist/components/json-diff.js +1 -3
- package/dist/components/json-diff.js.map +1 -1
- package/dist/components/json-tree-context.d.ts +13 -0
- package/dist/components/json-tree-context.d.ts.map +1 -0
- package/dist/components/json-tree-context.js +15 -0
- package/dist/components/json-tree-context.js.map +1 -0
- package/dist/components/json-tree-model.d.ts +56 -0
- package/dist/components/json-tree-model.d.ts.map +1 -0
- package/dist/components/json-tree-model.js +125 -0
- package/dist/components/json-tree-model.js.map +1 -0
- package/dist/components/json-tree-nodes.d.ts +35 -0
- package/dist/components/json-tree-nodes.d.ts.map +1 -0
- package/dist/components/json-tree-nodes.js +113 -0
- package/dist/components/json-tree-nodes.js.map +1 -0
- package/dist/components/json-tree.d.ts +20 -0
- package/dist/components/json-tree.d.ts.map +1 -1
- package/dist/components/json-tree.js +7 -315
- package/dist/components/json-tree.js.map +1 -1
- package/dist/components/json-value-format.d.ts +20 -0
- package/dist/components/json-value-format.d.ts.map +1 -0
- package/dist/components/json-value-format.js +63 -0
- package/dist/components/json-value-format.js.map +1 -0
- package/dist/components/markdown-blocks.d.ts +38 -0
- package/dist/components/markdown-blocks.d.ts.map +1 -0
- package/dist/components/markdown-blocks.js +168 -0
- package/dist/components/markdown-blocks.js.map +1 -0
- package/dist/components/markdown-inline.d.ts +24 -0
- package/dist/components/markdown-inline.d.ts.map +1 -0
- package/dist/components/markdown-inline.js +257 -0
- package/dist/components/markdown-inline.js.map +1 -0
- package/dist/components/markdown.d.ts +3 -52
- package/dist/components/markdown.d.ts.map +1 -1
- package/dist/components/markdown.js +4 -376
- package/dist/components/markdown.js.map +1 -1
- package/dist/components/observer-registry.d.ts +38 -0
- package/dist/components/observer-registry.d.ts.map +1 -0
- package/dist/components/observer-registry.js +131 -0
- package/dist/components/observer-registry.js.map +1 -0
- package/dist/components/overflow-measure.d.ts +38 -0
- package/dist/components/overflow-measure.d.ts.map +1 -0
- package/dist/components/overflow-measure.js +54 -0
- package/dist/components/overflow-measure.js.map +1 -0
- package/dist/components/page-fill.d.ts.map +1 -1
- package/dist/components/page-fill.js.map +1 -1
- package/dist/components/prose-regions.d.ts +81 -0
- package/dist/components/prose-regions.d.ts.map +1 -0
- package/dist/components/prose-regions.js +128 -0
- package/dist/components/prose-regions.js.map +1 -0
- package/dist/components/radio-group.d.ts.map +1 -1
- package/dist/components/radio-group.js.map +1 -1
- package/dist/components/scroll-region.d.ts +24 -0
- package/dist/components/scroll-region.d.ts.map +1 -1
- package/dist/components/scroll-region.js +3 -322
- package/dist/components/scroll-region.js.map +1 -1
- package/dist/components/tab-stop-parse.d.ts +53 -0
- package/dist/components/tab-stop-parse.d.ts.map +1 -0
- package/dist/components/tab-stop-parse.js +202 -0
- package/dist/components/tab-stop-parse.js.map +1 -0
- package/dist/components/table.d.ts +1 -1
- package/dist/components/table.d.ts.map +1 -1
- package/dist/components/tags.d.ts.map +1 -1
- package/dist/components/tags.js +1 -1
- package/dist/components/tags.js.map +1 -1
- package/dist/components/templated-text-field.d.ts +1 -1
- package/dist/components/templated-text-field.d.ts.map +1 -1
- package/dist/components/templated-text-field.js +10 -174
- package/dist/components/templated-text-field.js.map +1 -1
- package/dist/components/templated-text-kwargs-editor.d.ts +24 -0
- package/dist/components/templated-text-kwargs-editor.d.ts.map +1 -0
- package/dist/components/templated-text-kwargs-editor.js +48 -0
- package/dist/components/templated-text-kwargs-editor.js.map +1 -0
- package/dist/components/templated-text-kwargs.d.ts +37 -0
- package/dist/components/templated-text-kwargs.d.ts.map +1 -0
- package/dist/components/templated-text-kwargs.js +66 -0
- package/dist/components/templated-text-kwargs.js.map +1 -0
- package/dist/components/templated-text-source.d.ts +33 -0
- package/dist/components/templated-text-source.d.ts.map +1 -0
- package/dist/components/templated-text-source.js +53 -0
- package/dist/components/templated-text-source.js.map +1 -0
- package/dist/components/tool-picker-parts.d.ts +39 -0
- package/dist/components/tool-picker-parts.d.ts.map +1 -0
- package/dist/components/tool-picker-parts.js +87 -0
- package/dist/components/tool-picker-parts.js.map +1 -0
- package/dist/components/tool-picker.d.ts +1 -2
- package/dist/components/tool-picker.d.ts.map +1 -1
- package/dist/components/tool-picker.js +4 -66
- package/dist/components/tool-picker.js.map +1 -1
- package/dist/components/version-history-panel.d.ts.map +1 -1
- package/dist/components/version-history-panel.js +7 -34
- package/dist/components/version-history-panel.js.map +1 -1
- package/dist/components/version-history-rows.d.ts +48 -0
- package/dist/components/version-history-rows.d.ts.map +1 -0
- package/dist/components/version-history-rows.js +51 -0
- package/dist/components/version-history-rows.js.map +1 -0
- package/dist/components/view-toggle.d.ts.map +1 -1
- package/dist/components/view-toggle.js.map +1 -1
- package/dist/element-slot.d.ts +11 -0
- package/dist/element-slot.d.ts.map +1 -1
- package/dist/element-slot.js +0 -11
- package/dist/element-slot.js.map +1 -1
- package/dist/guards.d.ts +6 -0
- package/dist/guards.d.ts.map +1 -0
- package/dist/guards.js +8 -0
- package/dist/guards.js.map +1 -0
- package/dist/hooks/interactions-connection.d.ts +43 -0
- package/dist/hooks/interactions-connection.d.ts.map +1 -0
- package/dist/hooks/interactions-connection.js +171 -0
- package/dist/hooks/interactions-connection.js.map +1 -0
- package/dist/hooks/interactions-stream.d.ts +80 -0
- package/dist/hooks/interactions-stream.d.ts.map +1 -0
- package/dist/hooks/interactions-stream.js +233 -0
- package/dist/hooks/interactions-stream.js.map +1 -0
- package/dist/hooks/useApi.d.ts +2259 -2189
- package/dist/hooks/useApi.d.ts.map +1 -1
- package/dist/hooks/useApi.js +0 -11
- package/dist/hooks/useApi.js.map +1 -1
- package/dist/hooks/useAuth.d.ts +6 -0
- package/dist/hooks/useAuth.d.ts.map +1 -1
- package/dist/hooks/useAuth.js +0 -6
- package/dist/hooks/useAuth.js.map +1 -1
- package/dist/hooks/useCapabilities.d.ts +18 -2
- package/dist/hooks/useCapabilities.d.ts.map +1 -1
- package/dist/hooks/useCapabilities.js +1 -17
- package/dist/hooks/useCapabilities.js.map +1 -1
- package/dist/hooks/useSse.d.ts +34 -6
- package/dist/hooks/useSse.d.ts.map +1 -1
- package/dist/hooks/useSse.js +27 -471
- package/dist/hooks/useSse.js.map +1 -1
- package/dist/hooks/useSystemKinds.d.ts +1 -1
- package/dist/hooks/useSystemKinds.d.ts.map +1 -1
- package/dist/hooks/useSystemKinds.js +0 -18
- package/dist/hooks/useSystemKinds.js.map +1 -1
- package/dist/hooks/useTheme.d.ts +15 -0
- package/dist/hooks/useTheme.d.ts.map +1 -1
- package/dist/hooks/useTheme.js +0 -15
- package/dist/hooks/useTheme.js.map +1 -1
- package/dist/hooks/useToolDisplayNames.d.ts +0 -14
- package/dist/hooks/useToolDisplayNames.d.ts.map +1 -1
- package/dist/hooks/useToolDisplayNames.js +0 -14
- package/dist/hooks/useToolDisplayNames.js.map +1 -1
- package/dist/host.d.ts +3 -3
- package/dist/host.d.ts.map +1 -1
- package/dist/host.js +2 -9
- package/dist/host.js.map +1 -1
- package/dist/index.d.ts +103 -103
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +49 -62
- package/dist/index.js.map +1 -1
- package/dist/navigation/app-link.d.ts +25 -0
- package/dist/navigation/app-link.d.ts.map +1 -0
- package/dist/navigation/app-link.js +33 -0
- package/dist/navigation/app-link.js.map +1 -0
- package/dist/navigation/context.d.ts +3 -20
- package/dist/navigation/context.d.ts.map +1 -1
- package/dist/navigation/context.js +7 -267
- package/dist/navigation/context.js.map +1 -1
- package/dist/navigation/entry-state.d.ts +23 -0
- package/dist/navigation/entry-state.d.ts.map +1 -0
- package/dist/navigation/entry-state.js +39 -0
- package/dist/navigation/entry-state.js.map +1 -0
- package/dist/navigation/guard-registry.d.ts +30 -0
- package/dist/navigation/guard-registry.d.ts.map +1 -0
- package/dist/navigation/guard-registry.js +46 -0
- package/dist/navigation/guard-registry.js.map +1 -0
- package/dist/navigation/guarded-navigation.d.ts +24 -0
- package/dist/navigation/guarded-navigation.d.ts.map +1 -0
- package/dist/navigation/guarded-navigation.js +102 -0
- package/dist/navigation/guarded-navigation.js.map +1 -0
- package/dist/navigation/index.d.ts +5 -4
- package/dist/navigation/index.d.ts.map +1 -1
- package/dist/navigation/index.js +2 -1
- package/dist/navigation/index.js.map +1 -1
- package/dist/navigation/types.d.ts +8 -11
- package/dist/navigation/types.d.ts.map +1 -1
- package/dist/navigation/use-back-forward-guard.d.ts +12 -0
- package/dist/navigation/use-back-forward-guard.d.ts.map +1 -0
- package/dist/navigation/use-back-forward-guard.js +75 -0
- package/dist/navigation/use-back-forward-guard.js.map +1 -0
- package/dist/navigation/use-search-commit.d.ts.map +1 -1
- package/dist/navigation/use-search-commit.js.map +1 -1
- package/dist/plugin/host-state.d.ts.map +1 -1
- package/dist/plugin/host-state.js.map +1 -1
- package/dist/plugin/registry.d.ts +6 -15
- package/dist/plugin/registry.d.ts.map +1 -1
- package/dist/plugin/registry.js +83 -75
- package/dist/plugin/registry.js.map +1 -1
- package/dist/schema-editor/SchemaEditor.d.ts.map +1 -1
- package/dist/schema-editor/SchemaEditor.js.map +1 -1
- package/dist/schema-editor/index.d.ts +3 -3
- package/dist/schema-editor/index.d.ts.map +1 -1
- package/dist/schema-editor/index.js +1 -6
- package/dist/schema-editor/index.js.map +1 -1
- package/dist/schema-form/SecretRefField.d.ts +18 -3
- package/dist/schema-form/SecretRefField.d.ts.map +1 -1
- package/dist/schema-form/SecretRefField.js +21 -26
- package/dist/schema-form/SecretRefField.js.map +1 -1
- package/dist/schema-form/classify.d.ts +1 -113
- package/dist/schema-form/classify.d.ts.map +1 -1
- package/dist/schema-form/classify.js +174 -246
- package/dist/schema-form/classify.js.map +1 -1
- package/dist/schema-form/context.d.ts +6 -0
- package/dist/schema-form/context.d.ts.map +1 -1
- package/dist/schema-form/context.js +0 -6
- package/dist/schema-form/context.js.map +1 -1
- package/dist/schema-form/default-value.d.ts.map +1 -1
- package/dist/schema-form/default-value.js +42 -19
- package/dist/schema-form/default-value.js.map +1 -1
- package/dist/schema-form/enum-field.d.ts +1 -1
- package/dist/schema-form/enum-field.d.ts.map +1 -1
- package/dist/schema-form/field-group.d.ts +6 -0
- package/dist/schema-form/field-group.d.ts.map +1 -1
- package/dist/schema-form/field-group.js +0 -6
- package/dist/schema-form/field-group.js.map +1 -1
- package/dist/schema-form/field-model.d.ts +121 -0
- package/dist/schema-form/field-model.d.ts.map +1 -0
- package/dist/schema-form/field-model.js +2 -0
- package/dist/schema-form/field-model.js.map +1 -0
- package/dist/schema-form/field-node.d.ts.map +1 -1
- package/dist/schema-form/field-node.js +25 -14
- package/dist/schema-form/field-node.js.map +1 -1
- package/dist/schema-form/index.d.ts +8 -8
- package/dist/schema-form/index.d.ts.map +1 -1
- package/dist/schema-form/index.js +3 -34
- package/dist/schema-form/index.js.map +1 -1
- package/dist/schema-form/json-field.d.ts +19 -0
- package/dist/schema-form/json-field.d.ts.map +1 -1
- package/dist/schema-form/json-field.js +0 -19
- package/dist/schema-form/json-field.js.map +1 -1
- package/dist/schema-form/media-field.d.ts +1 -1
- package/dist/schema-form/media-field.d.ts.map +1 -1
- package/dist/schema-form/media-field.js +49 -30
- package/dist/schema-form/media-field.js.map +1 -1
- package/dist/schema-form/record-field.d.ts +12 -0
- package/dist/schema-form/record-field.d.ts.map +1 -1
- package/dist/schema-form/record-field.js +1 -13
- package/dist/schema-form/record-field.js.map +1 -1
- package/dist/schema-form/string-annotations.d.ts +20 -0
- package/dist/schema-form/string-annotations.d.ts.map +1 -0
- package/dist/schema-form/string-annotations.js +105 -0
- package/dist/schema-form/string-annotations.js.map +1 -0
- package/dist/schema-form/string-field.d.ts +1 -1
- package/dist/schema-form/string-field.d.ts.map +1 -1
- package/dist/schema-form/string-field.js +1 -1
- package/dist/schema-form/string-field.js.map +1 -1
- package/dist/schema-form/union-field.d.ts +1 -1
- package/dist/schema-form/union-field.d.ts.map +1 -1
- package/dist/schema-form/union-field.js.map +1 -1
- package/dist/schema-form/union.d.ts +8 -1
- package/dist/schema-form/union.d.ts.map +1 -1
- package/dist/schema-form/union.js +0 -7
- package/dist/schema-form/union.js.map +1 -1
- package/dist/schema-form/validate.d.ts.map +1 -1
- package/dist/schema-form/validate.js +126 -105
- package/dist/schema-form/validate.js.map +1 -1
- package/dist/state-binding/AdapterMapping.d.ts.map +1 -1
- package/dist/state-binding/AdapterMapping.js +0 -0
- package/dist/state-binding/AdapterMapping.js.map +1 -1
- package/dist/state-binding/BindingJqField.d.ts.map +1 -1
- package/dist/state-binding/BindingJqField.js +2 -2
- package/dist/state-binding/BindingJqField.js.map +1 -1
- package/dist/state-binding/InputInjectionRow.d.ts.map +1 -1
- package/dist/state-binding/InputInjectionRow.js +3 -3
- package/dist/state-binding/InputInjectionRow.js.map +1 -1
- package/dist/state-binding/StateAttachRow.d.ts.map +1 -1
- package/dist/state-binding/StateAttachRow.js +57 -41
- package/dist/state-binding/StateAttachRow.js.map +1 -1
- package/dist/state-binding/StateBindingSection.d.ts.map +1 -1
- package/dist/state-binding/StateBindingSection.js.map +1 -1
- package/dist/state-binding/SubjectScopeFields.d.ts.map +1 -1
- package/dist/state-binding/SubjectScopeFields.js.map +1 -1
- package/dist/state-binding/UpdateRow.d.ts.map +1 -1
- package/dist/state-binding/UpdateRow.js +2 -2
- package/dist/state-binding/UpdateRow.js.map +1 -1
- package/dist/state-binding/adapter-mapping-row.d.ts +17 -0
- package/dist/state-binding/adapter-mapping-row.d.ts.map +1 -0
- package/dist/state-binding/adapter-mapping-row.js +87 -0
- package/dist/state-binding/adapter-mapping-row.js.map +1 -0
- package/dist/state-binding/index.d.ts +21 -21
- package/dist/state-binding/index.d.ts.map +1 -1
- package/dist/state-binding/index.js +9 -15
- package/dist/state-binding/index.js.map +1 -1
- package/dist/state-binding/templated-text-catalog.d.ts.map +1 -1
- package/dist/state-binding/templated-text-catalog.js.map +1 -1
- package/dist/state-binding/types.d.ts +2 -2
- package/dist/state-binding/types.d.ts.map +1 -1
- package/dist/structured-output/StructuredOutput.d.ts.map +1 -1
- package/dist/structured-output/StructuredOutput.js +1 -3
- package/dist/structured-output/StructuredOutput.js.map +1 -1
- package/package.json +2 -2
- package/src/components/code-block.tsx +1 -1
- package/src/components/confirm-dialog.tsx +1 -1
- package/src/components/copy-field.tsx +1 -1
- package/src/components/date-range-picker.tsx +1 -1
- package/src/components/dialog.tsx +1 -1
- package/src/components/dirty-guard.tsx +3 -3
- package/src/components/explorer-body.tsx +239 -0
- package/src/components/explorer-page-size.ts +39 -0
- package/src/components/explorer-tag-filter.tsx +80 -0
- package/src/components/explorer-tags.ts +64 -0
- package/src/components/explorer-view.tsx +115 -367
- package/src/components/extension-combo-builder.tsx +35 -153
- package/src/components/extension-combo-parts.tsx +236 -0
- package/src/components/field.tsx +1 -1
- package/src/components/fleet-report.tsx +98 -55
- package/src/components/folder-nav.tsx +2 -2
- package/src/components/form-dialog.tsx +2 -2
- package/src/components/icons/chrome-marks.tsx +195 -0
- package/src/components/icons/icon-frame.tsx +50 -0
- package/src/components/icons/index.ts +84 -0
- package/src/components/icons/nav-map.ts +55 -0
- package/src/components/icons/nav-marks.tsx +205 -0
- package/src/components/icons/status-marks.tsx +46 -0
- package/src/components/icons/theme-marks.tsx +33 -0
- package/src/components/inputs.tsx +1 -1
- package/src/components/json-diff.tsx +1 -4
- package/src/components/json-tree-context.ts +26 -0
- package/src/components/json-tree-model.ts +139 -0
- package/src/components/json-tree-nodes.tsx +224 -0
- package/src/components/json-tree.tsx +15 -434
- package/src/components/json-value-format.ts +64 -0
- package/src/components/markdown-blocks.ts +198 -0
- package/src/components/markdown-inline.tsx +365 -0
- package/src/components/markdown.tsx +6 -472
- package/src/components/observer-registry.ts +139 -0
- package/src/components/overflow-measure.ts +69 -0
- package/src/components/page-fill.tsx +1 -1
- package/src/components/prose-regions.ts +153 -0
- package/src/components/radio-group.tsx +1 -1
- package/src/components/scroll-region.tsx +22 -361
- package/src/components/tab-stop-parse.ts +217 -0
- package/src/components/table.tsx +1 -1
- package/src/components/tags.tsx +2 -2
- package/src/components/templated-text-field.tsx +39 -332
- package/src/components/templated-text-kwargs-editor.tsx +147 -0
- package/src/components/templated-text-kwargs.ts +92 -0
- package/src/components/templated-text-source.tsx +226 -0
- package/src/components/tool-picker-parts.tsx +184 -0
- package/src/components/tool-picker.tsx +22 -114
- package/src/components/version-history-panel.tsx +39 -143
- package/src/components/version-history-rows.tsx +220 -0
- package/src/components/view-toggle.tsx +1 -1
- package/src/element-slot.ts +1 -1
- package/src/guards.ts +7 -0
- package/src/hooks/interactions-connection.ts +227 -0
- package/src/hooks/interactions-stream.ts +274 -0
- package/src/hooks/useApi.ts +1 -1
- package/src/hooks/useAuth.ts +1 -1
- package/src/hooks/useCapabilities.ts +3 -3
- package/src/hooks/useSse.ts +51 -478
- package/src/hooks/useSystemKinds.tsx +2 -2
- package/src/hooks/useTheme.ts +1 -1
- package/src/hooks/useToolDisplayNames.tsx +2 -2
- package/src/host.ts +7 -7
- package/src/index.ts +292 -292
- package/src/navigation/app-link.tsx +70 -0
- package/src/navigation/context.tsx +12 -331
- package/src/navigation/entry-state.ts +42 -0
- package/src/navigation/guard-registry.ts +65 -0
- package/src/navigation/guarded-navigation.ts +147 -0
- package/src/navigation/index.ts +14 -14
- package/src/navigation/types.ts +8 -11
- package/src/navigation/use-back-forward-guard.ts +90 -0
- package/src/navigation/use-search-commit.ts +1 -1
- package/src/plugin/host-state.ts +1 -1
- package/src/plugin/registry.ts +111 -90
- package/src/schema-editor/SchemaEditor.tsx +1 -1
- package/src/schema-editor/index.ts +3 -3
- package/src/schema-form/SecretRefField.tsx +122 -72
- package/src/schema-form/classify.ts +245 -396
- package/src/schema-form/context.ts +1 -1
- package/src/schema-form/default-value.ts +48 -17
- package/src/schema-form/enum-field.tsx +1 -1
- package/src/schema-form/field-group.tsx +1 -1
- package/src/schema-form/field-model.ts +133 -0
- package/src/schema-form/field-node.tsx +95 -39
- package/src/schema-form/index.ts +10 -10
- package/src/schema-form/json-field.tsx +1 -1
- package/src/schema-form/media-field.tsx +136 -67
- package/src/schema-form/record-field.tsx +2 -2
- package/src/schema-form/string-annotations.ts +111 -0
- package/src/schema-form/string-field.tsx +2 -2
- package/src/schema-form/union-field.tsx +3 -2
- package/src/schema-form/union.ts +1 -1
- package/src/schema-form/validate.ts +185 -104
- package/src/state-binding/AdapterMapping.tsx +0 -0
- package/src/state-binding/BindingJqField.tsx +3 -3
- package/src/state-binding/InputInjectionRow.tsx +4 -4
- package/src/state-binding/StateAttachRow.tsx +229 -154
- package/src/state-binding/StateBindingSection.tsx +1 -1
- package/src/state-binding/SubjectScopeFields.tsx +1 -1
- package/src/state-binding/UpdateRow.tsx +3 -3
- package/src/state-binding/adapter-mapping-row.tsx +232 -0
- package/src/state-binding/index.ts +43 -43
- package/src/state-binding/templated-text-catalog.ts +0 -1
- package/src/state-binding/types.ts +2 -2
- package/src/structured-output/StructuredOutput.tsx +1 -4
- package/dist/components/icons.d.ts +0 -160
- package/dist/components/icons.d.ts.map +0 -1
- package/dist/components/icons.js +0 -160
- package/dist/components/icons.js.map +0 -1
- package/src/components/icons.tsx +0 -586
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The explorer's directory body: the empty-state ladder, the card grid and the
|
|
3
|
+
* scrolling table (folders sorted above items in both), and the page footer. The
|
|
4
|
+
* pagination MATH lives in `ExplorerView`; this renders the result.
|
|
5
|
+
*/
|
|
6
|
+
import type { ReactNode } from 'react';
|
|
7
|
+
|
|
8
|
+
import { EntityCardGrid } from './entity-card-grid';
|
|
9
|
+
import { PAGE_SIZES } from './explorer-page-size';
|
|
10
|
+
import type { ExplorerColumn, ExplorerEmptyStates } from './explorer-view';
|
|
11
|
+
import { type Folder, FolderRow } from './folder-nav';
|
|
12
|
+
import { type OpenTargetProps } from './open-target';
|
|
13
|
+
import { Button, Card, EmptyState } from './primitives';
|
|
14
|
+
import { ScrollRegion } from './scroll-region';
|
|
15
|
+
import { Select } from './select';
|
|
16
|
+
import { Table, TBody, TD, TH, THead, TR } from './table';
|
|
17
|
+
import type { ViewMode } from './view-toggle';
|
|
18
|
+
|
|
19
|
+
/** One page entry: a subfolder (sorted first) or a filtered item, in one array. */
|
|
20
|
+
export type ExplorerEntry<T> =
|
|
21
|
+
| { readonly kind: 'folder'; readonly folder: Folder }
|
|
22
|
+
| { readonly kind: 'item'; readonly item: T };
|
|
23
|
+
|
|
24
|
+
/** A first-class folder entry — a `FolderRow` (icon + name, navigates inward)
|
|
25
|
+
* beside its optional actions, in the layout shared by the row cell and the card. */
|
|
26
|
+
function FolderEntry({
|
|
27
|
+
folder,
|
|
28
|
+
onNavigate,
|
|
29
|
+
renderFolderActions,
|
|
30
|
+
}: {
|
|
31
|
+
readonly folder: Folder;
|
|
32
|
+
readonly onNavigate: (folderId: string | null) => void;
|
|
33
|
+
readonly renderFolderActions: ((folder: Folder) => ReactNode) | undefined;
|
|
34
|
+
}): ReactNode {
|
|
35
|
+
return (
|
|
36
|
+
<div className="tai-explorer-folder">
|
|
37
|
+
<FolderRow folder={folder} onOpen={onNavigate} />
|
|
38
|
+
{renderFolderActions ? renderFolderActions(folder) : null}
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface ExplorerPagerProps {
|
|
44
|
+
readonly label: string;
|
|
45
|
+
readonly pageStart: number;
|
|
46
|
+
readonly pageSize: number;
|
|
47
|
+
readonly total: number;
|
|
48
|
+
readonly effectivePage: number;
|
|
49
|
+
readonly pageCount: number;
|
|
50
|
+
readonly onPageChange: (page: number) => void;
|
|
51
|
+
readonly onPageSizeChange: (size: number) => void;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function ExplorerPager({
|
|
55
|
+
label,
|
|
56
|
+
pageStart,
|
|
57
|
+
pageSize,
|
|
58
|
+
total,
|
|
59
|
+
effectivePage,
|
|
60
|
+
pageCount,
|
|
61
|
+
onPageChange,
|
|
62
|
+
onPageSizeChange,
|
|
63
|
+
}: ExplorerPagerProps): ReactNode {
|
|
64
|
+
return (
|
|
65
|
+
<nav className="tai-explorer-pagination" aria-label={`${label} pagination`}>
|
|
66
|
+
{/* The pager counts ENTRIES — subfolders plus filtered items in the
|
|
67
|
+
current directory — which is a different unit from the header's total
|
|
68
|
+
item count across every folder. Naming the unit keeps the two honest:
|
|
69
|
+
"1–4 of 4 entries" here versus "7 templates" above. */}
|
|
70
|
+
<span className="tai-muted">{`${String(pageStart + 1)}–${String(Math.min(pageStart + pageSize, total))} of ${String(total)} entries`}</span>
|
|
71
|
+
<div className="tai-row">
|
|
72
|
+
<Select
|
|
73
|
+
aria-label="Items per page"
|
|
74
|
+
value={String(pageSize)}
|
|
75
|
+
onValueChange={(value) => {
|
|
76
|
+
onPageSizeChange(Number(value));
|
|
77
|
+
}}
|
|
78
|
+
options={PAGE_SIZES.map((size) => ({
|
|
79
|
+
value: String(size),
|
|
80
|
+
label: `${String(size)} per page`,
|
|
81
|
+
}))}
|
|
82
|
+
/>
|
|
83
|
+
{/* aria-disabled, never the disabled attribute: a button removed from
|
|
84
|
+
the tab order at the bound drops focus to the body (WCAG 2.4.3).
|
|
85
|
+
The click guard makes activation at the bound an inert no-op. */}
|
|
86
|
+
<Button
|
|
87
|
+
variant="ghost"
|
|
88
|
+
aria-label="Previous page"
|
|
89
|
+
aria-disabled={effectivePage <= 1}
|
|
90
|
+
onClick={() => {
|
|
91
|
+
if (effectivePage <= 1) return;
|
|
92
|
+
onPageChange(effectivePage - 1);
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
Prev
|
|
96
|
+
</Button>
|
|
97
|
+
<Button
|
|
98
|
+
variant="ghost"
|
|
99
|
+
aria-label="Next page"
|
|
100
|
+
aria-disabled={effectivePage >= pageCount}
|
|
101
|
+
onClick={() => {
|
|
102
|
+
if (effectivePage >= pageCount) return;
|
|
103
|
+
onPageChange(effectivePage + 1);
|
|
104
|
+
}}
|
|
105
|
+
>
|
|
106
|
+
Next
|
|
107
|
+
</Button>
|
|
108
|
+
<span className="tai-muted">{`Page ${String(effectivePage)} of ${String(pageCount)}`}</span>
|
|
109
|
+
</div>
|
|
110
|
+
</nav>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface ExplorerBodyProps<T> {
|
|
115
|
+
readonly hasEntries: boolean;
|
|
116
|
+
/** Items in the current folder before filtering, so the empty ladder can tell
|
|
117
|
+
* "filter emptied it" (>0 → no-match) from "genuinely empty". */
|
|
118
|
+
readonly inFolderCount: number;
|
|
119
|
+
readonly emptyStates: ExplorerEmptyStates;
|
|
120
|
+
readonly viewMode: ViewMode;
|
|
121
|
+
readonly label: string;
|
|
122
|
+
readonly columns: readonly ExplorerColumn[];
|
|
123
|
+
readonly pageEntries: readonly ExplorerEntry<T>[];
|
|
124
|
+
readonly getItemKey: (item: T) => string;
|
|
125
|
+
readonly renderRow: (item: T) => ReactNode;
|
|
126
|
+
readonly renderCard: (item: T) => ReactNode;
|
|
127
|
+
readonly openProps: (item: T) => OpenTargetProps;
|
|
128
|
+
readonly onNavigate: (folderId: string | null) => void;
|
|
129
|
+
readonly renderFolderActions: ((folder: Folder) => ReactNode) | undefined;
|
|
130
|
+
readonly pager: ExplorerPagerProps;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** A card entry (folder card or item card) for the grid view. */
|
|
134
|
+
function CardEntry<T>(
|
|
135
|
+
props: ExplorerBodyProps<T> & { readonly entry: ExplorerEntry<T> },
|
|
136
|
+
): ReactNode {
|
|
137
|
+
const { entry, onNavigate, renderFolderActions, getItemKey, renderCard, openProps } = props;
|
|
138
|
+
if (entry.kind === 'folder') {
|
|
139
|
+
return (
|
|
140
|
+
<div role="listitem" key={`folder:${entry.folder.id}`}>
|
|
141
|
+
<Card interactive>
|
|
142
|
+
<FolderEntry
|
|
143
|
+
folder={entry.folder}
|
|
144
|
+
onNavigate={onNavigate}
|
|
145
|
+
renderFolderActions={renderFolderActions}
|
|
146
|
+
/>
|
|
147
|
+
</Card>
|
|
148
|
+
</div>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
return (
|
|
152
|
+
<div role="listitem" key={`item:${getItemKey(entry.item)}`} {...openProps(entry.item)}>
|
|
153
|
+
{renderCard(entry.item)}
|
|
154
|
+
</div>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** A table row (folder row spanning all columns, or item row) for the list view. */
|
|
159
|
+
function RowEntry<T>(
|
|
160
|
+
props: ExplorerBodyProps<T> & { readonly entry: ExplorerEntry<T> },
|
|
161
|
+
): ReactNode {
|
|
162
|
+
const { entry, columns, onNavigate, renderFolderActions, getItemKey, renderRow, openProps } =
|
|
163
|
+
props;
|
|
164
|
+
if (entry.kind === 'folder') {
|
|
165
|
+
return (
|
|
166
|
+
<TR key={`folder:${entry.folder.id}`}>
|
|
167
|
+
<TD colSpan={columns.length}>
|
|
168
|
+
<FolderEntry
|
|
169
|
+
folder={entry.folder}
|
|
170
|
+
onNavigate={onNavigate}
|
|
171
|
+
renderFolderActions={renderFolderActions}
|
|
172
|
+
/>
|
|
173
|
+
</TD>
|
|
174
|
+
</TR>
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
return (
|
|
178
|
+
<TR key={`item:${getItemKey(entry.item)}`} {...openProps(entry.item)}>
|
|
179
|
+
{renderRow(entry.item)}
|
|
180
|
+
</TR>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function ExplorerBody<T>(props: ExplorerBodyProps<T>): ReactNode {
|
|
185
|
+
const { hasEntries, inFolderCount, emptyStates, viewMode, label, columns, pageEntries, pager } =
|
|
186
|
+
props;
|
|
187
|
+
|
|
188
|
+
if (!hasEntries) {
|
|
189
|
+
// The current folder renders nothing. A filter emptied it (`inFolderCount` > 0)
|
|
190
|
+
// → "no match"; otherwise the folder is genuinely empty. The ladder decides on
|
|
191
|
+
// the full, unsliced sets, never on a page.
|
|
192
|
+
return <EmptyState {...(inFolderCount > 0 ? emptyStates.noMatch : emptyStates.emptyFolder)} />;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (viewMode === 'cards') {
|
|
196
|
+
return (
|
|
197
|
+
<>
|
|
198
|
+
<EntityCardGrid aria-label={label}>
|
|
199
|
+
{pageEntries.map((entry) => (
|
|
200
|
+
<CardEntry key={entryKey(entry, props.getItemKey)} {...props} entry={entry} />
|
|
201
|
+
))}
|
|
202
|
+
</EntityCardGrid>
|
|
203
|
+
<ExplorerPager {...pager} />
|
|
204
|
+
</>
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Folder rows share the item table, spanning every column, sorted above items —
|
|
209
|
+
// so a folder-with-only-subfolders is folder ROWS, never a header-only table.
|
|
210
|
+
// A too-wide table scrolls inside its own box rather than widening the page.
|
|
211
|
+
return (
|
|
212
|
+
<>
|
|
213
|
+
<ScrollRegion label={label}>
|
|
214
|
+
<Table>
|
|
215
|
+
<THead>
|
|
216
|
+
<TR>
|
|
217
|
+
{columns.map((column) => (
|
|
218
|
+
<TH key={column.key} numeric={column.numeric}>
|
|
219
|
+
{column.header}
|
|
220
|
+
</TH>
|
|
221
|
+
))}
|
|
222
|
+
</TR>
|
|
223
|
+
</THead>
|
|
224
|
+
<TBody>
|
|
225
|
+
{pageEntries.map((entry) => (
|
|
226
|
+
<RowEntry key={entryKey(entry, props.getItemKey)} {...props} entry={entry} />
|
|
227
|
+
))}
|
|
228
|
+
</TBody>
|
|
229
|
+
</Table>
|
|
230
|
+
</ScrollRegion>
|
|
231
|
+
<ExplorerPager {...pager} />
|
|
232
|
+
</>
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/** The stable React key for a page entry, folder or item. */
|
|
237
|
+
function entryKey<T>(entry: ExplorerEntry<T>, getItemKey: (item: T) => string): string {
|
|
238
|
+
return entry.kind === 'folder' ? `folder:${entry.folder.id}` : `item:${getItemKey(entry.item)}`;
|
|
239
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The explorer's persisted page size, per view surface. Mirrors `useViewMode`: an
|
|
3
|
+
* invalid or absent stored value degrades to the default, and a storage failure
|
|
4
|
+
* degrades to in-memory only — never a thrown boot.
|
|
5
|
+
*/
|
|
6
|
+
import { useCallback, useState } from 'react';
|
|
7
|
+
|
|
8
|
+
/** The page-size choices, and the default. */
|
|
9
|
+
export const PAGE_SIZES = [12, 24, 48, 96] as const;
|
|
10
|
+
const DEFAULT_PAGE_SIZE = 24;
|
|
11
|
+
|
|
12
|
+
const PAGE_SIZE_STORAGE_PREFIX = 'tai-studio.page-size.';
|
|
13
|
+
|
|
14
|
+
function readStoredPageSize(surface: string): number {
|
|
15
|
+
try {
|
|
16
|
+
const raw = globalThis.localStorage.getItem(PAGE_SIZE_STORAGE_PREFIX + surface);
|
|
17
|
+
const parsed = raw === null ? Number.NaN : Number(raw);
|
|
18
|
+
if ((PAGE_SIZES as readonly number[]).includes(parsed)) return parsed;
|
|
19
|
+
} catch {
|
|
20
|
+
// No storage (private mode / non-browser) — fall back to the default.
|
|
21
|
+
}
|
|
22
|
+
return DEFAULT_PAGE_SIZE;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function usePageSize(surface: string): readonly [number, (size: number) => void] {
|
|
26
|
+
const [size, setSizeState] = useState<number>(() => readStoredPageSize(surface));
|
|
27
|
+
const setSize = useCallback(
|
|
28
|
+
(next: number) => {
|
|
29
|
+
setSizeState(next);
|
|
30
|
+
try {
|
|
31
|
+
globalThis.localStorage.setItem(PAGE_SIZE_STORAGE_PREFIX + surface, String(next));
|
|
32
|
+
} catch {
|
|
33
|
+
// Storage unavailable — the choice still applies for this session.
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
[surface],
|
|
37
|
+
);
|
|
38
|
+
return [size, setSize];
|
|
39
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The explorer's tag filter row: a togglable chip per vocabulary entry, with the
|
|
3
|
+
* unselected chips beyond the cap collapsed into a static "+N more" count.
|
|
4
|
+
*/
|
|
5
|
+
import type { ReactNode } from 'react';
|
|
6
|
+
|
|
7
|
+
import type { TagVocabularyEntry } from './explorer-tags';
|
|
8
|
+
|
|
9
|
+
/** A togglable tag chip; `aria-pressed` reflects whether the tag filters the list. */
|
|
10
|
+
function TagChip({
|
|
11
|
+
entry,
|
|
12
|
+
active,
|
|
13
|
+
onToggle,
|
|
14
|
+
}: {
|
|
15
|
+
readonly entry: TagVocabularyEntry;
|
|
16
|
+
readonly active: boolean;
|
|
17
|
+
readonly onToggle: () => void;
|
|
18
|
+
}): ReactNode {
|
|
19
|
+
return (
|
|
20
|
+
<button
|
|
21
|
+
type="button"
|
|
22
|
+
className="tai-chip"
|
|
23
|
+
aria-pressed={active}
|
|
24
|
+
aria-label={`${entry.label} (${String(entry.count)})`}
|
|
25
|
+
onClick={onToggle}
|
|
26
|
+
>
|
|
27
|
+
<span>{entry.label}</span>
|
|
28
|
+
<span>{entry.count}</span>
|
|
29
|
+
</button>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The filter row: every selected chip plus as many unselected chips as fit under
|
|
34
|
+
* the cap, with the remainder collapsed into a STATIC "+N more" count. An unset
|
|
35
|
+
* cap shows every chip. */
|
|
36
|
+
export function TagFilterRow({
|
|
37
|
+
vocabulary,
|
|
38
|
+
selectedSet,
|
|
39
|
+
onToggle,
|
|
40
|
+
filterLabel,
|
|
41
|
+
maxVisibleTags,
|
|
42
|
+
}: {
|
|
43
|
+
readonly vocabulary: readonly TagVocabularyEntry[];
|
|
44
|
+
readonly selectedSet: ReadonlySet<string>;
|
|
45
|
+
readonly onToggle: (token: string) => void;
|
|
46
|
+
readonly filterLabel: string;
|
|
47
|
+
readonly maxVisibleTags: number | undefined;
|
|
48
|
+
}): ReactNode {
|
|
49
|
+
const visible: TagVocabularyEntry[] = [];
|
|
50
|
+
let hidden = 0;
|
|
51
|
+
let unselectedShown = 0;
|
|
52
|
+
for (const entry of vocabulary) {
|
|
53
|
+
if (selectedSet.has(entry.token)) {
|
|
54
|
+
visible.push(entry);
|
|
55
|
+
} else if (maxVisibleTags === undefined || unselectedShown < maxVisibleTags) {
|
|
56
|
+
visible.push(entry);
|
|
57
|
+
unselectedShown += 1;
|
|
58
|
+
} else {
|
|
59
|
+
hidden += 1;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div role="group" aria-label={filterLabel} className="tai-row">
|
|
65
|
+
{visible.map((entry) => (
|
|
66
|
+
<TagChip
|
|
67
|
+
key={entry.token}
|
|
68
|
+
entry={entry}
|
|
69
|
+
active={selectedSet.has(entry.token)}
|
|
70
|
+
onToggle={() => {
|
|
71
|
+
onToggle(entry.token);
|
|
72
|
+
}}
|
|
73
|
+
/>
|
|
74
|
+
))}
|
|
75
|
+
{hidden > 0 ? (
|
|
76
|
+
<span className="tai-chip tai-chip-static">{`+${String(hidden)} more`}</span>
|
|
77
|
+
) : null}
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The tag glue every explorer screen shares: the untagged sentinel, the tag
|
|
3
|
+
* vocabulary builder, and the OR-match rule — one vocabulary/untagged/OR
|
|
4
|
+
* definition rather than a copy per screen.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Reserved filter token for items carrying NO tag; namespaced so it never
|
|
8
|
+
* collides with a real tag. */
|
|
9
|
+
export const UNTAGGED_TOKEN = '__untagged__';
|
|
10
|
+
|
|
11
|
+
export interface TagVocabularyEntry {
|
|
12
|
+
readonly token: string;
|
|
13
|
+
readonly label: string;
|
|
14
|
+
readonly count: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** The tag vocabulary over `items`, name-sorted, plus an untagged pseudo-tag
|
|
18
|
+
* (labelled `untaggedLabel`) when any item is untagged; a selected token whose
|
|
19
|
+
* items vanished still appears (count 0) so it can be cleared. */
|
|
20
|
+
export function buildTagVocabulary<T>(
|
|
21
|
+
items: readonly T[],
|
|
22
|
+
getTags: (item: T) => readonly string[],
|
|
23
|
+
selectedTags: readonly string[],
|
|
24
|
+
untaggedLabel: string,
|
|
25
|
+
): TagVocabularyEntry[] {
|
|
26
|
+
const counts = new Map<string, number>();
|
|
27
|
+
let untagged = 0;
|
|
28
|
+
for (const item of items) {
|
|
29
|
+
const tags = getTags(item);
|
|
30
|
+
if (tags.length === 0) {
|
|
31
|
+
untagged += 1;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
for (const tag of tags) counts.set(tag, (counts.get(tag) ?? 0) + 1);
|
|
35
|
+
}
|
|
36
|
+
const vocabulary: TagVocabularyEntry[] = [...counts.entries()]
|
|
37
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
38
|
+
.map(([label, count]) => ({ token: label, label, count }));
|
|
39
|
+
if (untagged > 0) {
|
|
40
|
+
vocabulary.push({ token: UNTAGGED_TOKEN, label: untaggedLabel, count: untagged });
|
|
41
|
+
}
|
|
42
|
+
for (const token of selectedTags) {
|
|
43
|
+
if (!vocabulary.some((entry) => entry.token === token)) {
|
|
44
|
+
vocabulary.push({
|
|
45
|
+
token,
|
|
46
|
+
label: token === UNTAGGED_TOKEN ? untaggedLabel : token,
|
|
47
|
+
count: 0,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return vocabulary;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** OR semantics: an empty selection matches everything; otherwise an item
|
|
55
|
+
* matches when it carries any selected tag, or is untagged and UNTAGGED_TOKEN
|
|
56
|
+
* is selected. */
|
|
57
|
+
export function matchesSelectedTags(
|
|
58
|
+
itemTags: readonly string[],
|
|
59
|
+
selected: ReadonlySet<string>,
|
|
60
|
+
): boolean {
|
|
61
|
+
if (selected.size === 0) return true;
|
|
62
|
+
if (itemTags.length === 0) return selected.has(UNTAGGED_TOKEN);
|
|
63
|
+
return itemTags.some((tag) => selected.has(tag));
|
|
64
|
+
}
|