@jini-ai/ui 0.5.5 → 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.
Files changed (263) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/core/theme/validation.js +40 -38
  3. package/dist/features/a2ui/renderer.js +15 -13
  4. package/dist/features/about/react/components/AboutTab.js +64 -34
  5. package/dist/features/about/rules.d.ts +2 -2
  6. package/dist/features/about/rules.js +156 -129
  7. package/dist/features/admin-widgets/components/ImagePreviewModal.d.ts +4 -3
  8. package/dist/features/admin-widgets/components/ImagePreviewModal.js +6 -10
  9. package/dist/features/admin-widgets/components/InfoTip.d.ts +3 -2
  10. package/dist/features/admin-widgets/components/InfoTip.hooks.js +2 -0
  11. package/dist/features/admin-widgets/components/InfoTip.js +34 -7
  12. package/dist/features/admin-widgets/components/InfoTip.rules.d.ts +13 -0
  13. package/dist/features/admin-widgets/components/InfoTip.rules.js +43 -10
  14. package/dist/features/admin-widgets/components/Lightbox/Lightbox.d.ts +30 -0
  15. package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.d.ts +40 -0
  16. package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.js +128 -0
  17. package/dist/features/admin-widgets/components/Lightbox/Lightbox.js +18 -0
  18. package/dist/features/admin-widgets/components/MiddleTruncate.d.ts +14 -0
  19. package/dist/features/admin-widgets/components/MiddleTruncate.js +12 -0
  20. package/dist/features/admin-widgets/components/MiddleTruncate.rules.d.ts +20 -0
  21. package/dist/features/admin-widgets/components/MiddleTruncate.rules.js +21 -0
  22. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.d.ts +18 -0
  23. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.d.ts +16 -0
  24. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.js +45 -0
  25. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.js +18 -0
  26. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.d.ts +32 -0
  27. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.js +26 -0
  28. package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.hooks.js +29 -14
  29. package/dist/features/admin-widgets/index.d.ts +14 -2
  30. package/dist/features/admin-widgets/index.js +7 -1
  31. package/dist/features/admin-widgets/styles/admin-widgets.css +1 -0
  32. package/dist/features/asset-grid/react/components/AssetCard.js +7 -1
  33. package/dist/features/asset-grid/react/components/AssetGrid.d.ts +1 -1
  34. package/dist/features/asset-grid/react/components/AssetGrid.js +38 -18
  35. package/dist/features/asset-grid/react/components/useAssetGridFilters.d.ts +21 -0
  36. package/dist/features/asset-grid/react/components/useAssetGridFilters.js +19 -0
  37. package/dist/features/asset-grid/react/hooks/useAssetGridKeyboardShortcuts.js +16 -11
  38. package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.d.ts +2 -0
  39. package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.js +35 -11
  40. package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.d.ts +6 -6
  41. package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.js +10 -129
  42. package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.d.ts +50 -0
  43. package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.js +95 -0
  44. package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.d.ts +56 -0
  45. package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.js +80 -0
  46. package/dist/features/asset-tree-browser/rules.js +40 -22
  47. package/dist/features/browser-chrome/rules.js +74 -70
  48. package/dist/features/charts/browser.js +11 -5
  49. package/dist/features/charts/react.js +2 -2
  50. package/dist/features/charts/table.js +2 -2
  51. package/dist/features/command-palette/react/hooks/useCommandPalette.js +3 -9
  52. package/dist/features/connectors/ConnectorsBrowser.d.ts +4 -4
  53. package/dist/features/connectors/ConnectorsBrowser.js +26 -14
  54. package/dist/features/connectors/components/ConnectorCard.js +67 -38
  55. package/dist/features/connectors/components/ConnectorDetailDrawer.js +62 -31
  56. package/dist/features/connectors/components/ConnectorGrid.js +11 -6
  57. package/dist/features/connectors/hooks/useConnectorAuthorization.js +6 -0
  58. package/dist/features/connectors/hooks/useConnectorCatalog.d.ts +2 -0
  59. package/dist/features/connectors/hooks/useConnectorCatalog.js +32 -13
  60. package/dist/features/connectors/hooks/useWiredConnectorsBrowser.d.ts +3 -3
  61. package/dist/features/connectors/rules.d.ts +8 -1
  62. package/dist/features/connectors/rules.js +42 -20
  63. package/dist/features/connectors/types.d.ts +11 -0
  64. package/dist/features/execution/constants.d.ts +4 -10
  65. package/dist/features/execution/constants.js +9 -94
  66. package/dist/features/execution/react/components/ByokProviderForm.d.ts +2 -4
  67. package/dist/features/execution/react/components/ByokProviderForm.js +140 -43
  68. package/dist/features/execution/react/components/ExecutionTab.d.ts +1 -2
  69. package/dist/features/execution/react/components/ExecutionTab.js +52 -30
  70. package/dist/features/execution/react/components/LocalCliAgentCard.js +12 -3
  71. package/dist/features/execution/react/components/LocalCliAgentList.js +14 -3
  72. package/dist/features/execution/react/components/LocalCliAgentSettings.js +14 -3
  73. package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +54 -36
  74. package/dist/features/execution/react/hooks/useReasoningControl.js +114 -78
  75. package/dist/features/execution/rules.d.ts +2 -2
  76. package/dist/features/execution/rules.js +31 -15
  77. package/dist/features/execution/types.d.ts +4 -42
  78. package/dist/features/execution/types.js +0 -17
  79. package/dist/features/external-mcp/react/components/ExternalMcpTab.d.ts +6 -2
  80. package/dist/features/external-mcp/react/components/ExternalMcpTab.js +9 -2
  81. package/dist/features/file-dropzone/react/components/FileDropzone.js +24 -25
  82. package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.d.ts +2 -2
  83. package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.js +35 -30
  84. package/dist/features/file-dropzone/react/components/FileDropzoneThumbnailGrid.js +30 -24
  85. package/dist/features/file-dropzone/react/components/FileDropzoneZone.d.ts +14 -0
  86. package/dist/features/file-dropzone/react/components/FileDropzoneZone.js +26 -0
  87. package/dist/features/html-editor/canvas-content-wrapper.js +13 -13
  88. package/dist/features/html-editor/canvas-embed-placeholders.js +46 -37
  89. package/dist/features/html-editor/css.js +76 -69
  90. package/dist/features/html-editor/editor-blocks.js +47 -33
  91. package/dist/features/html-editor/editor-serialization.js +6 -5
  92. package/dist/features/html-editor/protected-elements.js +39 -28
  93. package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +4 -4
  94. package/dist/features/html-editor/source-splice.js +51 -30
  95. package/dist/features/i18n/dictionaries/settings-dialog.ja.js +1 -0
  96. package/dist/features/i18n/dictionaries/settings-dialog.zh-CN.js +1 -0
  97. package/dist/features/i18n/dictionaries/settings-dialog.zh-TW.js +1 -0
  98. package/dist/features/i18n/locale.js +20 -16
  99. package/dist/features/iframe-pool/react/dom-sync.js +8 -6
  100. package/dist/features/integrations/react/components/CodexInstallToggleButton.js +19 -4
  101. package/dist/features/integrations/react/components/IntegrationsTab.js +60 -14
  102. package/dist/features/interactive-ui/interactive-ui.css +1 -1
  103. package/dist/features/interactive-ui/providers/shadcn/data-table.js +10 -7
  104. package/dist/features/lexical-rich-text-editor/mention-parser.js +60 -57
  105. package/dist/features/lexical-rich-text-editor/react/hooks/useKeyboardCommands.js +33 -38
  106. package/dist/features/lexical-rich-text-editor/rules.js +87 -74
  107. package/dist/features/lexical-rich-text-editor/serialize.js +27 -25
  108. package/dist/features/mcp-ui/secret-card.js +111 -61
  109. package/dist/features/mcp-ui/surfaces/confirmation.js +39 -21
  110. package/dist/features/mcp-ui/surfaces/document.d.ts +1 -1
  111. package/dist/features/mcp-ui/surfaces/document.js +10 -2
  112. package/dist/features/mcp-ui/surfaces/fields.js +30 -50
  113. package/dist/features/mcp-ui/surfaces/form.d.ts +6 -0
  114. package/dist/features/mcp-ui/surfaces/form.js +43 -21
  115. package/dist/features/mcp-ui/surfaces/outcome.js +30 -20
  116. package/dist/features/mcp-ui/surfaces/text-input.js +33 -21
  117. package/dist/features/mcp-ui/surfaces/tokens.d.ts +6 -1
  118. package/dist/features/mcp-ui/surfaces/tokens.js +5 -2
  119. package/dist/features/media-providers/constants.d.ts +1 -0
  120. package/dist/features/media-providers/constants.js +2 -81
  121. package/dist/features/media-providers/index.d.ts +1 -1
  122. package/dist/features/media-providers/ports.d.ts +2 -0
  123. package/dist/features/media-providers/react/components/MediaProviderCard.d.ts +22 -0
  124. package/dist/features/media-providers/react/components/MediaProviderCard.js +50 -0
  125. package/dist/features/media-providers/react/components/MediaProvidersTab.d.ts +5 -6
  126. package/dist/features/media-providers/react/components/MediaProvidersTab.js +40 -72
  127. package/dist/features/media-providers/react/components/media-providers-tab-labels.d.ts +11 -0
  128. package/dist/features/media-providers/react/components/media-providers-tab-labels.js +57 -0
  129. package/dist/features/media-providers/react/hooks/useMediaProvidersTab.d.ts +4 -2
  130. package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +37 -23
  131. package/dist/features/media-providers/rules.js +17 -10
  132. package/dist/features/media-providers/types.d.ts +4 -22
  133. package/dist/features/media-providers/types.js +3 -8
  134. package/dist/features/memory/formatters.js +127 -92
  135. package/dist/features/memory/react/components/MemoryConnectedPanel.js +92 -36
  136. package/dist/features/memory/react/components/MemoryList.js +37 -18
  137. package/dist/features/memory/react/hooks/useMemoryExtractions.store.js +42 -36
  138. package/dist/features/notifications/react/components/NotificationsTab.js +28 -28
  139. package/dist/features/observability/long-task.d.ts +0 -12
  140. package/dist/features/observability/long-task.js +15 -19
  141. package/dist/features/observability/resource-error.d.ts +0 -10
  142. package/dist/features/observability/resource-error.js +18 -13
  143. package/dist/features/observability/stuck-run.js +10 -6
  144. package/dist/features/observability/telemetry-url.d.ts +6 -0
  145. package/dist/features/observability/telemetry-url.js +16 -0
  146. package/dist/features/observability/white-screen.js +12 -24
  147. package/dist/features/panel-kit/fetch-query/adapter.react.d.ts +2 -2
  148. package/dist/features/panel-kit/fetch-query/adapter.react.js +4 -2
  149. package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +46 -33
  150. package/dist/features/panel-kit/helpers/standing-draft-local-backup.js +3 -1
  151. package/dist/features/panel-kit/hooks/use-settings-slice.hooks.js +3 -1
  152. package/dist/features/privacy/react/components/PrivacyTab.js +24 -13
  153. package/dist/features/progress-card/components/ProgressCard.js +7 -3
  154. package/dist/features/progress-card/reference-adapters.js +59 -54
  155. package/dist/features/project-locations/react/components/ProjectLocationsTab.js +24 -15
  156. package/dist/features/project-locations/react/hooks/useProjectLocationsTab.d.ts +8 -0
  157. package/dist/features/project-locations/react/hooks/useProjectLocationsTab.js +31 -23
  158. package/dist/features/resource-dashboard/react/components/ResourceBoard.js +6 -47
  159. package/dist/features/resource-dashboard/react/components/ResourceBoardView.d.ts +2 -2
  160. package/dist/features/resource-dashboard/react/components/ResourceBoardView.js +3 -6
  161. package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.d.ts +15 -0
  162. package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.js +35 -0
  163. package/dist/features/resource-dashboard/react/components/ResourceCard.js +5 -16
  164. package/dist/features/resource-dashboard/react/components/ResourceCardParts.d.ts +34 -0
  165. package/dist/features/resource-dashboard/react/components/ResourceCardParts.js +34 -0
  166. package/dist/features/resource-dashboard/react/components/ResourceRowList.js +3 -1
  167. package/dist/features/resource-dashboard/react/components/ResourceRowListItem.js +2 -2
  168. package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.d.ts +19 -0
  169. package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.js +11 -0
  170. package/dist/features/resource-dashboard/react/components/ResourceRowListView.d.ts +1 -1
  171. package/dist/features/resource-dashboard/react/components/ResourceRowListView.js +4 -4
  172. package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.d.ts +10 -0
  173. package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.js +20 -0
  174. package/dist/features/resource-dashboard/react/components/resourceBoardProps.d.ts +48 -0
  175. package/dist/features/resource-dashboard/react/components/resourceBoardProps.js +70 -0
  176. package/dist/features/resource-dashboard/react/components/resourceRowListProps.d.ts +19 -0
  177. package/dist/features/resource-dashboard/react/components/resourceRowListProps.js +14 -0
  178. package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.d.ts +16 -0
  179. package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.js +13 -0
  180. package/dist/features/resource-dashboard/rules.js +2 -8
  181. package/dist/features/sketch-editor/dom.js +150 -99
  182. package/dist/features/sketch-editor/react/components/SketchEditor.js +26 -15
  183. package/dist/features/skills/react/components/SkillDraftForm.js +13 -19
  184. package/dist/features/skills/react/components/SkillDraftForm.labels.d.ts +31 -0
  185. package/dist/features/skills/react/components/SkillDraftForm.labels.js +54 -0
  186. package/dist/features/skills/react/components/SkillRow.js +38 -18
  187. package/dist/features/skills/react/components/SkillRow.labels.d.ts +7 -0
  188. package/dist/features/skills/react/components/SkillRow.labels.js +18 -0
  189. package/dist/features/skills/react/components/SkillsTab.js +24 -14
  190. package/dist/features/skills/react/components/SkillsTab.labels.d.ts +7 -0
  191. package/dist/features/skills/react/components/SkillsTab.labels.js +11 -0
  192. package/dist/features/skills/rules.js +32 -23
  193. package/dist/features/source-config-list/agent-handles.js +2 -1
  194. package/dist/features/source-config-list/dependencies.js +53 -49
  195. package/dist/features/source-config-list/index.d.ts +3 -3
  196. package/dist/features/source-config-list/react/components/SourceConfigAddForm.d.ts +6 -5
  197. package/dist/features/source-config-list/react/components/SourceConfigAddForm.js +38 -7
  198. package/dist/features/source-config-list/react/components/SourceConfigField.js +69 -25
  199. package/dist/features/source-config-list/react/components/SourceConfigItemCard.d.ts +6 -5
  200. package/dist/features/source-config-list/react/components/SourceConfigItemCard.js +76 -20
  201. package/dist/features/source-config-list/react/components/SourceConfigListView.d.ts +5 -3
  202. package/dist/features/source-config-list/react/components/SourceConfigListView.js +33 -3
  203. package/dist/features/source-config-list/react/components/SourceConfigTestControl.js +17 -1
  204. package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.d.ts +11 -0
  205. package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.js +12 -0
  206. package/dist/features/source-config-list/types.d.ts +14 -0
  207. package/dist/features/tab-launcher-menu/react/components/TabLauncherMenu.js +25 -1
  208. package/dist/features/tab-launcher-menu/react/hooks/useTabLauncherMenu.js +15 -16
  209. package/dist/features/tab-strip/react/components/TabBar.js +8 -1
  210. package/dist/features/tabbed-dialog/react/components/TabbedDialog.js +8 -30
  211. package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.d.ts +15 -0
  212. package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.js +8 -0
  213. package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.d.ts +12 -0
  214. package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.js +6 -0
  215. package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.d.ts +27 -0
  216. package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.js +12 -0
  217. package/dist/features/tabbed-dialog/react/components/tabbedDialogView.d.ts +43 -0
  218. package/dist/features/tabbed-dialog/react/components/tabbedDialogView.js +59 -0
  219. package/dist/features/version-manager/dependencies.d.ts +3 -1
  220. package/dist/features/version-manager/dependencies.js +3 -2
  221. package/dist/features/version-manager/react/components/VersionManagerModal.js +10 -6
  222. package/dist/features/version-manager/react/hooks/useVersionManager.js +7 -4
  223. package/dist/features/viewer-shell/react/components/CommentSidePanel.js +103 -50
  224. package/dist/features/viewer-shell/react/components/MarkdownSplitPane.js +28 -8
  225. package/dist/features/viewer-shell/react/hooks/useCommentReorder.js +22 -16
  226. package/dist/features/viewer-shell/rules.js +19 -23
  227. package/dist/react/components/CustomSelect.d.ts +38 -1
  228. package/dist/react/components/CustomSelect.js +94 -38
  229. package/dist/react/components/OnboardingDropdown.js +20 -8
  230. package/dist/react/components/RemixIcon.stylesheet.js +3 -1
  231. package/dist/react/components/Toast.js +13 -2
  232. package/dist/react/components/TooltipLayer.js +5 -14
  233. package/dist/react/components/WorkingDirPicker.js +78 -50
  234. package/dist/react/components/remixicon-font-recovery.js +38 -30
  235. package/dist/react/components/select-popover.d.ts +8 -6
  236. package/dist/react/components/select-popover.js +33 -29
  237. package/dist/react/mcp-ui/McpUiHost.d.ts +1 -1
  238. package/dist/react/mcp-ui/McpUiHost.js +10 -11
  239. package/dist/react/mcp-ui/host-message-source.d.ts +14 -2
  240. package/dist/react/mcp-ui/host-message-source.js +15 -5
  241. package/dist/react/mcp-ui/mcp-ui-host-frame.d.ts +41 -0
  242. package/dist/react/mcp-ui/mcp-ui-host-frame.js +39 -0
  243. package/dist/renderers/annotation-canvas/react/components/AnnotationCanvas.js +97 -69
  244. package/dist/renderers/preview-modal-shell/react/components/PreviewModalShell.js +59 -30
  245. package/dist/renderers/react/components/ArtifactView.js +9 -6
  246. package/dist/renderers/srcdoc/build.d.ts +4 -1
  247. package/dist/renderers/srcdoc/build.js +62 -48
  248. package/dist/styles/admin.css +29 -14
  249. package/dist/styles/lightbox.css +142 -0
  250. package/dist/styles/variables.css +128 -0
  251. package/dist/theme/apply.js +9 -5
  252. package/dist/utils/auto-open-file.d.ts +2 -1
  253. package/dist/utils/auto-open-file.js +69 -85
  254. package/dist/utils/markdown-scroll-sync.js +108 -87
  255. package/dist/utils/polygon-selection.js +25 -26
  256. package/dist/utils/smooth-scroll-to-top.d.ts +1 -1
  257. package/dist/utils/smooth-scroll-to-top.js +2 -32
  258. package/dist/utils/sse.js +26 -26
  259. package/dist/utils/unit-bezier.d.ts +7 -0
  260. package/dist/utils/unit-bezier.js +38 -0
  261. package/package.json +7 -10
  262. package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.d.ts +0 -13
  263. 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 { loading, loadError, filters, setSearch, setSourceFilter, setModeFilter, setCategoryFilter, filteredSkills, sourceOptions, modeOptions, categoryOptions, expandedId, toggleExpanded, bodyById, bodyLoadingId, filesById, filesLoadingId, editingId, creating, draft, setDraft, draftError, draftSaving, startCreate, requestEdit, confirmBuiltInEditId, confirmBuiltInEdit, cancelBuiltInEdit, cancelDraft, submitDraft, confirmDeleteId, armDelete, cancelDelete, commitDelete, } = useSkillsTab({ port, locale });
20
- const searchPlaceholder = labels?.searchPlaceholder ?? t('Search skills…');
21
- const newSkillLabel = labels?.newSkillLabel ?? t('New skill');
22
- const sourceFilterLabel = labels?.sourceFilterLabel ?? t('Source');
23
- const modeFilterLabel = labels?.modeFilterLabel ?? t('Type');
24
- const categoryFilterLabel = labels?.categoryFilterLabel ?? t('Category');
25
- const allLabel = labels?.allLabel ?? t('All');
26
- const noResultsLabel = labels?.noResultsLabel ?? t('No skills match these filters.');
27
- const loadErrorLabel = labels?.loadErrorLabel ?? t('Could not load skills: {error}', { error: loadError ?? '' });
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 (_jsxs("section", { className: "jini-settings-section jini-settings-skills", children: [_jsxs("div", { className: "jini-skills-toolbar", children: [_jsxs("div", { className: "jini-skills-toolbar-top", children: [_jsx("input", { type: "search", className: "jini-skills-search", placeholder: searchPlaceholder, value: filters.search, onChange: (event) => setSearch(event.target.value), "aria-label": searchPlaceholder, ...agentHandleProps({}, { base: agentHandle, ...({ action: 'search', role: 'field', label: searchPlaceholder }) }) }), _jsxs("button", { type: "button", className: "jini-button jini-button-primary", onClick: startCreate, "data-testid": "skills-new", ...agentHandleProps({}, { base: agentHandle, ...({ action: 'new', role: 'button', label: newSkillLabel }) }), children: [_jsx(Icon, { name: "plus", size: 13 }), _jsx("span", { children: newSkillLabel })] })] }), _jsxs("div", { className: "jini-skills-filter-selects", children: [_jsxs("label", { className: "jini-skills-filter-select", children: [_jsx("span", { children: sourceFilterLabel }), _jsxs("select", { value: filters.source, onChange: (event) => setSourceFilter(event.target.value), ...agentHandleProps({}, { base: agentHandle, ...({ action: 'filter-source', role: 'field', label: sourceFilterLabel }) }), children: [_jsxs("option", { value: "all", children: [allLabel, " (", sourceOptions.all, ")"] }), sourceOptions.options.map(([value, count]) => (_jsxs("option", { value: value, children: [value, " (", count, ")"] }, value)))] })] }), _jsxs("label", { className: "jini-skills-filter-select", children: [_jsx("span", { children: modeFilterLabel }), _jsxs("select", { value: filters.mode, onChange: (event) => setModeFilter(event.target.value), ...agentHandleProps({}, { base: agentHandle, ...({ action: 'filter-mode', role: 'field', label: modeFilterLabel }) }), children: [_jsxs("option", { value: "all", children: [allLabel, " (", modeOptions.all, ")"] }), modeOptions.options.map(([value, count]) => (_jsxs("option", { value: value, children: [value, " (", count, ")"] }, value)))] })] }), categoryOptions ? (_jsxs("label", { className: "jini-skills-filter-select", "data-testid": "skills-category-filters", children: [_jsx("span", { children: categoryFilterLabel }), _jsxs("select", { value: filters.category, onChange: (event) => setCategoryFilter(event.target.value), ...agentHandleProps({}, { base: agentHandle, ...({ action: 'filter-category', role: 'field', label: categoryFilterLabel }) }), children: [_jsxs("option", { value: "all", children: [allLabel, " (", categoryOptions.all, ")"] }), categoryOptions.options.map(([value, count]) => (_jsxs("option", { value: value, children: [humanizeSkillCategory(value), " (", count, ")"] }, value)))] })] })) : null] })] }), loadError ? (_jsx("div", { className: "jini-empty-card jini-empty-card-error", children: _jsx("strong", { children: loadErrorLabel }) })) : null, creating ? (_jsx(SkillDraftForm, { heading: newSkillLabel, draft: draft, onDraftChange: setDraft, error: draftError, saving: draftSaving, isEdit: false, onCancel: cancelDraft, onSubmit: submitDraft, labels: labels, ...(agentHandle ? { agentHandle: agentSubHandle({ base: agentHandle, action: 'create-form' }) } : {}) })) : null, !loading && filteredSkills.length === 0 ? (_jsx("div", { className: "jini-empty-card", children: _jsx("strong", { children: noResultsLabel }) })) : (_jsx("div", { className: "jini-skills-rows", "data-testid": "skills-list", children: filteredSkills.map((skill, index) => {
32
- const isExpanded = expandedId === skill.id;
33
- const isEditing = editingId === skill.id;
34
- return (_jsx(SkillRow, { ...(rowHandles?.[index] ? { agentHandle: rowHandles[index] } : {}), skill: skill, locale: locale, enabled: !disabledSkillIds.has(skill.id), expanded: isExpanded, editing: isEditing, body: bodyById[skill.id], bodyLoading: bodyLoadingId === skill.id, files: filesById[skill.id] ?? null, filesLoading: filesLoadingId === skill.id, confirmDelete: confirmDeleteId === skill.id, confirmBuiltInEdit: confirmBuiltInEditId === skill.id, draft: isEditing ? draft : null, draftError: isEditing ? draftError : null, draftSaving: isEditing && draftSaving, onDraftChange: setDraft, onToggleExpanded: () => toggleExpanded(skill.id), onToggleEnabled: (enabled) => onToggleEnabled(skill.id, enabled), onStartEdit: () => requestEdit(skill), onConfirmBuiltInEdit: confirmBuiltInEdit, onCancelBuiltInEdit: cancelBuiltInEdit, onArmDelete: () => armDelete(skill.id), onCancelDelete: cancelDelete, onCommitDelete: () => commitDelete(skill.id), onCancelEdit: cancelDraft, onSubmitEdit: submitDraft, labels: labels }, skill.id));
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 = ['all', 'user', 'built-in'];
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
- const counts = new Map(KNOWN_SOURCES.filter((s) => s !== 'all').map((s) => [s, 0]));
121
- for (const skill of matching) {
122
- // `undefined` means an origin outside the known vocabulary (an org
123
- // registry, a marketplace). Those are counted in `all` and get no pill.
124
- // One lookup, not a `has` + `get` pair with an unreachable `?? 0`.
125
- const current = counts.get(skill.source);
126
- if (current !== undefined)
127
- counts.set(skill.source, current + 1);
128
- }
129
- return {
130
- all: matching.length,
131
- options: [...counts.entries()]
132
- .map(([value, count]) => [value, count])
133
- .sort((a, b) => a[0].localeCompare(b[0])),
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
- // `mode` is required on every skill; `category` is optional, so a skill
137
- // without one contributes to `all` but to no pill.
138
- const valueOf = (skill) => dimension === 'mode' ? skill.mode : typeof skill.category === 'string' && skill.category ? skill.category : null;
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
- return agentHandle({ handle: handle }, { ...(options.role === undefined ? {} : { role: options.role }), ...(options.label === undefined ? {} : { label: options.label }) });
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 latencyMs = options.latencyMs ?? 0;
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
- if (options.supportsRefresh ?? true) {
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, SourceTrustOption } from '../../types.js';
2
- export interface SourceConfigAddFormProps {
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({ fieldSpecs, trustOptions, values, trust, validation, submitAttempted, submitting, submitError, addLabel, onFieldChange, onTrustChange, onSubmit, canTest, testing, testResult, onTest, agentHandle, onCancel, cancelLabel, }: SourceConfigAddFormProps): import("react").JSX.Element;
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({ fieldSpecs, trustOptions, values, trust, validation, submitAttempted, submitting, submitError, addLabel, onFieldChange, onTrustChange, onSubmit, canTest = false, testing = false, testResult, onTest, agentHandle, onCancel, cancelLabel, }) {
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: [fieldSpecs.map((spec) => {
43
- const issue = submitAttempted ? issueForField(validation, spec.key) : undefined;
44
- 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));
45
- }), trustOptions && trustOptions.length > 0 ? (_jsxs("label", { className: "source-config-field", htmlFor: "source-config-add-form-trust", children: [_jsx("span", { className: "source-config-field-label", children: trustLabel }), _jsxs("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: [!trust ? (_jsx("option", { value: "", disabled: true, hidden: true, children: t('Select…') })) : null, trustOptions.map((option) => (_jsx("option", { value: option.value, children: t(option.label) }, option.value)))] })] })) : null, canTest && onTest ? (_jsx(SourceConfigTestControl, { running: testing, disabled: submitting || !validation.ok, onTest: onTest, ...(testResult ? { result: testResult } : {}), ...(agentHandle ? { agentHandle: sourceConfigActionHandle(agentHandle, 'test') } : {}) })) : null, submitError ? (_jsx("div", { className: "source-config-add-form-error", role: "alert", children: t(submitError) })) : null, onCancel ? (_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: t(cancelLabel ?? 'Cancel'), action: 'cancel' }), onClick: onCancel, children: t(cancelLabel ?? 'Cancel') })] })) : (submitButton)] }));
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(spec.kind === 'secret-textarea' && Boolean(value));
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 = spec.kind === 'secret-textarea' && hadStoredSecretRef.current && !revealed;
75
- const fieldLabel = t(spec.label);
76
- const controlAgentProps = sourceConfigAgentProps(agentHandle, { role: 'field', label: fieldLabel });
77
- // Labelled by the field it reveals, not by the live "Show"/"Hide" on its face: an agent label is
78
- // stable page ontology, so it must not flip every time the toggle is clicked.
79
- const revealAgentProps = sourceConfigAgentProps(agentHandle, {
80
- role: 'button',
81
- label: t('Show or hide {label}', { label: fieldLabel }),
82
- action: 'reveal',
83
- });
84
- 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] }), spec.kind === 'select' ? (_jsxs("select", { id: inputId, value: value, disabled: disabled, "aria-invalid": Boolean(error) || undefined, "aria-describedby": errorId, ...controlAgentProps, onChange: (event) => onChange(event.target.value), 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)))] })) : spec.kind === 'textarea' || spec.kind === 'secret-textarea' ? (_jsxs("span", { className: "source-config-field-row", children: [_jsx("textarea", { id: inputId, value: isLockedSecret ? maskFieldValue(spec.kind, value) : value, placeholder: placeholder,
85
- // A masked textarea must not be typed into — the visible text is not
86
- // the real value, so an edit would commit the mask characters.
87
- // Revealing is the way in, exactly like the password field. Only
88
- // applies when there is a stored secret to protect — see
89
- // `isLockedSecret`.
90
- readOnly: isLockedSecret, disabled: disabled, "aria-invalid": Boolean(error) || undefined, "aria-describedby": errorId, ...controlAgentProps, onChange: (event) => onChange(event.target.value) }), spec.kind === 'secret-textarea' ? (_jsx("button", { type: "button", className: "source-config-field-toggle", disabled: disabled, ...revealAgentProps, onClick: () => setRevealed((current) => !current), title: revealed ? t('Hide') : t('Show'), children: revealed ? t('Hide') : t('Show') })) : null] })) : spec.kind === 'password' ? (_jsxs("span", { className: "source-config-field-row", children: [_jsx("input", { id: inputId, type: revealed ? 'text' : 'password',
91
- // `new-password`, NOT `off`: Chrome deliberately ignores `off` and fills a saved site
92
- // login into the first password input it finds (and the text input above it as the
93
- // username). A source's credential is never the operator's own login.
94
- autoComplete: "new-password", value: value, placeholder: placeholder, disabled: disabled, "aria-invalid": Boolean(error) || undefined, "aria-describedby": errorId, ...controlAgentProps, onChange: (event) => onChange(event.target.value) }), _jsx("button", { type: "button", className: "source-config-field-toggle", disabled: disabled, ...revealAgentProps, onClick: () => setRevealed((current) => !current), title: revealed ? t('Hide') : t('Show'), children: revealed ? t('Hide') : t('Show') })] })) : (_jsx("input", { id: inputId, type: spec.kind === 'url' ? 'url' : 'text', value: value, placeholder: placeholder, disabled: disabled, "aria-invalid": Boolean(error) || undefined, "aria-describedby": errorId, ...controlAgentProps, onChange: (event) => onChange(event.target.value) })), error ? (_jsx("span", { id: errorId, className: "source-config-field-error", role: "alert", children: error })) : null] }));
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