@jini-ai/ui 0.5.4 → 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 +10 -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/Select/Select.hooks.d.ts +21 -0
- package/dist/features/admin-widgets/components/Select/Select.hooks.js +24 -2
- package/dist/features/admin-widgets/components/Select/Select.js +4 -3
- 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.d.ts +1 -1
- package/dist/features/execution/react/hooks/useReasoningControl.js +116 -75
- package/dist/features/execution/rules.d.ts +13 -2
- package/dist/features/execution/rules.js +51 -11
- package/dist/features/execution/types.d.ts +6 -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/native/data-table.manifest.d.ts +6 -6
- package/dist/features/interactive-ui/providers/shadcn/data-table.js +10 -7
- package/dist/features/interactive-ui/providers/shadcn/data-table.manifest.d.ts +6 -6
- 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/preview-modal-shell/react/components/icons.js +4 -1
- 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,20 +2,22 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
2
2
|
import { useEffect, useId, useState } from 'react';
|
|
3
3
|
import { agentHandleProps, agentSubHandle } from '@jini-ai/agentic';
|
|
4
4
|
import { useT } from '../../../i18n/index.js';
|
|
5
|
-
import { CUSTOM_MODEL_SENTINEL
|
|
5
|
+
import { CUSTOM_MODEL_SENTINEL } from '../../constants.js';
|
|
6
6
|
import { apiKeyFormatWarning, parseMaxTokens, presetRequiresApiKey, shouldShowCustomModelInput, showsBaseUrlField, } from '../../rules.js';
|
|
7
7
|
import { SearchableModelSelect } from './SearchableModelSelect.js';
|
|
8
8
|
import { useByokFieldValidation } from '../hooks/use-byok-field-validation.hooks.js';
|
|
9
|
+
/** `' is-missing'` when `field` is a required field the operator still has to fill. */
|
|
10
|
+
function missingClass(validation, field) {
|
|
11
|
+
return validation.isMissing({ field }) ? ' is-missing' : '';
|
|
12
|
+
}
|
|
9
13
|
/**
|
|
10
14
|
* The BYOK credential card: API key, base URL, optional token cap, and model.
|
|
11
15
|
* Origin: `components/byok/*` (`ByokKeyField`, `ByokProviderBaseUrl`,
|
|
12
16
|
* `ByokModelField`, `ByokConnectionTestControl`) — already factored out
|
|
13
17
|
* upstream, so this is assembly plus the origin's required-field marking.
|
|
14
18
|
*/
|
|
15
|
-
export function ByokProviderForm({ config, onConfigChange, preset, presets =
|
|
19
|
+
export function ByokProviderForm({ config, onConfigChange, preset, presets = [], modelDiscovery, connectionTest, onTestConnection, canTestConnection = true, apiKeyFooter, formFooter, modelFooter, apiKeyStoredExternally = false, apiKeyPlaceholder, agentHandle, apiKeyActions, collapseAdvanced = false, deferMissingFeedback = false, }) {
|
|
16
20
|
const t = useT();
|
|
17
|
-
const keyInputId = useId();
|
|
18
|
-
const KeyField = apiKeyActions ? 'div' : 'label';
|
|
19
21
|
const [revealKey, setRevealKey] = useState(false);
|
|
20
22
|
/** Whether the operator explicitly picked "Custom…" in the model picker — distinct from "the
|
|
21
23
|
* saved model simply isn't in the live list". Same UI-local toggle, for the same reason, as
|
|
@@ -36,12 +38,53 @@ export function ByokProviderForm({ config, onConfigChange, preset, presets = DEF
|
|
|
36
38
|
useEffect(() => {
|
|
37
39
|
setRevealKey(false);
|
|
38
40
|
}, [config.providerId]);
|
|
39
|
-
const
|
|
41
|
+
const validation = useByokFieldValidation({ config, preset, apiKeyStoredExternally }, { deferMissingFeedback });
|
|
42
|
+
const patch = (next) => onConfigChange({ ...config, ...next });
|
|
43
|
+
const part = { config, patch, preset, agentHandle, validation };
|
|
44
|
+
const connectionFields = _jsx(ByokConnectionFields, { ...part });
|
|
45
|
+
return (_jsxs("div", { className: "jini-byok-card", children: [_jsx("div", { className: "jini-byok-card-head", children: _jsx("h4", { className: "jini-byok-card-title", children: preset ? preset.title : t('Custom endpoint') }) }), presetRequiresApiKey(preset) ? (_jsx(ByokApiKeyField, { ...part, presets: presets, revealKey: revealKey, onToggleReveal: () => setRevealKey((shown) => !shown), apiKeyFooter: apiKeyFooter, apiKeyPlaceholder: apiKeyPlaceholder, apiKeyActions: apiKeyActions })) : null, collapseAdvanced ? null : connectionFields, _jsx(ByokModelRow, { ...part, modelDiscovery: modelDiscovery, explicitCustomModel: explicitCustomModel, setExplicitCustomModel: setExplicitCustomModel, connectionTest: connectionTest, onTestConnection: onTestConnection, canTestConnection: canTestConnection }), _jsx(ByokDiscoveryError, { modelDiscovery: modelDiscovery }), _jsx(ByokConnectionResult, { connectionTest: connectionTest, canTestConnection: canTestConnection }), _jsx(ByokSlot, { className: "jini-byok-model-footer", children: modelFooter }), collapseAdvanced ? _jsx(ByokAdvanced, { validation: validation, children: connectionFields }) : null, _jsx(ByokSlot, { className: "jini-byok-form-footer", children: formFooter })] }));
|
|
46
|
+
}
|
|
47
|
+
/** Base URL (unless the preset has a fixed origin) and Max tokens, on one wrapping row. */
|
|
48
|
+
function ByokConnectionFields({ config, patch, preset, agentHandle, validation }) {
|
|
49
|
+
const t = useT();
|
|
50
|
+
return (_jsx(_Fragment, { children: _jsxs("div", { className: "jini-byok-field-row", children: [showsBaseUrlField(preset) ? (_jsxs("label", { className: "jini-field", onBlurCapture: () => validation.markTouched({ field: 'baseUrl' }), children: [_jsxs("span", { className: "jini-field-label", children: [t('Base URL'), preset?.baseUrl ? null : _jsx("span", { className: "jini-field-required", "aria-hidden": "true", children: "*" })] }), _jsx("input", { className: 'jini-input' + missingClass(validation, 'baseUrl'), type: "url", inputMode: "url", spellCheck: false, value: config.baseUrl, onChange: (event) => patch({ baseUrl: event.target.value }), ...agentHandleProps({}, { base: agentHandle, ...({ action: 'base-url', role: 'field', label: t('Base URL') }) }) }), _jsx("span", { className: 'jini-field-hint' + (validation.baseUrlInvalid ? ' is-error' : ''), children: validation.baseUrlInvalid
|
|
51
|
+
? t('Enter an absolute http(s) URL.')
|
|
52
|
+
: t('Default endpoint. Usually no need to change this.') })] })) : null, _jsxs("label", { className: "jini-field", children: [_jsx("span", { className: "jini-field-label", children: t('Max tokens (optional)') }), _jsx("input", { className: "jini-input", type: "number", min: 1, step: 1, value: config.maxTokens ?? '', onChange: (event) => patch({ maxTokens: parseMaxTokens(event.target.value) }), ...agentHandleProps({}, { base: agentHandle, ...({ action: 'max-tokens', role: 'field', label: t('Max tokens (optional)') }) }) }), _jsx("span", { className: "jini-field-hint", children: t('Cap on the response length. Leave blank to use the model default.') })] })] }) }));
|
|
53
|
+
}
|
|
54
|
+
/** The API-key field (with Show/Hide, host actions and the advisory format warning) plus the
|
|
55
|
+
* host's `apiKeyFooter` slot beneath it. */
|
|
56
|
+
function ByokApiKeyField({ config, patch, preset, agentHandle, validation, presets, revealKey, onToggleReveal, apiKeyFooter, apiKeyPlaceholder, apiKeyActions, }) {
|
|
57
|
+
const t = useT();
|
|
58
|
+
const keyInputId = useId();
|
|
59
|
+
const KeyField = apiKeyActions ? 'div' : 'label';
|
|
40
60
|
/** Deliberately NOT folded into `missing` above: that set drives `is-missing` styling and the
|
|
41
61
|
* Test-connection disable, and a wrong-SHAPED key must never reach either. */
|
|
42
62
|
const keyFormatWarning = apiKeyFormatWarning(config, preset, presets);
|
|
43
|
-
|
|
44
|
-
|
|
63
|
+
return (_jsxs(_Fragment, { children: [_jsxs(KeyField, { className: "jini-field", onBlurCapture: () => validation.markTouched({ field: 'apiKey' }), children: [_jsxs("span", { className: "jini-field-label", children: [_jsx(ByokApiKeyLabel, { keyInputId: apiKeyActions ? keyInputId : undefined }), preset?.apiKeyConsoleUrl ? (_jsx("a", { className: "jini-field-link", href: preset.apiKeyConsoleUrl, target: "_blank", rel: "noreferrer noopener", children: t('Get key') })) : null] }), _jsxs("span", { className: "jini-field-input-row", children: [_jsx("input", { ...(apiKeyActions ? { id: keyInputId } : {}), className: 'jini-input' + missingClass(validation, 'apiKey'), type: revealKey ? 'text' : 'password',
|
|
64
|
+
/* `new-password`, NOT `"off"` — Chrome deliberately ignores `off` on credential-shaped
|
|
65
|
+
fields (a long-standing intentional decision, not a bug). `off` here is what let the
|
|
66
|
+
reported autofill through: Chrome filled this field with the admin's own saved
|
|
67
|
+
PASSWORD, the form sent it, and the provider answered with its own "API key not
|
|
68
|
+
valid" — a true message about a string the operator never typed. `new-password` is
|
|
69
|
+
the value Chrome/Safari/Firefox actually honor for "this is not a saved-login
|
|
70
|
+
field", which suppresses both the credential dropdown and the silent fill.
|
|
71
|
+
|
|
72
|
+
Known trade-off, not fixed here: Chrome may now offer to GENERATE a password on
|
|
73
|
+
this field — a suggestion popup, not a silently wrong value. */
|
|
74
|
+
autoComplete: "new-password", spellCheck: false, placeholder: apiKeyPlaceholder, value: config.apiKey, onChange: (event) => patch({ apiKey: event.target.value }), ...agentHandleProps({}, { base: agentHandle, ...({ action: 'api-key', role: 'field', label: t('API key') }) }) }), _jsx("button", { type: "button", className: "jini-input-affix-btn", "aria-pressed": revealKey, onClick: onToggleReveal, ...agentHandleProps({}, { base: agentHandle, ...({ action: 'reveal-key', role: 'button', label: t('Reveal API key') }) }), children: revealKey ? t('Hide') : t('Show') })] }), apiKeyActions ? _jsx("span", { className: "jini-byok-key-actions", children: apiKeyActions }) : null, _jsx("span", { className: "jini-field-hint", children: t('Stored only by this host.') }), keyFormatWarning ? (_jsx("span", { className: "jini-field-hint is-error", role: "status", children: t(keyFormatWarning.message, keyFormatWarning.vars) })) : null] }), _jsx(ByokSlot, { className: "jini-byok-key-footer", children: apiKeyFooter })] }));
|
|
75
|
+
}
|
|
76
|
+
/** "API key *". With host key actions the field is a `<div>`, so the name gets its own `<label>`
|
|
77
|
+
* pointing at the input by id; otherwise the whole field is already the label. */
|
|
78
|
+
function ByokApiKeyLabel({ keyInputId }) {
|
|
79
|
+
const t = useT();
|
|
80
|
+
if (keyInputId) {
|
|
81
|
+
return (_jsxs("label", { className: "jini-field-label", htmlFor: keyInputId, children: [_jsx("span", { children: t('API key') }), _jsx("span", { className: "jini-field-required", "aria-hidden": "true", children: "*" })] }));
|
|
82
|
+
}
|
|
83
|
+
return (_jsxs(_Fragment, { children: [t('API key'), _jsx("span", { className: "jini-field-required", "aria-hidden": "true", children: "*" })] }));
|
|
84
|
+
}
|
|
85
|
+
/** The Model field (live picker, free-text box, or both) with "Test connection" beside it. */
|
|
86
|
+
function ByokModelRow({ config, patch, preset, agentHandle, validation, modelDiscovery, explicitCustomModel, setExplicitCustomModel, connectionTest, onTestConnection, canTestConnection, }) {
|
|
87
|
+
const t = useT();
|
|
45
88
|
/**
|
|
46
89
|
* Live discovery turns the Model field from a text box into a real picker.
|
|
47
90
|
*
|
|
@@ -66,41 +109,95 @@ export function ByokProviderForm({ config, onConfigChange, preset, presets = DEF
|
|
|
66
109
|
// opens the box for an explicit "Custom…" pick AND for a value that simply isn't in the list, so
|
|
67
110
|
// a hydrated or hand-typed id is never silently replaced by whatever sorts first.
|
|
68
111
|
const customModelActive = showModelPicker && shouldShowCustomModelInput(config.model, liveModels, explicitCustomModel);
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
112
|
+
const modelClassName = 'jini-input' + missingClass(validation, 'model');
|
|
113
|
+
return (
|
|
114
|
+
// "Test connection" sits BESIDE the Model control (owner ruling, 2026-09-02), not on a row of
|
|
115
|
+
// its own underneath it. It probes the endpoint the Model field belongs to, and a row's
|
|
116
|
+
// distance made it read as unrelated to any particular field.
|
|
117
|
+
//
|
|
118
|
+
// A SIBLING of the label, never a child: a `<button>` inside a `<label>` makes every click on
|
|
119
|
+
// the button also focus and activate the labelled control — here, opening the model picker —
|
|
120
|
+
// and nesting interactive controls in a label is an accessibility defect regardless. Same rule
|
|
121
|
+
// `apiKeyFooter` documents.
|
|
122
|
+
//
|
|
123
|
+
// Wrapping, and `align-items: flex-end`, so the button sits on the input's own line at a
|
|
124
|
+
// comfortable width and drops below the field at a narrow one. Both status lines
|
|
125
|
+
// (discovery error, connection result) are deliberately OUTSIDE this row: inside it they would
|
|
126
|
+
// either sit beside the button or, as label children, push it out of line the moment either
|
|
127
|
+
// appeared.
|
|
128
|
+
_jsxs("div", { className: "jini-byok-model-row", children: [_jsxs("label", { className: "jini-field", onBlurCapture: () => validation.markTouched({ field: 'model' }), children: [_jsxs("span", { className: "jini-field-label", children: [t('Model'), _jsx("span", { className: "jini-field-required", "aria-hidden": "true", children: "*" })] }), showModelPicker ? (_jsx(ByokLiveModelSelect, { className: modelClassName, agentHandle: agentHandle, value: customModelActive ? CUSTOM_MODEL_SENTINEL : config.model, liveModels: liveModels, patch: patch, setExplicitCustomModel: setExplicitCustomModel })) : null, !showModelPicker || customModelActive ? (_jsx(ByokModelTextInput, { className: modelClassName, value: config.model, patch: patch, agentHandle: agentHandle, suggestions: showModelPicker ? [] : modelSuggestions(modelDiscovery, preset) })) : null] }), _jsx(ByokTestConnectionButton, { agentHandle: agentHandle, validation: validation, connectionTest: connectionTest, onTestConnection: onTestConnection, canTestConnection: canTestConnection })] }));
|
|
129
|
+
}
|
|
130
|
+
/** The probe's RESULT keeps its own full-width line. Beside the button it would have made the
|
|
131
|
+
* Model row's width depend on the length of a provider's error message. Renders nothing until
|
|
132
|
+
* the probe has finished. */
|
|
133
|
+
function ByokConnectionResult({ connectionTest, canTestConnection }) {
|
|
134
|
+
const t = useT();
|
|
135
|
+
if (!canTestConnection)
|
|
136
|
+
return null;
|
|
137
|
+
if (connectionTest.status !== 'ok' && connectionTest.status !== 'error')
|
|
138
|
+
return null;
|
|
139
|
+
return (_jsx("div", { className: "jini-byok-test-row", children: _jsx("span", { className: `jini-byok-test-status is-${connectionTest.status}`, role: connectionTest.status === 'error' ? 'alert' : 'status', children: connectionTest.status === 'ok'
|
|
140
|
+
? (connectionTest.message !== undefined ? t(connectionTest.message) : t('Connection succeeded'))
|
|
141
|
+
: t(connectionTest.message) }) }));
|
|
142
|
+
}
|
|
143
|
+
/** Discovery failure, as an inline hint below the Model row. Renders nothing otherwise. */
|
|
144
|
+
function ByokDiscoveryError({ modelDiscovery }) {
|
|
145
|
+
const t = useT();
|
|
146
|
+
if (modelDiscovery.status !== 'error')
|
|
147
|
+
return null;
|
|
148
|
+
return (
|
|
149
|
+
// Non-blocking (the field above stays editable, with the preset's static
|
|
150
|
+
// suggestions) but never silent — a discovery failure is an operator-actionable
|
|
151
|
+
// fact (bad key, wrong base URL, unreachable endpoint), not "no models exist".
|
|
152
|
+
//
|
|
153
|
+
// Moved out of the Model `<label>` when the probe button moved up beside it: as a label
|
|
154
|
+
// child it grew the field and pushed the bottom-aligned button off the input's line every
|
|
155
|
+
// time discovery failed. Same element, same `.jini-field-hint.is-error[role="status"]`
|
|
156
|
+
// identity host suites locate it by — only its parent changed.
|
|
157
|
+
_jsx("span", { className: "jini-field-hint is-error", role: "status", children: t('Could not load live models: {message}', { message: t(modelDiscovery.message) }) }));
|
|
158
|
+
}
|
|
159
|
+
/** A host slot's wrapper `<div>`, rendered only when the host supplied content for it. */
|
|
160
|
+
function ByokSlot({ className, children }) {
|
|
161
|
+
return children ? _jsx("div", { className: className, children: children }) : null;
|
|
162
|
+
}
|
|
163
|
+
/** The collapsed "Advanced" disclosure for Base URL and Max tokens. Opens on its own while Base URL
|
|
164
|
+
* is invalid or missing, so a required-field problem is never hidden. */
|
|
165
|
+
function ByokAdvanced({ validation, children }) {
|
|
166
|
+
const t = useT();
|
|
167
|
+
return (_jsxs("details", { className: "jini-byok-advanced", open: validation.baseUrlInvalid || validation.missing.has('baseUrl') || undefined, children: [_jsx("summary", { children: t('Advanced') }), children] }));
|
|
168
|
+
}
|
|
169
|
+
/** The live-model picker. "Custom…" opens the free-text box beside it; any real pick closes it. */
|
|
170
|
+
function ByokLiveModelSelect({ className, agentHandle, value, liveModels, patch, setExplicitCustomModel, }) {
|
|
171
|
+
const t = useT();
|
|
172
|
+
return (_jsx(SearchableModelSelect, { className: className, ariaLabel: t('Model'), searchPlaceholder: t('Search models'), testId: "jini-byok-model-select", searchInputTestId: "jini-byok-model-search", ...(agentHandle ? { agentHandle: agentSubHandle({ base: agentHandle, action: 'model' }) } : {}), value: value, models: liveModels.map((model) => ({ id: model, label: model })), additionalOptions: [{ value: CUSTOM_MODEL_SENTINEL, label: t('Custom…') }], onChange: (next) => {
|
|
173
|
+
if (next === CUSTOM_MODEL_SENTINEL) {
|
|
174
|
+
// Open the free-text box WITHOUT clearing `config.model`. Blanking it here would
|
|
175
|
+
// discard a working model the moment someone opened the picker to look at it.
|
|
176
|
+
setExplicitCustomModel(true);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
setExplicitCustomModel(false);
|
|
180
|
+
patch({ model: next });
|
|
181
|
+
} }));
|
|
182
|
+
}
|
|
183
|
+
/** "Test connection", beside the Model field. Disabled while a probe runs or a required field is
|
|
184
|
+
* blank; absent for hosts with no probe endpoint. */
|
|
185
|
+
function ByokTestConnectionButton({ agentHandle, validation, connectionTest, onTestConnection, canTestConnection, }) {
|
|
186
|
+
const t = useT();
|
|
187
|
+
if (!canTestConnection)
|
|
188
|
+
return null;
|
|
189
|
+
return (_jsx("button", { type: "button", className: "jini-btn jini-byok-test-btn", disabled: connectionTest.status === 'testing' || validation.missing.size > 0, onClick: onTestConnection, ...agentHandleProps({}, { base: agentHandle, ...({ action: 'test-connection', role: 'button', label: t('Test connection') }) }), children: connectionTest.status === 'testing' ? t('Testing…') : t('Test connection') }));
|
|
190
|
+
}
|
|
191
|
+
/** Autocomplete hints for the free-text Model box: the live list when discovery succeeded, else the
|
|
192
|
+
* preset's static `preferredModels`. */
|
|
193
|
+
function modelSuggestions(modelDiscovery, preset) {
|
|
194
|
+
return modelDiscovery.status === 'ok' ? modelDiscovery.models : (preset?.preferredModels ?? []);
|
|
195
|
+
}
|
|
196
|
+
/** The free-text Model box, with a `<datalist>` autocomplete when there are suggestions. */
|
|
197
|
+
function ByokModelTextInput({ className, value, patch, agentHandle, suggestions, }) {
|
|
198
|
+
const t = useT();
|
|
199
|
+
const modelListId = 'jini-byok-model-options';
|
|
200
|
+
const showDatalist = suggestions.length > 0;
|
|
201
|
+
return (_jsxs(_Fragment, { children: [_jsx("input", { className: className, list: showDatalist ? modelListId : undefined, spellCheck: false, value: value, onChange: (event) => patch({ model: event.target.value }), ...agentHandleProps({}, { base: agentHandle, ...({ action: 'model', role: 'field', label: t('Model') }) }) }), showDatalist ? (_jsx("datalist", { id: modelListId, children: suggestions.map((model) => (_jsx("option", { value: model }, model))) })) : null] }));
|
|
105
202
|
}
|
|
106
203
|
//# sourceMappingURL=ByokProviderForm.js.map
|
|
@@ -5,8 +5,7 @@ export interface ExecutionTabProps {
|
|
|
5
5
|
config: ExecutionConfig;
|
|
6
6
|
onConfigChange: (config: ExecutionConfig) => void;
|
|
7
7
|
port: ExecutionPort;
|
|
8
|
-
/**
|
|
9
|
-
* with its own provider list passes it here rather than editing ours. */
|
|
8
|
+
/** Host-owned endpoint catalog. Omitted means manual endpoint entry. */
|
|
10
9
|
presets?: readonly ProviderPreset[];
|
|
11
10
|
/** Per-agent CLI env-var catalog (proxy URLs, custom config dirs, a
|
|
12
11
|
* binary-path override). Defaults to this package's starter set for the
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { useEffect } from 'react';
|
|
3
3
|
import { agentHandleProps, agentSubHandle } from '@jini-ai/agentic';
|
|
4
4
|
import { useT } from '../../../i18n/index.js';
|
|
5
|
-
import { DEFAULT_AGENT_CLI_ENV_FIELDS
|
|
5
|
+
import { DEFAULT_AGENT_CLI_ENV_FIELDS } from '../../constants.js';
|
|
6
6
|
import { groupPresets, isProviderConfigured, nextConfigForAgentCliEnvChange, nextConfigForAgentModel, nextConfigForAgentReasoning, nextConfigForAgentSelect, nextConfigForModeChange, nextConfigForPresetSelect, resolveSelectedPreset, selectedAgentModel, } from '../../rules.js';
|
|
7
7
|
import { useExecutionTab } from '../hooks/useExecutionTab.js';
|
|
8
8
|
import { ByokProviderForm } from './ByokProviderForm.js';
|
|
@@ -20,13 +20,14 @@ import { ProviderChipGroup } from './ProviderChipGroup.js';
|
|
|
20
20
|
* wallet — balance polling, top-up, sign-in coachmarks — is deliberately not
|
|
21
21
|
* ported; it is product-bound, not generic.
|
|
22
22
|
*/
|
|
23
|
-
export function ExecutionTab({ config, onConfigChange, port, presets =
|
|
23
|
+
export function ExecutionTab({ config, onConfigChange, port, presets = [], cliEnvFields = DEFAULT_AGENT_CLI_ENV_FIELDS, localCliUnavailableReason, renderAgentIcon, localCliScopeLabel, autoDetect = true, ariaLabel, apiKeyFooter, formFooter, apiKeyStoredExternally, apiKeyPlaceholder, canDiscoverModels = true, describeProbeError, agentHandle, }) {
|
|
24
24
|
const t = useT();
|
|
25
|
-
const
|
|
25
|
+
const tab = useExecutionTab({
|
|
26
26
|
port,
|
|
27
27
|
autoDetect: autoDetect && config.mode === 'local-cli',
|
|
28
28
|
...(describeProbeError ? { describeProbeError } : {}),
|
|
29
29
|
});
|
|
30
|
+
const { loadModels, resetModelDiscovery } = tab;
|
|
30
31
|
const selectedPreset = resolveSelectedPreset(presets, config.byok);
|
|
31
32
|
/**
|
|
32
33
|
* Whether a key EXISTS, never what it is. Keyed on the boolean specifically so the effect below
|
|
@@ -68,39 +69,60 @@ export function ExecutionTab({ config, onConfigChange, port, presets = DEFAULT_P
|
|
|
68
69
|
if (!canDiscoverModels)
|
|
69
70
|
resetModelDiscovery();
|
|
70
71
|
}, [canDiscoverModels, resetModelDiscovery]);
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
// No "local-cli while unavailable" guard here: `ExecutionModeSwitch` renders that tab `disabled`
|
|
73
|
+
// whenever `localCliUnavailableReason` is set, and React never dispatches `onClick` for a disabled
|
|
74
|
+
// button, so `setMode('local-cli')` cannot be reached in that state.
|
|
74
75
|
const setMode = (mode) => {
|
|
75
|
-
if (mode === 'local-cli' && localCliDisabled)
|
|
76
|
-
return;
|
|
77
76
|
onConfigChange(nextConfigForModeChange(config, mode));
|
|
78
77
|
};
|
|
79
|
-
const selectPreset = (preset) => onConfigChange({ ...config, byok: nextConfigForPresetSelect(config.byok, preset) });
|
|
80
78
|
const modes = [
|
|
81
79
|
{ id: 'local-cli', title: t('Local CLI'), meta: t('Run an agent installed on this machine') },
|
|
82
80
|
{ id: 'byok', title: t('BYOK'), meta: t('Use your own API credentials') },
|
|
83
81
|
];
|
|
84
|
-
return (_jsxs("div", { className: "jini-settings-execution", "aria-label": ariaLabel ?? t('Execution mode'), children: [_jsx(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
82
|
+
return (_jsxs("div", { className: "jini-settings-execution", "aria-label": ariaLabel ?? t('Execution mode'), children: [_jsx(ExecutionModeSwitch, { modes: modes, activeMode: config.mode, localCliUnavailableReason: localCliUnavailableReason, onSelect: setMode, agentHandle: agentHandle }), config.mode === 'local-cli' ? (_jsx(LocalCliPane, { config: config, onConfigChange: onConfigChange, tab: tab, cliEnvFields: cliEnvFields, renderAgentIcon: renderAgentIcon, localCliScopeLabel: localCliScopeLabel, agentHandle: agentHandle })) : (_jsx(ByokPane, { config: config, onConfigChange: onConfigChange, presets: presets, selectedPreset: selectedPreset, tab: tab, canDiscoverModels: canDiscoverModels, canListModels: typeof port.listModels === 'function', formProps: { apiKeyFooter, formFooter, apiKeyStoredExternally, apiKeyPlaceholder }, agentHandle: agentHandle }))] }));
|
|
83
|
+
}
|
|
84
|
+
/** The Local CLI ↔ BYOK segmented control. Local CLI is disabled, with the host's reason as its
|
|
85
|
+
* tooltip and caption, while the host says it is unavailable. */
|
|
86
|
+
function ExecutionModeSwitch({ modes, activeMode, localCliUnavailableReason, onSelect, agentHandle }) {
|
|
87
|
+
const t = useT();
|
|
88
|
+
const localCliDisabled = Boolean(localCliUnavailableReason);
|
|
89
|
+
return (_jsx("div", { className: "jini-seg-control", role: "tablist", "aria-label": t('Execution mode'), style: { '--seg-cols': modes.length }, children: modes.map((mode) => {
|
|
90
|
+
const disabled = mode.id === 'local-cli' && localCliDisabled;
|
|
91
|
+
return (_jsxs("button", { type: "button", role: "tab", "aria-selected": activeMode === mode.id, disabled: disabled, title: disabled ? localCliUnavailableReason : undefined, className: 'jini-seg-btn' + (activeMode === mode.id ? ' active' : ''), onClick: () => onSelect(mode.id), ...agentHandleProps({}, { base: agentHandle, ...({ action: `mode-${mode.id}`, role: 'button', label: mode.title }) }), children: [_jsx("span", { className: "jini-seg-title", children: mode.title }), _jsx("span", { className: "jini-seg-meta", children: disabled ? localCliUnavailableReason : mode.meta })] }, mode.id));
|
|
92
|
+
}) }));
|
|
93
|
+
}
|
|
94
|
+
/** The BYOK half of the tab: protocol and gateway chip rows over the credential card. */
|
|
95
|
+
function ByokPane({ config, onConfigChange, presets, selectedPreset, tab, canDiscoverModels, canListModels, formProps, agentHandle, }) {
|
|
96
|
+
const t = useT();
|
|
97
|
+
const { protocols, gateways } = groupPresets(presets);
|
|
98
|
+
const configuredPresetIds = new Set(presets.filter((preset) => isProviderConfigured(config.byok, preset)).map((preset) => preset.id));
|
|
99
|
+
const selectPreset = (preset) => onConfigChange({ ...config, byok: nextConfigForPresetSelect(config.byok, preset) });
|
|
100
|
+
const selectedPresetId = selectedPreset?.id ?? null;
|
|
101
|
+
return (_jsxs("section", { className: "jini-settings-section jini-settings-byok", children: [_jsx(ProviderChipGroup, { label: t('Protocols'), presets: protocols, selectedPresetId: selectedPresetId, configuredPresetIds: configuredPresetIds, onSelect: selectPreset, configuredLabel: t('Configured'), unsetLabel: t('Not configured'), ...subHandleProps(agentHandle, 'protocol') }), _jsx(ProviderChipGroup, { label: t('Gateways'), presets: gateways, selectedPresetId: selectedPresetId, configuredPresetIds: configuredPresetIds, onSelect: selectPreset, configuredLabel: t('Configured'), unsetLabel: t('Not configured'), ...subHandleProps(agentHandle, 'gateway') }), _jsx(ByokProviderForm, { config: config.byok, onConfigChange: (byok) => onConfigChange({ ...config, byok }), preset: selectedPreset, ...subHandleProps(agentHandle, 'byok'),
|
|
102
|
+
// The WHOLE catalog, not the `protocols`/`gateways` halves the chip rows take: the card
|
|
103
|
+
// only reads it to recognise a pasted key as some other row's, and a key pasted from a
|
|
104
|
+
// gateway into a protocol field is exactly the mistake worth naming.
|
|
105
|
+
presets: presets, modelDiscovery: tab.modelDiscovery, connectionTest: tab.connectionTest,
|
|
106
|
+
// Also re-runs discovery with the CURRENT byok config, not just the
|
|
107
|
+
// connectivity probe — see this file's model-discovery effect above
|
|
108
|
+
// for why that matters: a stale "could not load live models" error
|
|
109
|
+
// from before this key existed (or from any earlier transient
|
|
110
|
+
// failure) would otherwise never clear, even once Test Connection
|
|
111
|
+
// itself goes green with the same config.
|
|
112
|
+
onTestConnection: () => {
|
|
113
|
+
tab.testConnection(config.byok);
|
|
114
|
+
if (canDiscoverModels && canListModels)
|
|
115
|
+
tab.loadModels(config.byok);
|
|
116
|
+
}, ...(formProps.apiKeyFooter !== undefined ? { apiKeyFooter: formProps.apiKeyFooter } : {}), ...(formProps.formFooter !== undefined ? { formFooter: formProps.formFooter } : {}), ...(formProps.apiKeyStoredExternally !== undefined ? { apiKeyStoredExternally: formProps.apiKeyStoredExternally } : {}), ...(formProps.apiKeyPlaceholder !== undefined ? { apiKeyPlaceholder: formProps.apiKeyPlaceholder } : {}) })] }));
|
|
117
|
+
}
|
|
118
|
+
/** The Local CLI half of the tab: detected agents, wired to the config's next-state rules. */
|
|
119
|
+
function LocalCliPane({ config, onConfigChange, tab, cliEnvFields, renderAgentIcon, localCliScopeLabel, agentHandle }) {
|
|
120
|
+
return (_jsx(LocalCliAgentList, { agents: tab.agents, config: config.localCli, scan: tab.scan, agentTest: tab.agentTest, onSelect: (agentId) => onConfigChange(nextConfigForAgentSelect(config, agentId)), onModelChange: (agentId, model) => onConfigChange(nextConfigForAgentModel(config, agentId, model)), onReasoningChange: (agentId, reasoning) => onConfigChange(nextConfigForAgentReasoning(config, agentId, reasoning)), onEnvChange: (agentId, envKey, value) => onConfigChange(nextConfigForAgentCliEnvChange(config, agentId, envKey, value)), cliEnvFields: cliEnvFields, onRescan: tab.canRescan ? tab.rescan : undefined, onTest: tab.canTestAgent
|
|
121
|
+
? (agent) => tab.testAgent(agent.id, selectedAgentModel(config.localCli, agent) || undefined)
|
|
122
|
+
: undefined, renderAgentIcon: renderAgentIcon, scopeLabel: localCliScopeLabel, ...subHandleProps(agentHandle, 'local-cli') }));
|
|
123
|
+
}
|
|
124
|
+
/** `{ agentHandle }` for a child's sub-handle under this tab's base, or nothing when no base is set. */
|
|
125
|
+
function subHandleProps(agentHandle, action) {
|
|
126
|
+
return agentHandle ? { agentHandle: agentSubHandle({ base: agentHandle, action }) } : {};
|
|
105
127
|
}
|
|
106
128
|
//# sourceMappingURL=ExecutionTab.js.map
|
|
@@ -27,6 +27,17 @@ import { LocalCliAgentSettings } from './LocalCliAgentSettings.js';
|
|
|
27
27
|
export function LocalCliAgentCard({ agent, config, selected, onSelect, onModelChange, onReasoningChange, onEnvChange, cliEnvFields, renderIcon, onTest, agentTest, onRescan, agentHandle, }) {
|
|
28
28
|
const t = useT();
|
|
29
29
|
const card = useLocalCliAgentCard({ agent, config, agentTest, cliEnvFields, onModelChange, onReasoningChange, onRescan, onTest, t });
|
|
30
|
+
return (_jsxs("div", { className: 'jini-agent-card' +
|
|
31
|
+
(selected ? ' is-selected' : '') +
|
|
32
|
+
(agent.installed ? ' is-installed' : ' is-missing'), "data-testid": `jini-agent-card-${agent.id}`, children: [_jsxs("div", { className: "jini-agent-card-main", children: [_jsx(LocalCliAgentSelection, { agent: agent, config: config, selected: selected, onSelect: onSelect, renderIcon: renderIcon, agentHandle: agentHandle }), selected && onTest ? (_jsx("button", { type: "button", className: 'jini-btn jini-agent-card-test' + (card.testing ? ' is-loading' : ''), "data-testid": `jini-agent-test-${agent.id}`, disabled: card.testing, onClick: () => onTest(agent), ...agentHandleProps({}, { base: agentHandle, action: 'test', role: 'button', label: t('Test') }), children: card.testing ? t('Testing…') : t('Test') })) : null] }), (agent.diagnostics ?? []).map((diagnostic, index) => (_jsx(AgentDiagnosticRow, { diagnostic: diagnostic, handlers: card.diagnosticHandlers }, `${diagnostic.reason}-${index}`))), selected && card.hasSettings ? (_jsx(LocalCliAgentSettings, { agent: agent, config: config, card: card, cliEnvFields: cliEnvFields, onModelChange: onModelChange, onEnvChange: onEnvChange, agentHandle: agentHandle })) : null] }));
|
|
33
|
+
}
|
|
34
|
+
/** The selectable identity stays independent of the header's Test action. */
|
|
35
|
+
function LocalCliAgentSelection({ agent, config, selected, onSelect, renderIcon, agentHandle }) {
|
|
36
|
+
return (_jsxs("button", { type: "button", className: "jini-agent-card-select", "data-testid": `jini-agent-select-${agent.id}`, "aria-pressed": selected, disabled: !agent.installed, onClick: () => onSelect(agent.id), ...agentHandleProps({}, { base: agentHandle, action: 'select', role: 'button', label: agent.label }), children: [_jsx("span", { className: "jini-agent-card-icon", "aria-hidden": "true", children: renderIcon ? renderIcon(agent) : agent.label.slice(0, 1).toUpperCase() }), _jsx(LocalCliAgentSummary, { agent: agent, config: config, selected: selected }), selected ? (_jsx("span", { className: "jini-agent-card-check", "aria-hidden": "true", children: "\u2713" })) : null] }));
|
|
37
|
+
}
|
|
38
|
+
/** Detection metadata and the compact model summary for the card's identity. */
|
|
39
|
+
function LocalCliAgentSummary({ agent, config, selected }) {
|
|
40
|
+
const t = useT();
|
|
30
41
|
const description = agent.description ?? DEFAULT_AGENT_DESCRIPTIONS[agent.id];
|
|
31
42
|
const meta = agentMetaLabel(agent, {
|
|
32
43
|
authRequired: t('Authentication required'),
|
|
@@ -35,8 +46,6 @@ export function LocalCliAgentCard({ agent, config, selected, onSelect, onModelCh
|
|
|
35
46
|
notInstalled: t('Not installed'),
|
|
36
47
|
});
|
|
37
48
|
const summary = agentModelSummary(config, agent);
|
|
38
|
-
return (_jsxs("
|
|
39
|
-
(selected ? ' is-selected' : '') +
|
|
40
|
-
(agent.installed ? ' is-installed' : ' is-missing'), "data-testid": `jini-agent-card-${agent.id}`, children: [_jsxs("div", { className: "jini-agent-card-main", children: [_jsxs("button", { type: "button", className: "jini-agent-card-select", "data-testid": `jini-agent-select-${agent.id}`, "aria-pressed": selected, disabled: !agent.installed, onClick: () => onSelect(agent.id), ...agentHandleProps({}, { base: agentHandle, ...({ action: 'select', role: 'button', label: agent.label }) }), children: [_jsx("span", { className: "jini-agent-card-icon", "aria-hidden": "true", children: renderIcon ? renderIcon(agent) : agent.label.slice(0, 1).toUpperCase() }), _jsxs("span", { className: "jini-agent-card-body", children: [_jsxs("span", { className: "jini-agent-card-name", children: [_jsx("span", { className: "jini-agent-card-title", children: agent.label }), description ? (_jsx("span", { className: "jini-agent-card-tagline", children: description })) : null] }), agent.badges?.length ? (_jsx("span", { className: "jini-agent-card-badges", children: agent.badges.map((badge) => (_jsx("span", { className: "jini-agent-card-badge", children: badge }, badge))) })) : null, meta.text ? (_jsx("span", { className: "jini-agent-card-meta", children: _jsx("span", { title: meta.title || undefined, children: meta.text }) })) : null, !selected && summary ? (_jsxs("span", { className: "jini-agent-card-model-summary", children: [_jsx("span", { children: t('Model') }), _jsx("strong", { children: summary })] })) : null] }), selected ? (_jsx("span", { className: "jini-agent-card-check", "aria-hidden": "true", children: "\u2713" })) : null] }), selected && onTest ? (_jsx("button", { type: "button", className: 'jini-btn jini-agent-card-test' + (card.testing ? ' is-loading' : ''), "data-testid": `jini-agent-test-${agent.id}`, disabled: card.testing, onClick: () => onTest(agent), ...agentHandleProps({}, { base: agentHandle, ...({ action: 'test', role: 'button', label: t('Test') }) }), children: card.testing ? t('Testing…') : t('Test') })) : null] }), (agent.diagnostics ?? []).map((diagnostic, index) => (_jsx(AgentDiagnosticRow, { diagnostic: diagnostic, handlers: card.diagnosticHandlers }, `${diagnostic.reason}-${index}`))), selected && card.hasSettings ? (_jsx(LocalCliAgentSettings, { agent: agent, config: config, card: card, cliEnvFields: cliEnvFields, onModelChange: onModelChange, onEnvChange: onEnvChange, agentHandle: agentHandle })) : null] }));
|
|
49
|
+
return (_jsxs("span", { className: "jini-agent-card-body", children: [_jsxs("span", { className: "jini-agent-card-name", children: [_jsx("span", { className: "jini-agent-card-title", children: agent.label }), description ? (_jsx("span", { className: "jini-agent-card-tagline", children: description })) : null] }), agent.badges?.length ? (_jsx("span", { className: "jini-agent-card-badges", children: agent.badges.map((badge) => (_jsx("span", { className: "jini-agent-card-badge", children: badge }, badge))) })) : null, meta.text ? (_jsx("span", { className: "jini-agent-card-meta", children: _jsx("span", { title: meta.title || undefined, children: meta.text }) })) : null, !selected && summary ? (_jsxs("span", { className: "jini-agent-card-model-summary", children: [_jsx("span", { children: t('Model') }), _jsx("strong", { children: summary })] })) : null] }));
|
|
41
50
|
}
|
|
42
51
|
//# sourceMappingURL=LocalCliAgentCard.js.map
|
|
@@ -22,8 +22,19 @@ export function LocalCliAgentList({ agents, config, scan, onSelect, onModelChang
|
|
|
22
22
|
const handle = cardHandles.get(agent.id);
|
|
23
23
|
return (_jsx(LocalCliAgentCard, { agent: agent, config: config, selected: config.agentId === agent.id, onSelect: onSelect, onModelChange: onModelChange, onReasoningChange: onReasoningChange, onEnvChange: onEnvChange, cliEnvFields: cliEnvFields, renderIcon: renderAgentIcon, onTest: onTest, agentTest: agentTest, onRescan: onRescan, ...(handle ? { agentHandle: handle } : {}) }, agent.id));
|
|
24
24
|
};
|
|
25
|
-
return (_jsxs("section", { className: "jini-settings-section jini-local-cli", children: [_jsxs("div", { className: "jini-section-head", children: [_jsxs("div", { className: "jini-section-head-text", children: [_jsxs("h4", { className: "jini-agent-group-head", children: [t('Your CLIs'), " (", installed.length, ")"] }), _jsx("p", { className: "jini-field-hint", children: t('Pick the CLI that runs your prompts.') })] }), onRescan ? (_jsx("button", { type: "button", className: "jini-btn jini-local-cli-rescan", disabled: scan.status === 'scanning', onClick: onRescan, ...agentHandleProps({}, { base: agentHandle,
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
return (_jsxs("section", { className: "jini-settings-section jini-local-cli", children: [_jsxs("div", { className: "jini-section-head", children: [_jsxs("div", { className: "jini-section-head-text", children: [_jsxs("h4", { className: "jini-agent-group-head", children: [t('Your CLIs'), " (", installed.length, ")"] }), _jsx("p", { className: "jini-field-hint", children: t('Pick the CLI that runs your prompts.') })] }), onRescan ? (_jsx("button", { type: "button", className: "jini-btn jini-local-cli-rescan", disabled: scan.status === 'scanning', onClick: onRescan, ...agentHandleProps({}, { base: agentHandle, action: 'rescan', role: 'button', label: t('Rescan') }), children: scan.status === 'scanning' ? t('Scanning…') : t('↻ Rescan') })) : null] }), _jsx("p", { className: "jini-field-hint jini-local-cli-scope", children: scope }), scan.status === 'error' ? (_jsx("p", { className: "jini-field-hint is-error", role: "alert", children: scan.message })) : null, _jsx(LocalCliAgentGrid, { agents: agents, scan: scan, list: list, renderCard: renderCard, agentHandle: agentHandle })] }));
|
|
26
|
+
}
|
|
27
|
+
/** Scan-state precedence and the not-installed disclosure belong to one grid. */
|
|
28
|
+
function LocalCliAgentGrid({ agents, scan, list, renderCard, agentHandle }) {
|
|
29
|
+
const t = useT();
|
|
30
|
+
if (scan.status === 'scanning') {
|
|
31
|
+
return (_jsxs("div", { className: "jini-agent-scan-card", role: "status", "aria-live": "polite", children: [_jsx("span", { className: "jini-agent-scan-ring", "aria-hidden": "true" }), _jsx("strong", { children: t('Scanning for installed agents…') })] }));
|
|
32
|
+
}
|
|
33
|
+
if (agents.length === 0) {
|
|
34
|
+
return scan.status === 'error' ? null : _jsx("div", { className: "jini-empty-card", children: t('No agent CLIs detected.') });
|
|
35
|
+
}
|
|
36
|
+
return (_jsxs(_Fragment, { children: [_jsx("div", { className: "jini-agent-grid", children: list.visible.map(renderCard) }), list.collapsed.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", className: "jini-btn jini-local-cli-more", "aria-expanded": list.showCollapsed, onClick: () => list.toggleCollapsed(), ...agentHandleProps({}, { base: agentHandle, action: 'toggle-not-installed', role: 'button', label: t('Show not-installed CLIs') }), children: list.showCollapsed
|
|
37
|
+
? t('Hide not installed')
|
|
38
|
+
: t('Show {count} not installed').replace('{count}', String(list.collapsed.length)) }), list.showCollapsed ? _jsx("div", { className: "jini-agent-grid", children: list.collapsed.map(renderCard) }) : null] })) : null] }));
|
|
28
39
|
}
|
|
29
40
|
//# sourceMappingURL=LocalCliAgentList.js.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { agentHandleProps, agentSubHandle } from '@jini-ai/agentic';
|
|
3
3
|
import { useT } from '../../../i18n/index.js';
|
|
4
4
|
import { CUSTOM_MODEL_SENTINEL } from '../../constants.js';
|
|
@@ -12,9 +12,20 @@ import { SearchableModelSelect } from './SearchableModelSelect.js';
|
|
|
12
12
|
* visible provenance sentence inside the card so only that card grows taller.
|
|
13
13
|
*/
|
|
14
14
|
export function LocalCliAgentSettings({ agent, config, card, cliEnvFields, onModelChange, onEnvChange, agentHandle, }) {
|
|
15
|
+
return (_jsxs("div", { className: "jini-agent-settings", role: "group", "aria-label": agent.label, "data-testid": `jini-agent-settings-${agent.id}`, children: [_jsx(LocalCliAgentModelControls, { agent: agent, card: card, onModelChange: onModelChange, agentHandle: agentHandle }), _jsx(LocalCliAgentFeedback, { agent: agent, card: card, onEnvChange: onEnvChange }), _jsx(AgentCliEnvFields, { agentId: agent.id, fields: cliEnvFields, config: config, onChange: onEnvChange })] }));
|
|
16
|
+
}
|
|
17
|
+
/** Model, custom-id and effort controls share the hook's resolved model state. */
|
|
18
|
+
function LocalCliAgentModelControls({ agent, card, onModelChange, agentHandle }) {
|
|
15
19
|
const t = useT();
|
|
16
|
-
const { reasoning, source, sourceLabel, sourceHint
|
|
20
|
+
const { reasoning, source, sourceLabel, sourceHint } = card;
|
|
17
21
|
const { hasModels, hasReasoning, reasoningOptions, reasoningValue, reasoningDisabled, allowCustomModel, customActive, modelChoices, selectValue, customModelInputValue, } = reasoning;
|
|
18
|
-
|
|
22
|
+
const additionalOptions = allowCustomModel ? [{ value: CUSTOM_MODEL_SENTINEL, label: t('Custom…') }] : undefined;
|
|
23
|
+
return (_jsxs("div", { className: "jini-agent-settings-row", children: [hasModels ? (_jsxs("div", { className: "jini-agent-settings-field jini-agent-settings-model", children: [_jsxs("div", { className: "jini-agent-settings-label", children: [_jsx("span", { className: "jini-field-label", children: t('Model') }), sourceLabel ? (_jsx("span", { className: `jini-agent-model-source ${source}`, children: sourceLabel })) : null] }), _jsx(SearchableModelSelect, { className: "jini-input jini-agent-model-select", ariaLabel: t('Model'), searchPlaceholder: t('Search models'), testId: `jini-agent-model-${agent.id}`, searchInputTestId: `jini-agent-model-search-${agent.id}`, ...(agentHandle ? { agentHandle: agentSubHandle({ base: agentHandle, action: 'model' }) } : {}), value: selectValue, models: modelChoices, additionalOptions: additionalOptions, onChange: card.selectModel }), sourceHint ? _jsx("p", { className: "jini-field-hint", children: sourceHint }) : null] })) : null, customActive ? (_jsxs("label", { className: "jini-agent-settings-field", children: [_jsx("span", { className: "jini-field-label", children: t('Custom model id') }), _jsx("input", { className: "jini-input jini-agent-settings-custom", type: "text", "data-testid": `jini-agent-model-custom-${agent.id}`, value: customModelInputValue, placeholder: t('e.g. my-fine-tuned-model'), spellCheck: false, onChange: (event) => onModelChange(agent.id, event.target.value.trim()), ...agentHandleProps({}, { base: agentHandle, action: 'custom-model', role: 'field', label: t('Custom model id') }) })] })) : null, hasReasoning ? (_jsxs("label", { className: "jini-agent-settings-field", children: [_jsx("span", { className: "jini-field-label", children: t('Reasoning effort') }), _jsx("select", { className: "jini-input jini-agent-settings-reasoning", "data-testid": `jini-agent-reasoning-${agent.id}`, value: reasoningValue, disabled: reasoningDisabled, onChange: (event) => card.selectReasoning(event.target.value), ...agentHandleProps({}, { base: agentHandle, action: 'reasoning', role: 'field', label: t('Reasoning effort') }), children: reasoningOptions.map((option) => (_jsx("option", { value: option.id, children: option.label }, option.id))) })] })) : null] }));
|
|
24
|
+
}
|
|
25
|
+
/** Probe evidence and repair actions stay together beneath the model controls. */
|
|
26
|
+
function LocalCliAgentFeedback({ agent, card, onEnvChange }) {
|
|
27
|
+
const t = useT();
|
|
28
|
+
const { result, repair, repairField } = card;
|
|
29
|
+
return (_jsxs(_Fragment, { children: [result ? (_jsx("p", { className: 'jini-agent-card-test-result is-' + result.status, role: result.status === 'error' ? 'alert' : 'status', children: result.status === 'ok' ? (result.message ?? t('Agent is ready.')) : result.message })) : null, repair && repairField ? (_jsxs("div", { className: "jini-agent-card-path-repair", children: [_jsx("span", { className: "jini-field-hint", children: t('A custom path override did not work, so this used the automatically detected binary instead.') }), _jsxs("div", { className: "jini-agent-card-path-repair-actions", children: [repair.canUseDetected ? (_jsx("button", { type: "button", className: "jini-btn", "data-testid": `jini-agent-path-repair-use-${agent.id}`, onClick: () => onEnvChange(agent.id, repairField.envKey, repair.detectedPath), children: t('Use detected path') })) : null, _jsx("button", { type: "button", className: "jini-btn jini-btn-ghost", "data-testid": `jini-agent-path-repair-clear-${agent.id}`, onClick: () => onEnvChange(agent.id, repairField.envKey, ''), children: t('Clear custom path') })] })] })) : null] }));
|
|
19
30
|
}
|
|
20
31
|
//# sourceMappingURL=LocalCliAgentSettings.js.map
|