@jini-ai/ui 0.5.5 → 0.5.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/core/theme/validation.js +40 -38
- package/dist/features/a2ui/renderer.js +15 -13
- package/dist/features/about/react/components/AboutTab.js +64 -34
- package/dist/features/about/rules.d.ts +2 -2
- package/dist/features/about/rules.js +156 -129
- package/dist/features/admin-widgets/components/ImagePreviewModal.d.ts +4 -3
- package/dist/features/admin-widgets/components/ImagePreviewModal.js +6 -10
- package/dist/features/admin-widgets/components/InfoTip.d.ts +3 -2
- package/dist/features/admin-widgets/components/InfoTip.hooks.js +2 -0
- package/dist/features/admin-widgets/components/InfoTip.js +34 -7
- package/dist/features/admin-widgets/components/InfoTip.rules.d.ts +13 -0
- package/dist/features/admin-widgets/components/InfoTip.rules.js +43 -10
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.d.ts +30 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.d.ts +40 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.hooks.js +128 -0
- package/dist/features/admin-widgets/components/Lightbox/Lightbox.js +18 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.d.ts +14 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.js +12 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.rules.d.ts +20 -0
- package/dist/features/admin-widgets/components/MiddleTruncate.rules.js +21 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.d.ts +18 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.d.ts +16 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.hooks.js +45 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.js +18 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.d.ts +32 -0
- package/dist/features/admin-widgets/components/ScrollJump/ScrollJump.rules.js +26 -0
- package/dist/features/admin-widgets/components/SuggestInput/SuggestInput.hooks.js +29 -14
- package/dist/features/admin-widgets/index.d.ts +14 -2
- package/dist/features/admin-widgets/index.js +7 -1
- package/dist/features/admin-widgets/styles/admin-widgets.css +1 -0
- package/dist/features/asset-grid/react/components/AssetCard.js +7 -1
- package/dist/features/asset-grid/react/components/AssetGrid.d.ts +1 -1
- package/dist/features/asset-grid/react/components/AssetGrid.js +38 -18
- package/dist/features/asset-grid/react/components/useAssetGridFilters.d.ts +21 -0
- package/dist/features/asset-grid/react/components/useAssetGridFilters.js +19 -0
- package/dist/features/asset-grid/react/hooks/useAssetGridKeyboardShortcuts.js +16 -11
- package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.d.ts +2 -0
- package/dist/features/asset-grid/react/hooks/useAssetGridLiveUpdates.js +35 -11
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.d.ts +6 -6
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowser.js +10 -129
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.d.ts +50 -0
- package/dist/features/asset-tree-browser/react/components/AssetTreeBrowserParts.js +95 -0
- package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.d.ts +56 -0
- package/dist/features/asset-tree-browser/react/components/useAssetTreeBrowserController.js +80 -0
- package/dist/features/asset-tree-browser/rules.js +40 -22
- package/dist/features/browser-chrome/rules.js +74 -70
- package/dist/features/charts/browser.js +11 -5
- package/dist/features/charts/react.js +2 -2
- package/dist/features/charts/table.js +2 -2
- package/dist/features/command-palette/react/hooks/useCommandPalette.js +3 -9
- package/dist/features/connectors/ConnectorsBrowser.d.ts +4 -4
- package/dist/features/connectors/ConnectorsBrowser.js +26 -14
- package/dist/features/connectors/components/ConnectorCard.js +67 -38
- package/dist/features/connectors/components/ConnectorDetailDrawer.js +62 -31
- package/dist/features/connectors/components/ConnectorGrid.js +11 -6
- package/dist/features/connectors/hooks/useConnectorAuthorization.js +6 -0
- package/dist/features/connectors/hooks/useConnectorCatalog.d.ts +2 -0
- package/dist/features/connectors/hooks/useConnectorCatalog.js +32 -13
- package/dist/features/connectors/hooks/useWiredConnectorsBrowser.d.ts +3 -3
- package/dist/features/connectors/rules.d.ts +8 -1
- package/dist/features/connectors/rules.js +42 -20
- package/dist/features/connectors/types.d.ts +11 -0
- package/dist/features/execution/constants.d.ts +4 -10
- package/dist/features/execution/constants.js +9 -94
- package/dist/features/execution/react/components/ByokProviderForm.d.ts +2 -4
- package/dist/features/execution/react/components/ByokProviderForm.js +140 -43
- package/dist/features/execution/react/components/ExecutionTab.d.ts +1 -2
- package/dist/features/execution/react/components/ExecutionTab.js +52 -30
- package/dist/features/execution/react/components/LocalCliAgentCard.js +12 -3
- package/dist/features/execution/react/components/LocalCliAgentList.js +14 -3
- package/dist/features/execution/react/components/LocalCliAgentSettings.js +14 -3
- package/dist/features/execution/react/hooks/useLocalCliAgentCard.js +54 -36
- package/dist/features/execution/react/hooks/useReasoningControl.js +114 -78
- package/dist/features/execution/rules.d.ts +2 -2
- package/dist/features/execution/rules.js +31 -15
- package/dist/features/execution/types.d.ts +4 -42
- package/dist/features/execution/types.js +0 -17
- package/dist/features/external-mcp/react/components/ExternalMcpTab.d.ts +6 -2
- package/dist/features/external-mcp/react/components/ExternalMcpTab.js +9 -2
- package/dist/features/file-dropzone/react/components/FileDropzone.js +24 -25
- package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.d.ts +2 -2
- package/dist/features/file-dropzone/react/components/FileDropzoneLightbox.js +35 -30
- package/dist/features/file-dropzone/react/components/FileDropzoneThumbnailGrid.js +30 -24
- package/dist/features/file-dropzone/react/components/FileDropzoneZone.d.ts +14 -0
- package/dist/features/file-dropzone/react/components/FileDropzoneZone.js +26 -0
- package/dist/features/html-editor/canvas-content-wrapper.js +13 -13
- package/dist/features/html-editor/canvas-embed-placeholders.js +46 -37
- package/dist/features/html-editor/css.js +76 -69
- package/dist/features/html-editor/editor-blocks.js +47 -33
- package/dist/features/html-editor/editor-serialization.js +6 -5
- package/dist/features/html-editor/protected-elements.js +39 -28
- package/dist/features/html-editor/react/hooks/useInteractiveHtmlEditor.js +4 -4
- package/dist/features/html-editor/source-splice.js +51 -30
- package/dist/features/i18n/dictionaries/settings-dialog.ja.js +1 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-CN.js +1 -0
- package/dist/features/i18n/dictionaries/settings-dialog.zh-TW.js +1 -0
- package/dist/features/i18n/locale.js +20 -16
- package/dist/features/iframe-pool/react/dom-sync.js +8 -6
- package/dist/features/integrations/react/components/CodexInstallToggleButton.js +19 -4
- package/dist/features/integrations/react/components/IntegrationsTab.js +60 -14
- package/dist/features/interactive-ui/interactive-ui.css +1 -1
- package/dist/features/interactive-ui/providers/shadcn/data-table.js +10 -7
- package/dist/features/lexical-rich-text-editor/mention-parser.js +60 -57
- package/dist/features/lexical-rich-text-editor/react/hooks/useKeyboardCommands.js +33 -38
- package/dist/features/lexical-rich-text-editor/rules.js +87 -74
- package/dist/features/lexical-rich-text-editor/serialize.js +27 -25
- package/dist/features/mcp-ui/secret-card.js +111 -61
- package/dist/features/mcp-ui/surfaces/confirmation.js +39 -21
- package/dist/features/mcp-ui/surfaces/document.d.ts +1 -1
- package/dist/features/mcp-ui/surfaces/document.js +10 -2
- package/dist/features/mcp-ui/surfaces/fields.js +30 -50
- package/dist/features/mcp-ui/surfaces/form.d.ts +6 -0
- package/dist/features/mcp-ui/surfaces/form.js +43 -21
- package/dist/features/mcp-ui/surfaces/outcome.js +30 -20
- package/dist/features/mcp-ui/surfaces/text-input.js +33 -21
- package/dist/features/mcp-ui/surfaces/tokens.d.ts +6 -1
- package/dist/features/mcp-ui/surfaces/tokens.js +5 -2
- package/dist/features/media-providers/constants.d.ts +1 -0
- package/dist/features/media-providers/constants.js +2 -81
- package/dist/features/media-providers/index.d.ts +1 -1
- package/dist/features/media-providers/ports.d.ts +2 -0
- package/dist/features/media-providers/react/components/MediaProviderCard.d.ts +22 -0
- package/dist/features/media-providers/react/components/MediaProviderCard.js +50 -0
- package/dist/features/media-providers/react/components/MediaProvidersTab.d.ts +5 -6
- package/dist/features/media-providers/react/components/MediaProvidersTab.js +40 -72
- package/dist/features/media-providers/react/components/media-providers-tab-labels.d.ts +11 -0
- package/dist/features/media-providers/react/components/media-providers-tab-labels.js +57 -0
- package/dist/features/media-providers/react/hooks/useMediaProvidersTab.d.ts +4 -2
- package/dist/features/media-providers/react/hooks/useMediaProvidersTab.js +37 -23
- package/dist/features/media-providers/rules.js +17 -10
- package/dist/features/media-providers/types.d.ts +4 -22
- package/dist/features/media-providers/types.js +3 -8
- package/dist/features/memory/formatters.js +127 -92
- package/dist/features/memory/react/components/MemoryConnectedPanel.js +92 -36
- package/dist/features/memory/react/components/MemoryList.js +37 -18
- package/dist/features/memory/react/hooks/useMemoryExtractions.store.js +42 -36
- package/dist/features/notifications/react/components/NotificationsTab.js +28 -28
- package/dist/features/observability/long-task.d.ts +0 -12
- package/dist/features/observability/long-task.js +15 -19
- package/dist/features/observability/resource-error.d.ts +0 -10
- package/dist/features/observability/resource-error.js +18 -13
- package/dist/features/observability/stuck-run.js +10 -6
- package/dist/features/observability/telemetry-url.d.ts +6 -0
- package/dist/features/observability/telemetry-url.js +16 -0
- package/dist/features/observability/white-screen.js +12 -24
- package/dist/features/panel-kit/fetch-query/adapter.react.d.ts +2 -2
- package/dist/features/panel-kit/fetch-query/adapter.react.js +4 -2
- package/dist/features/panel-kit/fetch-query/adapter.tanstack.js +46 -33
- package/dist/features/panel-kit/helpers/standing-draft-local-backup.js +3 -1
- package/dist/features/panel-kit/hooks/use-settings-slice.hooks.js +3 -1
- package/dist/features/privacy/react/components/PrivacyTab.js +24 -13
- package/dist/features/progress-card/components/ProgressCard.js +7 -3
- package/dist/features/progress-card/reference-adapters.js +59 -54
- package/dist/features/project-locations/react/components/ProjectLocationsTab.js +24 -15
- package/dist/features/project-locations/react/hooks/useProjectLocationsTab.d.ts +8 -0
- package/dist/features/project-locations/react/hooks/useProjectLocationsTab.js +31 -23
- package/dist/features/resource-dashboard/react/components/ResourceBoard.js +6 -47
- package/dist/features/resource-dashboard/react/components/ResourceBoardView.d.ts +2 -2
- package/dist/features/resource-dashboard/react/components/ResourceBoardView.js +3 -6
- package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.d.ts +15 -0
- package/dist/features/resource-dashboard/react/components/ResourceBoardViewParts.js +35 -0
- package/dist/features/resource-dashboard/react/components/ResourceCard.js +5 -16
- package/dist/features/resource-dashboard/react/components/ResourceCardParts.d.ts +34 -0
- package/dist/features/resource-dashboard/react/components/ResourceCardParts.js +34 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowList.js +3 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListItem.js +2 -2
- package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.d.ts +19 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListItemParts.js +11 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListView.d.ts +1 -1
- package/dist/features/resource-dashboard/react/components/ResourceRowListView.js +4 -4
- package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.d.ts +10 -0
- package/dist/features/resource-dashboard/react/components/ResourceRowListViewParts.js +20 -0
- package/dist/features/resource-dashboard/react/components/resourceBoardProps.d.ts +48 -0
- package/dist/features/resource-dashboard/react/components/resourceBoardProps.js +70 -0
- package/dist/features/resource-dashboard/react/components/resourceRowListProps.d.ts +19 -0
- package/dist/features/resource-dashboard/react/components/resourceRowListProps.js +14 -0
- package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.d.ts +16 -0
- package/dist/features/resource-dashboard/react/components/translatedErrorLabelProps.js +13 -0
- package/dist/features/resource-dashboard/rules.js +2 -8
- package/dist/features/sketch-editor/dom.js +150 -99
- package/dist/features/sketch-editor/react/components/SketchEditor.js +26 -15
- package/dist/features/skills/react/components/SkillDraftForm.js +13 -19
- package/dist/features/skills/react/components/SkillDraftForm.labels.d.ts +31 -0
- package/dist/features/skills/react/components/SkillDraftForm.labels.js +54 -0
- package/dist/features/skills/react/components/SkillRow.js +38 -18
- package/dist/features/skills/react/components/SkillRow.labels.d.ts +7 -0
- package/dist/features/skills/react/components/SkillRow.labels.js +18 -0
- package/dist/features/skills/react/components/SkillsTab.js +24 -14
- package/dist/features/skills/react/components/SkillsTab.labels.d.ts +7 -0
- package/dist/features/skills/react/components/SkillsTab.labels.js +11 -0
- package/dist/features/skills/rules.js +32 -23
- package/dist/features/source-config-list/agent-handles.js +2 -1
- package/dist/features/source-config-list/dependencies.js +53 -49
- package/dist/features/source-config-list/index.d.ts +3 -3
- package/dist/features/source-config-list/react/components/SourceConfigAddForm.d.ts +6 -5
- package/dist/features/source-config-list/react/components/SourceConfigAddForm.js +38 -7
- package/dist/features/source-config-list/react/components/SourceConfigField.js +69 -25
- package/dist/features/source-config-list/react/components/SourceConfigItemCard.d.ts +6 -5
- package/dist/features/source-config-list/react/components/SourceConfigItemCard.js +76 -20
- package/dist/features/source-config-list/react/components/SourceConfigListView.d.ts +5 -3
- package/dist/features/source-config-list/react/components/SourceConfigListView.js +33 -3
- package/dist/features/source-config-list/react/components/SourceConfigTestControl.js +17 -1
- package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.d.ts +11 -0
- package/dist/features/source-config-list/react/components/SourceConfigTrustOptions.js +12 -0
- package/dist/features/source-config-list/types.d.ts +14 -0
- package/dist/features/tab-launcher-menu/react/components/TabLauncherMenu.js +25 -1
- package/dist/features/tab-launcher-menu/react/hooks/useTabLauncherMenu.js +15 -16
- package/dist/features/tab-strip/react/components/TabBar.js +8 -1
- package/dist/features/tabbed-dialog/react/components/TabbedDialog.js +8 -30
- package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.d.ts +15 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogChrome.js +8 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.d.ts +12 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogHeader.js +6 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.d.ts +27 -0
- package/dist/features/tabbed-dialog/react/components/TabbedDialogSidebar.js +12 -0
- package/dist/features/tabbed-dialog/react/components/tabbedDialogView.d.ts +43 -0
- package/dist/features/tabbed-dialog/react/components/tabbedDialogView.js +59 -0
- package/dist/features/version-manager/dependencies.d.ts +3 -1
- package/dist/features/version-manager/dependencies.js +3 -2
- package/dist/features/version-manager/react/components/VersionManagerModal.js +10 -6
- package/dist/features/version-manager/react/hooks/useVersionManager.js +7 -4
- package/dist/features/viewer-shell/react/components/CommentSidePanel.js +103 -50
- package/dist/features/viewer-shell/react/components/MarkdownSplitPane.js +28 -8
- package/dist/features/viewer-shell/react/hooks/useCommentReorder.js +22 -16
- package/dist/features/viewer-shell/rules.js +19 -23
- package/dist/react/components/CustomSelect.d.ts +38 -1
- package/dist/react/components/CustomSelect.js +94 -38
- package/dist/react/components/OnboardingDropdown.js +20 -8
- package/dist/react/components/RemixIcon.stylesheet.js +3 -1
- package/dist/react/components/Toast.js +13 -2
- package/dist/react/components/TooltipLayer.js +5 -14
- package/dist/react/components/WorkingDirPicker.js +78 -50
- package/dist/react/components/remixicon-font-recovery.js +38 -30
- package/dist/react/components/select-popover.d.ts +8 -6
- package/dist/react/components/select-popover.js +33 -29
- package/dist/react/mcp-ui/McpUiHost.d.ts +1 -1
- package/dist/react/mcp-ui/McpUiHost.js +10 -11
- package/dist/react/mcp-ui/host-message-source.d.ts +14 -2
- package/dist/react/mcp-ui/host-message-source.js +15 -5
- package/dist/react/mcp-ui/mcp-ui-host-frame.d.ts +41 -0
- package/dist/react/mcp-ui/mcp-ui-host-frame.js +39 -0
- package/dist/renderers/annotation-canvas/react/components/AnnotationCanvas.js +97 -69
- package/dist/renderers/preview-modal-shell/react/components/PreviewModalShell.js +59 -30
- package/dist/renderers/react/components/ArtifactView.js +9 -6
- package/dist/renderers/srcdoc/build.d.ts +4 -1
- package/dist/renderers/srcdoc/build.js +62 -48
- package/dist/styles/admin.css +29 -14
- package/dist/styles/lightbox.css +142 -0
- package/dist/styles/variables.css +128 -0
- package/dist/theme/apply.js +9 -5
- package/dist/utils/auto-open-file.d.ts +2 -1
- package/dist/utils/auto-open-file.js +69 -85
- package/dist/utils/markdown-scroll-sync.js +108 -87
- package/dist/utils/polygon-selection.js +25 -26
- package/dist/utils/smooth-scroll-to-top.d.ts +1 -1
- package/dist/utils/smooth-scroll-to-top.js +2 -32
- package/dist/utils/sse.js +26 -26
- package/dist/utils/unit-bezier.d.ts +7 -0
- package/dist/utils/unit-bezier.js +38 -0
- package/package.json +7 -10
- package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.d.ts +0 -13
- package/dist/features/admin-widgets/components/ImagePreviewModal.hooks.js +0 -46
|
@@ -2,27 +2,26 @@ import { DEFAULT_HOME_NAVIGATION_ENTRY, EMPTY_URL, HISTORY_LIMIT } from './const
|
|
|
2
2
|
function escapeRegExp(value) {
|
|
3
3
|
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
4
4
|
}
|
|
5
|
+
/** Resolves a `/`-rooted address: against `appOrigin` when it matches a configured app-route prefix, else as a local `file://` path. */
|
|
6
|
+
function resolveAbsolutePath(value, options) {
|
|
7
|
+
const { appRoutePrefixes = [], appOrigin } = options;
|
|
8
|
+
if (appOrigin && appRoutePrefixes.length > 0) {
|
|
9
|
+
const prefixPattern = new RegExp(`^/(${appRoutePrefixes.map(escapeRegExp).join('|')})(/|$)`);
|
|
10
|
+
if (prefixPattern.test(value))
|
|
11
|
+
return new URL(value, appOrigin).toString();
|
|
12
|
+
}
|
|
13
|
+
return `file://${encodeURI(value)}`;
|
|
14
|
+
}
|
|
5
15
|
export function normalizeBrowserAddress(rawAddress, options = {}) {
|
|
6
16
|
const value = rawAddress.trim();
|
|
7
|
-
if (!value)
|
|
8
|
-
return EMPTY_URL;
|
|
9
|
-
if (value === EMPTY_URL)
|
|
17
|
+
if (!value || value === EMPTY_URL)
|
|
10
18
|
return EMPTY_URL;
|
|
11
19
|
if (/^(https?|file):\/\//i.test(value))
|
|
12
20
|
return value;
|
|
13
|
-
if (/^localhost(:\d+)?(\/.*)?$/i.test(value))
|
|
21
|
+
if (/^(localhost|127\.0\.0\.1|0\.0\.0\.0)(:\d+)?(\/.*)?$/i.test(value))
|
|
14
22
|
return `http://${value}`;
|
|
15
|
-
if (
|
|
16
|
-
return
|
|
17
|
-
if (value.startsWith('/')) {
|
|
18
|
-
const { appRoutePrefixes = [], appOrigin } = options;
|
|
19
|
-
if (appOrigin && appRoutePrefixes.length > 0) {
|
|
20
|
-
const prefixPattern = new RegExp(`^/(${appRoutePrefixes.map(escapeRegExp).join('|')})(/|$)`);
|
|
21
|
-
if (prefixPattern.test(value))
|
|
22
|
-
return new URL(value, appOrigin).toString();
|
|
23
|
-
}
|
|
24
|
-
return `file://${encodeURI(value)}`;
|
|
25
|
-
}
|
|
23
|
+
if (value.startsWith('/'))
|
|
24
|
+
return resolveAbsolutePath(value, options);
|
|
26
25
|
if (/^[\w.-]+\.[a-z]{2,}(:\d+)?(\/.*)?$/i.test(value))
|
|
27
26
|
return `https://${value}`;
|
|
28
27
|
return `https://www.google.com/search?q=${encodeURIComponent(value)}`;
|
|
@@ -137,37 +136,37 @@ export function mergeHistoryEntry(history, url, meta = {}, options = {}, now = D
|
|
|
137
136
|
if (!isHistoryUrl(url))
|
|
138
137
|
return history;
|
|
139
138
|
const existing = history.find((entry) => sameUrl(entry.url, url));
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const nextTitle = meta.title && meta.title.trim()
|
|
143
|
-
? meta.title.trim()
|
|
144
|
-
: existing?.title || labelFromUrl(url);
|
|
145
|
-
const nextIconUrl = cleanIconUrl(meta.iconUrl) || existing?.iconUrl || faviconUrl(url);
|
|
146
|
-
const visitIncrement = options.countVisit === false ? 0 : 1;
|
|
147
|
-
const entry = existing
|
|
148
|
-
? {
|
|
149
|
-
...existing,
|
|
150
|
-
...(nextIconUrl !== undefined ? { iconUrl: nextIconUrl } : {}),
|
|
151
|
-
title: nextTitle,
|
|
152
|
-
lastVisitedAt: visitIncrement > 0 ? now : existing.lastVisitedAt,
|
|
153
|
-
visitCount: existing.visitCount + visitIncrement,
|
|
154
|
-
}
|
|
155
|
-
: {
|
|
156
|
-
...(nextIconUrl !== undefined ? { iconUrl: nextIconUrl } : {}),
|
|
157
|
-
title: nextTitle,
|
|
158
|
-
url,
|
|
159
|
-
lastVisitedAt: now,
|
|
160
|
-
visitCount: 1,
|
|
161
|
-
};
|
|
162
|
-
if (existing
|
|
163
|
-
&& existing.title === entry.title
|
|
164
|
-
&& existing.iconUrl === entry.iconUrl
|
|
165
|
-
&& existing.lastVisitedAt === entry.lastVisitedAt
|
|
166
|
-
&& existing.visitCount === entry.visitCount) {
|
|
139
|
+
const entry = buildHistoryEntry({ url, meta, now, countVisit: options.countVisit !== false }, { existing });
|
|
140
|
+
if (existing && sameHistoryEntryState(existing, entry))
|
|
167
141
|
return history;
|
|
168
|
-
}
|
|
169
142
|
return [entry, ...history.filter((item) => !sameUrl(item.url, url))].slice(0, HISTORY_LIMIT);
|
|
170
143
|
}
|
|
144
|
+
/** Builds the merged entry for `url`: an update of `existing` when present, otherwise a fresh first-visit entry. */
|
|
145
|
+
function buildHistoryEntry({ url, meta, now, countVisit }, { existing }) {
|
|
146
|
+
const resolved = resolveHistoryMeta({ url, meta }, { existing });
|
|
147
|
+
if (!existing)
|
|
148
|
+
return { ...resolved, url, lastVisitedAt: now, visitCount: 1 };
|
|
149
|
+
return {
|
|
150
|
+
...existing,
|
|
151
|
+
...resolved,
|
|
152
|
+
lastVisitedAt: countVisit ? now : existing.lastVisitedAt,
|
|
153
|
+
visitCount: existing.visitCount + (countVisit ? 1 : 0),
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/** Title and icon for a merged entry: the caller's meta wins, then the existing entry's, then values derived from `url`. */
|
|
157
|
+
function resolveHistoryMeta({ url, meta }, { existing }) {
|
|
158
|
+
// `isHistoryUrl` above already excludes `EMPTY_URL`, so `labelFromUrl`'s
|
|
159
|
+
// home-label branch can never trigger here — no `homeLabel` option to pass.
|
|
160
|
+
const title = meta.title?.trim() || existing?.title || labelFromUrl(url);
|
|
161
|
+
const iconUrl = cleanIconUrl(meta.iconUrl) || existing?.iconUrl || faviconUrl(url);
|
|
162
|
+
return iconUrl !== undefined ? { iconUrl, title } : { title };
|
|
163
|
+
}
|
|
164
|
+
function sameHistoryEntryState(left, right) {
|
|
165
|
+
return (left.title === right.title
|
|
166
|
+
&& left.iconUrl === right.iconUrl
|
|
167
|
+
&& left.lastVisitedAt === right.lastVisitedAt
|
|
168
|
+
&& left.visitCount === right.visitCount);
|
|
169
|
+
}
|
|
171
170
|
// ---------------------------------------------------------------------------
|
|
172
171
|
// Navigation stack
|
|
173
172
|
// ---------------------------------------------------------------------------
|
|
@@ -201,6 +200,20 @@ export function recordNavigation(state, url, title, options = {}) {
|
|
|
201
200
|
if (url !== EMPTY_URL && !isHistoryUrl(url))
|
|
202
201
|
return state;
|
|
203
202
|
const { navigationStack: stack, navigationIndex: index } = state;
|
|
203
|
+
const nextTitle = navigationTitle({ url }, { title, homeLabel: options.homeLabel });
|
|
204
|
+
const rejoin = findRejoinTarget({ state, url }, options);
|
|
205
|
+
if (rejoin) {
|
|
206
|
+
const next = stack.slice();
|
|
207
|
+
// `nextTitle` is only ever '' for EMPTY_URL with an explicit '' homeLabel;
|
|
208
|
+
// keep the rejoined entry's own title rather than blanking it.
|
|
209
|
+
next[rejoin.index] = { title: nextTitle || rejoin.entry.title, url };
|
|
210
|
+
return { navigationStack: next, navigationIndex: rejoin.index };
|
|
211
|
+
}
|
|
212
|
+
const base = index >= 0 ? stack.slice(0, index + 1) : [];
|
|
213
|
+
const nextStack = [...base, { title: nextTitle, url }].slice(-HISTORY_LIMIT);
|
|
214
|
+
return { navigationStack: nextStack, navigationIndex: nextStack.length - 1 };
|
|
215
|
+
}
|
|
216
|
+
function navigationTitle({ url }, { title, homeLabel }) {
|
|
204
217
|
// Bug fix: this used to hardcode DEFAULT_HOME_NAVIGATION_ENTRY.title here,
|
|
205
218
|
// ignoring a caller-supplied `options.homeLabel` — so a host configuring a
|
|
206
219
|
// custom `homeEntry` (via useBrowserNavigationStack) would see the entry's
|
|
@@ -208,34 +221,25 @@ export function recordNavigation(state, url, title, options = {}) {
|
|
|
208
221
|
// even though `initialNavigationState`/`labelFromUrl` both honor the
|
|
209
222
|
// custom label correctly. Falls back to the generic default only when no
|
|
210
223
|
// homeLabel is supplied.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
};
|
|
223
|
-
const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
return { navigationStack: updateEntry(stack, index), navigationIndex: index };
|
|
227
|
-
}
|
|
228
|
-
const previousIndex = index - 1;
|
|
229
|
-
if (previousIndex >= 0 && sameUrl(stack[previousIndex]?.url ?? '', url)) {
|
|
230
|
-
return { navigationStack: updateEntry(stack, previousIndex), navigationIndex: previousIndex };
|
|
231
|
-
}
|
|
232
|
-
const nextIndex = index + 1;
|
|
233
|
-
if (nextIndex < stack.length && sameUrl(stack[nextIndex]?.url ?? '', url)) {
|
|
234
|
-
return { navigationStack: updateEntry(stack, nextIndex), navigationIndex: nextIndex };
|
|
224
|
+
if (url === EMPTY_URL)
|
|
225
|
+
return homeLabel ?? DEFAULT_HOME_NAVIGATION_ENTRY.title;
|
|
226
|
+
return title?.trim() || labelFromUrl(url, homeLabel);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* The stack entry `url` should update in place instead of appending: the
|
|
230
|
+
* current entry (same url, or the pending-load target being replaced), else
|
|
231
|
+
* the adjacent back entry, else the adjacent forward entry. An out-of-range
|
|
232
|
+
* index reads as `undefined`, which never matches.
|
|
233
|
+
*/
|
|
234
|
+
function findRejoinTarget({ state, url }, { replacePendingTarget, pendingTarget }) {
|
|
235
|
+
const { navigationStack: stack, navigationIndex: index } = state;
|
|
236
|
+
const current = stack[index];
|
|
237
|
+
if (current && (sameUrl(current.url, url) || (replacePendingTarget && pendingTarget && sameUrl(current.url, pendingTarget)))) {
|
|
238
|
+
return { index, entry: current };
|
|
235
239
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
240
|
+
return [index - 1, index + 1]
|
|
241
|
+
.map((candidate) => ({ index: candidate, entry: stack[candidate] }))
|
|
242
|
+
.find((target) => target.entry !== undefined && sameUrl(target.entry.url, url));
|
|
239
243
|
}
|
|
240
244
|
export function updateCurrentNavigationTitle(state, title) {
|
|
241
245
|
const trimmedTitle = title?.trim();
|
|
@@ -59,6 +59,12 @@ export function mountChart({ element, spec, registry }, options = {}) {
|
|
|
59
59
|
function candidates() {
|
|
60
60
|
return selectChartProviders({ registry, spec: input.spec }, { siteProvider: options.siteProvider }).filter(({ id }) => !failed.has(id));
|
|
61
61
|
}
|
|
62
|
+
function isStaleMount({ token }, _options = {}) {
|
|
63
|
+
return destroyed || token !== generation;
|
|
64
|
+
}
|
|
65
|
+
function isCurrentUpdate({ current, updateRevision }, _options = {}) {
|
|
66
|
+
return !destroyed && active === current && updateRevision === revision;
|
|
67
|
+
}
|
|
62
68
|
/** Async renderer errors arrive after mount; defer teardown outside the provider's commit. */
|
|
63
69
|
function renderError(entry, error, token) {
|
|
64
70
|
queueMicrotask(() => {
|
|
@@ -76,7 +82,7 @@ export function mountChart({ element, spec, registry }, options = {}) {
|
|
|
76
82
|
let renderRevision = revision;
|
|
77
83
|
try {
|
|
78
84
|
const provider = await entry.load({});
|
|
79
|
-
if (
|
|
85
|
+
if (isStaleMount({ token }))
|
|
80
86
|
return;
|
|
81
87
|
const frame = element.ownerDocument.createElement('div');
|
|
82
88
|
renderer.replaceChildren(frame);
|
|
@@ -84,13 +90,13 @@ export function mountChart({ element, spec, registry }, options = {}) {
|
|
|
84
90
|
const instance = provider.mount({ element: frame, ...input }, { onError: (error) => renderError(entry, error, token) });
|
|
85
91
|
active = { entry, instance };
|
|
86
92
|
await instance.ready;
|
|
87
|
-
if (
|
|
93
|
+
if (isStaleMount({ token }) || renderRevision !== revision)
|
|
88
94
|
return;
|
|
89
95
|
fallback.hidden = true;
|
|
90
96
|
return;
|
|
91
97
|
}
|
|
92
98
|
catch (error) {
|
|
93
|
-
if (
|
|
99
|
+
if (isStaleMount({ token }) || renderRevision !== revision)
|
|
94
100
|
return;
|
|
95
101
|
failed.add(entry.id);
|
|
96
102
|
report(entry, error);
|
|
@@ -113,12 +119,12 @@ export function mountChart({ element, spec, registry }, options = {}) {
|
|
|
113
119
|
const current = active;
|
|
114
120
|
try {
|
|
115
121
|
await current.instance.update(input);
|
|
116
|
-
if (
|
|
122
|
+
if (isCurrentUpdate({ current, updateRevision }))
|
|
117
123
|
fallback.hidden = true;
|
|
118
124
|
return;
|
|
119
125
|
}
|
|
120
126
|
catch (error) {
|
|
121
|
-
if (
|
|
127
|
+
if (!isCurrentUpdate({ current, updateRevision }))
|
|
122
128
|
return;
|
|
123
129
|
failed.add(current.entry.id);
|
|
124
130
|
report(current.entry, error);
|
|
@@ -13,8 +13,8 @@ export function ChartHost({ spec, registry, theme = DEFAULT_CHART_THEME, sitePro
|
|
|
13
13
|
const instance = useRef(undefined);
|
|
14
14
|
const previous = useRef({ spec, theme });
|
|
15
15
|
useEffect(() => {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
// The container `<div>` below is rendered unconditionally, so React has always attached the ref
|
|
17
|
+
// by the time this effect runs; the old `if (!element.current) return` could never fire.
|
|
18
18
|
const mounted = mountChart({ element: element.current, spec, registry }, {
|
|
19
19
|
theme, siteProvider, ...(onProviderError ? { onProviderError } : {}),
|
|
20
20
|
});
|
|
@@ -41,8 +41,8 @@ export function renderChartTable({ element, spec }, _options = {}) {
|
|
|
41
41
|
const tr = body.insertRow();
|
|
42
42
|
for (const { key } of columns) {
|
|
43
43
|
const cell = tr.insertCell();
|
|
44
|
-
const value = row[key];
|
|
45
|
-
cell.textContent =
|
|
44
|
+
const value = row[key] ?? '';
|
|
45
|
+
cell.textContent = typeof value === 'object' ? JSON.stringify(value) : String(value);
|
|
46
46
|
cell.dataset.numeric = String(numeric.has(key));
|
|
47
47
|
}
|
|
48
48
|
}
|
|
@@ -30,18 +30,12 @@ export function useCommandPalette(options, dependencies) {
|
|
|
30
30
|
onClose();
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
|
-
if (event.key === 'ArrowDown') {
|
|
33
|
+
if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
|
|
34
34
|
event.preventDefault();
|
|
35
35
|
if (results.length === 0)
|
|
36
36
|
return;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
if (event.key === 'ArrowUp') {
|
|
41
|
-
event.preventDefault();
|
|
42
|
-
if (results.length === 0)
|
|
43
|
-
return;
|
|
44
|
-
setCursor((current) => nextCursor(current, results.length, -1));
|
|
37
|
+
const direction = event.key === 'ArrowDown' ? 1 : -1;
|
|
38
|
+
setCursor((current) => nextCursor(current, results.length, direction));
|
|
45
39
|
return;
|
|
46
40
|
}
|
|
47
41
|
if (event.key === 'Enter') {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { ConnectorsDependencies } from './ports.js';
|
|
2
2
|
import type { Connector, ConnectorAuthResultEvent, ProviderTab } from './types.js';
|
|
3
|
-
import { useConnectorCatalog } from './hooks/useConnectorCatalog.js';
|
|
4
|
-
import { useConnectorAuthorization } from './hooks/useConnectorAuthorization.js';
|
|
5
|
-
import { useConnectorDetail } from './hooks/useConnectorDetail.js';
|
|
3
|
+
import type { useConnectorCatalog } from './hooks/useConnectorCatalog.js';
|
|
4
|
+
import type { useConnectorAuthorization } from './hooks/useConnectorAuthorization.js';
|
|
5
|
+
import type { useConnectorDetail } from './hooks/useConnectorDetail.js';
|
|
6
6
|
import type { ConnectorGateProps } from './components/ConnectorGate.js';
|
|
7
7
|
export interface ConnectorsBrowserProps {
|
|
8
8
|
/** Whether the host's provider is configured (e.g. an API key is saved) — gates enrichment + unmasks the grid. */
|
|
@@ -36,5 +36,5 @@ export interface ConnectorsBrowserProps {
|
|
|
36
36
|
* messages. Ported from OD's `ConnectorsBrowser.tsx` — see
|
|
37
37
|
* `packages/ui/source-map.md` for full provenance.
|
|
38
38
|
*/
|
|
39
|
-
export declare function ConnectorsBrowser({ unlocked, providerTabs, catalogRefreshKey, dependencies, getCategoryLabel, getDisplayableAccountLabel, gate, onProviderTabClick, onConnectorAuthResult, onConnectorsChanged, useConnectorCatalog
|
|
39
|
+
export declare function ConnectorsBrowser({ unlocked, providerTabs, catalogRefreshKey, dependencies, getCategoryLabel, getDisplayableAccountLabel, gate, onProviderTabClick, onConnectorAuthResult, onConnectorsChanged, useConnectorCatalog, useConnectorAuthorization, useConnectorDetail, agentHandle, }: ConnectorsBrowserProps): import("react").JSX.Element;
|
|
40
40
|
//# sourceMappingURL=ConnectorsBrowser.d.ts.map
|
|
@@ -4,9 +4,6 @@ import { agentSubHandle } from '@jini-ai/agentic';
|
|
|
4
4
|
import { useT } from '../i18n/index.js';
|
|
5
5
|
import { AUTHORIZATION_CANCEL_FAILED_MESSAGE, DEFAULT_PROVIDER_TAB_ID, DEFAULT_PROVIDER_TABS, } from './constants.js';
|
|
6
6
|
import { connectorPanelAlerts, scopeConnectorsToProvider, sortConnectorsForSearch, } from './rules.js';
|
|
7
|
-
import { useConnectorCatalog } from './hooks/useConnectorCatalog.js';
|
|
8
|
-
import { useConnectorAuthorization } from './hooks/useConnectorAuthorization.js';
|
|
9
|
-
import { useConnectorDetail } from './hooks/useConnectorDetail.js';
|
|
10
7
|
import { useWiredConnectorsBrowser } from './hooks/useWiredConnectorsBrowser.js';
|
|
11
8
|
import { CenteredLoader } from '../../react/components/Loading.js';
|
|
12
9
|
import { ProviderTabBar } from './components/ProviderTabBar.js';
|
|
@@ -14,6 +11,18 @@ import { ConnectorSearchBar } from './components/ConnectorSearchBar.js';
|
|
|
14
11
|
import { ConnectorAlertList } from './components/ConnectorAlertList.js';
|
|
15
12
|
import { ConnectorGrid } from './components/ConnectorGrid.js';
|
|
16
13
|
import { ConnectorDetailDrawer } from './components/ConnectorDetailDrawer.js';
|
|
14
|
+
/** `{ agentHandle }` for a child derived from the browser's own handle, or `{}` when the host published none. */
|
|
15
|
+
function subHandleProp({ base, action }) {
|
|
16
|
+
return base ? { agentHandle: agentSubHandle({ base, action }) } : {};
|
|
17
|
+
}
|
|
18
|
+
/** The detail drawer for the connector currently opened, or nothing when none is. */
|
|
19
|
+
function ConnectorsDetailPane({ detail, authorization, unlocked, actions, getCategoryLabel, getDisplayableAccountLabel, agentHandle, }) {
|
|
20
|
+
const connector = detail.detailConnector;
|
|
21
|
+
if (!connector)
|
|
22
|
+
return null;
|
|
23
|
+
const { pendingConnectorAction } = authorization;
|
|
24
|
+
return (_jsx(ConnectorDetailDrawer, { connector: connector, disabled: !unlocked, pendingAction: pendingConnectorAction?.connectorId === connector.id ? pendingConnectorAction.action : null, authorizationPending: authorization.pending[connector.id], authorizationCancelFailed: authorization.cancelFailed[connector.id] === true, authorizationError: authorization.authError[connector.id] ?? null, toolsPreviewLoading: detail.toolPreviewLoading, toolsLoaded: detail.toolsLoaded, onClose: detail.closeDetails, ...actions, onLoadMoreTools: (connectorId, cursor) => void detail.loadMoreTools(connectorId, cursor), ...(getCategoryLabel ? { getCategoryLabel } : {}), ...(getDisplayableAccountLabel ? { getDisplayableAccountLabel } : {}), ...subHandleProp({ base: agentHandle, action: 'detail' }) }));
|
|
25
|
+
}
|
|
17
26
|
/**
|
|
18
27
|
* Connector cards + search — an OAuth integration marketplace UI. Owns its
|
|
19
28
|
* own data lifecycle: fetches the catalog on mount, lazily enriches once
|
|
@@ -21,7 +30,7 @@ import { ConnectorDetailDrawer } from './components/ConnectorDetailDrawer.js';
|
|
|
21
30
|
* messages. Ported from OD's `ConnectorsBrowser.tsx` — see
|
|
22
31
|
* `packages/ui/source-map.md` for full provenance.
|
|
23
32
|
*/
|
|
24
|
-
export function ConnectorsBrowser({ unlocked, providerTabs = DEFAULT_PROVIDER_TABS, catalogRefreshKey
|
|
33
|
+
export function ConnectorsBrowser({ unlocked, providerTabs = DEFAULT_PROVIDER_TABS, catalogRefreshKey, dependencies, getCategoryLabel, getDisplayableAccountLabel, gate, onProviderTabClick, onConnectorAuthResult, onConnectorsChanged, useConnectorCatalog, useConnectorAuthorization, useConnectorDetail, agentHandle, }) {
|
|
25
34
|
const t = useT();
|
|
26
35
|
const [filter, setFilter] = useState('');
|
|
27
36
|
const [selectedProvider, setSelectedProvider] = useState(providerTabs[0]?.id ?? DEFAULT_PROVIDER_TAB_ID);
|
|
@@ -34,16 +43,15 @@ export function ConnectorsBrowser({ unlocked, providerTabs = DEFAULT_PROVIDER_TA
|
|
|
34
43
|
dependencies,
|
|
35
44
|
unlocked,
|
|
36
45
|
catalogRefreshKey,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
useConnectorCatalog
|
|
40
|
-
useConnectorAuthorization
|
|
41
|
-
useConnectorDetail
|
|
46
|
+
onConnectorsChanged,
|
|
47
|
+
onConnectorAuthResult,
|
|
48
|
+
useConnectorCatalog,
|
|
49
|
+
useConnectorAuthorization,
|
|
50
|
+
useConnectorDetail,
|
|
42
51
|
});
|
|
43
52
|
const providerScopedConnectors = useMemo(() => scopeConnectorsToProvider(catalog.connectors, providerTabs, selectedProvider), [catalog.connectors, providerTabs, selectedProvider]);
|
|
44
53
|
const filteredConnectors = useMemo(() => sortConnectorsForSearch(providerScopedConnectors, filter), [providerScopedConnectors, filter]);
|
|
45
|
-
const
|
|
46
|
-
const hasNoResults = hasQuery && filteredConnectors.length === 0;
|
|
54
|
+
const hasNoResults = filter.trim().length > 0 && filteredConnectors.length === 0;
|
|
47
55
|
const alerts = useMemo(() => connectorPanelAlerts(catalog.connectors, detail.detailConnectorId, authorization.authError, authorization.cancelFailed, t(AUTHORIZATION_CANCEL_FAILED_MESSAGE)), [catalog.connectors, detail.detailConnectorId, authorization.authError, authorization.cancelFailed, t]);
|
|
48
56
|
const handleProviderTabSelect = useCallback((id) => {
|
|
49
57
|
onProviderTabClick?.('provider_chip');
|
|
@@ -53,8 +61,12 @@ export function ConnectorsBrowser({ unlocked, providerTabs = DEFAULT_PROVIDER_TA
|
|
|
53
61
|
onProviderTabClick?.('gate_card');
|
|
54
62
|
gate?.onClick?.();
|
|
55
63
|
}, [onProviderTabClick, gate]);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
64
|
+
const actions = {
|
|
65
|
+
onConnect: (connectorId) => void authorization.runConnectorAction(connectorId, 'connect'),
|
|
66
|
+
onDisconnect: (connectorId) => void authorization.runConnectorAction(connectorId, 'disconnect'),
|
|
67
|
+
onCancelAuthorization: (connectorId) => void authorization.cancelAuthorization(connectorId),
|
|
68
|
+
onOpenExternalUrl: (url) => void deps.data.openExternalUrl(url),
|
|
69
|
+
};
|
|
70
|
+
return (_jsxs("div", { className: "tab-panel connectors-panel connectors-panel-embedded", children: [_jsxs("div", { className: "tab-panel-toolbar", children: [_jsx("div", { className: "toolbar-left connectors-heading", children: _jsxs("div", { children: [_jsx("h2", { children: t('Connectors') }), _jsx("p", { children: t('Connect third-party tools and services.') })] }) }), _jsxs("div", { className: "toolbar-right", children: [_jsx(ProviderTabBar, { tabs: providerTabs, selectedId: selectedProvider, onSelect: handleProviderTabSelect, ...subHandleProp({ base: agentHandle, action: 'provider' }) }), _jsx(ConnectorSearchBar, { value: filter, onChange: setFilter, disabled: !unlocked, onFocus: () => onProviderTabClick?.('search_connectors'), ...subHandleProp({ base: agentHandle, action: 'search' }) })] })] }), _jsx(ConnectorAlertList, { alerts: alerts, onOpenDetails: detail.openDetails }), catalog.loading ? (_jsx(CenteredLoader, { label: t('Loading…') })) : (_jsx(ConnectorGrid, { connectors: filteredConnectors, locked: !unlocked, hasNoResults: hasNoResults, searchQuery: filter, pendingConnectorAction: authorization.pendingConnectorAction, authorizationPending: authorization.pending, authorizationCancelFailed: authorization.cancelFailed, toolsLoaded: catalog.enriched, ...actions, onOpenDetails: detail.openDetails, ...(getCategoryLabel ? { getCategoryLabel } : {}), onClearSearch: () => setFilter(''), ...(gate ? { gate: { ...gate, onClick: handleGateClick } } : {}), ...subHandleProp({ base: agentHandle, action: 'connector' }) })), _jsx(ConnectorsDetailPane, { detail: detail, authorization: authorization, unlocked: unlocked, actions: actions, getCategoryLabel: getCategoryLabel, getDisplayableAccountLabel: getDisplayableAccountLabel, agentHandle: agentHandle })] }));
|
|
59
71
|
}
|
|
60
72
|
//# sourceMappingURL=ConnectorsBrowser.js.map
|
|
@@ -1,25 +1,77 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { agentHandleProps } from '@jini-ai/agentic';
|
|
3
3
|
import { useT } from '../../i18n/index.js';
|
|
4
|
-
import { getConnectorDisplayToolCount, statusLabel, toolsBadgeTranslation } from '../rules.js';
|
|
4
|
+
import { connectorActionFlags, getConnectorDisplayToolCount, statusLabel, toolsBadgeTranslation } from '../rules.js';
|
|
5
5
|
import { Icon } from '../../../react/components/Icon.js';
|
|
6
6
|
import { ConnectorLogo } from './ConnectorLogo.js';
|
|
7
|
-
|
|
7
|
+
function stopPropagation(event) {
|
|
8
|
+
event.stopPropagation();
|
|
9
|
+
}
|
|
10
|
+
/** Click handler for a card action: stops the click from also opening the card's details, then acts. */
|
|
11
|
+
function stopThen(onActivate) {
|
|
12
|
+
return (event) => {
|
|
13
|
+
stopPropagation(event);
|
|
14
|
+
onActivate();
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function ConnectorCardTitleDot({ status, isAuthorizationPending }) {
|
|
18
|
+
const t = useT();
|
|
19
|
+
if (status === 'connected') {
|
|
20
|
+
return (_jsx("span", { className: `connector-status-dot connector-card-title-dot status-${status}`, "aria-label": t(statusLabel(status)), title: t(statusLabel(status)), role: "img" }));
|
|
21
|
+
}
|
|
22
|
+
if (!isAuthorizationPending)
|
|
23
|
+
return null;
|
|
24
|
+
return (_jsx("span", { className: "connector-status-dot connector-card-title-dot status-pending", "aria-label": t('Authorization pending'), title: t('Authorization pending'), role: "img" }));
|
|
25
|
+
}
|
|
26
|
+
function ConnectorCardToolsBadge({ connector, toolsLoaded }) {
|
|
8
27
|
const t = useT();
|
|
9
|
-
const resolvedCancelFailedMessage = cancelFailedMessage ?? t("Couldn't cancel authorization. Try again.");
|
|
10
|
-
const resolvedContinueInBrowserLabel = continueInBrowserLabel ?? t('Continue in browser');
|
|
11
|
-
const isConnecting = pendingAction === 'connect';
|
|
12
|
-
const isDisconnecting = pendingAction === 'disconnect';
|
|
13
|
-
const isConnected = connector.status === 'connected';
|
|
14
|
-
const isAuthorizationPending = !isConnected && authorizationPending !== undefined;
|
|
15
|
-
const isPending = pendingAction !== null || isAuthorizationPending;
|
|
16
|
-
const canConnect = !disabled && !isPending && connector.status === 'available';
|
|
17
|
-
const canDisconnect = !disabled && !isPending && isConnected;
|
|
18
|
-
const toolCount = getConnectorDisplayToolCount(connector);
|
|
19
28
|
const showToolsBadge = connector.toolCount !== undefined || connector.tools.length > 0 || toolsLoaded;
|
|
20
|
-
const toolsBadge = toolsBadgeTranslation(
|
|
29
|
+
const toolsBadge = toolsBadgeTranslation(getConnectorDisplayToolCount(connector));
|
|
21
30
|
const toolsBadgeLabel = t(toolsBadge.key, toolsBadge.vars);
|
|
31
|
+
return (_jsx("span", { className: "connector-meta-tools", "aria-hidden": !showToolsBadge, children: showToolsBadge ? (_jsx("span", { className: "connector-tools-badge is-ready", title: toolsBadgeLabel, children: _jsx("span", { children: toolsBadgeLabel }) })) : null }));
|
|
32
|
+
}
|
|
33
|
+
function ConnectorDisconnectButton({ flags, disabled, agentHandle, onActivate }) {
|
|
34
|
+
const t = useT();
|
|
35
|
+
const { isDisconnecting } = flags;
|
|
36
|
+
return (_jsx("button", { type: "button", className: `icon-only connector-action is-disconnect${isDisconnecting ? ' is-loading' : ''}`, disabled: !flags.canDisconnect, "aria-busy": isDisconnecting || undefined, "aria-label": t('Disconnect'), title: t('Disconnect'), tabIndex: disabled ? -1 : undefined, onMouseDown: stopPropagation, onKeyDown: stopPropagation, onClick: stopThen(onActivate), ...agentHandleProps({}, { base: agentHandle, action: 'disconnect', role: 'button', label: t('Disconnect') }), children: _jsx(Icon, { name: isDisconnecting ? 'spinner' : 'close', size: 12 }) }));
|
|
37
|
+
}
|
|
38
|
+
function ConnectorConnectButton({ flags, disabled, agentHandle, onActivate }) {
|
|
39
|
+
const t = useT();
|
|
40
|
+
const { isAuthorizationPending } = flags;
|
|
41
|
+
const isBusy = flags.isConnecting || isAuthorizationPending;
|
|
42
|
+
return (_jsx("button", { type: "button", className: `icon-only connector-action is-connect${isBusy ? ' is-loading' : ''}`, disabled: !flags.canConnect, "aria-busy": isBusy || undefined, "aria-label": isAuthorizationPending ? t('Authorization pending') : t('Connect'), title: isAuthorizationPending ? t('Authorization in progress') : t('Connect'), tabIndex: disabled ? -1 : undefined, onMouseDown: stopPropagation, onKeyDown: stopPropagation, onClick: stopThen(onActivate), ...agentHandleProps({}, { base: agentHandle, action: 'connect', role: 'button', label: t('Connect') }), children: _jsx(Icon, { name: isBusy ? 'spinner' : 'plus', size: 12 }) }));
|
|
43
|
+
}
|
|
44
|
+
function ConnectorCancelAuthorizationButton({ onActivate }) {
|
|
45
|
+
const t = useT();
|
|
46
|
+
return (_jsx("button", { type: "button", className: "icon-only connector-action is-cancel-authorization", "aria-label": t('Cancel authorization'), title: t('Cancel authorization'), onMouseDown: stopPropagation, onKeyDown: stopPropagation, onClick: stopThen(onActivate), children: _jsx(Icon, { name: "close", size: 12 }) }));
|
|
47
|
+
}
|
|
48
|
+
function ConnectorStatusPill({ status }) {
|
|
49
|
+
const t = useT();
|
|
50
|
+
if (status !== 'error' && status !== 'disabled')
|
|
51
|
+
return null;
|
|
52
|
+
return _jsx("span", { className: `connector-status-pill status-${status}`, children: t(statusLabel(status)) });
|
|
53
|
+
}
|
|
54
|
+
/** The cancel-failed alert and the continue-in-browser link under the card body. */
|
|
55
|
+
function ConnectorCardHints({ authorizationCancelFailed, redirectUrl, cancelFailedMessage, continueInBrowserLabel, onOpenExternalUrl, }) {
|
|
56
|
+
const t = useT();
|
|
57
|
+
function continueAuthorization(event) {
|
|
58
|
+
stopPropagation(event);
|
|
59
|
+
// `continueAuthorization`'s only call site (the "continue in browser"
|
|
60
|
+
// button below) only ever renders while
|
|
61
|
+
// `isAuthorizationPending && authorizationPending.redirectUrl` already
|
|
62
|
+
// holds in that same render, and React re-binds this closure fresh on
|
|
63
|
+
// every render — so a re-check here was dead code for every real
|
|
64
|
+
// click, removed rather than tested around (see
|
|
65
|
+
// packages/ui/source-map.md's 2026-07-22 dated entry).
|
|
66
|
+
onOpenExternalUrl?.(redirectUrl);
|
|
67
|
+
}
|
|
68
|
+
return (_jsxs(_Fragment, { children: [authorizationCancelFailed ? (_jsx("p", { className: "connector-authorization-hint connector-authorization-error", role: "alert", children: cancelFailedMessage ?? t("Couldn't cancel authorization. Try again.") })) : null, redirectUrl ? (_jsx("button", { type: "button", className: "connector-authorization-link", title: t('Authorization in progress'), onClick: continueAuthorization, children: continueInBrowserLabel ?? t('Continue in browser') })) : null] }));
|
|
69
|
+
}
|
|
70
|
+
export function ConnectorCard({ connector, disabled = false, pendingAction, authorizationPending, authorizationCancelFailed, toolsLoaded, onConnect, onDisconnect, onCancelAuthorization, onOpenDetails, getCategoryLabel = (category) => category, cancelFailedMessage, continueInBrowserLabel, onOpenExternalUrl, agentHandle, }) {
|
|
71
|
+
const t = useT();
|
|
72
|
+
const flags = connectorActionFlags({ connector, pendingAction, authorizationPending, disabled });
|
|
22
73
|
const categoryLabel = getCategoryLabel(connector.category);
|
|
74
|
+
const actionProps = { flags, disabled, agentHandle };
|
|
23
75
|
function openDetails() {
|
|
24
76
|
if (disabled)
|
|
25
77
|
return;
|
|
@@ -33,29 +85,6 @@ export function ConnectorCard({ connector, disabled = false, pendingAction, auth
|
|
|
33
85
|
event.preventDefault();
|
|
34
86
|
openDetails();
|
|
35
87
|
}
|
|
36
|
-
|
|
37
|
-
event.stopPropagation();
|
|
38
|
-
}
|
|
39
|
-
function continueAuthorization(event) {
|
|
40
|
-
stop(event);
|
|
41
|
-
// `continueAuthorization`'s only call site (the "continue in browser"
|
|
42
|
-
// button below) only ever renders while
|
|
43
|
-
// `isAuthorizationPending && authorizationPending.redirectUrl` already
|
|
44
|
-
// holds in that same render, and React re-binds this closure fresh on
|
|
45
|
-
// every render — so a re-check here was dead code for every real
|
|
46
|
-
// click, removed rather than tested around (see
|
|
47
|
-
// packages/ui/source-map.md's 2026-07-22 dated entry).
|
|
48
|
-
onOpenExternalUrl?.(authorizationPending.redirectUrl);
|
|
49
|
-
}
|
|
50
|
-
return (_jsxs("article", { className: `connector-card status-${connector.status}${disabled ? ' is-locked' : ''}`, "data-connector-id": connector.id, role: "button", tabIndex: disabled ? -1 : 0, "aria-disabled": disabled || undefined, "aria-label": t('Open details for {name}', { name: connector.name }), onClick: openDetails, onKeyDown: onKeyActivate, ...agentHandleProps({}, { base: agentHandle, ...({ role: 'button', label: connector.name }) }), children: [_jsxs("div", { className: "connector-card-top", children: [_jsx(ConnectorLogo, { connectorId: connector.id, connectorName: connector.name, logoUrl: connector.logoUrl, size: "sm" }), _jsxs("div", { className: "connector-card-head", children: [_jsxs("h3", { className: "connector-card-title", children: [_jsx("span", { className: "connector-card-title-name", children: connector.name }), isConnected ? (_jsx("span", { className: `connector-status-dot connector-card-title-dot status-${connector.status}`, "aria-label": t(statusLabel(connector.status)), title: t(statusLabel(connector.status)), role: "img" })) : isAuthorizationPending ? (_jsx("span", { className: "connector-status-dot connector-card-title-dot status-pending", "aria-label": t('Authorization pending'), title: t('Authorization pending'), role: "img" })) : null] }), _jsxs("div", { className: "connector-meta", children: [_jsx("span", { className: "connector-meta-item connector-meta-category", title: categoryLabel, children: categoryLabel }), _jsx("span", { className: "connector-meta-tools", "aria-hidden": !showToolsBadge, children: showToolsBadge ? (_jsx("span", { className: "connector-tools-badge is-ready", title: toolsBadgeLabel, children: _jsx("span", { children: toolsBadgeLabel }) })) : null })] })] }), _jsxs("div", { className: "connector-card-actions", children: [isConnected ? (_jsx("button", { type: "button", className: `icon-only connector-action is-disconnect${isDisconnecting ? ' is-loading' : ''}`, disabled: !canDisconnect, "aria-busy": isDisconnecting || undefined, "aria-label": t('Disconnect'), title: t('Disconnect'), tabIndex: disabled ? -1 : undefined, onMouseDown: stop, onKeyDown: stop, onClick: (e) => {
|
|
51
|
-
stop(e);
|
|
52
|
-
onDisconnect(connector.id);
|
|
53
|
-
}, ...agentHandleProps({}, { base: agentHandle, ...({ action: 'disconnect', role: 'button', label: t('Disconnect') }) }), children: _jsx(Icon, { name: isDisconnecting ? 'spinner' : 'close', size: 12 }) })) : (_jsx("button", { type: "button", className: `icon-only connector-action is-connect${isConnecting || isAuthorizationPending ? ' is-loading' : ''}`, disabled: !canConnect, "aria-busy": isConnecting || isAuthorizationPending || undefined, "aria-label": isAuthorizationPending ? t('Authorization pending') : t('Connect'), title: isAuthorizationPending ? t('Authorization in progress') : t('Connect'), tabIndex: disabled ? -1 : undefined, onMouseDown: stop, onKeyDown: stop, onClick: (e) => {
|
|
54
|
-
stop(e);
|
|
55
|
-
onConnect(connector.id);
|
|
56
|
-
}, ...agentHandleProps({}, { base: agentHandle, ...({ action: 'connect', role: 'button', label: t('Connect') }) }), children: _jsx(Icon, { name: isConnecting || isAuthorizationPending ? 'spinner' : 'plus', size: 12 }) })), isAuthorizationPending ? (_jsx("button", { type: "button", className: "icon-only connector-action is-cancel-authorization", "aria-label": t('Cancel authorization'), title: t('Cancel authorization'), onMouseDown: stop, onKeyDown: stop, onClick: (e) => {
|
|
57
|
-
stop(e);
|
|
58
|
-
onCancelAuthorization(connector.id);
|
|
59
|
-
}, children: _jsx(Icon, { name: "close", size: 12 }) })) : null, connector.status === 'error' || connector.status === 'disabled' ? (_jsx("span", { className: `connector-status-pill status-${connector.status}`, children: t(statusLabel(connector.status)) })) : null] })] }), authorizationCancelFailed ? (_jsx("p", { className: "connector-authorization-hint connector-authorization-error", role: "alert", children: resolvedCancelFailedMessage })) : null, isAuthorizationPending && authorizationPending.redirectUrl ? (_jsx("button", { type: "button", className: "connector-authorization-link", title: t('Authorization in progress'), onClick: continueAuthorization, children: resolvedContinueInBrowserLabel })) : null] }));
|
|
88
|
+
return (_jsxs("article", { className: `connector-card status-${connector.status}${disabled ? ' is-locked' : ''}`, "data-connector-id": connector.id, role: "button", tabIndex: disabled ? -1 : 0, "aria-disabled": disabled || undefined, "aria-label": t('Open details for {name}', { name: connector.name }), onClick: openDetails, onKeyDown: onKeyActivate, ...agentHandleProps({}, { base: agentHandle, role: 'button', label: connector.name }), children: [_jsxs("div", { className: "connector-card-top", children: [_jsx(ConnectorLogo, { connectorId: connector.id, connectorName: connector.name, logoUrl: connector.logoUrl, size: "sm" }), _jsxs("div", { className: "connector-card-head", children: [_jsxs("h3", { className: "connector-card-title", children: [_jsx("span", { className: "connector-card-title-name", children: connector.name }), _jsx(ConnectorCardTitleDot, { status: connector.status, isAuthorizationPending: flags.isAuthorizationPending })] }), _jsxs("div", { className: "connector-meta", children: [_jsx("span", { className: "connector-meta-item connector-meta-category", title: categoryLabel, children: categoryLabel }), _jsx(ConnectorCardToolsBadge, { connector: connector, toolsLoaded: toolsLoaded })] })] }), _jsxs("div", { className: "connector-card-actions", children: [flags.isConnected ? (_jsx(ConnectorDisconnectButton, { ...actionProps, onActivate: () => onDisconnect(connector.id) })) : (_jsx(ConnectorConnectButton, { ...actionProps, onActivate: () => onConnect(connector.id) })), flags.isAuthorizationPending ? (_jsx(ConnectorCancelAuthorizationButton, { onActivate: () => onCancelAuthorization(connector.id) })) : null, _jsx(ConnectorStatusPill, { status: connector.status })] })] }), _jsx(ConnectorCardHints, { authorizationCancelFailed: authorizationCancelFailed, redirectUrl: flags.redirectUrl, cancelFailedMessage: cancelFailedMessage, continueInBrowserLabel: continueInBrowserLabel, onOpenExternalUrl: onOpenExternalUrl })] }));
|
|
60
89
|
}
|
|
61
90
|
//# sourceMappingURL=ConnectorCard.js.map
|