@jini-ai/ui 0.6.15-rc.1 → 0.6.15

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 (195) hide show
  1. package/dist/browser/useDismissOnOutsideOrEscape.js +1 -1
  2. package/dist/browser/useGlobalKeydown.js +2 -2
  3. package/dist/browser/useModalWindowDragGuard.js +1 -1
  4. package/dist/core/theme/css-name.d.ts +3 -0
  5. package/dist/core/theme/css-name.js +5 -0
  6. package/dist/core/theme/stylesheet.js +2 -1
  7. package/dist/core/theme/validation.js +15 -4
  8. package/dist/features/about/rules.js +2 -1
  9. package/dist/features/admin-widgets/components/InfoTip.hooks.js +22 -12
  10. package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.js +1 -1
  11. package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.js +1 -1
  12. package/dist/features/admin-widgets/components/SeeMore/SeeMore.hooks.js +2 -2
  13. package/dist/features/admin-widgets/components/SeeMore/SeeMore.js +4 -2
  14. package/dist/features/admin-widgets/components/Select/Select.hooks.js +2 -1
  15. package/dist/features/admin-widgets/components/Select/Select.js +2 -1
  16. package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.js +4 -2
  17. package/dist/features/admin-widgets/components/useDebouncedHtmlPreview.hooks.js +3 -2
  18. package/dist/features/asset-grid/react/components/AssetGrid.js +8 -3
  19. package/dist/features/asset-grid/react/hooks/useAssetGridKeyboardShortcuts.js +7 -6
  20. package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.js +8 -10
  21. package/dist/features/asset-grid/react/hooks/useRubberBandDrag.js +1 -1
  22. package/dist/features/asset-tree-browser/react/components/AssetTreeFileRow.js +6 -8
  23. package/dist/features/asset-tree-browser/react/hooks/useAssetTreeRowMenu.js +1 -1
  24. package/dist/features/asset-tree-browser/rules.js +1 -3
  25. package/dist/features/browser-chrome/rules.js +10 -8
  26. package/dist/features/charts/browser.js +2 -1
  27. package/dist/features/charts/react.js +3 -1
  28. package/dist/features/connectors/ConnectorsBrowser.js +3 -1
  29. package/dist/features/connectors/hooks/useConnectorAuthorization.js +1 -1
  30. package/dist/features/connectors/hooks/useConnectorCatalog.js +2 -2
  31. package/dist/features/connectors/rules.js +10 -14
  32. package/dist/features/execution/react/components/AgentDiagnosticRow.js +2 -0
  33. package/dist/features/execution/react/components/ByokProviderForm.js +1 -3
  34. package/dist/features/execution/react/components/LocalCliAgentSettings.js +2 -1
  35. package/dist/features/execution/react/hooks/use-byok-field-validation.hooks.js +6 -2
  36. package/dist/features/execution/react/hooks/useExecutionTab.js +9 -5
  37. package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +3 -6
  38. package/dist/features/execution/react/hooks/useReasoningControl.js +3 -3
  39. package/dist/features/execution/rules.js +23 -18
  40. package/dist/features/external-mcp/react/components/ExternalMcpTab.js +10 -1
  41. package/dist/features/file-dropzone/rules.js +3 -2
  42. package/dist/features/html-editor/canvas-embed-placeholders.js +2 -3
  43. package/dist/features/html-editor/css.js +7 -5
  44. package/dist/features/html-editor/editor-blocks.js +60 -6
  45. package/dist/features/html-editor/protected-elements.js +5 -3
  46. package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +3 -3
  47. package/dist/features/html-editor/source-splice.js +6 -4
  48. package/dist/features/iframe-pool/react/components/IframeKeepAliveProvider.js +5 -5
  49. package/dist/features/iframe-pool/react/dom-sync.js +2 -2
  50. package/dist/features/integrations/react/components/IntegrationsTab.js +3 -1
  51. package/dist/features/integrations/rules.js +6 -4
  52. package/dist/features/interactive-ui/interactive-ui.css +1 -1
  53. package/dist/features/interactive-ui/providers/shadcn/button.d.ts +8 -6
  54. package/dist/features/interactive-ui/providers/shadcn/button.js +5 -6
  55. package/dist/features/interactive-ui/providers/shadcn/card.d.ts +3 -3
  56. package/dist/features/interactive-ui/providers/shadcn/card.js +3 -4
  57. package/dist/features/interactive-ui/providers/shadcn/data-table.js +10 -5
  58. package/dist/features/interactive-ui/providers/shadcn/select.d.ts +3 -5
  59. package/dist/features/interactive-ui/providers/shadcn/select.js +3 -7
  60. package/dist/features/interactive-ui/providers/shadcn/table.d.ts +4 -5
  61. package/dist/features/interactive-ui/providers/shadcn/table.js +4 -9
  62. package/dist/features/interactive-ui/table-data.js +1 -1
  63. package/dist/features/lexical-rich-text-editor/deserialize.js +2 -2
  64. package/dist/features/lexical-rich-text-editor/mention-parser.js +4 -4
  65. package/dist/features/lexical-rich-text-editor/react/components/RichTextInput.js +2 -1
  66. package/dist/features/lexical-rich-text-editor/react/hooks/useCaretFloatingLayerPosition.js +1 -1
  67. package/dist/features/lexical-rich-text-editor/react/hooks/useMentionColorStamping.js +1 -1
  68. package/dist/features/lexical-rich-text-editor/serialize.js +13 -10
  69. package/dist/features/list-detail-panel/react/components/ListDetailPanel.js +1 -1
  70. package/dist/features/mcp-ui/confirmation-store.js +3 -6
  71. package/dist/features/mcp-ui/surfaces/confirmation.d.ts +5 -0
  72. package/dist/features/mcp-ui/surfaces/confirmation.js +1 -0
  73. package/dist/features/mcp-ui/surfaces/document.d.ts +3 -15
  74. package/dist/features/mcp-ui/surfaces/document.js +37 -6
  75. package/dist/features/mcp-ui/surfaces/fields.js +2 -0
  76. package/dist/features/mcp-ui/surfaces/host-theme.js +2 -1
  77. package/dist/features/mcp-ui/surfaces/index.d.ts +1 -0
  78. package/dist/features/mcp-ui/surfaces/index.js +1 -0
  79. package/dist/features/mcp-ui/surfaces/outcome.js +1 -1
  80. package/dist/features/mcp-ui/surfaces/select.js +2 -1
  81. package/dist/features/mcp-ui/surfaces/structured-details.d.ts +40 -0
  82. package/dist/features/mcp-ui/surfaces/structured-details.js +159 -0
  83. package/dist/features/mcp-ui/surfaces/text-input.js +1 -1
  84. package/dist/features/mcp-ui/surfaces/tool-approval.d.ts +21 -0
  85. package/dist/features/mcp-ui/surfaces/tool-approval.js +41 -0
  86. package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +2 -1
  87. package/dist/features/memory/async-commit-guard.js +4 -1
  88. package/dist/features/memory/formatters.js +5 -1
  89. package/dist/features/memory/react/components/MemoryConnectedPanel.js +3 -1
  90. package/dist/features/memory/react/components/MemoryEntryCard.js +1 -1
  91. package/dist/features/memory/react/components/MemorySettingsPanel.js +3 -1
  92. package/dist/features/memory/react/hooks/useMemoryConfig.hooks.js +12 -10
  93. package/dist/features/memory/react/hooks/useMemoryConnectors.hooks.js +2 -5
  94. package/dist/features/memory/react/hooks/useMemoryConnectors.rules.js +10 -9
  95. package/dist/features/memory/react/hooks/useMemoryEntries.hooks.js +4 -2
  96. package/dist/features/memory/react/hooks/useMemoryFlash.hooks.js +1 -1
  97. package/dist/features/memory/rules.js +2 -1
  98. package/dist/features/panel-kit/fetch-query/adapter.react.js +3 -2
  99. package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +3 -2
  100. package/dist/features/panel-kit/fetch-query/binding.react.js +2 -1
  101. package/dist/features/panel-kit/helpers/standing-draft-recovery-message.js +13 -4
  102. package/dist/features/panel-kit/hooks/use-dirty-guard.hooks.js +1 -1
  103. package/dist/features/panel-kit/hooks/use-focus-trap.hooks.js +1 -1
  104. package/dist/features/panel-kit/hooks/use-settings-slice.hooks.js +14 -10
  105. package/dist/features/panel-kit/hooks/use-standing-draft-autosave.hooks.js +2 -2
  106. package/dist/features/progress-card/components/ProgressCard.d.ts +1 -1
  107. package/dist/features/progress-card/reference-adapters.js +23 -13
  108. package/dist/features/progress-card/rules.d.ts +0 -1
  109. package/dist/features/progress-card/rules.js +14 -20
  110. package/dist/features/progress-card/types.d.ts +1 -1
  111. package/dist/features/project-locations/dependencies.js +6 -1
  112. package/dist/features/project-locations/react/components/ProjectLocationsTab.js +2 -1
  113. package/dist/features/project-locations/rules.js +2 -1
  114. package/dist/features/resource-dashboard/react/components/ResourceBoardToolbar.js +8 -1
  115. package/dist/features/resource-dashboard/react/components/ResourceBoardView.js +3 -2
  116. package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.d.ts +0 -2
  117. package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.js +0 -6
  118. package/dist/features/resource-dashboard/react/components/ResourceCardParts.js +2 -1
  119. package/dist/features/resource-dashboard/react/components/ResourceRowListItem.js +3 -1
  120. package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.js +2 -1
  121. package/dist/features/resource-dashboard/react/components/ResourceRowListView.js +1 -1
  122. package/dist/features/resource-dashboard/react/hooks/useResourceBoard.js +1 -1
  123. package/dist/features/schedule-picker/rules.js +13 -7
  124. package/dist/features/sketch-editor/constants.d.ts +0 -6
  125. package/dist/features/sketch-editor/constants.js +17 -15
  126. package/dist/features/sketch-editor/dom.js +4 -7
  127. package/dist/features/sketch-editor/react/components/SketchMainMenu.js +2 -1
  128. package/dist/features/sketch-editor/react/components/SketchSaveStateBadge.js +2 -1
  129. package/dist/features/sketch-editor/react/hooks/useSketchDomEnhancements.js +1 -1
  130. package/dist/features/sketch-editor/rules.js +13 -12
  131. package/dist/features/skills/dependencies.js +9 -4
  132. package/dist/features/skills/react/components/SkillRow.js +2 -1
  133. package/dist/features/skills/react/components/SkillsTab.js +2 -1
  134. package/dist/features/skills/rules.js +3 -3
  135. package/dist/features/source-config-list/agent-handles.js +4 -3
  136. package/dist/features/source-config-list/react/components/SourceConfigItemCard.js +3 -1
  137. package/dist/features/tab-strip/react/components/TabBar.hooks.js +4 -2
  138. package/dist/features/version-manager/react/components/VersionPreviewFrame.js +4 -1
  139. package/dist/features/version-manager/react/components/VersionSidebar.js +8 -6
  140. package/dist/features/version-manager/react/hooks/usePreviewCanvasSize.js +1 -1
  141. package/dist/features/version-manager/react/hooks/useVersionManager.js +5 -7
  142. package/dist/features/version-manager/rules.js +3 -5
  143. package/dist/features/viewer-shell/react/components/CommentSidePanel.js +2 -1
  144. package/dist/features/viewer-shell/react/components/SegmentedToggle.js +2 -1
  145. package/dist/features/viewer-shell/react/components/ViewerShell.js +2 -1
  146. package/dist/features/viewer-shell/rules.js +8 -7
  147. package/dist/react/components/BrandLogo.js +10 -2
  148. package/dist/react/components/CustomSelect.js +1 -1
  149. package/dist/react/components/EditorIcon.js +17 -14
  150. package/dist/react/components/Loading.js +2 -1
  151. package/dist/react/components/OnboardingChipField.js +5 -1
  152. package/dist/react/components/OnboardingDropdown.js +6 -4
  153. package/dist/react/components/PaletteTweaks.js +7 -6
  154. package/dist/react/components/PillButton.js +2 -1
  155. package/dist/react/components/PopoverMenu.js +2 -1
  156. package/dist/react/components/RemixIcon.js +2 -1
  157. package/dist/react/components/SecretInput.hooks.d.ts +2 -25
  158. package/dist/react/components/SecretInput.hooks.js +2 -24
  159. package/dist/react/components/SecretInput.js +5 -4
  160. package/dist/react/components/Toast.js +4 -2
  161. package/dist/react/components/TooltipLayer.js +4 -1
  162. package/dist/react/components/WorkingDirPicker.js +5 -4
  163. package/dist/react/components/remixicon-font-recovery.js +9 -1
  164. package/dist/react/components/select-popover.js +2 -2
  165. package/dist/react/hooks/useBrandFonts.js +1 -1
  166. package/dist/react/hooks/useEdgeAutoScroll.js +1 -1
  167. package/dist/react/hooks/useInView.js +9 -9
  168. package/dist/react/hooks/useResizableSplitPane.js +12 -20
  169. package/dist/react/mcp-ui/useHostSurfaceTokens.js +1 -1
  170. package/dist/renderers/annotation-canvas/react/components/AnnotationCanvas.js +7 -1
  171. package/dist/renderers/annotation-canvas/react/hooks/useAnnotationCanvas.controller.js +4 -2
  172. package/dist/renderers/annotation-canvas/react/hooks/useAnnotationCanvas.js +9 -5
  173. package/dist/renderers/annotation-canvas/rules.js +9 -13
  174. package/dist/renderers/annotation-canvas/theme.js +5 -2
  175. package/dist/renderers/renderers/index.js +1 -1
  176. package/dist/renderers/renderers/markdown.js +4 -6
  177. package/dist/theme/apply.js +7 -3
  178. package/dist/utils/class-names.d.ts +3 -0
  179. package/dist/utils/class-names.js +5 -0
  180. package/dist/utils/design-md.js +3 -3
  181. package/dist/utils/ime-composing.d.ts +1 -1
  182. package/dist/utils/ime-composing.js +1 -2
  183. package/dist/utils/localized-url.js +2 -11
  184. package/dist/utils/markdown-scroll-sync.js +1 -1
  185. package/dist/utils/omit-keys.d.ts +3 -0
  186. package/dist/utils/omit-keys.js +8 -0
  187. package/dist/utils/polygon-selection.js +1 -1
  188. package/dist/utils/sse.js +3 -0
  189. package/dist/utils/trim-chars.d.ts +13 -0
  190. package/dist/utils/trim-chars.js +30 -0
  191. package/dist/utils/unhandled-case.d.ts +10 -0
  192. package/dist/utils/unhandled-case.js +12 -0
  193. package/dist/utils/unit-bezier.js +1 -3
  194. package/dist/utils/zip.js +6 -10
  195. package/package.json +10 -9
@@ -246,11 +246,8 @@ export function useMemoryConnectors(port, coord) {
246
246
  const connectedMemoryConnectors = useMemo(() => memoryConnectors.filter((connector) => connector.status === 'connected'), [memoryConnectors]);
247
247
  const selectedConnectedConnectorIds = useMemo(() => [...selectedConnectorIds].filter((id) => connectedMemoryConnectors.some((connector) => connector.id === id)), [selectedConnectorIds, connectedMemoryConnectors]);
248
248
  const connectedCount = connectedMemoryConnectors.length;
249
- const connectorScanLabel = connectorExtracting
250
- ? 'Scanning apps'
251
- : selectedConnectedConnectorIds.length === 0
252
- ? 'Select apps to scan'
253
- : 'Scan selected apps';
249
+ const idleScanLabel = selectedConnectedConnectorIds.length === 0 ? 'Select apps to scan' : 'Scan selected apps';
250
+ const connectorScanLabel = connectorExtracting ? 'Scanning apps' : idleScanLabel;
254
251
  const selectedConnectorSuggestions = useMemo(() => connectorSuggestions.filter((suggestion) => selectedSuggestionIds.has(suggestion.id)), [connectorSuggestions, selectedSuggestionIds]);
255
252
  const connectorLoadError = connectorCatalogueLoadError ?? connectorStatusLoadError;
256
253
  // Prune selection down to still-connected apps: disconnecting an app should
@@ -68,14 +68,15 @@ export function isRecentFailedConnectorExtraction(record, scanStartedAt) {
68
68
  return record.kind === 'connector' && record.phase === 'failed' && record.startedAt >= scanStartedAt - 5_000;
69
69
  }
70
70
  export function describeConnectorSuggestionsSaveOutcome({ savedCount, totalCount, failure, }) {
71
- const status = savedCount > 0 ? `Saved ${savedCount} memor${savedCount === 1 ? 'y' : 'ies'} from connected apps.` : null;
72
- const error = failure
73
- ? failure instanceof Error
74
- ? failure.message
75
- : String(failure)
76
- : savedCount !== totalCount
77
- ? `Saved ${savedCount} of ${totalCount} selected memories. Please try the remaining items again.`
78
- : null;
79
- return { status, error };
71
+ const noun = savedCount === 1 ? 'memory' : 'memories';
72
+ const status = savedCount > 0 ? `Saved ${savedCount} ${noun} from connected apps.` : null;
73
+ return { status, error: connectorSaveError({ savedCount, totalCount, failure }) };
74
+ }
75
+ function connectorSaveError({ savedCount, totalCount, failure }) {
76
+ if (failure)
77
+ return failure instanceof Error ? failure.message : String(failure);
78
+ return savedCount !== totalCount
79
+ ? `Saved ${savedCount} of ${totalCount} selected memories. Please try the remaining items again.`
80
+ : null;
80
81
  }
81
82
  //# sourceMappingURL=useMemoryConnectors.rules.js.map
@@ -148,7 +148,8 @@ export function useMemoryEntries(port, coord) {
148
148
  setPreviewBody(null);
149
149
  return;
150
150
  }
151
- const token = ++previewRequestTokenRef.current;
151
+ previewRequestTokenRef.current += 1;
152
+ const token = previewRequestTokenRef.current;
152
153
  setPreviewId(id);
153
154
  setPreviewBody(null);
154
155
  let entry;
@@ -173,7 +174,8 @@ export function useMemoryEntries(port, coord) {
173
174
  setPreviewBody(entry?.body ?? '');
174
175
  }, [previewId, port]);
175
176
  const startEdit = useCallback(async (id) => {
176
- const token = ++editRequestTokenRef.current;
177
+ editRequestTokenRef.current += 1;
178
+ const token = editRequestTokenRef.current;
177
179
  let entry;
178
180
  try {
179
181
  entry = await port.fetchMemoryEntry(id);
@@ -15,7 +15,7 @@ export function useMemoryFlash() {
15
15
  }, []);
16
16
  useEffect(() => {
17
17
  if (!flash)
18
- return;
18
+ return undefined;
19
19
  const id = setTimeout(() => setFlash(null), 1800);
20
20
  return () => clearTimeout(id);
21
21
  }, [flash]);
@@ -16,6 +16,7 @@
16
16
  // stay here: the tool-cursor-aware single-connector merge this slice's
17
17
  // discovery hydration needs, and the "mark pending authorization" transform.
18
18
  import { applyConnectorStatuses, mergeConnectors } from '../connectors/rules.js';
19
+ import { omitKeys } from '../../utils/omit-keys.js';
19
20
  /** Patch body for flipping the master memory switch. */
20
21
  export function enabledPatch(enabled) {
21
22
  return { enabled };
@@ -64,7 +65,7 @@ export function applyMemoryConnectorStatus(connector, status) {
64
65
  * tracks pending state separately rather than mutating the connector's
65
66
  * displayed status, so this transform is genuinely local to this slice. */
66
67
  export function connectorWithPendingAuthorization(connector) {
67
- const { accountLabel: _accountLabel, lastError: _lastError, ...base } = connector;
68
+ const base = omitKeys(connector, ['accountLabel', 'lastError']);
68
69
  return {
69
70
  ...base,
70
71
  status: base.status === 'disabled' ? 'disabled' : 'available',
@@ -59,7 +59,7 @@ export function useFetchQuery(required, optional = {}) {
59
59
  const fetch = useCallback(() => latest.current.fetch(), []);
60
60
  useEffect(() => {
61
61
  if (!enabled)
62
- return;
62
+ return undefined;
63
63
  const release = cache.observe({ entry: entry, observer: { fetch, staleTime, focus: refetchOnWindowFocus } });
64
64
  void cache.load({ entry: entry, fetch: fetch, staleTime: staleTime });
65
65
  return release;
@@ -84,7 +84,8 @@ export function useFetchMutation(required, optional = {}) {
84
84
  useEffect(() => { mounted.current = true; return () => { mounted.current = false; }; }, []);
85
85
  const [state, setState] = useState({ status: 'idle', error: null });
86
86
  const mutate = useCallback(({ input }) => {
87
- const current = ++generation.current;
87
+ generation.current += 1;
88
+ const current = generation.current;
88
89
  const { run, invalidates } = latest.current;
89
90
  setState({ status: 'pending', error: null });
90
91
  // Surface a rejected write immediately instead of silently retrying authorization or
@@ -70,7 +70,8 @@ async function read({ scope, key, fetch }) {
70
70
  const query = scope.client.getQueryCache().find({ queryKey: key, exact: true });
71
71
  const history = historyFor({ scope, query });
72
72
  const generation = history.replacement;
73
- const request = ++history.request;
73
+ history.request += 1;
74
+ const request = history.request;
74
75
  try {
75
76
  const value = await scope.gate.runOnline({ run: fetch });
76
77
  if (generation !== history.replacement)
@@ -132,7 +133,7 @@ function useFetchQuery({ key, fetch }, { enabled = true, staleTime = DEFAULT_STA
132
133
  }, [scope, refresh, JSON.stringify(key)]);
133
134
  useEffect(() => {
134
135
  if (!enabled || !refetchOnWindowFocus)
135
- return;
136
+ return undefined;
136
137
  return scope.environment.subscribeFocus({ listener: () => {
137
138
  const cached = scope.client.getQueryCache().find({ queryKey: key, exact: true });
138
139
  if (scope.environment.isOnline() && cached?.isStaleByTime(staleTime) && cached.state.fetchStatus !== 'fetching')
@@ -7,7 +7,8 @@ function createQueryScopes(_required, _options = {}) {
7
7
  return ({ owner }, _optional = {}) => {
8
8
  let scope = scopes.get(owner);
9
9
  if (scope === undefined) {
10
- scope = ++nextScope;
10
+ nextScope += 1;
11
+ scope = nextScope;
11
12
  scopes.set(owner, scope);
12
13
  }
13
14
  return scope;
@@ -9,9 +9,18 @@ function formatSavedAtLocal(iso) {
9
9
  export function standingDraftRecoveryMessage({ draft, t, serverUpdatedAt }, { formatSavedAt = formatSavedAtLocal } = {}) {
10
10
  const captured = Date.parse(draft.savedAt);
11
11
  const server = Date.parse(serverUpdatedAt ?? draft.serverUpdatedAt ?? "");
12
- const comparison = server > captured ? "Server content is newer."
13
- : server < captured ? "Local changes are newer."
14
- : server === captured ? "Both copies have the same timestamp." : "";
15
- return `${t("Restore unsaved changes from")} ${formatSavedAt(draft.savedAt)}${comparison ? ` · ${t(comparison)}` : ""}`;
12
+ const comparison = compareTimestamps(server, captured);
13
+ const suffix = comparison ? ` · ${t(comparison)}` : "";
14
+ return `${t("Restore unsaved changes from")} ${formatSavedAt(draft.savedAt)}${suffix}`;
15
+ }
16
+ /** Which copy is newer; empty when either timestamp failed to parse (NaN compares unequal to all). */
17
+ function compareTimestamps(server, captured) {
18
+ if (server > captured)
19
+ return "Server content is newer.";
20
+ if (server < captured)
21
+ return "Local changes are newer.";
22
+ if (server === captured)
23
+ return "Both copies have the same timestamp.";
24
+ return "";
16
25
  }
17
26
  //# sourceMappingURL=standing-draft-recovery-message.js.map
@@ -13,7 +13,7 @@ export function useDirtyGuard({ current, original }, { translate = (key) => key,
13
13
  const isDirty = original !== null && !shallowJsonEqual(current, original);
14
14
  useEffect(() => {
15
15
  if (!isDirty)
16
- return;
16
+ return undefined;
17
17
  function onBeforeUnload(e) {
18
18
  e.preventDefault();
19
19
  // Both assignments are the standard cross-browser incantation (the returned string is
@@ -45,7 +45,7 @@ function redirectTarget(container, shiftKey) {
45
45
  export function useFocusTrap({ containerRef }, { active = true } = {}) {
46
46
  useEffect(() => {
47
47
  if (!active)
48
- return;
48
+ return undefined;
49
49
  // Captured before anything inside the dialog takes focus, so keyboard users land back on the
50
50
  // control they opened it from instead of at the top of the page. An element already inside the
51
51
  // container (an autoFocus child committed first) is not the opener, so nothing is restored then.
@@ -261,9 +261,15 @@ export function useSettingsSlice(options, _optional = {}) {
261
261
  // left to paint. The write itself still has to happen — through the same
262
262
  // lane as the debounce path, so it diffs against the base that is
263
263
  // current when it RUNS, not the one that was current when it was queued.
264
- void writes.run({ task: () => runSave().then(() => { },
265
- // No view remains to show the failure; settings and native errors may contain secrets.
266
- () => { console.error('[settings] Final save failed after unmount.'); }) });
264
+ // No view remains to show the failure; settings and native errors may contain secrets.
265
+ const reportFinalFailure = () => { console.error('[settings] Final save failed after unmount.'); };
266
+ const finalSave = async () => { try {
267
+ await runSave();
268
+ }
269
+ catch {
270
+ reportFinalFailure();
271
+ } };
272
+ void writes.run({ task: finalSave });
267
273
  }, [runSave, writes]);
268
274
  const onChange = useCallback((next) => {
269
275
  setValue(next);
@@ -278,14 +284,12 @@ export function useSettingsSlice(options, _optional = {}) {
278
284
  // "operator has work in flight" signal, and a handle that never cleared would refuse every
279
285
  // external refresh for the rest of the component's life after the first keystroke.
280
286
  timer.current = null;
281
- const ticket = ++saveTicket.current;
287
+ saveTicket.current += 1;
288
+ const ticket = saveTicket.current;
282
289
  setSaveState({ status: "saving" });
283
- void writes.run({ task: () => commitQueuedSave({ ticket, deps: {
284
- runSave,
285
- currentTicket: () => saveTicket.current,
286
- hasUnsavedEdits: () => hasUnsavedEdits.current,
287
- setSaveState,
288
- } }, {}) });
290
+ const deps = { runSave, currentTicket: () => saveTicket.current,
291
+ hasUnsavedEdits: () => hasUnsavedEdits.current, setSaveState };
292
+ void writes.run({ task: () => commitQueuedSave({ ticket, deps }, {}) });
289
293
  }, SAVE_DEBOUNCE_MS);
290
294
  }, [runSave, writes]);
291
295
  /**
@@ -88,7 +88,7 @@ export function useStandingDraftAutosave(deps, _options = {}) {
88
88
  minBaseVersionRef.current = null;
89
89
  latestDraftRef.current = null;
90
90
  if (!enabled || !entryId)
91
- return;
91
+ return undefined;
92
92
  let cancelled = false;
93
93
  port
94
94
  .getAutosave({ id: entryId }, {})
@@ -241,7 +241,7 @@ export function useStandingDraftAutosave(deps, _options = {}) {
241
241
  // events (a close fires blur AND pagehide) cost one write, not three.
242
242
  useEffect(() => {
243
243
  if (!enabled || !entryId)
244
- return;
244
+ return undefined;
245
245
  // Wrapped rather than passed straight to `addEventListener`: a listener is called WITH the
246
246
  // Event, which would arrive as `flushPendingAutosave`'s `keepalive` argument — a truthy object,
247
247
  // so every flush would silently request keepalive whether or not it is an exit.
@@ -2,7 +2,7 @@ import type { ProgressCardData } from '../types.js';
2
2
  export interface ProgressCardProps {
3
3
  data: ProgressCardData;
4
4
  /** Caps how many `steps` render before the rest are truncated. Matches
5
- * the source `WorkspaceActivityCard`'s todo-list cap. */
5
+ * the source `WorkspaceActivityCard`'s to-do list cap. */
6
6
  maxSteps?: number;
7
7
  /** Caps how many `secondaryItems` render. Matches the source's
8
8
  * files-touched cap. */
@@ -23,7 +23,7 @@ export function parseTodoWriteInput(input) {
23
23
  if (!input || typeof input !== 'object')
24
24
  return [];
25
25
  const record = input;
26
- const rawItems = Array.isArray(record.todos) ? record.todos : Array.isArray(record.plan) ? record.plan : [];
26
+ const rawItems = [record.todos, record.plan].find(Array.isArray) ?? [];
27
27
  return rawItems
28
28
  .map((todo) => {
29
29
  if (!todo || typeof todo !== 'object')
@@ -91,7 +91,8 @@ function extractFileOpPath(input) {
91
91
  if (!input || typeof input !== 'object')
92
92
  return null;
93
93
  const record = input;
94
- const filePath = record.file_path ?? record.filePath ?? record.path ?? record.filename ?? record.target_path ?? record.targetPath;
94
+ let filePath = record.file_path ?? record.filePath ?? record.path;
95
+ filePath ??= record.filename ?? record.target_path ?? record.targetPath;
95
96
  return typeof filePath === 'string' && filePath.trim() ? filePath : null;
96
97
  }
97
98
  function basename(path) {
@@ -137,7 +138,9 @@ function fileOpFromAgentEvent({ event, resultByToolUseId }, _options = {}) {
137
138
  if (!fullPath)
138
139
  return null;
139
140
  const result = resultByToolUseId.get(event.id);
140
- const status = result === undefined ? 'running' : result.isError ? 'error' : 'done';
141
+ let status = 'running';
142
+ if (result !== undefined)
143
+ status = result.isError ? 'error' : 'done';
141
144
  return { fullPath, kind, status };
142
145
  }
143
146
  export function deriveFileOpsFromAgentEvents(events) {
@@ -155,14 +158,15 @@ export function deriveFileOpsFromAgentEvents(events) {
155
158
  if (!existing.ops.includes(entry.kind))
156
159
  existing.ops.push(entry.kind);
157
160
  existing.status = mergeFileOpStatus(existing.status, entry.status);
158
- continue;
159
161
  }
160
- byPath.set(entry.fullPath, {
161
- path: basename(entry.fullPath),
162
- fullPath: entry.fullPath,
163
- ops: [entry.kind],
164
- status: entry.status,
165
- });
162
+ else {
163
+ byPath.set(entry.fullPath, {
164
+ path: basename(entry.fullPath),
165
+ fullPath: entry.fullPath,
166
+ ops: [entry.kind],
167
+ status: entry.status,
168
+ });
169
+ }
166
170
  }
167
171
  return Array.from(byPath.values());
168
172
  }
@@ -202,7 +206,7 @@ function fallbackChatActivitySteps(status, fileOps) {
202
206
  {
203
207
  id: 'read-current-state',
204
208
  label: 'Read current state',
205
- status: hasRead || hasMutation || status === 'succeeded' ? 'succeeded' : status === 'running' ? 'running' : 'pending',
209
+ status: fallbackReadStatus({ status, done: hasRead || hasMutation }),
206
210
  },
207
211
  {
208
212
  id: 'update-files',
@@ -212,10 +216,15 @@ function fallbackChatActivitySteps(status, fileOps) {
212
216
  {
213
217
  id: 'finalize',
214
218
  label: 'Finalize',
215
- status: status === 'succeeded' ? 'succeeded' : status === 'failed' ? 'failed' : 'pending',
219
+ status: status === 'succeeded' || status === 'failed' ? status : 'pending',
216
220
  },
217
221
  ];
218
222
  }
223
+ function fallbackReadStatus({ status, done }) {
224
+ if (done || status === 'succeeded')
225
+ return 'succeeded';
226
+ return status === 'running' ? 'running' : 'pending';
227
+ }
219
228
  function fallbackUpdateStatus({ status, fileOps, hasError, hasMutation }, _options = {}) {
220
229
  if (hasError)
221
230
  return 'failed';
@@ -242,7 +251,8 @@ export function chatActivityToProgressCard(message, options) {
242
251
  const fileOps = deriveFileOpsFromAgentEvents(events);
243
252
  const status = chatActivityStatus(message, options.active);
244
253
  const statusDetail = latestStatusDetailFromAgentEvents(events);
245
- const hasActivity = options.active || todos.length > 0 || fileOps.length > 0 || statusDetail !== null || status === 'failed';
254
+ const hasSteps = todos.length > 0 || fileOps.length > 0;
255
+ const hasActivity = options.active || hasSteps || statusDetail !== null || status === 'failed';
246
256
  if (!hasActivity)
247
257
  return null;
248
258
  const steps = chatActivitySteps({ todos, status, fileOps });
@@ -14,7 +14,6 @@ export declare function progressCardStatusLabel(status: ProgressStatus): string;
14
14
  * generic — the source cards' actual default copy is branded product voice,
15
15
  * not part of the generic component (see `packages/ui/archived provenance ledger`). */
16
16
  export declare function defaultProgressCardTitle(status: ProgressStatus): string;
17
- /** Neutral fallback detail line used when a host doesn't supply one. */
18
17
  export declare function defaultProgressCardDetail(status: ProgressStatus): string;
19
18
  export declare function clampProgressPercent(value: number): number;
20
19
  /** CSS width percentage for the progress bar fill, or `null` for an
@@ -15,17 +15,14 @@ export function progressCardStatusIcon(status) {
15
15
  export function progressCardItemIcon(status) {
16
16
  return status === 'succeeded' ? 'check' : null;
17
17
  }
18
+ const STATUS_LABELS = {
19
+ pending: 'Queued',
20
+ running: 'Running',
21
+ succeeded: 'Complete',
22
+ failed: 'Needs attention',
23
+ };
18
24
  export function progressCardStatusLabel(status) {
19
- switch (status) {
20
- case 'pending':
21
- return 'Queued';
22
- case 'running':
23
- return 'Running';
24
- case 'succeeded':
25
- return 'Complete';
26
- case 'failed':
27
- return 'Needs attention';
28
- }
25
+ return STATUS_LABELS[status];
29
26
  }
30
27
  /** Neutral fallback title used when a host doesn't supply one. Deliberately
31
28
  * generic — the source cards' actual default copy is branded product voice,
@@ -34,17 +31,14 @@ export function defaultProgressCardTitle(status) {
34
31
  return progressCardStatusLabel(status);
35
32
  }
36
33
  /** Neutral fallback detail line used when a host doesn't supply one. */
34
+ const DEFAULT_DETAILS = {
35
+ pending: 'Waiting to start.',
36
+ running: 'In progress.',
37
+ succeeded: 'Completed.',
38
+ failed: 'Needs attention.',
39
+ };
37
40
  export function defaultProgressCardDetail(status) {
38
- switch (status) {
39
- case 'pending':
40
- return 'Waiting to start.';
41
- case 'running':
42
- return 'In progress.';
43
- case 'succeeded':
44
- return 'Completed.';
45
- case 'failed':
46
- return 'Needs attention.';
47
- }
41
+ return DEFAULT_DETAILS[status];
48
42
  }
49
43
  export function clampProgressPercent(value) {
50
44
  if (!Number.isFinite(value))
@@ -25,7 +25,7 @@ export interface ProgressCardData {
25
25
  * 'indeterminate' (both always compute a percentage) — it's included as a
26
26
  * forward-looking capability for Jini's own Run/Agent/Tool dashboards. */
27
27
  progress: number | 'indeterminate';
28
- /** The primary step/todo checklist. */
28
+ /** The primary step/to-do checklist. */
29
29
  steps: ProgressCardItem[];
30
30
  /** An optional secondary list, e.g. "files touched" by an agent run. */
31
31
  secondaryItems?: ProgressCardItem[];
@@ -6,6 +6,11 @@ const DEFAULT_BUILT_IN = {
6
6
  builtIn: true,
7
7
  };
8
8
  let nextFakeId = 1;
9
+ function takeFakeId() {
10
+ const id = `fake-location-${nextFakeId}`;
11
+ nextFakeId += 1;
12
+ return id;
13
+ }
9
14
  /**
10
15
  * An in-memory test/demo double. Per this package's established convention
11
16
  * (see `execution/dependencies.ts`, `integrations/dependencies.ts`), ships a
@@ -30,7 +35,7 @@ export function createFakeProjectLocationsPort(options = {}) {
30
35
  saveLocations(drafts) {
31
36
  const builtIn = locations.filter((location) => location.builtIn);
32
37
  const nextExternal = drafts.map((draft) => ({
33
- id: draft.id ?? `fake-location-${nextFakeId++}`,
38
+ id: draft.id ?? takeFakeId(),
34
39
  name: draft.path.split(/[\\/]/).filter(Boolean).pop() || draft.path,
35
40
  path: draft.path,
36
41
  }));
@@ -56,7 +56,8 @@ export function ProjectLocationsTab({ port, defaultLocationId, onDefaultLocation
56
56
  return null;
57
57
  }
58
58
  })();
59
- const errorNotice = result.status === 'save-error' ? saveErrorLabel : result.status === 'scan-error' ? scanErrorLabel : null;
59
+ const errorNoticeByStatus = { 'save-error': saveErrorLabel, 'scan-error': scanErrorLabel };
60
+ const errorNotice = errorNoticeByStatus[result.status] ?? null;
60
61
  return (_jsxs("section", { className: "jini-settings-section jini-settings-project-locations", children: [_jsx("div", { className: "jini-section-head", children: _jsxs("div", { children: [_jsx("h4", { children: title }), _jsx("p", { className: "jini-hint", children: description })] }) }), builtIn ? (_jsxs("div", { className: "jini-project-location-card jini-project-location-card-built-in", children: [_jsxs("div", { className: "jini-project-location-card-main", children: [_jsx("strong", { children: builtInLabel }), _jsx("code", { children: builtIn.path })] }), _jsxs("label", { className: "jini-project-location-default-control", children: [_jsx("input", { type: "radio", name: "jini-project-location-default", checked: effectiveDefaultLocationId === builtIn.id, onChange: () => setDefaultLocationId(builtIn.id) }), _jsx("span", { children: defaultControlLabel(effectiveDefaultLocationId === builtIn.id) })] })] })) : null, _jsx("div", { className: "jini-project-location-list", children: drafts.map((draft, index) => (_jsxs("div", { className: "jini-project-location-card", children: [_jsxs("div", { className: "jini-project-location-card-main", children: [_jsx("strong", { children: locationLabel(draft.path) }), _jsx("code", { children: draft.path }), _jsx("small", { className: "jini-hint", children: rowHint })] }), draft.id ? (_jsxs("label", { className: "jini-project-location-default-control", children: [_jsx("input", { type: "radio", name: "jini-project-location-default", checked: effectiveDefaultLocationId === draft.id, onChange: () => setDefaultLocationId(draft.id) }), _jsx("span", { children: defaultControlLabel(effectiveDefaultLocationId === draft.id) })] })) : null, _jsxs("button", { type: "button", className: "jini-button jini-button-ghost", onClick: () => removeDraft(index), disabled: saving, children: [_jsx(Icon, { name: "trash", size: 13 }), _jsx("span", { children: deleteLabel })] })] }, `${draft.id ?? 'new'}-${index}`))) }), _jsxs("button", { type: "button", className: "jini-button jini-button-ghost", onClick: addFolder, disabled: saving, children: [_jsx(Icon, { name: "plus", size: 12 }), _jsx("span", { children: addFolderLabel })] }), notice ? (_jsx("p", { className: "jini-hint", role: "status", children: notice })) : null, errorNotice ? (_jsx("p", { className: "jini-hint jini-hint-error", role: "alert", children: errorNotice })) : null] }));
61
62
  }
62
63
  //# sourceMappingURL=ProjectLocationsTab.js.map
@@ -1,3 +1,4 @@
1
+ import { trimTrailingChars } from '../../utils/trim-chars.js';
1
2
  /**
2
3
  * The id meaning "the host's own default root".
3
4
  *
@@ -77,6 +78,6 @@ function normalizePathForCompare(value) {
77
78
  const trimmed = value.trim();
78
79
  if (trimmed.length <= 1)
79
80
  return trimmed;
80
- return trimmed.replace(/[\\/]+$/, '') || trimmed;
81
+ return trimTrailingChars(trimmed, '\\/') || trimmed;
81
82
  }
82
83
  //# sourceMappingURL=rules.js.map
@@ -1,4 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /** The select-mode bar while selecting, otherwise the button that enters select mode. */
3
+ function ResourceBoardSelectControls({ selectMode, selectedCount, bulkDeleteBusy, onEnterSelectMode, onExitSelectMode, onBulkDelete, selectModeLabel, selectedCountLabel, deleteSelectedLabel, cancelSelectLabel, }) {
4
+ if (!selectMode) {
5
+ return (_jsx("button", { type: "button", className: "resource-board-select-toggle", onClick: onEnterSelectMode, children: selectModeLabel }));
6
+ }
7
+ return (_jsxs("div", { className: "resource-board-select-bar", role: "group", children: [_jsx("span", { className: "resource-board-select-count", children: selectedCountLabel(selectedCount) }), _jsx("button", { type: "button", disabled: selectedCount === 0 || bulkDeleteBusy, onClick: onBulkDelete, children: deleteSelectedLabel }), _jsx("button", { type: "button", onClick: onExitSelectMode, children: cancelSelectLabel })] }));
8
+ }
2
9
  /**
3
10
  * DesignsTab's toolbar: sub-tab sort pills + a create button + search +
4
11
  * select-mode/bulk-delete bar (grid view only) + the grid/kanban view
@@ -9,6 +16,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
9
16
  */
10
17
  export function ResourceBoardToolbar({ sortOptions, activeSort, onSortChange, sortAriaLabel, query, onQueryChange, searchPlaceholder, viewMode, onViewModeChange, viewToggleAriaLabel, gridViewLabel, kanbanViewLabel, enableBulkDelete, selectMode, selectedCount, bulkDeleteBusy, onEnterSelectMode, onExitSelectMode, onBulkDelete, selectModeLabel, selectedCountLabel, deleteSelectedLabel, cancelSelectLabel, createLabel, onCreate, }) {
11
18
  const showSelectControls = enableBulkDelete && viewMode === 'grid';
12
- return (_jsxs("div", { className: "resource-board-toolbar", children: [_jsx("div", { className: "resource-board-toolbar-left", children: sortOptions.length > 0 ? (_jsx("div", { className: "resource-board-sort-pill", role: "group", "aria-label": sortAriaLabel, children: sortOptions.map((option) => (_jsx("button", { type: "button", "aria-pressed": activeSort === option.value, className: activeSort === option.value ? 'active' : '', onClick: () => onSortChange(option.value), children: option.label }, option.value))) })) : null }), _jsxs("div", { className: "resource-board-toolbar-right", children: [onCreate && createLabel ? (_jsx("button", { type: "button", className: "resource-board-create-button", onClick: onCreate, children: createLabel })) : null, _jsx("div", { className: "resource-board-search", children: _jsx("input", { placeholder: searchPlaceholder, value: query, onChange: (event) => onQueryChange(event.target.value) }) }), showSelectControls ? (selectMode ? (_jsxs("div", { className: "resource-board-select-bar", role: "group", children: [_jsx("span", { className: "resource-board-select-count", children: selectedCountLabel(selectedCount) }), _jsx("button", { type: "button", disabled: selectedCount === 0 || bulkDeleteBusy, onClick: onBulkDelete, children: deleteSelectedLabel }), _jsx("button", { type: "button", onClick: onExitSelectMode, children: cancelSelectLabel })] })) : (_jsx("button", { type: "button", className: "resource-board-select-toggle", onClick: onEnterSelectMode, children: selectModeLabel }))) : null, _jsxs("div", { className: "resource-board-view-pill", role: "group", "aria-label": viewToggleAriaLabel, children: [_jsx("button", { "aria-pressed": viewMode === 'grid', className: viewMode === 'grid' ? 'active' : '', title: gridViewLabel, onClick: () => onViewModeChange('grid'), children: gridViewLabel }), _jsx("button", { "aria-pressed": viewMode === 'kanban', className: viewMode === 'kanban' ? 'active' : '', title: kanbanViewLabel, onClick: () => onViewModeChange('kanban'), children: kanbanViewLabel })] })] })] }));
19
+ return (_jsxs("div", { className: "resource-board-toolbar", children: [_jsx("div", { className: "resource-board-toolbar-left", children: sortOptions.length > 0 ? (_jsx("div", { className: "resource-board-sort-pill", role: "group", "aria-label": sortAriaLabel, children: sortOptions.map((option) => (_jsx("button", { type: "button", "aria-pressed": activeSort === option.value, className: activeSort === option.value ? 'active' : '', onClick: () => onSortChange(option.value), children: option.label }, option.value))) })) : null }), _jsxs("div", { className: "resource-board-toolbar-right", children: [onCreate && createLabel ? (_jsx("button", { type: "button", className: "resource-board-create-button", onClick: onCreate, children: createLabel })) : null, _jsx("div", { className: "resource-board-search", children: _jsx("input", { placeholder: searchPlaceholder, value: query, onChange: (event) => onQueryChange(event.target.value) }) }), showSelectControls ? (_jsx(ResourceBoardSelectControls, { selectMode: selectMode, selectedCount: selectedCount, bulkDeleteBusy: bulkDeleteBusy, onEnterSelectMode: onEnterSelectMode, onExitSelectMode: onExitSelectMode, onBulkDelete: onBulkDelete, selectModeLabel: selectModeLabel, selectedCountLabel: selectedCountLabel, deleteSelectedLabel: deleteSelectedLabel, cancelSelectLabel: cancelSelectLabel })) : null, _jsxs("div", { className: "resource-board-view-pill", role: "group", "aria-label": viewToggleAriaLabel, children: [_jsx("button", { "aria-pressed": viewMode === 'grid', className: viewMode === 'grid' ? 'active' : '', title: gridViewLabel, onClick: () => onViewModeChange('grid'), children: gridViewLabel }), _jsx("button", { "aria-pressed": viewMode === 'kanban', className: viewMode === 'kanban' ? 'active' : '', title: kanbanViewLabel, onClick: () => onViewModeChange('kanban'), children: kanbanViewLabel })] })] })] }));
13
20
  }
14
21
  //# sourceMappingURL=ResourceBoardToolbar.js.map
@@ -1,11 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { ResourceBoardAlerts, ResourceBoardContent, ResourceBoardViewToolbar } from './ResourceBoardViewParts.js';
2
+ import { ResourceBoardAlerts, ResourceBoardContent } from './ResourceBoardViewParts.js';
3
+ import { ResourceBoardToolbar } from './ResourceBoardToolbar.js';
3
4
  /**
4
5
  * Pure composition (props in, JSX out): the toolbar, then either the empty
5
6
  * state, the card grid, or the kanban board — DesignsTab's own
6
7
  * `filtered.length === 0 ? empty : view === "grid" ? grid : kanban` branch.
7
8
  */
8
9
  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 })] }));
10
+ return (_jsxs("div", { className: `resource-board${props.viewMode === 'kanban' ? ' is-kanban' : ''}`, children: [_jsx(ResourceBoardToolbar, { ...props, selectedCount: props.selected.size }), _jsx(ResourceBoardAlerts, { ...props }), _jsx(ResourceBoardContent, { ...props })] }));
10
11
  }
11
12
  //# sourceMappingURL=ResourceBoardView.js.map
@@ -1,6 +1,4 @@
1
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
2
  /** The LOAD-failure banner and, independently, the single-item action-failure banner (shown ABOVE the still-visible item list). */
5
3
  export declare function ResourceBoardAlerts<TBody>({ error, errorLabel, actionError, actionErrorLabel, }: Pick<ResourceBoardViewProps<TBody>, 'error' | 'errorLabel' | 'actionError' | 'actionErrorLabel'>): import("react").JSX.Element;
6
4
  /** The card grid: one `ResourceCard` per item, with the item's id bound into each per-card callback. */
@@ -1,12 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { ResourceBoardToolbar } from './ResourceBoardToolbar.js';
3
2
  import { ResourceCard } from './ResourceCard.js';
4
3
  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
4
  /** The LOAD-failure banner and, independently, the single-item action-failure banner (shown ABOVE the still-visible item list). */
11
5
  export function ResourceBoardAlerts({ error, errorLabel, actionError, actionErrorLabel, }) {
12
6
  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] }));
@@ -29,6 +29,7 @@ export function ResourceCardMenu({ menuActions, menuOpen, busy, moreLabel, menuC
29
29
  }
30
30
  /** Title, optional subtitle, and the status badge (only when the item has a status AND a pre-translated label). */
31
31
  export function ResourceCardMeta({ item, statusLabel, toneMap, }) {
32
- return (_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] }));
32
+ const toneMapProps = toneMap ? { toneMap } : {};
33
+ return (_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, ...toneMapProps }) : null] }));
33
34
  }
34
35
  //# sourceMappingURL=ResourceCardParts.js.map
@@ -9,6 +9,8 @@ import { ResourceRunHistoryList } from './ResourceRunHistoryList.js';
9
9
  * `ResourceRunHistoryList` sublist.
10
10
  */
11
11
  export function ResourceRowListItem({ row, busy, statusLabel, toneMap, canExpandHistory, expanded, showHistoryLabel, hideHistoryLabel, historyItems, historyLoading, historyTitleLabel, historyLoadingLabel, historyEmptyLabel, onToggleExpand, onAction, onHistoryItemAction, }) {
12
- return (_jsxs("li", { className: `resource-row-list-item${row.paused ? ' is-paused' : ''}`, "data-testid": "resource-row-list-item", children: [_jsx("div", { className: "resource-row-list-item-main", children: _jsx(ResourceRowListItemContent, { row: row, statusLabel: statusLabel, toneMap: toneMap }) }), _jsx(ResourceRowListItemActions, { row: row, busy: busy, canExpandHistory: canExpandHistory, expanded: expanded, showHistoryLabel: showHistoryLabel, hideHistoryLabel: hideHistoryLabel, onToggleExpand: onToggleExpand, onAction: onAction }), expanded ? (_jsx(ResourceRunHistoryList, { items: historyItems, loading: historyLoading, titleLabel: historyTitleLabel, loadingLabel: historyLoadingLabel, emptyLabel: historyEmptyLabel, statusLabel: statusLabel, ...(toneMap ? { toneMap } : {}), ...(onHistoryItemAction ? { onAction: onHistoryItemAction } : {}) })) : null] }));
12
+ const toneMapProps = toneMap ? { toneMap } : {};
13
+ const historyActionProps = onHistoryItemAction ? { onAction: onHistoryItemAction } : {};
14
+ return (_jsxs("li", { className: `resource-row-list-item${row.paused ? ' is-paused' : ''}`, "data-testid": "resource-row-list-item", children: [_jsx("div", { className: "resource-row-list-item-main", children: _jsx(ResourceRowListItemContent, { row: row, statusLabel: statusLabel, toneMap: toneMap }) }), _jsx(ResourceRowListItemActions, { row: row, busy: busy, canExpandHistory: canExpandHistory, expanded: expanded, showHistoryLabel: showHistoryLabel, hideHistoryLabel: hideHistoryLabel, onToggleExpand: onToggleExpand, onAction: onAction }), expanded ? (_jsx(ResourceRunHistoryList, { items: historyItems, loading: historyLoading, titleLabel: historyTitleLabel, loadingLabel: historyLoadingLabel, emptyLabel: historyEmptyLabel, statusLabel: statusLabel, ...toneMapProps, ...historyActionProps })) : null] }));
13
15
  }
14
16
  //# sourceMappingURL=ResourceRowListItem.js.map
@@ -2,7 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { StatusPill } from './StatusPill.js';
3
3
  /** Title/meta/detail lines plus the last-run `StatusPill` + label of one `ResourceRowListItem`. */
4
4
  export function ResourceRowListItemContent({ row, statusLabel, toneMap, }) {
5
- return (_jsxs("div", { className: "resource-row-list-item-content", children: [_jsx("span", { className: "resource-row-list-item-title", children: row.title }), row.metaLine ? _jsx("span", { className: "resource-row-list-item-meta", children: row.metaLine }) : null, row.detailLine ? _jsx("span", { className: "resource-row-list-item-detail", children: row.detailLine }) : null, row.lastRunStatus ? (_jsxs("span", { className: "resource-row-list-item-last-run", children: [_jsx(StatusPill, { status: row.lastRunStatus, label: statusLabel(row.lastRunStatus), ...(toneMap ? { toneMap } : {}) }), row.lastRunLabel ? _jsx("span", { children: row.lastRunLabel }) : null] })) : null] }));
5
+ const toneMapProps = toneMap ? { toneMap } : {};
6
+ return (_jsxs("div", { className: "resource-row-list-item-content", children: [_jsx("span", { className: "resource-row-list-item-title", children: row.title }), row.metaLine ? _jsx("span", { className: "resource-row-list-item-meta", children: row.metaLine }) : null, row.detailLine ? _jsx("span", { className: "resource-row-list-item-detail", children: row.detailLine }) : null, row.lastRunStatus ? (_jsxs("span", { className: "resource-row-list-item-last-run", children: [_jsx(StatusPill, { status: row.lastRunStatus, label: statusLabel(row.lastRunStatus), ...toneMapProps }), row.lastRunLabel ? _jsx("span", { children: row.lastRunLabel }) : null] })) : null] }));
6
7
  }
7
8
  /** Always-visible inline action buttons (never a kebab menu, unlike `ResourceCard`) plus the optional history-expand toggle. */
8
9
  export function ResourceRowListItemActions({ row, busy, canExpandHistory, expanded, showHistoryLabel, hideHistoryLabel, onToggleExpand, onAction, }) {
@@ -13,6 +13,6 @@ import { ResourceRowListAlerts, ResourceRowListEmpty, ResourceRowListHero, Resou
13
13
  export function ResourceRowListView(props) {
14
14
  const { loading, rows, sectionLabel, loadingLabel } = props;
15
15
  const isEmpty = !loading && rows.length === 0;
16
- return (_jsxs("section", { className: "resource-row-list", children: [_jsx(ResourceRowListHero, { ...props }), _jsx(ResourceRowListAlerts, { ...props }), _jsxs("section", { className: "resource-row-list-saved", "aria-label": sectionLabel, children: [_jsxs("div", { className: "resource-row-list-section-head", children: [_jsx("h2", { children: sectionLabel }), loading ? _jsx("span", { className: "resource-row-list-section-meta", children: loadingLabel }) : null] }), isEmpty ? _jsx(ResourceRowListEmpty, { ...props }) : rows.length > 0 ? _jsx(ResourceRowListRows, { ...props }) : null] })] }));
16
+ return (_jsxs("section", { className: "resource-row-list", children: [_jsx(ResourceRowListHero, { ...props }), _jsx(ResourceRowListAlerts, { ...props }), _jsxs("section", { className: "resource-row-list-saved", "aria-label": sectionLabel, children: [_jsxs("div", { className: "resource-row-list-section-head", children: [_jsx("h2", { children: sectionLabel }), loading ? _jsx("span", { className: "resource-row-list-section-meta", children: loadingLabel }) : null] }), isEmpty ? _jsx(ResourceRowListEmpty, { ...props }) : null, rows.length > 0 ? _jsx(ResourceRowListRows, { ...props }) : null] })] }));
17
17
  }
18
18
  //# sourceMappingURL=ResourceRowListView.js.map
@@ -76,7 +76,7 @@ export function useResourceBoard(params) {
76
76
  // same guard DesignsTab's own `menuContainerRef`-based effect uses.
77
77
  useEffect(() => {
78
78
  if (!openMenuId)
79
- return;
79
+ return undefined;
80
80
  const onKey = (event) => {
81
81
  if (event.key === 'Escape')
82
82
  setOpenMenuId(null);