@jini-ai/ui 0.5.5 → 0.6.10

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 +91 -2
  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 +9 -12
  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
@@ -6,6 +6,27 @@ import { hasMadeConsentDecision, isSharingEnabled, nextStateForDeclineAll, nextS
6
6
  function ToggleRow({ label, hint, checked, onChange, agentHandle }) {
7
7
  return (_jsxs("button", { type: "button", className: `jini-toggle-row${checked ? ' on' : ''}`, onClick: () => onChange(!checked), "aria-pressed": checked, ...agentHandleProps({}, { base: agentHandle, ...({ role: 'checkbox', label }) }), children: [_jsxs("div", { className: "jini-toggle-row-text", children: [_jsx("span", { className: "jini-toggle-row-label", children: label }), _jsx("span", { className: "jini-toggle-row-hint", children: hint })] }), _jsx("span", { className: "jini-toggle-row-switch", "aria-hidden": true })] }));
8
8
  }
9
+ function resolveConsentLabels({ labels }, { t }) {
10
+ return {
11
+ consentKicker: labels.consentKicker ?? t('Help improve this product'),
12
+ consentLead: labels.consentLead ?? t('Choose what you share. You can change this anytime.'),
13
+ consentFooter: labels.consentFooter ?? t('Nothing is shared unless you opt in.'),
14
+ declineLabel: labels.declineLabel ?? t("Don't share"),
15
+ shareLabel: labels.shareLabel ?? t('Share usage'),
16
+ metricsLabel: labels.metricsLabel ?? t('Anonymous metrics'),
17
+ metricsHint: labels.metricsHint ?? t('Feature usage and performance data, with no personal content.'),
18
+ contentLabel: labels.contentLabel ?? t('Conversation and tool content'),
19
+ contentHint: labels.contentHint ?? t('Helps improve model quality. Off by default.'),
20
+ };
21
+ }
22
+ function resolveInstallationLabels({ labels }, { t }) {
23
+ return {
24
+ installationIdLabel: labels.installationIdLabel ?? t('Installation ID'),
25
+ installationIdHint: labels.installationIdHint ?? t('An anonymous id used to group your shared data.'),
26
+ optedOutLabel: labels.optedOutLabel ?? t('Not sharing'),
27
+ deleteMyDataLabel: labels.deleteMyDataLabel ?? t('Delete my data'),
28
+ };
29
+ }
9
30
  /**
10
31
  * Telemetry consent card (share/decline + two per-category toggles) over a
11
32
  * generic `{ metrics, content }` shape, plus an installation-id
@@ -19,19 +40,9 @@ export function PrivacyTab({ state, onChange, labels, now = Date.now, agentHandl
19
40
  const t = useT();
20
41
  const decided = hasMadeConsentDecision(state);
21
42
  const sharing = decided ? isSharingEnabled(state.telemetry) : undefined;
22
- const consentKicker = labels?.consentKicker ?? t('Help improve this product');
23
- const consentLead = labels?.consentLead ?? t('Choose what you share. You can change this anytime.');
24
- const consentFooter = labels?.consentFooter ?? t('Nothing is shared unless you opt in.');
25
- const declineLabel = labels?.declineLabel ?? t("Don't share");
26
- const shareLabel = labels?.shareLabel ?? t('Share usage');
27
- const metricsLabel = labels?.metricsLabel ?? t('Anonymous metrics');
28
- const metricsHint = labels?.metricsHint ?? t('Feature usage and performance data, with no personal content.');
29
- const contentLabel = labels?.contentLabel ?? t('Conversation and tool content');
30
- const contentHint = labels?.contentHint ?? t('Helps improve model quality. Off by default.');
31
- const installationIdLabel = labels?.installationIdLabel ?? t('Installation ID');
32
- const installationIdHint = labels?.installationIdHint ?? t('An anonymous id used to group your shared data.');
33
- const optedOutLabel = labels?.optedOutLabel ?? t('Not sharing');
34
- const deleteMyDataLabel = labels?.deleteMyDataLabel ?? t('Delete my data');
43
+ const labelOverrides = labels ?? {};
44
+ const { consentKicker, consentLead, consentFooter, declineLabel, shareLabel, metricsLabel, metricsHint, contentLabel, contentHint, } = resolveConsentLabels({ labels: labelOverrides }, { t });
45
+ const { installationIdLabel, installationIdHint, optedOutLabel, deleteMyDataLabel, } = resolveInstallationLabels({ labels: labelOverrides }, { t });
35
46
  return (_jsxs("section", { className: "jini-settings-section jini-settings-privacy", children: [_jsxs("div", { className: "jini-settings-subsection", children: [_jsx("div", { className: "jini-section-head", children: _jsxs("div", { children: [_jsx("h4", { children: consentKicker }), _jsx("p", { className: "jini-hint", children: consentLead })] }) }), _jsxs("dl", { className: "jini-settings-privacy-disclosure", children: [_jsxs("div", { children: [_jsx("dt", { children: metricsLabel }), _jsx("dd", { children: metricsHint })] }), _jsxs("div", { children: [_jsx("dt", { children: contentLabel }), _jsx("dd", { children: contentHint })] })] }), _jsx("p", { className: "jini-hint", children: consentFooter }), _jsxs("div", { className: "jini-privacy-consent-actions", role: "group", "aria-label": consentKicker, children: [_jsx("button", { type: "button", className: `jini-privacy-consent-action${sharing === false ? ' is-active' : ''}`, "aria-pressed": sharing === false, onClick: () => onChange(nextStateForDeclineAll(state, now())), ...agentHandleProps({}, { base: agentHandle, ...({ action: 'decline', role: 'button', label: declineLabel }) }), children: declineLabel }), _jsx("button", { type: "button", className: `jini-privacy-consent-action jini-privacy-consent-action--primary${sharing === true ? ' is-active' : ''}`, "aria-pressed": sharing === true, onClick: () => onChange(nextStateForShareAll(state, now())), ...agentHandleProps({}, { base: agentHandle, ...({ action: 'share', role: 'button', label: shareLabel }) }), children: shareLabel })] })] }), decided ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: "jini-settings-privacy-toggles", children: [_jsx(ToggleRow, { label: metricsLabel, hint: metricsHint, checked: state.telemetry.metrics === true, onChange: (v) => onChange(nextStateForTelemetryPatch(state, { metrics: v }, now())), ...(agentHandle ? { agentHandle: agentSubHandle({ base: agentHandle, action: 'metrics-toggle' }) } : {}) }), _jsx(ToggleRow, { label: contentLabel, hint: contentHint, checked: state.telemetry.content === true, onChange: (v) => onChange(nextStateForTelemetryPatch(state, { content: v }, now())), ...(agentHandle ? { agentHandle: agentSubHandle({ base: agentHandle, action: 'content-toggle' }) } : {}) })] }), _jsxs("div", { className: "jini-settings-subsection", children: [_jsx("div", { className: "jini-section-head", children: _jsxs("div", { children: [_jsx("h4", { children: installationIdLabel }), _jsx("p", { className: "jini-hint", children: installationIdHint })] }) }), _jsx("div", { className: "jini-settings-field", children: _jsx("input", { type: "text", readOnly: true, value: state.installationId ?? optedOutLabel, "aria-label": installationIdLabel, ...agentHandleProps({}, { base: agentHandle, ...({ action: 'installation-id', role: 'field', label: installationIdLabel }) }) }) }), _jsxs("button", { type: "button", className: "jini-button jini-button-ghost", onClick: () => onChange(nextStateForDeleteMyData(state, now())), ...agentHandleProps({}, { base: agentHandle, ...({ action: 'delete-my-data', role: 'button', label: deleteMyDataLabel }) }), children: [_jsx(Icon, { name: "trash", size: 13 }), _jsx("span", { children: deleteMyDataLabel })] })] })] })) : null] }));
36
47
  }
37
48
  //# sourceMappingURL=PrivacyTab.js.map
@@ -14,11 +14,15 @@ export function ProgressCard({ data, maxSteps = 6, maxSecondaryItems = 5 }) {
14
14
  const title = data.title ?? t(defaultProgressCardTitle(data.status));
15
15
  const detail = data.detail ?? t(defaultProgressCardDetail(data.status));
16
16
  const secondaryHeading = t(data.secondaryItemsLabel ?? 'Files touched');
17
- const widthPercent = progressBarWidthPercent(data.progress);
18
- const ariaValueNow = progressBarAriaValueNow(data.progress);
19
17
  const visibleSteps = data.steps.slice(0, maxSteps);
20
18
  const visibleSecondaryItems = (data.secondaryItems ?? []).slice(0, maxSecondaryItems);
21
- return (_jsxs("section", { className: `progress-card is-${data.status}`, "data-progress-card-id": data.id, children: [_jsxs("div", { className: "progress-card-head", children: [_jsx(Icon, { name: progressCardStatusIcon(data.status) }), _jsxs("span", { children: [_jsx("strong", { children: title }), _jsx("small", { children: detail })] })] }), _jsx("div", { className: `progress-card-bar${widthPercent === null ? ' is-indeterminate' : ''}`, role: "progressbar", "aria-label": t('{title} progress', { title }), "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": ariaValueNow, children: _jsx("span", { style: widthPercent === null ? undefined : { width: `${widthPercent}%` } }) }), visibleSteps.length > 0 ? _jsx(ProgressCardItemList, { items: visibleSteps, className: "progress-card-steps" }) : null, visibleSecondaryItems.length > 0 ? (_jsxs("div", { className: "progress-card-secondary-items", children: [_jsx("span", { children: secondaryHeading }), _jsx(ProgressCardItemList, { items: visibleSecondaryItems, className: "progress-card-secondary-item-list", asCode: true })] })) : null] }));
19
+ return (_jsxs("section", { className: `progress-card is-${data.status}`, "data-progress-card-id": data.id, children: [_jsxs("div", { className: "progress-card-head", children: [_jsx(Icon, { name: progressCardStatusIcon(data.status) }), _jsxs("span", { children: [_jsx("strong", { children: title }), _jsx("small", { children: detail })] })] }), _jsx(ProgressCardBar, { progress: data.progress, label: t('{title} progress', { title }) }), visibleSteps.length > 0 ? _jsx(ProgressCardItemList, { items: visibleSteps, className: "progress-card-steps" }) : null, visibleSecondaryItems.length > 0 ? (_jsxs("div", { className: "progress-card-secondary-items", children: [_jsx("span", { children: secondaryHeading }), _jsx(ProgressCardItemList, { items: visibleSecondaryItems, className: "progress-card-secondary-item-list", asCode: true })] })) : null] }));
20
+ }
21
+ /** Presents the existing progress rules as a determinate or indeterminate accessible bar. */
22
+ function ProgressCardBar({ progress, label }) {
23
+ const widthPercent = progressBarWidthPercent(progress);
24
+ const ariaValueNow = progressBarAriaValueNow(progress);
25
+ return (_jsx("div", { className: `progress-card-bar${widthPercent === null ? ' is-indeterminate' : ''}`, role: "progressbar", "aria-label": label, "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": ariaValueNow, children: _jsx("span", { style: widthPercent === null ? undefined : { width: `${widthPercent}%` } }) }));
22
26
  }
23
27
  function ProgressCardItemList({ items, className, asCode, }) {
24
28
  const Tag = asCode ? 'code' : 'span';
@@ -29,17 +29,13 @@ export function parseTodoWriteInput(input) {
29
29
  if (!todo || typeof todo !== 'object')
30
30
  return null;
31
31
  const todoRecord = todo;
32
- const content = typeof todoRecord.content === 'string'
33
- ? todoRecord.content
34
- : typeof todoRecord.step === 'string'
35
- ? todoRecord.step
36
- : typeof todoRecord.description === 'string'
37
- ? todoRecord.description
38
- : typeof todoRecord.label === 'string'
39
- ? todoRecord.label
40
- : typeof todoRecord.text === 'string'
41
- ? todoRecord.text
42
- : '';
32
+ let content = '';
33
+ for (const key of ['content', 'step', 'description', 'label', 'text']) {
34
+ if (typeof todoRecord[key] === 'string') {
35
+ content = todoRecord[key];
36
+ break;
37
+ }
38
+ }
43
39
  if (!content)
44
40
  return null;
45
41
  return { content, status: normalizeTodoStatus(todoRecord.status) };
@@ -118,48 +114,55 @@ export function dedupeToolUsesById(events) {
118
114
  let deduped = null;
119
115
  for (let index = 0; index < events.length; index += 1) {
120
116
  const event = events[index];
121
- if (isToolUseEvent(event)) {
122
- if (seen.has(event.id)) {
123
- if (!deduped)
124
- deduped = events.slice(0, index);
125
- continue;
126
- }
117
+ if (!isToolUseEvent(event)) {
118
+ deduped?.push(event);
119
+ }
120
+ else if (seen.has(event.id)) {
121
+ deduped ??= events.slice(0, index);
122
+ }
123
+ else {
127
124
  seen.add(event.id);
125
+ deduped?.push(event);
128
126
  }
129
- if (deduped)
130
- deduped.push(event);
131
127
  }
132
128
  return deduped ?? events;
133
129
  }
130
+ function fileOpFromAgentEvent({ event, resultByToolUseId }, _options = {}) {
131
+ if (!isToolUseEvent(event))
132
+ return null;
133
+ const kind = classifyFileOp(event.name);
134
+ if (!kind)
135
+ return null;
136
+ const fullPath = extractFileOpPath(event.input);
137
+ if (!fullPath)
138
+ return null;
139
+ const result = resultByToolUseId.get(event.id);
140
+ const status = result === undefined ? 'running' : result.isError ? 'error' : 'done';
141
+ return { fullPath, kind, status };
142
+ }
134
143
  export function deriveFileOpsFromAgentEvents(events) {
135
144
  if (!events || events.length === 0)
136
145
  return [];
137
146
  const dedupedEvents = dedupeToolUsesById(events);
138
- const resultByToolUseId = new Map();
139
- for (const event of dedupedEvents) {
140
- if (isToolResultEvent(event))
141
- resultByToolUseId.set(event.toolUseId, event);
142
- }
147
+ const resultByToolUseId = new Map(dedupedEvents.filter(isToolResultEvent).map((event) => [event.toolUseId, event]));
143
148
  const byPath = new Map();
144
149
  for (const event of dedupedEvents) {
145
- if (!isToolUseEvent(event))
146
- continue;
147
- const kind = classifyFileOp(event.name);
148
- if (!kind)
149
- continue;
150
- const fullPath = extractFileOpPath(event.input);
151
- if (!fullPath)
150
+ const entry = fileOpFromAgentEvent({ event, resultByToolUseId });
151
+ if (!entry)
152
152
  continue;
153
- const result = resultByToolUseId.get(event.id);
154
- const status = result === undefined ? 'running' : result.isError ? 'error' : 'done';
155
- const existing = byPath.get(fullPath);
153
+ const existing = byPath.get(entry.fullPath);
156
154
  if (existing) {
157
- if (!existing.ops.includes(kind))
158
- existing.ops.push(kind);
159
- existing.status = mergeFileOpStatus(existing.status, status);
155
+ if (!existing.ops.includes(entry.kind))
156
+ existing.ops.push(entry.kind);
157
+ existing.status = mergeFileOpStatus(existing.status, entry.status);
160
158
  continue;
161
159
  }
162
- byPath.set(fullPath, { path: basename(fullPath), fullPath, ops: [kind], status });
160
+ byPath.set(entry.fullPath, {
161
+ path: basename(entry.fullPath),
162
+ fullPath: entry.fullPath,
163
+ ops: [entry.kind],
164
+ status: entry.status,
165
+ });
163
166
  }
164
167
  return Array.from(byPath.values());
165
168
  }
@@ -204,15 +207,7 @@ function fallbackChatActivitySteps(status, fileOps) {
204
207
  {
205
208
  id: 'update-files',
206
209
  label: 'Update files',
207
- status: hasError
208
- ? 'failed'
209
- : hasMutation
210
- ? fileOps.some((entry) => entry.status === 'running')
211
- ? 'running'
212
- : 'succeeded'
213
- : status === 'running'
214
- ? 'pending'
215
- : 'succeeded',
210
+ status: fallbackUpdateStatus({ status, fileOps, hasError, hasMutation }),
216
211
  },
217
212
  {
218
213
  id: 'finalize',
@@ -221,6 +216,22 @@ function fallbackChatActivitySteps(status, fileOps) {
221
216
  },
222
217
  ];
223
218
  }
219
+ function fallbackUpdateStatus({ status, fileOps, hasError, hasMutation }, _options = {}) {
220
+ if (hasError)
221
+ return 'failed';
222
+ if (hasMutation)
223
+ return fileOps.some((entry) => entry.status === 'running') ? 'running' : 'succeeded';
224
+ return status === 'running' ? 'pending' : 'succeeded';
225
+ }
226
+ function chatActivitySteps({ todos, status, fileOps }, _options = {}) {
227
+ if (todos.length === 0)
228
+ return fallbackChatActivitySteps(status, fileOps);
229
+ return todos.map((todo, index) => ({
230
+ id: `${todo.content}-${index}`,
231
+ label: todo.content,
232
+ status: todoStatusToProgressStatus(todo.status),
233
+ }));
234
+ }
224
235
  /** Maps a chat message's agent-event stream onto `ProgressCardData`. Returns
225
236
  * `null` when there's nothing worth showing (mirrors the source's own
226
237
  * `hasActivity` early-return — a message with no run, no todos, no file
@@ -234,13 +245,7 @@ export function chatActivityToProgressCard(message, options) {
234
245
  const hasActivity = options.active || todos.length > 0 || fileOps.length > 0 || statusDetail !== null || status === 'failed';
235
246
  if (!hasActivity)
236
247
  return null;
237
- const steps = todos.length > 0
238
- ? todos.map((todo, index) => ({
239
- id: `${todo.content}-${index}`,
240
- label: todo.content,
241
- status: todoStatusToProgressStatus(todo.status),
242
- }))
243
- : fallbackChatActivitySteps(status, fileOps);
248
+ const steps = chatActivitySteps({ todos, status, fileOps });
244
249
  const secondaryItems = fileOps.map((entry) => ({
245
250
  id: entry.fullPath,
246
251
  label: entry.path,
@@ -3,6 +3,29 @@ import { useT } from '../../../i18n/index.js';
3
3
  import { Icon } from '../../../../react/components/Icon.js';
4
4
  import { locationLabel } from '../../rules.js';
5
5
  import { useProjectLocationsTab } from '../hooks/useProjectLocationsTab.js';
6
+ function resolveLabels({ t }, labels = {}) {
7
+ const copy = {
8
+ title: 'Project locations',
9
+ description: 'Where new projects are created and existing ones are found.',
10
+ builtInLabel: 'Default location',
11
+ defaultBadge: 'Default',
12
+ makeDefaultLabel: 'Make default',
13
+ deleteLabel: 'Delete',
14
+ addFolderLabel: 'Add folder',
15
+ rowHint: 'Used as a project root.',
16
+ noFolderSelectedLabel: 'No folder selected.',
17
+ duplicateLabel: 'That folder is already a project location.',
18
+ savedLabel: 'Saved.',
19
+ defaultSavedLabel: 'Default location updated.',
20
+ saveErrorLabel: 'Could not save project locations.',
21
+ scanErrorLabel: 'Could not scan the new folder for existing projects.',
22
+ scanCompleteTemplate: 'Imported {imported}, {existing} already tracked.',
23
+ };
24
+ for (const key of Object.keys(copy)) {
25
+ copy[key] = labels?.[key] ?? t(copy[key]);
26
+ }
27
+ return copy;
28
+ }
6
29
  /**
7
30
  * Configured project roots: the host's built-in default plus operator-added
8
31
  * folders, each markable as the new-project default and removable. Origin:
@@ -13,21 +36,7 @@ import { useProjectLocationsTab } from '../hooks/useProjectLocationsTab.js';
13
36
  export function ProjectLocationsTab({ port, defaultLocationId, onDefaultLocationIdChange, labels }) {
14
37
  const t = useT();
15
38
  const { drafts, builtIn, effectiveDefaultLocationId, saving, result, addFolder, removeDraft, setDefaultLocationId } = useProjectLocationsTab({ port, defaultLocationId, onDefaultLocationIdChange });
16
- const title = labels?.title ?? t('Project locations');
17
- const description = labels?.description ?? t('Where new projects are created and existing ones are found.');
18
- const builtInLabel = labels?.builtInLabel ?? t('Default location');
19
- const defaultBadge = labels?.defaultBadge ?? t('Default');
20
- const makeDefaultLabel = labels?.makeDefaultLabel ?? t('Make default');
21
- const deleteLabel = labels?.deleteLabel ?? t('Delete');
22
- const addFolderLabel = labels?.addFolderLabel ?? t('Add folder');
23
- const rowHint = labels?.rowHint ?? t('Used as a project root.');
24
- const noFolderSelectedLabel = labels?.noFolderSelectedLabel ?? t('No folder selected.');
25
- const duplicateLabel = labels?.duplicateLabel ?? t('That folder is already a project location.');
26
- const savedLabel = labels?.savedLabel ?? t('Saved.');
27
- const defaultSavedLabel = labels?.defaultSavedLabel ?? t('Default location updated.');
28
- const saveErrorLabel = labels?.saveErrorLabel ?? t('Could not save project locations.');
29
- const scanErrorLabel = labels?.scanErrorLabel ?? t('Could not scan the new folder for existing projects.');
30
- const scanCompleteTemplate = labels?.scanCompleteTemplate ?? t('Imported {imported}, {existing} already tracked.');
39
+ const { title, description, builtInLabel, defaultBadge, makeDefaultLabel, deleteLabel, addFolderLabel, rowHint, noFolderSelectedLabel, duplicateLabel, savedLabel, defaultSavedLabel, saveErrorLabel, scanErrorLabel, scanCompleteTemplate, } = resolveLabels({ t }, labels);
31
40
  function defaultControlLabel(active) {
32
41
  return active ? defaultBadge : makeDefaultLabel;
33
42
  }
@@ -26,6 +26,14 @@ export interface UseProjectLocationsTabResult {
26
26
  removeDraft: (index: number) => void;
27
27
  setDefaultLocationId: (id: string) => void;
28
28
  }
29
+ /** Scan a saved location; disposed callers cannot publish success or failure. */
30
+ export declare function scanAddedLocation({ port, alive, setResult }: {
31
+ port: ProjectLocationsPort;
32
+ alive: {
33
+ readonly current: boolean;
34
+ };
35
+ setResult: (result: ProjectLocationsActionResult) => void;
36
+ }, _options?: {}): Promise<void>;
29
37
  /**
30
38
  * Owns the tab's async edges: the initial locations fetch, the add-folder ->
31
39
  * duplicate-check -> save -> (optional) scan sequence, and removal. Origin:
@@ -1,5 +1,22 @@
1
1
  import { useCallback, useEffect, useRef, useState } from 'react';
2
2
  import { DEFAULT_LOCATION_ID, externalLocations, isDuplicatePath, resolveDefaultLocationId, saveableDrafts, } from '../../rules.js';
3
+ /** Scan a saved location; disposed callers cannot publish success or failure. */
4
+ export async function scanAddedLocation({ port, alive, setResult }, _options = {}) {
5
+ const scan = port.scanLocations;
6
+ if (!scan)
7
+ return;
8
+ try {
9
+ const scanResult = await scan.call(port);
10
+ if (!alive.current)
11
+ return;
12
+ setResult({ status: 'scan-complete', imported: scanResult.imported.length, existing: scanResult.existing.length });
13
+ }
14
+ catch (error) {
15
+ if (!alive.current)
16
+ return;
17
+ setResult({ status: 'scan-error', message: error instanceof Error ? error.message : String(error) });
18
+ }
19
+ }
3
20
  /**
4
21
  * Owns the tab's async edges: the initial locations fetch, the add-folder ->
5
22
  * duplicate-check -> save -> (optional) scan sequence, and removal. Origin:
@@ -56,11 +73,7 @@ export function useProjectLocationsTab({ port, defaultLocationId, onDefaultLocat
56
73
  };
57
74
  }, [port]);
58
75
  const persist = useCallback(async (nextDrafts) => {
59
- setSaving(true);
60
- try {
61
- const saved = await portRef.current.saveLocations(saveableDrafts(nextDrafts));
62
- if (!alive.current)
63
- return null;
76
+ const applySaved = (saved) => {
64
77
  setLocations(saved);
65
78
  setDrafts(externalLocations(saved));
66
79
  setResult({ status: 'saved' });
@@ -72,17 +85,25 @@ export function useProjectLocationsTab({ port, defaultLocationId, onDefaultLocat
72
85
  if (effective !== configured)
73
86
  onDefaultLocationIdChangeRef.current?.(effective);
74
87
  return saved;
88
+ };
89
+ setSaving(true);
90
+ // One return after the try statement (null unless a still-mounted save succeeded), so no
91
+ // unreachable continuation follows a try and a catch that both return.
92
+ let persisted = null;
93
+ try {
94
+ const saved = await portRef.current.saveLocations(saveableDrafts(nextDrafts));
95
+ if (alive.current)
96
+ persisted = applySaved(saved);
75
97
  }
76
98
  catch (error) {
77
- if (!alive.current)
78
- return null;
79
- setResult({ status: 'save-error', message: error instanceof Error ? error.message : String(error) });
80
- return null;
99
+ if (alive.current)
100
+ setResult({ status: 'save-error', message: error instanceof Error ? error.message : String(error) });
81
101
  }
82
102
  finally {
83
103
  if (alive.current)
84
104
  setSaving(false);
85
105
  }
106
+ return persisted;
86
107
  }, []);
87
108
  const addFolder = useCallback(() => {
88
109
  void (async () => {
@@ -111,20 +132,7 @@ export function useProjectLocationsTab({ port, defaultLocationId, onDefaultLocat
111
132
  setDrafts(previous);
112
133
  return;
113
134
  }
114
- const scan = portRef.current.scanLocations;
115
- if (!scan)
116
- return;
117
- try {
118
- const scanResult = await scan.call(portRef.current);
119
- if (!alive.current)
120
- return;
121
- setResult({ status: 'scan-complete', imported: scanResult.imported.length, existing: scanResult.existing.length });
122
- }
123
- catch (error) {
124
- if (!alive.current)
125
- return;
126
- setResult({ status: 'scan-error', message: error instanceof Error ? error.message : String(error) });
127
- }
135
+ await scanAddedLocation({ port: portRef.current, alive, setResult });
128
136
  })();
129
137
  }, [persist]);
130
138
  const removeDraft = useCallback((index) => {
@@ -2,7 +2,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useT } from '../../../i18n/index.js';
3
3
  import { useWiredResourceBoard } from '../hooks/useResourceBoard.js';
4
4
  import { ResourceBoardView } from './ResourceBoardView.js';
5
- import { UNMATCHED_STATUS_BUCKET } from '../../constants.js';
5
+ import { boardCreateProps, buildKanbanColumns, createItemActionHandler, resourceBoardHookParams, statusLabelFor } from './resourceBoardProps.js';
6
+ import { translatedErrorLabelProps } from './translatedErrorLabelProps.js';
6
7
  /**
7
8
  * The DesignsTab-shaped orchestrator: wires `useWiredResourceBoard` +
8
9
  * `useT()` + `ResourceBoardView`. `rename`/`duplicate`/`delete` are the
@@ -14,51 +15,9 @@ import { UNMATCHED_STATUS_BUCKET } from '../../constants.js';
14
15
  */
15
16
  export function ResourceBoard({ dependencies, statusOptions, toneMap, defaultStatus, normalizeStatus, sortOptions = [], initialSort, storageScopeKey, defaultViewMode, enableBulkDelete = true, onOpenItem, onCreate, createLabel, onRenameRequest, onCustomItemAction, refreshToken, renderBody, useWiredResourceBoard: useWiredResourceBoardHook = useWiredResourceBoard, }) {
16
17
  const t = useT();
17
- const board = useWiredResourceBoardHook({
18
- dependencies,
19
- statusOrder: statusOptions.map((option) => option.value),
20
- ...(defaultStatus !== undefined ? { defaultStatus } : {}),
21
- ...(normalizeStatus !== undefined ? { normalizeStatus } : {}),
22
- ...(initialSort !== undefined ? { initialSort } : {}),
23
- ...(storageScopeKey !== undefined ? { storageScopeKey } : {}),
24
- ...(defaultViewMode !== undefined ? { defaultViewMode } : {}),
25
- ...(refreshToken !== undefined ? { refreshToken } : {}),
26
- });
27
- const kanbanColumns = statusOptions.map((option) => ({
28
- status: option.value,
29
- label: t(option.label),
30
- // Non-null: `useWiredResourceBoard` above is called with `statusOrder:
31
- // statusOptions.map(option => option.value)`, and `groupItemsByStatus`
32
- // (rules.ts) always seeds one Map entry per `statusOrder` value before
33
- // placing any item — so every `option.value` here is guaranteed present.
34
- items: board.kanbanColumns.get(option.value),
35
- }));
36
- const unmatched = board.kanbanColumns.get(UNMATCHED_STATUS_BUCKET);
37
- if (unmatched && unmatched.length > 0) {
38
- kanbanColumns.push({ status: UNMATCHED_STATUS_BUCKET, label: t('Other'), items: unmatched });
39
- }
40
- const handleItemAction = (id, kind) => {
41
- if (kind === 'delete') {
42
- void board.remove(id);
43
- return;
44
- }
45
- if (kind === 'duplicate') {
46
- void board.duplicate(id);
47
- return;
48
- }
49
- if (kind === 'rename') {
50
- board.closeMenu();
51
- // Non-null: `id` only ever reaches this handler via a menu-action
52
- // click closure `ResourceBoardView` builds per rendered item (from
53
- // this SAME render's `board.visibleItems`), so the item is always
54
- // still present in the array at lookup time.
55
- const current = board.visibleItems.find((item) => item.id === id);
56
- onRenameRequest?.(id, current.title);
57
- return;
58
- }
59
- board.closeMenu();
60
- onCustomItemAction?.(id, kind);
61
- };
62
- return (_jsx(ResourceBoardView, { loading: board.loading, error: board.error, ...(board.error ? { errorLabel: t(board.error) } : {}), actionError: board.actionError, ...(board.actionError ? { actionErrorLabel: t(board.actionError) } : {}), hasAnyItems: board.totalCount > 0, items: board.visibleItems, kanbanColumns: kanbanColumns, sortOptions: sortOptions, ...(board.sort !== undefined ? { activeSort: board.sort } : {}), onSortChange: board.setSort, sortAriaLabel: t('Sort'), query: board.query, onQueryChange: board.setQuery, searchPlaceholder: t('Search…'), viewMode: board.viewMode, onViewModeChange: board.setViewMode, viewToggleAriaLabel: t('View'), gridViewLabel: t('Grid view'), kanbanViewLabel: t('Kanban view'), enableBulkDelete: enableBulkDelete, selectMode: board.selectMode, selected: board.selected, bulkDeleteBusy: board.bulkDeleteBusy, onEnterSelectMode: board.enterSelectMode, onExitSelectMode: board.exitSelectMode, onBulkDelete: () => void board.bulkDelete(), selectModeLabel: t('Select'), selectedCountLabel: (n) => t('{n} selected', { n }), deleteSelectedLabel: t('Delete selected'), cancelSelectLabel: t('Cancel'), ...(createLabel !== undefined || onCreate ? { createLabel: createLabel ?? t('New') } : {}), ...(onCreate ? { onCreate } : {}), openMenuId: board.openMenuId, menuContainerRef: board.menuContainerRef, onToggleMenu: board.toggleMenu, onItemAction: handleItemAction, isItemBusy: board.isItemBusy, onOpenItem: onOpenItem, onToggleSelected: board.toggleSelected, onKanbanDelete: (id) => void board.remove(id), statusLabel: (status) => t(statusOptions.find((option) => option.value === status)?.label ?? status), ...(toneMap ? { toneMap } : {}), menuActionLabel: (_kind, fallback) => t(fallback), moreLabel: t('More'), deleteLabel: t('Delete'), deleteAriaLabel: (title) => t('Delete {name}', { name: title }), emptyColumnLabel: t('No items in this column.'), emptyStateTitle: t('No items yet.'), emptyStateNoMatch: t('No items match your search.'), ...(renderBody ? { renderBody } : {}) }));
18
+ const board = useWiredResourceBoardHook(resourceBoardHookParams({ dependencies, statusOptions }, { defaultStatus, normalizeStatus, initialSort, storageScopeKey, defaultViewMode, refreshToken }));
19
+ const kanbanColumns = buildKanbanColumns({ statusOptions, columns: board.kanbanColumns, t });
20
+ const handleItemAction = createItemActionHandler({ board }, { onRenameRequest, onCustomItemAction });
21
+ return (_jsx(ResourceBoardView, { loading: board.loading, error: board.error, actionError: board.actionError, ...translatedErrorLabelProps({ t, error: board.error, actionError: board.actionError }), hasAnyItems: board.totalCount > 0, items: board.visibleItems, kanbanColumns: kanbanColumns, sortOptions: sortOptions, ...(board.sort !== undefined ? { activeSort: board.sort } : {}), onSortChange: board.setSort, sortAriaLabel: t('Sort'), query: board.query, onQueryChange: board.setQuery, searchPlaceholder: t('Search…'), viewMode: board.viewMode, onViewModeChange: board.setViewMode, viewToggleAriaLabel: t('View'), gridViewLabel: t('Grid view'), kanbanViewLabel: t('Kanban view'), enableBulkDelete: enableBulkDelete, selectMode: board.selectMode, selected: board.selected, bulkDeleteBusy: board.bulkDeleteBusy, onEnterSelectMode: board.enterSelectMode, onExitSelectMode: board.exitSelectMode, onBulkDelete: () => void board.bulkDelete(), selectModeLabel: t('Select'), selectedCountLabel: (n) => t('{n} selected', { n }), deleteSelectedLabel: t('Delete selected'), cancelSelectLabel: t('Cancel'), ...boardCreateProps({ t }, { createLabel, onCreate }), openMenuId: board.openMenuId, menuContainerRef: board.menuContainerRef, onToggleMenu: board.toggleMenu, onItemAction: handleItemAction, isItemBusy: board.isItemBusy, onOpenItem: onOpenItem, onToggleSelected: board.toggleSelected, onKanbanDelete: (id) => void board.remove(id), statusLabel: statusLabelFor({ t, statusOptions }), ...(toneMap ? { toneMap } : {}), menuActionLabel: (_kind, fallback) => t(fallback), moreLabel: t('More'), deleteLabel: t('Delete'), deleteAriaLabel: (title) => t('Delete {name}', { name: title }), emptyColumnLabel: t('No items in this column.'), emptyStateTitle: t('No items yet.'), emptyStateNoMatch: t('No items match your search.'), ...(renderBody ? { renderBody } : {}) }));
63
22
  }
64
23
  //# sourceMappingURL=ResourceBoard.js.map
@@ -1,5 +1,5 @@
1
1
  import type { ReactNode, RefObject } from 'react';
2
- import { type ResourceKanbanColumn } from './ResourceKanbanBoard.js';
2
+ import type { ResourceKanbanColumn } from './ResourceKanbanBoard.js';
3
3
  import type { ResourceBoardItem, ResourceBoardViewMode, ResourceSortOption, ResourceStatusToneMap } from '../../types.js';
4
4
  export interface ResourceBoardViewProps<TBody = unknown> {
5
5
  loading: boolean;
@@ -61,5 +61,5 @@ export interface ResourceBoardViewProps<TBody = unknown> {
61
61
  * state, the card grid, or the kanban board — DesignsTab's own
62
62
  * `filtered.length === 0 ? empty : view === "grid" ? grid : kanban` branch.
63
63
  */
64
- export declare function ResourceBoardView<TBody = unknown>({ loading, error, errorLabel, actionError, actionErrorLabel, hasAnyItems, items, kanbanColumns, sortOptions, activeSort, onSortChange, sortAriaLabel, query, onQueryChange, searchPlaceholder, viewMode, onViewModeChange, viewToggleAriaLabel, gridViewLabel, kanbanViewLabel, enableBulkDelete, selectMode, selected, bulkDeleteBusy, onEnterSelectMode, onExitSelectMode, onBulkDelete, selectModeLabel, selectedCountLabel, deleteSelectedLabel, cancelSelectLabel, createLabel, onCreate, openMenuId, menuContainerRef, onToggleMenu, onItemAction, isItemBusy, onOpenItem, onToggleSelected, onKanbanDelete, statusLabel, toneMap, menuActionLabel, moreLabel, deleteLabel, deleteAriaLabel, emptyColumnLabel, emptyStateTitle, emptyStateNoMatch, renderBody, }: ResourceBoardViewProps<TBody>): import("react").JSX.Element;
64
+ export declare function ResourceBoardView<TBody = unknown>(props: ResourceBoardViewProps<TBody>): import("react").JSX.Element;
65
65
  //# sourceMappingURL=ResourceBoardView.d.ts.map
@@ -1,14 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { ResourceBoardToolbar } from './ResourceBoardToolbar.js';
3
- import { ResourceCard } from './ResourceCard.js';
4
- import { ResourceKanbanBoard } from './ResourceKanbanBoard.js';
2
+ import { ResourceBoardAlerts, ResourceBoardContent, ResourceBoardViewToolbar } from './ResourceBoardViewParts.js';
5
3
  /**
6
4
  * Pure composition (props in, JSX out): the toolbar, then either the empty
7
5
  * state, the card grid, or the kanban board — DesignsTab's own
8
6
  * `filtered.length === 0 ? empty : view === "grid" ? grid : kanban` branch.
9
7
  */
10
- export function ResourceBoardView({ loading, error, errorLabel, actionError, actionErrorLabel, hasAnyItems, items, kanbanColumns, sortOptions, activeSort, onSortChange, sortAriaLabel, query, onQueryChange, searchPlaceholder, viewMode, onViewModeChange, viewToggleAriaLabel, gridViewLabel, kanbanViewLabel, enableBulkDelete, selectMode, selected, bulkDeleteBusy, onEnterSelectMode, onExitSelectMode, onBulkDelete, selectModeLabel, selectedCountLabel, deleteSelectedLabel, cancelSelectLabel, createLabel, onCreate, openMenuId, menuContainerRef, onToggleMenu, onItemAction, isItemBusy, onOpenItem, onToggleSelected, onKanbanDelete, statusLabel, toneMap, menuActionLabel, moreLabel, deleteLabel, deleteAriaLabel, emptyColumnLabel, emptyStateTitle, emptyStateNoMatch, renderBody, }) {
11
- const isEmpty = !loading && !error && items.length === 0;
12
- return (_jsxs("div", { className: `resource-board${viewMode === 'kanban' ? ' is-kanban' : ''}`, children: [_jsx(ResourceBoardToolbar, { sortOptions: sortOptions, ...(activeSort !== undefined ? { activeSort } : {}), onSortChange: onSortChange, sortAriaLabel: sortAriaLabel, query: query, onQueryChange: onQueryChange, searchPlaceholder: searchPlaceholder, viewMode: viewMode, onViewModeChange: onViewModeChange, viewToggleAriaLabel: viewToggleAriaLabel, gridViewLabel: gridViewLabel, kanbanViewLabel: kanbanViewLabel, enableBulkDelete: enableBulkDelete, selectMode: selectMode, selectedCount: selected.size, bulkDeleteBusy: bulkDeleteBusy, onEnterSelectMode: onEnterSelectMode, onExitSelectMode: onExitSelectMode, onBulkDelete: onBulkDelete, selectModeLabel: selectModeLabel, selectedCountLabel: selectedCountLabel, deleteSelectedLabel: deleteSelectedLabel, cancelSelectLabel: cancelSelectLabel, ...(createLabel !== undefined ? { createLabel } : {}), ...(onCreate !== undefined ? { onCreate } : {}) }), error ? (_jsx("div", { className: "resource-board-error", role: "alert", children: errorLabel ?? error })) : null, actionError ? (_jsx("div", { className: "resource-board-action-error", role: "alert", children: actionErrorLabel ?? actionError })) : null, loading ? (_jsx("div", { className: "resource-board-loading", role: "status" })) : isEmpty ? (_jsx("div", { className: "resource-board-empty", children: hasAnyItems ? emptyStateNoMatch : emptyStateTitle })) : viewMode === 'grid' ? (_jsx("div", { className: "resource-board-grid", "data-testid": "resource-board-grid", children: items.map((item) => (_jsx(ResourceCard, { item: item, selectMode: selectMode, selected: selected.has(item.id), menuOpen: openMenuId === item.id, busy: isItemBusy(item.id), ...(item.status ? { statusLabel: statusLabel(item.status) } : {}), ...(toneMap ? { toneMap } : {}), ...(menuActionLabel ? { menuActionLabel } : {}), moreLabel: moreLabel, ...(menuContainerRef ? { menuContainerRef } : {}), ...(renderBody ? { renderBody } : {}), onOpen: () => onOpenItem(item.id), onToggleSelected: () => onToggleSelected(item.id), onToggleMenu: () => onToggleMenu(item.id), onAction: (kind) => onItemAction(item.id, kind) }, item.id))) })) : (_jsx(ResourceKanbanBoard, { columns: kanbanColumns, emptyColumnLabel: emptyColumnLabel, deleteLabel: deleteLabel, deleteAriaLabel: deleteAriaLabel, isBusy: isItemBusy, onOpen: onOpenItem, ...(onKanbanDelete ? { onDelete: onKanbanDelete } : {}) }))] }));
8
+ export function ResourceBoardView(props) {
9
+ return (_jsxs("div", { className: `resource-board${props.viewMode === 'kanban' ? ' is-kanban' : ''}`, children: [_jsx(ResourceBoardViewToolbar, { ...props }), _jsx(ResourceBoardAlerts, { ...props }), _jsx(ResourceBoardContent, { ...props })] }));
13
10
  }
14
11
  //# sourceMappingURL=ResourceBoardView.js.map
@@ -0,0 +1,15 @@
1
+ import type { ResourceBoardViewProps } from './ResourceBoardView.js';
2
+ /** Maps the view's props onto `ResourceBoardToolbar` (sort, search, view toggle, select-mode/bulk-delete, create CTA). */
3
+ export declare function ResourceBoardViewToolbar<TBody>(props: ResourceBoardViewProps<TBody>): import("react").JSX.Element;
4
+ /** The LOAD-failure banner and, independently, the single-item action-failure banner (shown ABOVE the still-visible item list). */
5
+ export declare function ResourceBoardAlerts<TBody>({ error, errorLabel, actionError, actionErrorLabel, }: Pick<ResourceBoardViewProps<TBody>, 'error' | 'errorLabel' | 'actionError' | 'actionErrorLabel'>): import("react").JSX.Element;
6
+ /** The card grid: one `ResourceCard` per item, with the item's id bound into each per-card callback. */
7
+ export declare function ResourceBoardGrid<TBody>({ items, selectMode, selected, openMenuId, isItemBusy, statusLabel, toneMap, menuActionLabel, moreLabel, menuContainerRef, renderBody, onOpenItem, onToggleSelected, onToggleMenu, onItemAction, }: ResourceBoardViewProps<TBody>): import("react").JSX.Element;
8
+ /**
9
+ * DesignsTab's own `filtered.length === 0 ? empty : view === "grid" ? grid : kanban`
10
+ * branch, behind a loading state. The empty state is suppressed while a load
11
+ * error is showing, and picks "search matched nothing" over "nothing exists
12
+ * yet" whenever the port returned any item at all.
13
+ */
14
+ export declare function ResourceBoardContent<TBody>(props: ResourceBoardViewProps<TBody>): import("react").JSX.Element;
15
+ //# sourceMappingURL=ResourceBoardViewParts.d.ts.map
@@ -0,0 +1,35 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ResourceBoardToolbar } from './ResourceBoardToolbar.js';
3
+ import { ResourceCard } from './ResourceCard.js';
4
+ import { ResourceKanbanBoard } from './ResourceKanbanBoard.js';
5
+ /** Maps the view's props onto `ResourceBoardToolbar` (sort, search, view toggle, select-mode/bulk-delete, create CTA). */
6
+ export function ResourceBoardViewToolbar(props) {
7
+ const { activeSort, createLabel, onCreate } = props;
8
+ return (_jsx(ResourceBoardToolbar, { sortOptions: props.sortOptions, ...(activeSort !== undefined ? { activeSort } : {}), onSortChange: props.onSortChange, sortAriaLabel: props.sortAriaLabel, query: props.query, onQueryChange: props.onQueryChange, searchPlaceholder: props.searchPlaceholder, viewMode: props.viewMode, onViewModeChange: props.onViewModeChange, viewToggleAriaLabel: props.viewToggleAriaLabel, gridViewLabel: props.gridViewLabel, kanbanViewLabel: props.kanbanViewLabel, enableBulkDelete: props.enableBulkDelete, selectMode: props.selectMode, selectedCount: props.selected.size, bulkDeleteBusy: props.bulkDeleteBusy, onEnterSelectMode: props.onEnterSelectMode, onExitSelectMode: props.onExitSelectMode, onBulkDelete: props.onBulkDelete, selectModeLabel: props.selectModeLabel, selectedCountLabel: props.selectedCountLabel, deleteSelectedLabel: props.deleteSelectedLabel, cancelSelectLabel: props.cancelSelectLabel, ...(createLabel !== undefined ? { createLabel } : {}), ...(onCreate !== undefined ? { onCreate } : {}) }));
9
+ }
10
+ /** The LOAD-failure banner and, independently, the single-item action-failure banner (shown ABOVE the still-visible item list). */
11
+ export function ResourceBoardAlerts({ error, errorLabel, actionError, actionErrorLabel, }) {
12
+ return (_jsxs(_Fragment, { children: [error ? (_jsx("div", { className: "resource-board-error", role: "alert", children: errorLabel ?? error })) : null, actionError ? (_jsx("div", { className: "resource-board-action-error", role: "alert", children: actionErrorLabel ?? actionError })) : null] }));
13
+ }
14
+ /** The card grid: one `ResourceCard` per item, with the item's id bound into each per-card callback. */
15
+ export function ResourceBoardGrid({ items, selectMode, selected, openMenuId, isItemBusy, statusLabel, toneMap, menuActionLabel, moreLabel, menuContainerRef, renderBody, onOpenItem, onToggleSelected, onToggleMenu, onItemAction, }) {
16
+ return (_jsx("div", { className: "resource-board-grid", "data-testid": "resource-board-grid", children: items.map((item) => (_jsx(ResourceCard, { item: item, selectMode: selectMode, selected: selected.has(item.id), menuOpen: openMenuId === item.id, busy: isItemBusy(item.id), ...(item.status ? { statusLabel: statusLabel(item.status) } : {}), ...(toneMap ? { toneMap } : {}), ...(menuActionLabel ? { menuActionLabel } : {}), moreLabel: moreLabel, ...(menuContainerRef ? { menuContainerRef } : {}), ...(renderBody ? { renderBody } : {}), onOpen: () => onOpenItem(item.id), onToggleSelected: () => onToggleSelected(item.id), onToggleMenu: () => onToggleMenu(item.id), onAction: (kind) => onItemAction(item.id, kind) }, item.id))) }));
17
+ }
18
+ /**
19
+ * DesignsTab's own `filtered.length === 0 ? empty : view === "grid" ? grid : kanban`
20
+ * branch, behind a loading state. The empty state is suppressed while a load
21
+ * error is showing, and picks "search matched nothing" over "nothing exists
22
+ * yet" whenever the port returned any item at all.
23
+ */
24
+ export function ResourceBoardContent(props) {
25
+ const { loading, error, items, hasAnyItems, viewMode, onKanbanDelete } = props;
26
+ if (loading)
27
+ return _jsx("div", { className: "resource-board-loading", role: "status" });
28
+ if (!error && items.length === 0) {
29
+ return _jsx("div", { className: "resource-board-empty", children: hasAnyItems ? props.emptyStateNoMatch : props.emptyStateTitle });
30
+ }
31
+ if (viewMode === 'grid')
32
+ return _jsx(ResourceBoardGrid, { ...props });
33
+ return (_jsx(ResourceKanbanBoard, { columns: props.kanbanColumns, emptyColumnLabel: props.emptyColumnLabel, deleteLabel: props.deleteLabel, deleteAriaLabel: props.deleteAriaLabel, isBusy: props.isItemBusy, onOpen: props.onOpenItem, ...(onKanbanDelete ? { onDelete: onKanbanDelete } : {}) }));
34
+ }
35
+ //# sourceMappingURL=ResourceBoardViewParts.js.map
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { StatusPill } from './StatusPill.js';
2
+ import { isCardActivationKey, resourceCardClassName, ResourceCardMenu, ResourceCardMeta } from './ResourceCardParts.js';
3
3
  /**
4
4
  * One dashboard card: DesignsTab's `design-card` grid item — clickable to
5
5
  * open (or, in select-mode, to toggle selection), a select-mode checkbox OR
@@ -15,23 +15,12 @@ export function ResourceCard({ item, selectMode, selected, menuOpen, busy, statu
15
15
  else
16
16
  onOpen();
17
17
  };
18
- const hasMenu = !selectMode && item.menuActions && item.menuActions.length > 0;
19
- return (_jsxs("div", { className: `resource-board-card${selected ? ' is-selected' : ''}${selectMode ? ' select-mode' : ''}`, role: "button", tabIndex: 0, "data-testid": "resource-board-card", onClick: handleActivate, onKeyDown: (event) => {
20
- if (event.key === 'Enter' || event.key === ' ') {
18
+ const menuActions = selectMode ? [] : (item.menuActions ?? []);
19
+ return (_jsxs("div", { className: resourceCardClassName({ selected, selectMode }), role: "button", tabIndex: 0, "data-testid": "resource-board-card", onClick: handleActivate, onKeyDown: (event) => {
20
+ if (isCardActivationKey(event)) {
21
21
  event.preventDefault();
22
22
  handleActivate();
23
23
  }
24
- }, children: [selectMode ? (_jsx("span", { className: `resource-board-card-checkbox${selected ? ' checked' : ''}`, "aria-hidden": true, "data-testid": "resource-board-card-checkbox" })) : hasMenu ? (_jsxs("div", { className: "resource-board-card-menu-anchor", ref: menuOpen ? menuContainerRef : undefined, children: [_jsx("button", { type: "button", className: "resource-board-card-more", "aria-label": moreLabel, "aria-haspopup": "menu", "aria-expanded": menuOpen, onClick: (event) => {
25
- event.stopPropagation();
26
- onToggleMenu();
27
- },
28
- // `stopPropagation` on `onClick` above only stops the CLICK the
29
- // browser synthesizes from an Enter/Space keydown — the raw
30
- // keydown event itself still bubbles to the outer card's own
31
- // `onKeyDown` (a separate event), which would otherwise ALSO
32
- // treat that same keypress as "activate the card" and open/
33
- // toggle-select it at the same time this button's own action
34
- // runs. Stop it here too.
35
- onKeyDown: (event) => event.stopPropagation(), children: moreLabel }), menuOpen ? (_jsx("div", { className: "resource-board-card-menu", role: "menu", onClick: (event) => event.stopPropagation(), onKeyDown: (event) => event.stopPropagation(), children: item.menuActions.map((action) => (_jsx("button", { type: "button", role: "menuitem", className: action.danger ? 'danger' : undefined, disabled: busy, onClick: () => onAction(action.kind), children: menuActionLabel ? menuActionLabel(action.kind, action.label) : action.label }, action.kind))) })) : null] })) : null, _jsx("div", { className: "resource-board-card-body", children: renderBody ? renderBody(item) : null }), _jsxs("div", { className: "resource-board-card-meta", children: [_jsx("div", { className: "resource-board-card-title", title: item.title, children: item.title }), item.subtitle ? _jsx("div", { className: "resource-board-card-subtitle", children: item.subtitle }) : null, item.status && statusLabel ? _jsx(StatusPill, { status: item.status, label: statusLabel, ...(toneMap ? { toneMap } : {}) }) : null] })] }));
24
+ }, children: [selectMode ? (_jsx("span", { className: `resource-board-card-checkbox${selected ? ' checked' : ''}`, "aria-hidden": true, "data-testid": "resource-board-card-checkbox" })) : null, menuActions.length > 0 ? (_jsx(ResourceCardMenu, { menuActions: menuActions, menuOpen: menuOpen, busy: busy, moreLabel: moreLabel, menuContainerRef: menuContainerRef, menuActionLabel: menuActionLabel, onToggleMenu: onToggleMenu, onAction: onAction })) : null, _jsx("div", { className: "resource-board-card-body", children: renderBody ? renderBody(item) : null }), _jsx(ResourceCardMeta, { item: item, statusLabel: statusLabel, toneMap: toneMap })] }));
36
25
  }
37
26
  //# sourceMappingURL=ResourceCard.js.map