@jini-ai/ui 0.6.15-rc.2 → 0.6.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/browser/useDismissOnOutsideOrEscape.js +1 -1
- package/dist/browser/useGlobalKeydown.js +2 -2
- package/dist/browser/useModalWindowDragGuard.js +1 -1
- package/dist/core/theme/css-name.d.ts +3 -0
- package/dist/core/theme/css-name.js +5 -0
- package/dist/core/theme/stylesheet.js +2 -1
- package/dist/core/theme/validation.js +15 -4
- package/dist/core.d.ts +1 -1
- package/dist/core.js +1 -1
- package/dist/features/about/rules.js +2 -1
- package/dist/features/admin-widgets/components/InfoTip.hooks.js +22 -12
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.js +1 -1
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.js +1 -1
- package/dist/features/admin-widgets/components/SeeMore/SeeMore.hooks.js +2 -2
- package/dist/features/admin-widgets/components/SeeMore/SeeMore.js +4 -2
- package/dist/features/admin-widgets/components/Select/Select.hooks.js +2 -1
- package/dist/features/admin-widgets/components/Select/Select.js +2 -1
- package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.js +4 -2
- package/dist/features/admin-widgets/components/useDebouncedHtmlPreview.hooks.js +3 -2
- package/dist/features/appearance/constants.d.ts +28 -1
- package/dist/features/appearance/constants.js +12 -9
- package/dist/features/appearance/react/components/AppearanceTab.js +4 -4
- package/dist/features/asset-grid/react/components/AssetGrid.js +8 -3
- package/dist/features/asset-grid/react/hooks/useAssetGridKeyboardShortcuts.js +7 -6
- package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.js +8 -10
- package/dist/features/asset-grid/react/hooks/useRubberBandDrag.js +1 -1
- package/dist/features/asset-tree-browser/react/components/AssetTreeFileRow.js +6 -8
- package/dist/features/asset-tree-browser/react/hooks/useAssetTreeRowMenu.js +1 -1
- package/dist/features/asset-tree-browser/rules.js +1 -3
- package/dist/features/browser-chrome/rules.js +10 -8
- package/dist/features/charts/browser.js +2 -1
- package/dist/features/charts/contract.d.ts +4 -4
- package/dist/features/charts/react.js +5 -3
- package/dist/features/charts/wire.d.ts +19 -0
- package/dist/features/charts/wire.js +20 -2
- package/dist/features/connectors/ConnectorsBrowser.js +3 -1
- package/dist/features/connectors/hooks/useConnectorAuthorization.js +1 -1
- package/dist/features/connectors/hooks/useConnectorCatalog.js +2 -2
- package/dist/features/connectors/rules.js +10 -14
- package/dist/features/execution/constants.js +0 -1
- package/dist/features/execution/react/components/AgentDiagnosticRow.js +2 -0
- package/dist/features/execution/react/components/ByokProviderForm.js +1 -3
- package/dist/features/execution/react/components/LocalCliAgentSettings.js +2 -1
- package/dist/features/execution/react/hooks/use-byok-field-validation.hooks.js +6 -2
- package/dist/features/execution/react/hooks/useExecutionTab.js +9 -5
- package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +3 -6
- package/dist/features/execution/react/hooks/useReasoningControl.js +3 -3
- package/dist/features/execution/rules.js +23 -18
- package/dist/features/external-mcp/react/components/ExternalMcpTab.js +10 -1
- package/dist/features/file-dropzone/rules.js +3 -2
- package/dist/features/folder-path-drop/rules.d.ts +2 -3
- package/dist/features/folder-path-drop/rules.js +3 -4
- package/dist/features/html-editor/canvas-embed-placeholders.js +2 -3
- package/dist/features/html-editor/css.js +7 -5
- package/dist/features/html-editor/editor-blocks.js +60 -6
- package/dist/features/html-editor/protected-elements.js +5 -3
- package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +3 -3
- package/dist/features/html-editor/source-splice.js +6 -4
- package/dist/features/i18n/dictionaries/settings-dialog.ar.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.bn.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.de.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.en.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.es.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.fa.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.fr.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.hi.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.hu.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.id.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.it.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.ja.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.ko.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.pl.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.pt-BR.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.ru.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.th.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.tr.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.uk.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.ur.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-CN.js +8 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-TW.js +8 -0
- package/dist/features/iframe-pool/react/components/IframeKeepAliveProvider.js +5 -5
- package/dist/features/iframe-pool/react/dom-sync.js +2 -2
- package/dist/features/integrations/react/components/IntegrationsTab.js +3 -1
- package/dist/features/integrations/rules.js +6 -4
- package/dist/features/interactive-ui/providers/shadcn/data-table.js +10 -5
- package/dist/features/interactive-ui/table-data.js +1 -1
- package/dist/features/lexical-rich-text-editor/deserialize.js +2 -2
- package/dist/features/lexical-rich-text-editor/mention-parser.js +4 -4
- package/dist/features/lexical-rich-text-editor/react/components/RichTextInput.js +2 -1
- package/dist/features/lexical-rich-text-editor/react/hooks/useCaretFloatingLayerPosition.js +1 -1
- package/dist/features/lexical-rich-text-editor/react/hooks/useMentionColorStamping.js +1 -1
- package/dist/features/lexical-rich-text-editor/serialize.js +13 -10
- package/dist/features/list-detail-panel/react/components/ListDetailPanel.js +1 -1
- package/dist/features/mcp-ui/confirmation-store.js +3 -6
- package/dist/features/mcp-ui/surfaces/checkbox.d.ts +2 -0
- package/dist/features/mcp-ui/surfaces/choice-group.d.ts +2 -0
- package/dist/features/mcp-ui/surfaces/choice-group.js +2 -2
- package/dist/features/mcp-ui/surfaces/confirmation.d.ts +5 -0
- package/dist/features/mcp-ui/surfaces/confirmation.js +1 -0
- package/dist/features/mcp-ui/surfaces/document.d.ts +14 -16
- package/dist/features/mcp-ui/surfaces/document.js +46 -7
- package/dist/features/mcp-ui/surfaces/fields.d.ts +7 -1
- package/dist/features/mcp-ui/surfaces/fields.js +14 -11
- package/dist/features/mcp-ui/surfaces/form.js +6 -1
- package/dist/features/mcp-ui/surfaces/host-theme.js +2 -1
- package/dist/features/mcp-ui/surfaces/index.d.ts +1 -0
- package/dist/features/mcp-ui/surfaces/index.js +1 -0
- package/dist/features/mcp-ui/surfaces/outcome.js +1 -1
- package/dist/features/mcp-ui/surfaces/select.d.ts +2 -0
- package/dist/features/mcp-ui/surfaces/select.js +2 -1
- package/dist/features/mcp-ui/surfaces/structured-details.d.ts +40 -0
- package/dist/features/mcp-ui/surfaces/structured-details.js +159 -0
- package/dist/features/mcp-ui/surfaces/text-input.d.ts +2 -0
- package/dist/features/mcp-ui/surfaces/text-input.js +1 -1
- package/dist/features/mcp-ui/surfaces/tool-approval.d.ts +21 -0
- package/dist/features/mcp-ui/surfaces/tool-approval.js +42 -0
- package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +2 -1
- package/dist/features/memory/async-commit-guard.js +4 -1
- package/dist/features/memory/formatters.js +5 -1
- package/dist/features/memory/react/components/MemoryConnectedPanel.js +3 -1
- package/dist/features/memory/react/components/MemoryEntryCard.js +1 -1
- package/dist/features/memory/react/components/MemorySettingsPanel.js +3 -1
- package/dist/features/memory/react/hooks/useMemoryConfig.hooks.js +12 -10
- package/dist/features/memory/react/hooks/useMemoryConnectors.hooks.js +2 -5
- package/dist/features/memory/react/hooks/useMemoryConnectors.rules.js +10 -9
- package/dist/features/memory/react/hooks/useMemoryEntries.hooks.js +4 -2
- package/dist/features/memory/react/hooks/useMemoryFlash.hooks.js +1 -1
- package/dist/features/memory/rules.js +2 -1
- package/dist/features/panel-kit/fetch-query/adapter.react.js +3 -2
- package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +3 -2
- package/dist/features/panel-kit/fetch-query/binding.react.js +2 -1
- package/dist/features/panel-kit/helpers/standing-draft-recovery-message.js +13 -4
- package/dist/features/panel-kit/hooks/use-dirty-guard.hooks.js +1 -1
- package/dist/features/panel-kit/hooks/use-focus-trap.hooks.js +1 -1
- package/dist/features/panel-kit/hooks/use-settings-slice.hooks.js +14 -10
- package/dist/features/panel-kit/hooks/use-standing-draft-autosave.hooks.js +2 -2
- package/dist/features/progress-card/components/ProgressCard.d.ts +1 -1
- package/dist/features/progress-card/reference-adapters.js +23 -13
- package/dist/features/progress-card/rules.d.ts +0 -1
- package/dist/features/progress-card/rules.js +14 -20
- package/dist/features/progress-card/types.d.ts +1 -1
- package/dist/features/project-locations/dependencies.js +6 -1
- package/dist/features/project-locations/react/components/ProjectLocationsTab.js +2 -1
- package/dist/features/project-locations/rules.js +2 -1
- package/dist/features/resource-dashboard/react/components/ResourceBoardToolbar.js +8 -1
- package/dist/features/resource-dashboard/react/components/ResourceCardParts.js +2 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListItem.js +3 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.js +2 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListView.js +1 -1
- package/dist/features/resource-dashboard/react/hooks/useResourceBoard.js +1 -1
- package/dist/features/schedule-picker/rules.js +13 -7
- package/dist/features/sketch-editor/constants.d.ts +0 -6
- package/dist/features/sketch-editor/constants.js +17 -15
- package/dist/features/sketch-editor/dom.js +4 -7
- package/dist/features/sketch-editor/react/components/SketchMainMenu.js +2 -1
- package/dist/features/sketch-editor/react/components/SketchSaveStateBadge.js +2 -1
- package/dist/features/sketch-editor/react/hooks/useSketchDomEnhancements.js +1 -1
- package/dist/features/sketch-editor/rules.js +13 -12
- package/dist/features/skills/dependencies.js +9 -4
- package/dist/features/skills/react/components/SkillRow.js +2 -1
- package/dist/features/skills/react/components/SkillsTab.js +2 -1
- package/dist/features/skills/rules.js +3 -3
- package/dist/features/source-config-list/agent-handles.js +4 -3
- package/dist/features/source-config-list/react/components/SourceConfigItemCard.js +3 -1
- package/dist/features/tab-strip/react/components/TabBar.hooks.js +4 -2
- package/dist/features/version-manager/react/components/VersionPreviewFrame.js +4 -1
- package/dist/features/version-manager/react/components/VersionSidebar.js +8 -6
- package/dist/features/version-manager/react/hooks/usePreviewCanvasSize.js +1 -1
- package/dist/features/version-manager/react/hooks/useVersionManager.js +5 -7
- package/dist/features/version-manager/rules.js +3 -5
- package/dist/features/viewer-shell/react/components/CommentSidePanel.js +2 -1
- package/dist/features/viewer-shell/react/components/SegmentedToggle.js +2 -1
- package/dist/features/viewer-shell/react/components/ViewerShell.js +2 -1
- package/dist/features/viewer-shell/rules.js +8 -7
- package/dist/react/components/AgentIcon.js +0 -1
- package/dist/react/components/BrandLogo.js +10 -2
- package/dist/react/components/CustomSelect.js +1 -1
- package/dist/react/components/EditorIcon.js +17 -14
- package/dist/react/components/Loading.js +2 -1
- package/dist/react/components/OnboardingChipField.js +5 -1
- package/dist/react/components/OnboardingDropdown.js +6 -4
- package/dist/react/components/PaletteTweaks.js +7 -6
- package/dist/react/components/PillButton.js +2 -1
- package/dist/react/components/PopoverMenu.js +2 -1
- package/dist/react/components/RemixIcon.js +2 -1
- package/dist/react/components/SecretInput.hooks.d.ts +2 -25
- package/dist/react/components/SecretInput.hooks.js +2 -24
- package/dist/react/components/SecretInput.js +5 -4
- package/dist/react/components/Toast.js +4 -2
- package/dist/react/components/TooltipLayer.js +4 -1
- package/dist/react/components/WorkingDirPicker.js +5 -4
- package/dist/react/components/agent-icon-data-uris.generated.js +0 -1
- package/dist/react/components/remixicon-font-recovery.js +9 -1
- package/dist/react/components/select-popover.js +2 -2
- package/dist/react/hooks/useBrandFonts.js +1 -1
- package/dist/react/hooks/useEdgeAutoScroll.js +1 -1
- package/dist/react/hooks/useInView.js +9 -9
- package/dist/react/hooks/useResizableSplitPane.js +12 -20
- package/dist/react/mcp-ui/useHostSurfaceTokens.js +1 -1
- package/dist/renderers/annotation-canvas/react/components/AnnotationCanvas.js +7 -1
- package/dist/renderers/annotation-canvas/react/hooks/useAnnotationCanvas.controller.js +4 -2
- package/dist/renderers/annotation-canvas/react/hooks/useAnnotationCanvas.js +9 -5
- package/dist/renderers/annotation-canvas/rules.js +9 -13
- package/dist/renderers/annotation-canvas/theme.js +5 -2
- package/dist/renderers/renderers/index.js +1 -1
- package/dist/renderers/renderers/markdown.js +4 -6
- package/dist/renderers/shiki.js +7 -1
- package/dist/theme/apply.js +7 -3
- package/dist/utils/class-names.d.ts +3 -0
- package/dist/utils/class-names.js +5 -0
- package/dist/utils/design-md.js +3 -3
- package/dist/utils/ime-composing.d.ts +1 -1
- package/dist/utils/ime-composing.js +1 -2
- package/dist/utils/localized-url.js +2 -11
- package/dist/utils/markdown-scroll-sync.js +1 -1
- package/dist/utils/omit-keys.d.ts +3 -0
- package/dist/utils/omit-keys.js +8 -0
- package/dist/utils/polygon-selection.js +1 -1
- package/dist/utils/sse.js +3 -0
- package/dist/utils/trim-chars.d.ts +13 -0
- package/dist/utils/trim-chars.js +30 -0
- package/dist/utils/unhandled-case.d.ts +10 -0
- package/dist/utils/unhandled-case.js +12 -0
- package/dist/utils/unit-bezier.js +1 -3
- package/dist/utils/zip.js +6 -10
- package/package.json +32 -29
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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
|
-
|
|
287
|
+
saveTicket.current += 1;
|
|
288
|
+
const ticket = saveTicket.current;
|
|
282
289
|
setSaveState({ status: "saving" });
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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:
|
|
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'
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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/
|
|
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 ??
|
|
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
|
|
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
|
|
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 ? (
|
|
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
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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);
|
|
@@ -23,8 +23,12 @@ export function formatTime12h(time) {
|
|
|
23
23
|
const h = Number(m[1]);
|
|
24
24
|
const mm = m[2];
|
|
25
25
|
const suffix = h >= 12 ? 'PM' : 'AM';
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
return `${to12Hour(h)}:${mm} ${suffix}`;
|
|
27
|
+
}
|
|
28
|
+
function to12Hour(h) {
|
|
29
|
+
if (h === 0)
|
|
30
|
+
return 12;
|
|
31
|
+
return h > 12 ? h - 12 : h;
|
|
28
32
|
}
|
|
29
33
|
function weekdayLongName(weekday, weekdays) {
|
|
30
34
|
return weekdays.find((w) => w.value === weekday)?.long ?? weekdays[0]?.long ?? 'Sunday';
|
|
@@ -39,11 +43,13 @@ export function decomposeSchedule(schedule, weekdays = DEFAULT_WEEKDAYS) {
|
|
|
39
43
|
if (schedule.kind === 'hourly') {
|
|
40
44
|
return { kind: 'hourly', minute: String(schedule.minute).padStart(2, '0') };
|
|
41
45
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
let freq;
|
|
47
|
+
if (schedule.kind === 'daily')
|
|
48
|
+
freq = 'Daily';
|
|
49
|
+
else if (schedule.kind === 'weekdays')
|
|
50
|
+
freq = 'Weekdays';
|
|
51
|
+
else
|
|
52
|
+
freq = weekdayLongName(schedule.weekday, weekdays);
|
|
47
53
|
return { kind: 'timed', freq, time: formatTime12h(schedule.time), tz: schedule.timezone };
|
|
48
54
|
}
|
|
49
55
|
/** Plain-English one-line summary, e.g. `'Hourly at :05'` or
|
|
@@ -2,12 +2,6 @@ import type { SketchTooltipTarget } from './types.js';
|
|
|
2
2
|
export declare const SAVED_VISIBLE_MS = 2000;
|
|
3
3
|
export declare const EXPORTED_IMAGE_MIME_TYPE = "image/png";
|
|
4
4
|
export declare const SKETCH_CONTEXT_MENU_MARGIN = 8;
|
|
5
|
-
/**
|
|
6
|
-
* Default tool/menu tooltip targets — these selectors and `data-testid`
|
|
7
|
-
* values are Excalidraw's own toolbar markup, not host-product content.
|
|
8
|
-
* Host-overridable via `SketchEditorProps.tooltipTargets` for a forked or
|
|
9
|
-
* newer Excalidraw build with different markup.
|
|
10
|
-
*/
|
|
11
5
|
export declare const DEFAULT_SKETCH_TOOLTIP_TARGETS: readonly SketchTooltipTarget[];
|
|
12
6
|
/**
|
|
13
7
|
* Default context-menu action allow-list + order. These are Excalidraw's
|
|
@@ -7,23 +7,25 @@ export const SKETCH_CONTEXT_MENU_MARGIN = 8;
|
|
|
7
7
|
* Host-overridable via `SketchEditorProps.tooltipTargets` for a forked or
|
|
8
8
|
* newer Excalidraw build with different markup.
|
|
9
9
|
*/
|
|
10
|
+
/** Anchor the tooltip on the toolbar button's wrapping `<label>`. */
|
|
11
|
+
const CLOSEST_LABEL = 'closest-label';
|
|
10
12
|
export const DEFAULT_SKETCH_TOOLTIP_TARGETS = [
|
|
11
13
|
{ selector: '[data-testid="main-menu-trigger"]', label: 'mainMenu', placement: 'bottom' },
|
|
12
|
-
{ selector: '[data-testid="toolbar-lock"]', target:
|
|
13
|
-
{ selector: '[data-testid="toolbar-hand"]', target:
|
|
14
|
-
{ selector: '[data-testid="toolbar-selection"]', target:
|
|
15
|
-
{ selector: '[data-testid="toolbar-rectangle"]', target:
|
|
16
|
-
{ selector: '[data-testid="toolbar-diamond"]', target:
|
|
17
|
-
{ selector: '[data-testid="toolbar-ellipse"]', target:
|
|
18
|
-
{ selector: '[data-testid="toolbar-arrow"]', target:
|
|
19
|
-
{ selector: '[data-testid="toolbar-line"]', target:
|
|
20
|
-
{ selector: '[data-testid="toolbar-freedraw"]', target:
|
|
21
|
-
{ selector: '[data-testid="toolbar-text"]', target:
|
|
22
|
-
{ selector: '[data-testid="toolbar-image"]', target:
|
|
23
|
-
{ selector: '[data-testid="toolbar-eraser"]', target:
|
|
24
|
-
{ selector: '[data-testid="toolbar-frame"]', target:
|
|
25
|
-
{ selector: '[data-testid="toolbar-embeddable"]', target:
|
|
26
|
-
{ selector: '[data-testid="toolbar-laser"]', target:
|
|
14
|
+
{ selector: '[data-testid="toolbar-lock"]', target: CLOSEST_LABEL, label: 'lock', placement: 'bottom' },
|
|
15
|
+
{ selector: '[data-testid="toolbar-hand"]', target: CLOSEST_LABEL, label: 'hand', placement: 'bottom' },
|
|
16
|
+
{ selector: '[data-testid="toolbar-selection"]', target: CLOSEST_LABEL, label: 'selection', placement: 'bottom' },
|
|
17
|
+
{ selector: '[data-testid="toolbar-rectangle"]', target: CLOSEST_LABEL, label: 'rectangle', placement: 'bottom' },
|
|
18
|
+
{ selector: '[data-testid="toolbar-diamond"]', target: CLOSEST_LABEL, label: 'diamond', placement: 'bottom' },
|
|
19
|
+
{ selector: '[data-testid="toolbar-ellipse"]', target: CLOSEST_LABEL, label: 'ellipse', placement: 'bottom' },
|
|
20
|
+
{ selector: '[data-testid="toolbar-arrow"]', target: CLOSEST_LABEL, label: 'arrow', placement: 'bottom' },
|
|
21
|
+
{ selector: '[data-testid="toolbar-line"]', target: CLOSEST_LABEL, label: 'line', placement: 'bottom' },
|
|
22
|
+
{ selector: '[data-testid="toolbar-freedraw"]', target: CLOSEST_LABEL, label: 'freedraw', placement: 'bottom' },
|
|
23
|
+
{ selector: '[data-testid="toolbar-text"]', target: CLOSEST_LABEL, label: 'text', placement: 'bottom' },
|
|
24
|
+
{ selector: '[data-testid="toolbar-image"]', target: CLOSEST_LABEL, label: 'image', placement: 'bottom' },
|
|
25
|
+
{ selector: '[data-testid="toolbar-eraser"]', target: CLOSEST_LABEL, label: 'eraser', placement: 'bottom' },
|
|
26
|
+
{ selector: '[data-testid="toolbar-frame"]', target: CLOSEST_LABEL, label: 'frame', placement: 'bottom' },
|
|
27
|
+
{ selector: '[data-testid="toolbar-embeddable"]', target: CLOSEST_LABEL, label: 'embeddable', placement: 'bottom' },
|
|
28
|
+
{ selector: '[data-testid="toolbar-laser"]', target: CLOSEST_LABEL, label: 'laser', placement: 'bottom' },
|
|
27
29
|
{ selector: '.App-toolbar__extra-tools-trigger', label: 'moreTools', placement: 'bottom' },
|
|
28
30
|
];
|
|
29
31
|
/**
|
|
@@ -109,18 +109,15 @@ function hasRecognizedContextMenuAction(menu, recognized) {
|
|
|
109
109
|
function pruneContextMenuItems(menu, allowed) {
|
|
110
110
|
const byAction = new Map();
|
|
111
111
|
for (const child of Array.from(menu.children)) {
|
|
112
|
-
if (child instanceof HTMLHRElement)
|
|
112
|
+
if (child instanceof HTMLHRElement)
|
|
113
113
|
child.remove();
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
114
|
if (!(child instanceof HTMLLIElement))
|
|
117
115
|
continue;
|
|
118
116
|
const actionName = child.getAttribute('data-testid') ?? '';
|
|
119
|
-
if (
|
|
117
|
+
if (allowed.has(actionName))
|
|
118
|
+
byAction.set(actionName, child);
|
|
119
|
+
else
|
|
120
120
|
child.remove();
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
byAction.set(actionName, child);
|
|
124
121
|
}
|
|
125
122
|
return byAction;
|
|
126
123
|
}
|
|
@@ -2,7 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { Icon } from '../../../../react/components/Icon.js';
|
|
3
3
|
/** The composed `<MainMenu>` Excalidraw renders inside its own menu popover. */
|
|
4
4
|
export function SketchMainMenu({ MainMenu, t, saving, showSaved, canSave, onSave, exportAvailable, exporting, canExport, onExportImage, canClear, onClear, }) {
|
|
5
|
-
const
|
|
5
|
+
const idleSaveLabel = showSaved ? t('Saved') : t('Save');
|
|
6
|
+
const saveLabel = saving ? t('Saving…') : idleSaveLabel;
|
|
6
7
|
const exportLabel = exporting ? t('Exporting image…') : t('Export image');
|
|
7
8
|
return (_jsxs(MainMenu, { children: [_jsx(MainMenu.Item, { "data-testid": "sketch-menu-save", icon: showSaved ? _jsx(Icon, { name: "check", size: 16 }) : undefined, onClick: onSave, disabled: saving || !canSave, "aria-label": saveLabel, children: saveLabel }), exportAvailable ? (_jsx(MainMenu.Item, { "data-testid": "sketch-menu-export-image", icon: _jsx(Icon, { name: "download", size: 16 }), onClick: onExportImage, disabled: exporting || !canExport, "aria-label": exportLabel, children: exportLabel })) : null, _jsx(MainMenu.Separator, {}), _jsx(MainMenu.DefaultItems.SearchMenu, {}), _jsx(MainMenu.DefaultItems.Help, {}), _jsx(MainMenu.Item, { "data-testid": "sketch-menu-clear", icon: _jsx(Icon, { name: "trash", size: 16 }), onClick: onClear, disabled: !canClear, children: t('Clear canvas') }), _jsx(MainMenu.Separator, {}), _jsx(MainMenu.DefaultItems.ChangeCanvasBackground, {})] }));
|
|
8
9
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Icon } from '../../../../react/components/Icon.js';
|
|
3
|
+
const STATE_ICONS = { saving: 'spinner', dirty: 'alert-triangle' };
|
|
3
4
|
/** The small save-state indicator rendered in Excalidraw's own top-right UI slot. */
|
|
4
5
|
export function SketchSaveStateBadge({ state, label }) {
|
|
5
|
-
return (_jsx("div", { className: "sketch-excalidraw-actions", "data-testid": "sketch-save-state", children: _jsxs("span", { className: `sketch-save-state is-${state}`, role: "status", "aria-live": "polite", children: [_jsx(Icon, { name: state
|
|
6
|
+
return (_jsx("div", { className: "sketch-excalidraw-actions", "data-testid": "sketch-save-state", children: _jsxs("span", { className: `sketch-save-state is-${state}`, role: "status", "aria-live": "polite", children: [_jsx(Icon, { name: STATE_ICONS[state] ?? 'check', size: 12, className: state === 'saving' ? 'icon-spin' : undefined }), _jsx("span", { children: label })] }) }));
|
|
6
7
|
}
|
|
7
8
|
//# sourceMappingURL=SketchSaveStateBadge.js.map
|
|
@@ -16,7 +16,7 @@ export function useSketchDomEnhancements({ containerRef, t, domTextOverrides, to
|
|
|
16
16
|
useEffect(() => {
|
|
17
17
|
const root = containerRef.current;
|
|
18
18
|
if (!root)
|
|
19
|
-
return;
|
|
19
|
+
return undefined;
|
|
20
20
|
let frame = null;
|
|
21
21
|
const applyEnhancements = () => {
|
|
22
22
|
frame = null;
|