@jini-ai/ui 0.5.4 → 0.5.6
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/CHANGELOG.md +10 -0
- package/dist/core/theme/validation.js +40 -38
- package/dist/features/a2ui/renderer.js +15 -13
- package/dist/features/about/react/components/AboutTab.js +64 -34
- package/dist/features/about/rules.d.ts +2 -2
- package/dist/features/about/rules.js +156 -129
- package/dist/features/admin-widgets/components/ImagePreviewModal.d.ts +4 -3
- package/dist/features/admin-widgets/components/ImagePreviewModal.js +6 -10
- package/dist/features/admin-widgets/components/InfoTip.d.ts +3 -2
- package/dist/features/admin-widgets/components/InfoTip.hooks.js +2 -0
- package/dist/features/admin-widgets/components/InfoTip.js +34 -7
- package/dist/features/admin-widgets/components/InfoTip.rules.d.ts +13 -0
- package/dist/features/admin-widgets/components/InfoTip.rules.js +43 -10
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.d.ts +30 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.d.ts +40 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.js +128 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.js +18 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.d.ts +14 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.js +12 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.rules.d.ts +20 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.rules.js +21 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.d.ts +18 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.d.ts +16 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.js +45 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.js +18 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.d.ts +32 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.js +26 -0
- package/dist/features/admin-widgets/components/Select/Select.hooks.d.ts +21 -0
- package/dist/features/admin-widgets/components/Select/Select.hooks.js +24 -2
- package/dist/features/admin-widgets/components/Select/Select.js +4 -3
- package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.hooks.js +29 -14
- package/dist/features/admin-widgets/index.d.ts +14 -2
- package/dist/features/admin-widgets/index.js +7 -1
- package/dist/features/admin-widgets/styles/admin-widgets.css +1 -0
- package/dist/features/asset-grid/react/components/AssetCard.js +7 -1
- package/dist/features/asset-grid/react/components/AssetGrid.d.ts +1 -1
- package/dist/features/asset-grid/react/components/AssetGrid.js +38 -18
- package/dist/features/asset-grid/react/components/useAssetGridFilters.d.ts +21 -0
- package/dist/features/asset-grid/react/components/useAssetGridFilters.js +19 -0
- package/dist/features/asset-grid/react/hooks/useAssetGridKeyboardShortcuts.js +16 -11
- package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.d.ts +2 -0
- package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.js +35 -11
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.d.ts +6 -6
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.js +10 -129
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.d.ts +50 -0
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.js +95 -0
- package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.d.ts +56 -0
- package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.js +80 -0
- package/dist/features/asset-tree-browser/rules.js +40 -22
- package/dist/features/browser-chrome/rules.js +74 -70
- package/dist/features/charts/browser.js +11 -5
- package/dist/features/charts/react.js +2 -2
- package/dist/features/charts/table.js +2 -2
- package/dist/features/command-palette/react/hooks/useCommandPalette.js +3 -9
- package/dist/features/connectors/ConnectorsBrowser.d.ts +4 -4
- package/dist/features/connectors/ConnectorsBrowser.js +26 -14
- package/dist/features/connectors/components/ConnectorCard.js +67 -38
- package/dist/features/connectors/components/ConnectorDetailDrawer.js +62 -31
- package/dist/features/connectors/components/ConnectorGrid.js +11 -6
- package/dist/features/connectors/hooks/useConnectorAuthorization.js +6 -0
- package/dist/features/connectors/hooks/useConnectorCatalog.d.ts +2 -0
- package/dist/features/connectors/hooks/useConnectorCatalog.js +32 -13
- package/dist/features/connectors/hooks/useWiredConnectorsBrowser.d.ts +3 -3
- package/dist/features/connectors/rules.d.ts +8 -1
- package/dist/features/connectors/rules.js +42 -20
- package/dist/features/connectors/types.d.ts +11 -0
- package/dist/features/execution/constants.d.ts +4 -10
- package/dist/features/execution/constants.js +9 -94
- package/dist/features/execution/react/components/ByokProviderForm.d.ts +2 -4
- package/dist/features/execution/react/components/ByokProviderForm.js +140 -43
- package/dist/features/execution/react/components/ExecutionTab.d.ts +1 -2
- package/dist/features/execution/react/components/ExecutionTab.js +52 -30
- package/dist/features/execution/react/components/LocalCliAgentCard.js +12 -3
- package/dist/features/execution/react/components/LocalCliAgentList.js +14 -3
- package/dist/features/execution/react/components/LocalCliAgentSettings.js +14 -3
- package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +54 -36
- package/dist/features/execution/react/hooks/useReasoningControl.d.ts +1 -1
- package/dist/features/execution/react/hooks/useReasoningControl.js +116 -75
- package/dist/features/execution/rules.d.ts +13 -2
- package/dist/features/execution/rules.js +51 -11
- package/dist/features/execution/types.d.ts +6 -42
- package/dist/features/execution/types.js +0 -17
- package/dist/features/external-mcp/react/components/ExternalMcpTab.d.ts +6 -2
- package/dist/features/external-mcp/react/components/ExternalMcpTab.js +9 -2
- package/dist/features/file-dropzone/react/components/FileDropzone.js +24 -25
- package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.d.ts +2 -2
- package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.js +35 -30
- package/dist/features/file-dropzone/react/components/FileDropzoneThumbnailGrid.js +30 -24
- package/dist/features/file-dropzone/react/components/FileDropzoneZone.d.ts +14 -0
- package/dist/features/file-dropzone/react/components/FileDropzoneZone.js +26 -0
- package/dist/features/html-editor/canvas-content-wrapper.js +13 -13
- package/dist/features/html-editor/canvas-embed-placeholders.js +46 -37
- package/dist/features/html-editor/css.js +76 -69
- package/dist/features/html-editor/editor-blocks.js +47 -33
- package/dist/features/html-editor/editor-serialization.js +6 -5
- package/dist/features/html-editor/protected-elements.js +39 -28
- package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +4 -4
- package/dist/features/html-editor/source-splice.js +51 -30
- package/dist/features/i18n/dictionaries/settings-dialog.ja.js +1 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-CN.js +1 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-TW.js +1 -0
- package/dist/features/i18n/locale.js +20 -16
- package/dist/features/iframe-pool/react/dom-sync.js +8 -6
- package/dist/features/integrations/react/components/CodexInstallToggleButton.js +19 -4
- package/dist/features/integrations/react/components/IntegrationsTab.js +60 -14
- package/dist/features/interactive-ui/interactive-ui.css +1 -1
- package/dist/features/interactive-ui/providers/native/data-table.manifest.d.ts +6 -6
- package/dist/features/interactive-ui/providers/shadcn/data-table.js +10 -7
- package/dist/features/interactive-ui/providers/shadcn/data-table.manifest.d.ts +6 -6
- package/dist/features/lexical-rich-text-editor/mention-parser.js +60 -57
- package/dist/features/lexical-rich-text-editor/react/hooks/useKeyboardCommands.js +33 -38
- package/dist/features/lexical-rich-text-editor/rules.js +87 -74
- package/dist/features/lexical-rich-text-editor/serialize.js +27 -25
- package/dist/features/mcp-ui/secret-card.js +111 -61
- package/dist/features/mcp-ui/surfaces/confirmation.js +39 -21
- package/dist/features/mcp-ui/surfaces/document.d.ts +1 -1
- package/dist/features/mcp-ui/surfaces/document.js +10 -2
- package/dist/features/mcp-ui/surfaces/fields.js +30 -50
- package/dist/features/mcp-ui/surfaces/form.d.ts +6 -0
- package/dist/features/mcp-ui/surfaces/form.js +43 -21
- package/dist/features/mcp-ui/surfaces/outcome.js +30 -20
- package/dist/features/mcp-ui/surfaces/text-input.js +33 -21
- package/dist/features/mcp-ui/surfaces/tokens.d.ts +6 -1
- package/dist/features/mcp-ui/surfaces/tokens.js +5 -2
- package/dist/features/media-providers/constants.d.ts +1 -0
- package/dist/features/media-providers/constants.js +2 -81
- package/dist/features/media-providers/index.d.ts +1 -1
- package/dist/features/media-providers/ports.d.ts +2 -0
- package/dist/features/media-providers/react/components/MediaProviderCard.d.ts +22 -0
- package/dist/features/media-providers/react/components/MediaProviderCard.js +50 -0
- package/dist/features/media-providers/react/components/MediaProvidersTab.d.ts +5 -6
- package/dist/features/media-providers/react/components/MediaProvidersTab.js +40 -72
- package/dist/features/media-providers/react/components/media-providers-tab-labels.d.ts +11 -0
- package/dist/features/media-providers/react/components/media-providers-tab-labels.js +57 -0
- package/dist/features/media-providers/react/hooks/useMediaProvidersTab.d.ts +4 -2
- package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +37 -23
- package/dist/features/media-providers/rules.js +17 -10
- package/dist/features/media-providers/types.d.ts +4 -22
- package/dist/features/media-providers/types.js +3 -8
- package/dist/features/memory/formatters.js +127 -92
- package/dist/features/memory/react/components/MemoryConnectedPanel.js +92 -36
- package/dist/features/memory/react/components/MemoryList.js +37 -18
- package/dist/features/memory/react/hooks/useMemoryExtractions.store.js +42 -36
- package/dist/features/notifications/react/components/NotificationsTab.js +28 -28
- package/dist/features/observability/long-task.d.ts +0 -12
- package/dist/features/observability/long-task.js +15 -19
- package/dist/features/observability/resource-error.d.ts +0 -10
- package/dist/features/observability/resource-error.js +18 -13
- package/dist/features/observability/stuck-run.js +10 -6
- package/dist/features/observability/telemetry-url.d.ts +6 -0
- package/dist/features/observability/telemetry-url.js +16 -0
- package/dist/features/observability/white-screen.js +12 -24
- package/dist/features/panel-kit/fetch-query/adapter.react.d.ts +2 -2
- package/dist/features/panel-kit/fetch-query/adapter.react.js +4 -2
- package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +46 -33
- package/dist/features/panel-kit/helpers/standing-draft-local-backup.js +3 -1
- package/dist/features/panel-kit/hooks/use-settings-slice.hooks.js +3 -1
- package/dist/features/privacy/react/components/PrivacyTab.js +24 -13
- package/dist/features/progress-card/components/ProgressCard.js +7 -3
- package/dist/features/progress-card/reference-adapters.js +59 -54
- package/dist/features/project-locations/react/components/ProjectLocationsTab.js +24 -15
- package/dist/features/project-locations/react/hooks/useProjectLocationsTab.d.ts +8 -0
- package/dist/features/project-locations/react/hooks/useProjectLocationsTab.js +31 -23
- package/dist/features/resource-dashboard/react/components/ResourceBoard.js +6 -47
- package/dist/features/resource-dashboard/react/components/ResourceBoardView.d.ts +2 -2
- package/dist/features/resource-dashboard/react/components/ResourceBoardView.js +3 -6
- package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.d.ts +15 -0
- package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.js +35 -0
- package/dist/features/resource-dashboard/react/components/ResourceCard.js +5 -16
- package/dist/features/resource-dashboard/react/components/ResourceCardParts.d.ts +34 -0
- package/dist/features/resource-dashboard/react/components/ResourceCardParts.js +34 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowList.js +3 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListItem.js +2 -2
- package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.d.ts +19 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.js +11 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListView.d.ts +1 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListView.js +4 -4
- package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.d.ts +10 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.js +20 -0
- package/dist/features/resource-dashboard/react/components/resourceBoardProps.d.ts +48 -0
- package/dist/features/resource-dashboard/react/components/resourceBoardProps.js +70 -0
- package/dist/features/resource-dashboard/react/components/resourceRowListProps.d.ts +19 -0
- package/dist/features/resource-dashboard/react/components/resourceRowListProps.js +14 -0
- package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.d.ts +16 -0
- package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.js +13 -0
- package/dist/features/resource-dashboard/rules.js +2 -8
- package/dist/features/sketch-editor/dom.js +150 -99
- package/dist/features/sketch-editor/react/components/SketchEditor.js +26 -15
- package/dist/features/skills/react/components/SkillDraftForm.js +13 -19
- package/dist/features/skills/react/components/SkillDraftForm.labels.d.ts +31 -0
- package/dist/features/skills/react/components/SkillDraftForm.labels.js +54 -0
- package/dist/features/skills/react/components/SkillRow.js +38 -18
- package/dist/features/skills/react/components/SkillRow.labels.d.ts +7 -0
- package/dist/features/skills/react/components/SkillRow.labels.js +18 -0
- package/dist/features/skills/react/components/SkillsTab.js +24 -14
- package/dist/features/skills/react/components/SkillsTab.labels.d.ts +7 -0
- package/dist/features/skills/react/components/SkillsTab.labels.js +11 -0
- package/dist/features/skills/rules.js +32 -23
- package/dist/features/source-config-list/agent-handles.js +2 -1
- package/dist/features/source-config-list/dependencies.js +53 -49
- package/dist/features/source-config-list/index.d.ts +3 -3
- package/dist/features/source-config-list/react/components/SourceConfigAddForm.d.ts +6 -5
- package/dist/features/source-config-list/react/components/SourceConfigAddForm.js +38 -7
- package/dist/features/source-config-list/react/components/SourceConfigField.js +69 -25
- package/dist/features/source-config-list/react/components/SourceConfigItemCard.d.ts +6 -5
- package/dist/features/source-config-list/react/components/SourceConfigItemCard.js +76 -20
- package/dist/features/source-config-list/react/components/SourceConfigListView.d.ts +5 -3
- package/dist/features/source-config-list/react/components/SourceConfigListView.js +33 -3
- package/dist/features/source-config-list/react/components/SourceConfigTestControl.js +17 -1
- package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.d.ts +11 -0
- package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.js +12 -0
- package/dist/features/source-config-list/types.d.ts +14 -0
- package/dist/features/tab-launcher-menu/react/components/TabLauncherMenu.js +25 -1
- package/dist/features/tab-launcher-menu/react/hooks/useTabLauncherMenu.js +15 -16
- package/dist/features/tab-strip/react/components/TabBar.js +8 -1
- package/dist/features/tabbed-dialog/react/components/TabbedDialog.js +8 -30
- package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.d.ts +15 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.js +8 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.d.ts +12 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.js +6 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.d.ts +27 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.js +12 -0
- package/dist/features/tabbed-dialog/react/components/tabbedDialogView.d.ts +43 -0
- package/dist/features/tabbed-dialog/react/components/tabbedDialogView.js +59 -0
- package/dist/features/version-manager/dependencies.d.ts +3 -1
- package/dist/features/version-manager/dependencies.js +3 -2
- package/dist/features/version-manager/react/components/VersionManagerModal.js +10 -6
- package/dist/features/version-manager/react/hooks/useVersionManager.js +7 -4
- package/dist/features/viewer-shell/react/components/CommentSidePanel.js +103 -50
- package/dist/features/viewer-shell/react/components/MarkdownSplitPane.js +28 -8
- package/dist/features/viewer-shell/react/hooks/useCommentReorder.js +22 -16
- package/dist/features/viewer-shell/rules.js +19 -23
- package/dist/react/components/CustomSelect.d.ts +38 -1
- package/dist/react/components/CustomSelect.js +94 -38
- package/dist/react/components/OnboardingDropdown.js +20 -8
- package/dist/react/components/RemixIcon.stylesheet.js +3 -1
- package/dist/react/components/Toast.js +13 -2
- package/dist/react/components/TooltipLayer.js +5 -14
- package/dist/react/components/WorkingDirPicker.js +78 -50
- package/dist/react/components/remixicon-font-recovery.js +38 -30
- package/dist/react/components/select-popover.d.ts +8 -6
- package/dist/react/components/select-popover.js +33 -29
- package/dist/react/mcp-ui/McpUiHost.d.ts +1 -1
- package/dist/react/mcp-ui/McpUiHost.js +10 -11
- package/dist/react/mcp-ui/host-message-source.d.ts +14 -2
- package/dist/react/mcp-ui/host-message-source.js +15 -5
- package/dist/react/mcp-ui/mcp-ui-host-frame.d.ts +41 -0
- package/dist/react/mcp-ui/mcp-ui-host-frame.js +39 -0
- package/dist/renderers/annotation-canvas/react/components/AnnotationCanvas.js +97 -69
- package/dist/renderers/preview-modal-shell/react/components/PreviewModalShell.js +59 -30
- package/dist/renderers/preview-modal-shell/react/components/icons.js +4 -1
- package/dist/renderers/react/components/ArtifactView.js +9 -6
- package/dist/renderers/srcdoc/build.d.ts +4 -1
- package/dist/renderers/srcdoc/build.js +62 -48
- package/dist/styles/admin.css +29 -14
- package/dist/styles/lightbox.css +142 -0
- package/dist/styles/variables.css +128 -0
- package/dist/theme/apply.js +9 -5
- package/dist/utils/auto-open-file.d.ts +2 -1
- package/dist/utils/auto-open-file.js +69 -85
- package/dist/utils/markdown-scroll-sync.js +108 -87
- package/dist/utils/polygon-selection.js +25 -26
- package/dist/utils/smooth-scroll-to-top.d.ts +1 -1
- package/dist/utils/smooth-scroll-to-top.js +2 -32
- package/dist/utils/sse.js +26 -26
- package/dist/utils/unit-bezier.d.ts +7 -0
- package/dist/utils/unit-bezier.js +38 -0
- package/package.json +7 -10
- package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.d.ts +0 -13
- package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.js +0 -46
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SkillRowLabels } from './SkillRow.js';
|
|
2
|
+
/** The row's own label keys (the inline edit form resolves its own). */
|
|
3
|
+
export type SkillRowOwnLabelKey = 'expandLabel' | 'collapseLabel' | 'editLabel' | 'overrideCreateLabel' | 'deleteLabel' | 'deleteConfirmLabel' | 'cancelLabel' | 'enableToggleLabel' | 'loadingLabel' | 'filesHeading' | 'noFilesLabel' | 'bodyHeading' | 'userBadge' | 'overrideWarning';
|
|
4
|
+
export type ResolvedSkillRowLabels = Required<Pick<SkillRowLabels, SkillRowOwnLabelKey>>;
|
|
5
|
+
/** Untranslated defaults for every row label; see `resolveLabels`. */
|
|
6
|
+
export declare const DEFAULT_SKILL_ROW_LABELS: ResolvedSkillRowLabels;
|
|
7
|
+
//# sourceMappingURL=SkillRow.labels.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/** Untranslated defaults for every row label; see `resolveLabels`. */
|
|
2
|
+
export const DEFAULT_SKILL_ROW_LABELS = {
|
|
3
|
+
expandLabel: 'Expand',
|
|
4
|
+
collapseLabel: 'Collapse',
|
|
5
|
+
editLabel: 'Edit',
|
|
6
|
+
overrideCreateLabel: 'Create override',
|
|
7
|
+
deleteLabel: 'Delete',
|
|
8
|
+
deleteConfirmLabel: 'Confirm delete',
|
|
9
|
+
cancelLabel: 'Cancel',
|
|
10
|
+
enableToggleLabel: 'Enabled',
|
|
11
|
+
loadingLabel: 'Loading…',
|
|
12
|
+
filesHeading: 'Files',
|
|
13
|
+
noFilesLabel: 'No files.',
|
|
14
|
+
bodyHeading: 'SKILL.md',
|
|
15
|
+
userBadge: 'user',
|
|
16
|
+
overrideWarning: 'This skill ships with the host. Editing it creates your own copy — the original is unaffected.',
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=SkillRow.labels.js.map
|
|
@@ -5,7 +5,9 @@ import { useT } from '../../../i18n/index.js';
|
|
|
5
5
|
import { Icon } from '../../../../react/components/Icon.js';
|
|
6
6
|
import { useSkillsTab } from '../hooks/useSkillsTab.js';
|
|
7
7
|
import { SkillDraftForm } from './SkillDraftForm.js';
|
|
8
|
+
import { resolveLabels } from './SkillDraftForm.labels.js';
|
|
8
9
|
import { SkillRow } from './SkillRow.js';
|
|
10
|
+
import { DEFAULT_SKILLS_TAB_LABELS } from './SkillsTab.labels.js';
|
|
9
11
|
/**
|
|
10
12
|
* Skill library: search + source/mode/category filters, a create form, and
|
|
11
13
|
* one collapsible row per skill (enable toggle, preview, file tree, inline
|
|
@@ -16,22 +18,30 @@ import { SkillRow } from './SkillRow.js';
|
|
|
16
18
|
*/
|
|
17
19
|
export function SkillsTab({ port, disabledSkillIds, onToggleEnabled, locale = 'en', labels, agentHandle }) {
|
|
18
20
|
const t = useT();
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const
|
|
27
|
-
|
|
21
|
+
const tab = useSkillsTab({ port, locale });
|
|
22
|
+
const l = resolveLabels({ defaults: DEFAULT_SKILLS_TAB_LABELS, t }, { labels });
|
|
23
|
+
const loadErrorLabel = labels?.loadErrorLabel ?? t('Could not load skills: {error}', { error: tab.loadError ?? '' });
|
|
24
|
+
return (_jsxs("section", { className: "jini-settings-section jini-settings-skills", children: [_jsx(SkillsTabToolbar, { tab: tab, labels: l, agentHandle: agentHandle }), tab.loadError ? (_jsx("div", { className: "jini-empty-card jini-empty-card-error", children: _jsx("strong", { children: loadErrorLabel }) })) : null, tab.creating ? (_jsx(SkillDraftForm, { heading: l.newSkillLabel, draft: tab.draft, onDraftChange: tab.setDraft, error: tab.draftError, saving: tab.draftSaving, isEdit: false, onCancel: tab.cancelDraft, onSubmit: tab.submitDraft, labels: labels, ...(agentHandle ? { agentHandle: agentSubHandle({ base: agentHandle, action: 'create-form' }) } : {}) })) : null, !tab.loading && tab.filteredSkills.length === 0 ? (_jsx("div", { className: "jini-empty-card", children: _jsx("strong", { children: l.noResultsLabel }) })) : (_jsx(SkillsTabRows, { tab: tab, disabledSkillIds: disabledSkillIds, onToggleEnabled: onToggleEnabled, locale: locale, labels: labels, agentHandle: agentHandle }))] }));
|
|
25
|
+
}
|
|
26
|
+
/** Search box, "New skill" button, and the source/mode/(category) selects. */
|
|
27
|
+
function SkillsTabToolbar({ tab, labels: l, agentHandle, }) {
|
|
28
|
+
const { filters, categoryOptions } = tab;
|
|
29
|
+
return (_jsxs("div", { className: "jini-skills-toolbar", children: [_jsxs("div", { className: "jini-skills-toolbar-top", children: [_jsx("input", { type: "search", className: "jini-skills-search", placeholder: l.searchPlaceholder, value: filters.search, onChange: (event) => tab.setSearch(event.target.value), "aria-label": l.searchPlaceholder, ...agentHandleProps({}, { base: agentHandle, action: 'search', role: 'field', label: l.searchPlaceholder }) }), _jsxs("button", { type: "button", className: "jini-button jini-button-primary", onClick: tab.startCreate, "data-testid": "skills-new", ...agentHandleProps({}, { base: agentHandle, action: 'new', role: 'button', label: l.newSkillLabel }), children: [_jsx(Icon, { name: "plus", size: 13 }), _jsx("span", { children: l.newSkillLabel })] })] }), _jsxs("div", { className: "jini-skills-filter-selects", children: [_jsx(SkillFilterSelect, { label: l.sourceFilterLabel, allLabel: l.allLabel, value: filters.source, row: tab.sourceOptions, onChange: (value) => tab.setSourceFilter(value), action: "filter-source", agentHandle: agentHandle }), _jsx(SkillFilterSelect, { label: l.modeFilterLabel, allLabel: l.allLabel, value: filters.mode, row: tab.modeOptions, onChange: tab.setModeFilter, action: "filter-mode", agentHandle: agentHandle }), categoryOptions ? (_jsx(SkillFilterSelect, { label: l.categoryFilterLabel, allLabel: l.allLabel, value: filters.category, row: categoryOptions, onChange: tab.setCategoryFilter, action: "filter-category", agentHandle: agentHandle, formatValue: humanizeSkillCategory, testId: "skills-category-filters" })) : null] })] }));
|
|
30
|
+
}
|
|
31
|
+
const identity = (value) => value;
|
|
32
|
+
/** One labelled filter `<select>`: an "All (n)" option then one per value. */
|
|
33
|
+
function SkillFilterSelect({ label, allLabel, value, row, onChange, action, agentHandle, formatValue = identity, testId, }) {
|
|
34
|
+
return (_jsxs("label", { className: "jini-skills-filter-select", "data-testid": testId, children: [_jsx("span", { children: label }), _jsxs("select", { value: value, onChange: (event) => onChange(event.target.value), ...agentHandleProps({}, { base: agentHandle, action, role: 'field', label }), children: [_jsxs("option", { value: "all", children: [allLabel, " (", row.all, ")"] }), row.options.map(([optionValue, count]) => (_jsxs("option", { value: optionValue, children: [formatValue(optionValue), " (", count, ")"] }, optionValue)))] })] }));
|
|
35
|
+
}
|
|
36
|
+
/** One `SkillRow` per filtered skill, each with its own derived agent handle. */
|
|
37
|
+
function SkillsTabRows({ tab, disabledSkillIds, onToggleEnabled, locale, labels, agentHandle, }) {
|
|
38
|
+
const { filteredSkills, draft, draftError, draftSaving } = tab;
|
|
28
39
|
const rowHandles = agentHandle
|
|
29
40
|
? buildAgentListHandles({ prefix: agentSubHandle({ base: agentHandle, action: 'skill' }), ids: filteredSkills.map((skill) => skill.id) })
|
|
30
41
|
: undefined;
|
|
31
|
-
return (
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}) }))] }));
|
|
42
|
+
return (_jsx("div", { className: "jini-skills-rows", "data-testid": "skills-list", children: filteredSkills.map((skill, index) => {
|
|
43
|
+
const isEditing = tab.editingId === skill.id;
|
|
44
|
+
return (_jsx(SkillRow, { ...(rowHandles?.[index] ? { agentHandle: rowHandles[index] } : {}), skill: skill, locale: locale, enabled: !disabledSkillIds.has(skill.id), expanded: tab.expandedId === skill.id, editing: isEditing, body: tab.bodyById[skill.id], bodyLoading: tab.bodyLoadingId === skill.id, files: tab.filesById[skill.id] ?? null, filesLoading: tab.filesLoadingId === skill.id, confirmDelete: tab.confirmDeleteId === skill.id, confirmBuiltInEdit: tab.confirmBuiltInEditId === skill.id, draft: isEditing ? draft : null, draftError: isEditing ? draftError : null, draftSaving: isEditing && draftSaving, onDraftChange: tab.setDraft, onToggleExpanded: () => tab.toggleExpanded(skill.id), onToggleEnabled: (enabled) => onToggleEnabled(skill.id, enabled), onStartEdit: () => tab.requestEdit(skill), onConfirmBuiltInEdit: tab.confirmBuiltInEdit, onCancelBuiltInEdit: tab.cancelBuiltInEdit, onArmDelete: () => tab.armDelete(skill.id), onCancelDelete: tab.cancelDelete, onCommitDelete: () => tab.commitDelete(skill.id), onCancelEdit: tab.cancelDraft, onSubmitEdit: tab.submitDraft, labels: labels }, skill.id));
|
|
45
|
+
}) }));
|
|
36
46
|
}
|
|
37
47
|
//# sourceMappingURL=SkillsTab.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SkillsTabLabels } from './SkillsTab.js';
|
|
2
|
+
/** The tab's own plain labels. `loadErrorLabel` is resolved separately in
|
|
3
|
+
* `SkillsTab` because its default interpolates the load error. */
|
|
4
|
+
export type ResolvedSkillsTabLabels = Required<Pick<SkillsTabLabels, 'searchPlaceholder' | 'newSkillLabel' | 'sourceFilterLabel' | 'modeFilterLabel' | 'categoryFilterLabel' | 'allLabel' | 'noResultsLabel'>>;
|
|
5
|
+
/** Untranslated defaults for the tab's own labels; see `resolveLabels`. */
|
|
6
|
+
export declare const DEFAULT_SKILLS_TAB_LABELS: ResolvedSkillsTabLabels;
|
|
7
|
+
//# sourceMappingURL=SkillsTab.labels.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Untranslated defaults for the tab's own labels; see `resolveLabels`. */
|
|
2
|
+
export const DEFAULT_SKILLS_TAB_LABELS = {
|
|
3
|
+
searchPlaceholder: 'Search skills…',
|
|
4
|
+
newSkillLabel: 'New skill',
|
|
5
|
+
sourceFilterLabel: 'Source',
|
|
6
|
+
modeFilterLabel: 'Type',
|
|
7
|
+
categoryFilterLabel: 'Category',
|
|
8
|
+
allLabel: 'All',
|
|
9
|
+
noResultsLabel: 'No skills match these filters.',
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=SkillsTab.labels.js.map
|
|
@@ -31,7 +31,7 @@ export const EMPTY_SKILL_DRAFT = {
|
|
|
31
31
|
/** The two origins the source filter offers explicitly. A host may report
|
|
32
32
|
* others (an org registry, a marketplace); those are counted under `all` and
|
|
33
33
|
* get no pill of their own, matching the origin's behaviour. */
|
|
34
|
-
const KNOWN_SOURCES = ['
|
|
34
|
+
const KNOWN_SOURCES = ['user', 'built-in'];
|
|
35
35
|
/**
|
|
36
36
|
* The skill's name in `locale`, falling back to the untranslated `name`.
|
|
37
37
|
*
|
|
@@ -116,26 +116,37 @@ export function filterSkills(skills, filters, locale) {
|
|
|
116
116
|
*/
|
|
117
117
|
export function skillFilterOptions(skills, filters, locale, dimension) {
|
|
118
118
|
const matching = skills.filter((skill) => skillMatchesFilters(skill, filters, locale, dimension));
|
|
119
|
-
if (dimension === 'source')
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
119
|
+
if (dimension === 'source')
|
|
120
|
+
return sourceFilterOptions({ matching });
|
|
121
|
+
return valueFilterOptions({ skills, matching, valueOf: dimension === 'mode' ? modeValue : categoryValue });
|
|
122
|
+
}
|
|
123
|
+
/** Sorted by value (`localeCompare`) so the pill row is stable across renders. */
|
|
124
|
+
function sortedOptions(options) {
|
|
125
|
+
return options.sort((a, b) => a[0].localeCompare(b[0]));
|
|
126
|
+
}
|
|
127
|
+
/** The `source` pills: always the known vocabulary, counted over `matching`. */
|
|
128
|
+
function sourceFilterOptions({ matching }) {
|
|
129
|
+
const counts = new Map(KNOWN_SOURCES.map((s) => [s, 0]));
|
|
130
|
+
for (const skill of matching) {
|
|
131
|
+
// `undefined` means an origin outside the known vocabulary (an org
|
|
132
|
+
// registry, a marketplace). Those are counted in `all` and get no pill.
|
|
133
|
+
// One lookup, not a `has` + `get` pair with an unreachable `?? 0`.
|
|
134
|
+
const current = counts.get(skill.source);
|
|
135
|
+
if (current !== undefined)
|
|
136
|
+
counts.set(skill.source, current + 1);
|
|
135
137
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
138
|
+
return {
|
|
139
|
+
all: matching.length,
|
|
140
|
+
options: sortedOptions([...counts.entries()].map(([value, count]) => [value, count])),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
// `mode` is required on every skill; `category` is optional, so a skill
|
|
144
|
+
// without one contributes to `all` but to no pill.
|
|
145
|
+
const modeValue = (skill) => skill.mode;
|
|
146
|
+
const categoryValue = (skill) => typeof skill.category === 'string' && skill.category ? skill.category : null;
|
|
147
|
+
/** The data-derived pills (`mode`, `category`): option SET from every skill,
|
|
148
|
+
* COUNTS from `matching` — see `skillFilterOptions`. */
|
|
149
|
+
function valueFilterOptions({ skills, matching, valueOf, }) {
|
|
139
150
|
const values = new Set();
|
|
140
151
|
for (const skill of skills) {
|
|
141
152
|
const value = valueOf(skill);
|
|
@@ -151,9 +162,7 @@ export function skillFilterOptions(skills, filters, locale, dimension) {
|
|
|
151
162
|
}
|
|
152
163
|
return {
|
|
153
164
|
all: matching.length,
|
|
154
|
-
options: [...values]
|
|
155
|
-
.map((value) => [value, counts.get(value) ?? 0])
|
|
156
|
-
.sort((a, b) => a[0].localeCompare(b[0])),
|
|
165
|
+
options: sortedOptions([...values].map((value) => [value, counts.get(value) ?? 0])),
|
|
157
166
|
};
|
|
158
167
|
}
|
|
159
168
|
/**
|
|
@@ -146,6 +146,7 @@ export function sourceConfigAgentProps(base, options) {
|
|
|
146
146
|
if (base === undefined)
|
|
147
147
|
return {};
|
|
148
148
|
const handle = options.action === undefined ? base : sourceConfigActionHandle(base, options.action);
|
|
149
|
-
|
|
149
|
+
// `role` and `label` are required by SourceConfigAgentPropsOptions, so both are always forwarded.
|
|
150
|
+
return agentHandle({ handle: handle }, { role: options.role, label: options.label });
|
|
150
151
|
}
|
|
151
152
|
//# sourceMappingURL=agent-handles.js.map
|
|
@@ -1,8 +1,58 @@
|
|
|
1
|
+
function createDelay({ latencyMs }) {
|
|
2
|
+
return (value) => latencyMs > 0 ? new Promise((resolve) => setTimeout(() => resolve(value), latencyMs)) : Promise.resolve(value);
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Replaces the stored source with `id` by `transform(current)`; resolves
|
|
6
|
+
* `null` (and leaves the store untouched) when no source has that id.
|
|
7
|
+
*/
|
|
8
|
+
function replaceById({ fake: { store, delay }, id, transform, }) {
|
|
9
|
+
const index = store.findIndex((source) => source.id === id);
|
|
10
|
+
if (index === -1)
|
|
11
|
+
return delay(null);
|
|
12
|
+
const updated = transform(store[index]);
|
|
13
|
+
store[index] = updated;
|
|
14
|
+
return delay(updated);
|
|
15
|
+
}
|
|
16
|
+
/** The default `onUpdate`: `fields` merged key-by-key, `label`/`enabled` replaced only when the patch carries them. */
|
|
17
|
+
function mergeSourcePatch(current, patch) {
|
|
18
|
+
return {
|
|
19
|
+
...current,
|
|
20
|
+
...(patch.label !== undefined ? { label: patch.label } : {}),
|
|
21
|
+
...(patch.enabled !== undefined ? { enabled: patch.enabled } : {}),
|
|
22
|
+
...(patch.fields !== undefined ? { fields: { ...current.fields, ...patch.fields } } : {}),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
const DEFAULT_TEST_RESULT = { ok: true, message: 'Connection ok.', latencyMs: 0 };
|
|
26
|
+
function createTestSource({ store, delay }, { onTest }) {
|
|
27
|
+
return (id, draft) => {
|
|
28
|
+
const source = id === undefined ? undefined : store.find((s) => s.id === id);
|
|
29
|
+
return delay(onTest ? onTest(id, draft, source) : { ...DEFAULT_TEST_RESULT });
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** Wires the optional refresh/trust/test/update capabilities each `supports*` flag enables (all default to true). */
|
|
33
|
+
function wireOptionalCapabilities({ port, fake, options, }) {
|
|
34
|
+
if (options.supportsRefresh ?? true) {
|
|
35
|
+
const onRefresh = options.onRefresh ?? ((source) => source);
|
|
36
|
+
port.refreshSource = (id) => replaceById({ fake, id, transform: onRefresh });
|
|
37
|
+
}
|
|
38
|
+
if (options.supportsTrust ?? true) {
|
|
39
|
+
port.setTrust = (id, trust) => replaceById({ fake, id, transform: (current) => ({ ...current, trust }) });
|
|
40
|
+
}
|
|
41
|
+
wireTestAndUpdate({ port, fake, options });
|
|
42
|
+
}
|
|
43
|
+
function wireTestAndUpdate({ port, fake, options, }) {
|
|
44
|
+
if (options.supportsTest ?? true) {
|
|
45
|
+
port.testSource = createTestSource(fake, options);
|
|
46
|
+
}
|
|
47
|
+
if (options.supportsUpdate ?? true) {
|
|
48
|
+
const onUpdate = options.onUpdate ?? mergeSourcePatch;
|
|
49
|
+
port.updateSource = (id, patch) => replaceById({ fake, id, transform: (current) => onUpdate(current, patch) });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
1
52
|
/** An in-memory test double good enough for demos and for driving this feature's own hook/component tests. */
|
|
2
53
|
export function createFakeSourceConfigPort(options) {
|
|
3
54
|
const store = options.sources ? [...options.sources] : [];
|
|
4
|
-
const
|
|
5
|
-
const delay = (value) => latencyMs > 0 ? new Promise((resolve) => setTimeout(() => resolve(value), latencyMs)) : Promise.resolve(value);
|
|
55
|
+
const delay = createDelay({ latencyMs: options.latencyMs ?? 0 });
|
|
6
56
|
const port = {
|
|
7
57
|
fetchSources() {
|
|
8
58
|
return delay([...store]);
|
|
@@ -20,53 +70,7 @@ export function createFakeSourceConfigPort(options) {
|
|
|
20
70
|
return delay(true);
|
|
21
71
|
},
|
|
22
72
|
};
|
|
23
|
-
|
|
24
|
-
port.refreshSource = (id) => {
|
|
25
|
-
const index = store.findIndex((source) => source.id === id);
|
|
26
|
-
if (index === -1)
|
|
27
|
-
return delay(null);
|
|
28
|
-
const current = store[index];
|
|
29
|
-
const refreshed = (options.onRefresh ?? ((source) => source))(current);
|
|
30
|
-
store[index] = refreshed;
|
|
31
|
-
return delay(refreshed);
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
if (options.supportsTrust ?? true) {
|
|
35
|
-
port.setTrust = (id, trust) => {
|
|
36
|
-
const index = store.findIndex((source) => source.id === id);
|
|
37
|
-
if (index === -1)
|
|
38
|
-
return delay(null);
|
|
39
|
-
const updated = { ...store[index], trust };
|
|
40
|
-
store[index] = updated;
|
|
41
|
-
return delay(updated);
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
if (options.supportsTest ?? true) {
|
|
45
|
-
port.testSource = (id, draft) => {
|
|
46
|
-
const source = id === undefined ? undefined : store.find((s) => s.id === id);
|
|
47
|
-
const defaultResult = { ok: true, message: 'Connection ok.', latencyMs: 0 };
|
|
48
|
-
const result = options.onTest ? options.onTest(id, draft, source) : defaultResult;
|
|
49
|
-
return delay(result);
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
if (options.supportsUpdate ?? true) {
|
|
53
|
-
port.updateSource = (id, patch) => {
|
|
54
|
-
const index = store.findIndex((source) => source.id === id);
|
|
55
|
-
if (index === -1)
|
|
56
|
-
return delay(null);
|
|
57
|
-
const current = store[index];
|
|
58
|
-
const updated = options.onUpdate
|
|
59
|
-
? options.onUpdate(current, patch)
|
|
60
|
-
: {
|
|
61
|
-
...current,
|
|
62
|
-
...(patch.label !== undefined ? { label: patch.label } : {}),
|
|
63
|
-
...(patch.enabled !== undefined ? { enabled: patch.enabled } : {}),
|
|
64
|
-
...(patch.fields !== undefined ? { fields: { ...current.fields, ...patch.fields } } : {}),
|
|
65
|
-
};
|
|
66
|
-
store[index] = updated;
|
|
67
|
-
return delay(updated);
|
|
68
|
-
};
|
|
69
|
-
}
|
|
73
|
+
wireOptionalCapabilities({ port, fake: { store, delay }, options });
|
|
70
74
|
return port;
|
|
71
75
|
}
|
|
72
76
|
export function createFakeSourceConfigDependencies(options) {
|
|
@@ -4,7 +4,7 @@ export { MASK_CHAR, MASKED_VALUE_MIN_MASK_LENGTH, MASKED_VALUE_VISIBLE_SUFFIX_LE
|
|
|
4
4
|
export { createFakeSourceConfigDependencies, createFakeSourceConfigPort, type FakeSourceConfigPortOptions, } from './dependencies.js';
|
|
5
5
|
export type { SourceConfigDependencies, SourceConfigPort } from './ports.js';
|
|
6
6
|
export { emptySourceDraft, isActionPending, issueForField, maskFieldValue, pendingActionKey, removeSourceById, sourceDisplayLabel, updateSourceById, upsertSourceById, validateSourceDraft, withoutPendingAction, withPendingAction, } from './rules.js';
|
|
7
|
-
export type { AddSourceInput, AddSourceResult, SourceActionKind, SourceConfigItem, SourceConnectionStatus, SourceDraftIssue, SourceDraftValidation, SourceFieldKind, SourceFieldOption, SourceFieldSpec, SourceFieldValues, SourceTestResult, SourceTrustOption, } from './types.js';
|
|
7
|
+
export type { AddSourceInput, AddSourceResult, SourceActionKind, SourceConfigItem, SourceConnectionStatus, SourceDraftIssue, SourceDraftValidation, SourceFieldKind, SourceFieldOption, SourceFieldSpec, SourceFieldValues, SourceTestResult, SourceTrustOption, SourceTrustSelectorProps, } from './types.js';
|
|
8
8
|
export { useSourceConfigList, useWiredSourceConfigList } from './react/hooks/useSourceConfigList.js';
|
|
9
9
|
export type { SourceConfigListCapabilities, SourceConfigListController, UseSourceConfigListParams, UseWiredSourceConfigListParams, } from './react/hooks/useSourceConfigList.js';
|
|
10
10
|
export { useSourceConfigAddForm, useWiredSourceConfigAddForm } from './react/hooks/useSourceConfigAddForm.js';
|
|
@@ -14,9 +14,9 @@ export type { SourceConfigFieldProps } from './react/components/SourceConfigFiel
|
|
|
14
14
|
export { SourceConfigTestControl } from './react/components/SourceConfigTestControl.js';
|
|
15
15
|
export type { SourceConfigTestControlProps } from './react/components/SourceConfigTestControl.js';
|
|
16
16
|
export { SourceConfigAddForm } from './react/components/SourceConfigAddForm.js';
|
|
17
|
-
export type { SourceConfigAddFormProps } from './react/components/SourceConfigAddForm.js';
|
|
17
|
+
export type { SourceConfigAddFormBaseProps, SourceConfigAddFormProps } from './react/components/SourceConfigAddForm.js';
|
|
18
18
|
export { SourceConfigItemCard } from './react/components/SourceConfigItemCard.js';
|
|
19
|
-
export type { SourceConfigItemCardProps } from './react/components/SourceConfigItemCard.js';
|
|
19
|
+
export type { SourceConfigItemCardBaseProps, SourceConfigItemCardProps } from './react/components/SourceConfigItemCard.js';
|
|
20
20
|
export { SourceConfigListView } from './react/components/SourceConfigListView.js';
|
|
21
21
|
export type { SourceConfigListViewProps } from './react/components/SourceConfigListView.js';
|
|
22
22
|
export { SourceConfigList } from './react/components/SourceConfigList.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { SourceDraftValidation, SourceFieldSpec, SourceFieldValues, SourceTestResult,
|
|
2
|
-
|
|
1
|
+
import type { SourceDraftValidation, SourceFieldSpec, SourceFieldValues, SourceTestResult, SourceTrustSelectorProps } from '../../types.js';
|
|
2
|
+
/** Every add-form prop except the trust selector's pair (see {@link SourceTrustSelectorProps}). */
|
|
3
|
+
export interface SourceConfigAddFormBaseProps {
|
|
3
4
|
fieldSpecs: readonly SourceFieldSpec[];
|
|
4
|
-
trustOptions?: readonly SourceTrustOption[];
|
|
5
5
|
values: SourceFieldValues;
|
|
6
6
|
trust?: string | undefined;
|
|
7
7
|
validation: SourceDraftValidation;
|
|
@@ -10,7 +10,6 @@ export interface SourceConfigAddFormProps {
|
|
|
10
10
|
submitError?: string | null | undefined;
|
|
11
11
|
addLabel?: string;
|
|
12
12
|
onFieldChange: (key: string, value: string) => void;
|
|
13
|
-
onTrustChange: (value: string) => void;
|
|
14
13
|
onSubmit: () => void;
|
|
15
14
|
/**
|
|
16
15
|
* Test-before-save (the origin BYOK `EntryShell.tsx`/`ByokConnectionTestControl`
|
|
@@ -44,6 +43,8 @@ export interface SourceConfigAddFormProps {
|
|
|
44
43
|
/** Cancel button copy, translated. Defaults to `'Cancel'`. */
|
|
45
44
|
cancelLabel?: string;
|
|
46
45
|
}
|
|
46
|
+
/** `onTrustChange` is required only together with `trustOptions` — see {@link SourceTrustSelectorProps}. */
|
|
47
|
+
export type SourceConfigAddFormProps = SourceConfigAddFormBaseProps & SourceTrustSelectorProps;
|
|
47
48
|
/**
|
|
48
49
|
* The "add a source" form: one `SourceConfigField` per host-supplied field
|
|
49
50
|
* spec, an optional trust selector (rendered only when `trustOptions` is
|
|
@@ -71,5 +72,5 @@ export interface SourceConfigAddFormProps {
|
|
|
71
72
|
* caller's next `page.find_elements` sees them, because that verb re-queries
|
|
72
73
|
* the DOM rather than replaying an earlier snapshot.
|
|
73
74
|
*/
|
|
74
|
-
export declare function SourceConfigAddForm(
|
|
75
|
+
export declare function SourceConfigAddForm(props: SourceConfigAddFormProps): import("react").JSX.Element;
|
|
75
76
|
//# sourceMappingURL=SourceConfigAddForm.d.ts.map
|
|
@@ -4,6 +4,7 @@ import { sourceConfigActionHandle, sourceConfigAgentProps, sourceConfigFieldHand
|
|
|
4
4
|
import { issueForField } from '../../rules.js';
|
|
5
5
|
import { SourceConfigField } from './SourceConfigField.js';
|
|
6
6
|
import { SourceConfigTestControl } from './SourceConfigTestControl.js';
|
|
7
|
+
import { SourceConfigTrustOptions } from './SourceConfigTrustOptions.js';
|
|
7
8
|
/**
|
|
8
9
|
* The "add a source" form: one `SourceConfigField` per host-supplied field
|
|
9
10
|
* spec, an optional trust selector (rendered only when `trustOptions` is
|
|
@@ -31,17 +32,47 @@ import { SourceConfigTestControl } from './SourceConfigTestControl.js';
|
|
|
31
32
|
* caller's next `page.find_elements` sees them, because that verb re-queries
|
|
32
33
|
* the DOM rather than replaying an earlier snapshot.
|
|
33
34
|
*/
|
|
34
|
-
export function SourceConfigAddForm(
|
|
35
|
+
export function SourceConfigAddForm(props) {
|
|
36
|
+
const { addLabel, onSubmit, agentHandle, submitError } = props;
|
|
35
37
|
const t = useT();
|
|
36
38
|
const submitLabel = addLabel ? t(addLabel) : t('Add source');
|
|
37
|
-
const trustLabel = t('Trust level');
|
|
38
|
-
const submitButton = (_jsx("button", { type: "submit", className: "source-config-add-form-submit", disabled: submitting, ...sourceConfigAgentProps(agentHandle, { role: 'button', label: submitLabel, action: 'submit' }), children: submitting ? t('Adding…') : submitLabel }));
|
|
39
39
|
return (_jsxs("form", { className: "source-config-add-form", ...sourceConfigAgentProps(agentHandle, { role: 'form', label: submitLabel }), onSubmit: (event) => {
|
|
40
40
|
event.preventDefault();
|
|
41
41
|
onSubmit();
|
|
42
|
-
}, children: [
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
}, children: [_jsx(AddFormFields, { ...props }), _jsx(AddFormTrustSelect, { ...props }), _jsx(AddFormTestControl, { ...props }), submitError ? (_jsx("div", { className: "source-config-add-form-error", role: "alert", children: t(submitError) })) : null, _jsx(AddFormActions, { ...props, submitLabel: submitLabel })] }));
|
|
43
|
+
}
|
|
44
|
+
/** One `SourceConfigField` per spec; a field's error only shows once a submit has been attempted. */
|
|
45
|
+
function AddFormFields({ fieldSpecs, values, validation, submitAttempted, submitting, onFieldChange, agentHandle }) {
|
|
46
|
+
const t = useT();
|
|
47
|
+
return fieldSpecs.map((spec) => {
|
|
48
|
+
const issue = submitAttempted ? issueForField(validation, spec.key) : undefined;
|
|
49
|
+
return (_jsx(SourceConfigField, { spec: spec, value: values[spec.key] ?? '', disabled: submitting, onChange: (value) => onFieldChange(spec.key, value), ...(issue ? { error: t(issue.message, { label: t(spec.label) }) } : {}), ...(agentHandle ? { agentHandle: sourceConfigFieldHandle(agentHandle, spec.key) } : {}) }, spec.key));
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/** Rendered only when `trustOptions` is non-empty — the origin MCP-server shape has no trust concept at all. */
|
|
53
|
+
function AddFormTrustSelect(props) {
|
|
54
|
+
const t = useT();
|
|
55
|
+
// Narrow on `props` itself (not a destructured copy) so the non-empty `trustOptions` check also
|
|
56
|
+
// proves `onTrustChange` present — the `SourceTrustSelectorProps` union binds the two.
|
|
57
|
+
if (!props.trustOptions || props.trustOptions.length === 0)
|
|
58
|
+
return null;
|
|
59
|
+
const { trustOptions, trust, submitting, onTrustChange, agentHandle } = props;
|
|
60
|
+
const trustLabel = t('Trust level');
|
|
61
|
+
return (_jsxs("label", { className: "source-config-field", htmlFor: "source-config-add-form-trust", children: [_jsx("span", { className: "source-config-field-label", children: trustLabel }), _jsx("select", { id: "source-config-add-form-trust", value: trust ?? '', disabled: submitting, "aria-label": trustLabel, ...sourceConfigAgentProps(agentHandle, { role: 'field', label: trustLabel, action: 'trust' }), onChange: (event) => onTrustChange(event.target.value), children: _jsx(SourceConfigTrustOptions, { trust: trust, trustOptions: trustOptions }) })] }));
|
|
62
|
+
}
|
|
63
|
+
/** Test-before-save: only when the host can test (`canTest`) and wired `onTest`; disabled while the draft is invalid. */
|
|
64
|
+
function AddFormTestControl({ canTest = false, onTest, testing = false, submitting, validation, testResult, agentHandle }) {
|
|
65
|
+
if (!canTest || !onTest)
|
|
66
|
+
return null;
|
|
67
|
+
return (_jsx(SourceConfigTestControl, { running: testing, disabled: submitting || !validation.ok, onTest: onTest, ...(testResult ? { result: testResult } : {}), ...(agentHandle ? { agentHandle: sourceConfigActionHandle(agentHandle, 'test') } : {}) }));
|
|
68
|
+
}
|
|
69
|
+
/** The submit button alone, or wrapped beside a Cancel button when `onCancel` is given. */
|
|
70
|
+
function AddFormActions({ submitting, agentHandle, onCancel, cancelLabel, submitLabel }) {
|
|
71
|
+
const t = useT();
|
|
72
|
+
const submitButton = (_jsx("button", { type: "submit", className: "source-config-add-form-submit", disabled: submitting, ...sourceConfigAgentProps(agentHandle, { role: 'button', label: submitLabel, action: 'submit' }), children: submitting ? t('Adding…') : submitLabel }));
|
|
73
|
+
if (!onCancel)
|
|
74
|
+
return submitButton;
|
|
75
|
+
const resolvedCancelLabel = t(cancelLabel ?? 'Cancel');
|
|
76
|
+
return (_jsxs("div", { className: "source-config-add-form-actions", children: [submitButton, _jsx("button", { type: "button", className: "source-config-add-form-cancel", disabled: submitting, ...sourceConfigAgentProps(agentHandle, { role: 'button', label: resolvedCancelLabel, action: 'cancel' }), onClick: onCancel, children: resolvedCancelLabel })] }));
|
|
46
77
|
}
|
|
47
78
|
//# sourceMappingURL=SourceConfigAddForm.js.map
|
|
@@ -36,6 +36,33 @@ import { maskFieldValue } from '../../rules.js';
|
|
|
36
36
|
*/
|
|
37
37
|
export function SourceConfigField({ spec, value, error, disabled = false, idPrefix = 'source-config-field', agentHandle, onChange }) {
|
|
38
38
|
const t = useT();
|
|
39
|
+
const { revealed, toggleRevealed, isLockedSecret } = useSecretReveal({ kind: spec.kind, value });
|
|
40
|
+
const inputId = `${idPrefix}-${spec.key}`;
|
|
41
|
+
const errorId = error ? `${inputId}-error` : undefined;
|
|
42
|
+
const fieldLabel = t(spec.label);
|
|
43
|
+
const shared = {
|
|
44
|
+
disabled,
|
|
45
|
+
'aria-invalid': Boolean(error) || undefined,
|
|
46
|
+
'aria-describedby': errorId,
|
|
47
|
+
...sourceConfigAgentProps(agentHandle, { role: 'field', label: fieldLabel }),
|
|
48
|
+
onChange: (event) => onChange(event.target.value),
|
|
49
|
+
};
|
|
50
|
+
// Labelled by the field it reveals, not by the live "Show"/"Hide" on its face: an agent label is
|
|
51
|
+
// stable page ontology, so it must not flip every time the toggle is clicked.
|
|
52
|
+
const revealAgentProps = sourceConfigAgentProps(agentHandle, {
|
|
53
|
+
role: 'button',
|
|
54
|
+
label: t('Show or hide {label}', { label: fieldLabel }),
|
|
55
|
+
action: 'reveal',
|
|
56
|
+
});
|
|
57
|
+
const reveal = { revealed, disabled, agentProps: revealAgentProps, onToggle: toggleRevealed };
|
|
58
|
+
return (_jsxs("label", { className: "source-config-field", htmlFor: inputId, children: [_jsxs("span", { className: "source-config-field-label", children: [fieldLabel, spec.required ? (_jsx("span", { className: "source-config-field-required", "aria-label": t('required'), children: "*" })) : null] }), _jsx(SourceConfigFieldControl, { spec: spec, value: value, inputId: inputId, shared: shared, reveal: reveal, isLockedSecret: isLockedSecret }), error ? (_jsx("span", { id: errorId, className: "source-config-field-error", role: "alert", children: error })) : null] }));
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The `password`/`secret-textarea` show-hide state. The toggle is small local
|
|
62
|
+
* disclosure state (per the vertical-slice guardrail allowing that in a leaf
|
|
63
|
+
* component).
|
|
64
|
+
*/
|
|
65
|
+
function useSecretReveal({ kind, value }) {
|
|
39
66
|
const [revealed, setRevealed] = useState(false);
|
|
40
67
|
// Whether THIS mount ever had a pre-existing secret to protect, captured
|
|
41
68
|
// once rather than recomputed from `value` on every render. A plain
|
|
@@ -46,7 +73,7 @@ export function SourceConfigField({ spec, value, error, disabled = false, idPref
|
|
|
46
73
|
// up. A ref survives across renders without itself triggering one, so it
|
|
47
74
|
// can be flipped on (below, in the empty-value effect) without disturbing
|
|
48
75
|
// in-progress typing.
|
|
49
|
-
const hadStoredSecretRef = useRef(
|
|
76
|
+
const hadStoredSecretRef = useRef(kind === 'secret-textarea' && Boolean(value));
|
|
50
77
|
// Re-hide as soon as the field empties. The add form clears its values after a
|
|
51
78
|
// successful submit but keeps this component mounted, so a `revealed` left on
|
|
52
79
|
// from the previous entry meant the NEXT credential was typed into a visible
|
|
@@ -64,33 +91,50 @@ export function SourceConfigField({ spec, value, error, disabled = false, idPref
|
|
|
64
91
|
hadStoredSecretRef.current = false;
|
|
65
92
|
}
|
|
66
93
|
}, [value]);
|
|
67
|
-
const inputId = `${idPrefix}-${spec.key}`;
|
|
68
|
-
const errorId = error ? `${inputId}-error` : undefined;
|
|
69
|
-
const placeholder = spec.placeholder ? t(spec.placeholder) : undefined;
|
|
70
94
|
// Gate (mask + block direct typing) only when there is an actual stored
|
|
71
95
|
// secret still un-revealed. A field with nothing to protect — first-time
|
|
72
96
|
// entry, or one already cleared out — is immediately editable, no
|
|
73
97
|
// "Show"/reveal click required.
|
|
74
|
-
const isLockedSecret =
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
const isLockedSecret = kind === 'secret-textarea' && hadStoredSecretRef.current && !revealed;
|
|
99
|
+
return { revealed, toggleRevealed: () => setRevealed((current) => !current), isLockedSecret };
|
|
100
|
+
}
|
|
101
|
+
/** Picks the control for `spec.kind`: a select, a (secret-)textarea, a password input, or a plain text/url input. */
|
|
102
|
+
function SourceConfigFieldControl(props) {
|
|
103
|
+
const t = useT();
|
|
104
|
+
const { spec, value, inputId, shared } = props;
|
|
105
|
+
const placeholder = spec.placeholder ? t(spec.placeholder) : undefined;
|
|
106
|
+
if (spec.kind === 'select')
|
|
107
|
+
return _jsx(SelectControl, { spec: spec, value: value, inputId: inputId, shared: shared, placeholder: placeholder });
|
|
108
|
+
if (spec.kind === 'textarea' || spec.kind === 'secret-textarea')
|
|
109
|
+
return _jsx(TextareaControl, { ...props, placeholder: placeholder });
|
|
110
|
+
if (spec.kind === 'password')
|
|
111
|
+
return _jsx(PasswordControl, { ...props, placeholder: placeholder });
|
|
112
|
+
return _jsx("input", { id: inputId, type: spec.kind === 'url' ? 'url' : 'text', value: value, placeholder: placeholder, ...shared });
|
|
113
|
+
}
|
|
114
|
+
function SelectControl({ spec, value, inputId, shared, placeholder, }) {
|
|
115
|
+
const t = useT();
|
|
116
|
+
return (_jsxs("select", { id: inputId, value: value, ...shared, children: [_jsx("option", { value: "", disabled: true, hidden: true, children: placeholder ?? t('Select…') }), (spec.options ?? []).map((option) => (_jsx("option", { value: option.value, children: t(option.label) }, option.value)))] }));
|
|
117
|
+
}
|
|
118
|
+
function TextareaControl({ spec, value, inputId, shared, reveal, isLockedSecret, placeholder }) {
|
|
119
|
+
return (_jsxs("span", { className: "source-config-field-row", children: [_jsx("textarea", { id: inputId, value: isLockedSecret ? maskFieldValue(spec.kind, value) : value, placeholder: placeholder,
|
|
120
|
+
// A masked textarea must not be typed into — the visible text is not
|
|
121
|
+
// the real value, so an edit would commit the mask characters.
|
|
122
|
+
// Revealing is the way in, exactly like the password field. Only
|
|
123
|
+
// applies when there is a stored secret to protect — see
|
|
124
|
+
// `isLockedSecret`.
|
|
125
|
+
readOnly: isLockedSecret, ...shared }), spec.kind === 'secret-textarea' ? _jsx(RevealToggle, { ...reveal }) : null] }));
|
|
126
|
+
}
|
|
127
|
+
function PasswordControl({ value, inputId, shared, reveal, placeholder }) {
|
|
128
|
+
return (_jsxs("span", { className: "source-config-field-row", children: [_jsx("input", { id: inputId, type: reveal.revealed ? 'text' : 'password',
|
|
129
|
+
// `new-password`, NOT `off`: Chrome deliberately ignores `off` and fills a saved site
|
|
130
|
+
// login into the first password input it finds (and the text input above it as the
|
|
131
|
+
// username). A source's credential is never the operator's own login.
|
|
132
|
+
autoComplete: "new-password", value: value, placeholder: placeholder, ...shared }), _jsx(RevealToggle, { ...reveal })] }));
|
|
133
|
+
}
|
|
134
|
+
/** The `password`/`secret-textarea` Show/Hide button. */
|
|
135
|
+
function RevealToggle({ revealed, disabled, agentProps, onToggle }) {
|
|
136
|
+
const t = useT();
|
|
137
|
+
const label = revealed ? t('Hide') : t('Show');
|
|
138
|
+
return (_jsx("button", { type: "button", className: "source-config-field-toggle", disabled: disabled, ...agentProps, onClick: onToggle, title: label, children: label }));
|
|
95
139
|
}
|
|
96
140
|
//# sourceMappingURL=SourceConfigField.js.map
|