@nextclaw/ui 0.12.9 → 0.12.11
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 +102 -0
- package/dist/assets/ChannelsList-SQ7Oxotv.js +8 -0
- package/dist/assets/DocBrowser-BCO2k6XD.js +1 -0
- package/dist/assets/{DocBrowser-6ReNjvzF.js → DocBrowser-rDOjI3ga.js} +1 -1
- package/dist/assets/{DocBrowserContext-B6SpA7Qs.js → DocBrowserContext-BUq3Wo8O.js} +1 -1
- package/dist/assets/{LogoBadge-ByNLYg65.js → LogoBadge-DP8Ye7wJ.js} +1 -1
- package/dist/assets/ModelConfig-C77Ae9ru.js +1 -0
- package/dist/assets/ProviderScopedModelInput-CEnK61uo.js +1 -0
- package/dist/assets/ProvidersList-BCupBayq.js +1 -0
- package/dist/assets/RuntimeConfig-Ad-CAcmy.js +1 -0
- package/dist/assets/SearchConfig-BfCz4wJ4.js +1 -0
- package/dist/assets/SecretsConfig-DjmBIhyy.js +3 -0
- package/dist/assets/{SessionsConfig-ChHQ7M5c.js → SessionsConfig-CvjxU40H.js} +2 -2
- package/dist/assets/{book-open-BdcxxoQu.js → book-open-BE8M56IM.js} +1 -1
- package/dist/assets/chat-page-JKC6ln-y.js +58 -0
- package/dist/assets/chat-session-display-YcRMrAMa.js +1 -0
- package/dist/assets/{chunk-JZWAC4HX-DK5HPmIK.js → chunk-JZWAC4HX-erTUn3b8.js} +1 -1
- package/dist/assets/client-CszWMVKi.js +7 -0
- package/dist/assets/config-split-page-BAGSzUR3.js +1 -0
- package/dist/assets/{createLucideIcon-BSeTgkZW.js → createLucideIcon-CCiTGX8L.js} +1 -1
- package/dist/assets/desktop-DfkLlkG2.js +1 -0
- package/dist/assets/desktop-update-config-BXeGlqHD.js +1 -0
- package/dist/assets/dialog-BghZFPch.js +5 -0
- package/dist/assets/{dist-6TrrnPCR.js → dist-Dd9cr-kz.js} +1 -1
- package/dist/assets/dist-ZwoAXs46.js +9 -0
- package/dist/assets/{download-BhDxnyvU.js → download-D7LOizcW.js} +1 -1
- package/dist/assets/es2015-CEAreese.js +41 -0
- package/dist/assets/{external-link-BgErLCNT.js → external-link-qsnCMhw1.js} +1 -1
- package/dist/assets/{hash-Bl7dr_UG.js → hash-0zjWsNl-.js} +1 -1
- package/dist/assets/{i18n-eDHeDY0n.js → i18n-DvzXOGQX.js} +1 -1
- package/dist/assets/index-DvVTC9FF.css +1 -0
- package/dist/assets/index-lr6rQUSd.js +2 -0
- package/dist/assets/key-round-BLe9D8ND.js +1 -0
- package/dist/assets/loader-circle-wj7kARHv.js +1 -0
- package/dist/assets/{logos-x89HbrZ4.js → logos-_v5b2SdG.js} +1 -1
- package/dist/assets/marketplace-page-CAAk1Khc.js +1 -0
- package/dist/assets/marketplace-page-CfCiq90S.js +49 -0
- package/dist/assets/mcp-marketplace-page-D0Pp9Hs-.js +40 -0
- package/dist/assets/play-o6NmwGTi.js +1 -0
- package/dist/assets/plus-I9pBS4Fl.js +1 -0
- package/dist/assets/{refresh-cw-C47QSEwg.js → refresh-cw-MNqgR3LZ.js} +1 -1
- package/dist/assets/remote-C9fXm4V5.js +1 -0
- package/dist/assets/{save-3S6-H3Xw.js → save-D4bObrmH.js} +1 -1
- package/dist/assets/search-DxmL3IWE.js +1 -0
- package/dist/assets/security-config-BUm6FFfl.js +1 -0
- package/dist/assets/select-BILPf7zs.js +1 -0
- package/dist/assets/setting-row-BATDgg4r.js +1 -0
- package/dist/assets/skeleton-COKMAnJy.js +1 -0
- package/dist/assets/{switch-BsLtHOH-.js → switch-CBOzecWS.js} +1 -1
- package/dist/assets/{tabs-custom-D3HYMt6k.js → tabs-custom-Bx3cNhD-.js} +1 -1
- package/dist/assets/tag-chip-zUaDE2-H.js +1 -0
- package/dist/assets/{trash-2-G48scll7.js → trash-2-CQUgYyRn.js} +1 -1
- package/dist/assets/use-infinite-scroll-loader-B5V2Klve.js +1 -0
- package/dist/assets/useConfirmDialog-patAnl1g.js +1 -0
- package/dist/assets/{useMutation-CBWjE2uj.js → useMutation-__AYv-Pz.js} +1 -1
- package/dist/assets/x-BHUGQIUv.js +1 -0
- package/dist/index.html +22 -22
- package/dist/runtime-icons/claude.ico +0 -0
- package/dist/runtime-icons/codex-openai.svg +6 -0
- package/dist/runtime-icons/hermes-agent.png +0 -0
- package/module-structure.config.json +7 -0
- package/package.json +6 -6
- package/public/runtime-icons/claude.ico +0 -0
- package/public/runtime-icons/codex-openai.svg +6 -0
- package/public/runtime-icons/hermes-agent.png +0 -0
- package/src/api/chat-session-type.types.ts +7 -0
- package/src/api/config.ts +10 -0
- package/src/api/raw-client.test.ts +1 -1
- package/src/api/{raw-client.ts → raw-client.utils.ts} +2 -0
- package/src/api/runtime-control.types.ts +8 -0
- package/src/api/types.ts +48 -0
- package/src/app/components/app-manager-provider.tsx +20 -0
- package/src/app/managers/app.manager.ts +12 -0
- package/src/app.tsx +223 -59
- package/src/components/agents/agent-dialogs.tsx +499 -0
- package/src/components/agents/agents-page.test.tsx +238 -0
- package/src/components/agents/agents-page.tsx +435 -0
- package/src/components/chat/chat-conversation-panel.test.tsx +30 -0
- package/src/components/chat/chat-conversation-panel.tsx +83 -13
- package/src/components/chat/chat-input/ncp-chat-input-availability.utils.test.ts +92 -0
- package/src/components/chat/chat-input/ncp-chat-input-availability.utils.ts +45 -0
- package/src/components/chat/chat-page-shell.tsx +19 -13
- package/src/components/chat/chat-session-type-option-item.test.tsx +46 -0
- package/src/components/chat/chat-session-type-option-item.tsx +68 -0
- package/src/components/chat/chat-session-workspace-file-preview.test.tsx +87 -0
- package/src/components/chat/chat-session-workspace-file-preview.tsx +14 -43
- package/src/components/chat/chat-session-workspace-panel-nav.tsx +8 -2
- package/src/components/chat/chat-sidebar-project-groups.tsx +11 -36
- package/src/components/chat/containers/chat-input-bar.container.tsx +24 -12
- package/src/components/chat/{ChatSidebar.test.tsx → containers/chat-sidebar.test.tsx} +5 -4
- package/src/components/chat/{ChatSidebar.tsx → containers/chat-sidebar.tsx} +24 -72
- package/src/components/chat/hooks/use-chat-sidebar-session-label-editor.ts +49 -0
- package/src/components/chat/ncp/__tests__/ncp-session-adapter.cancelled-tool.test.ts +77 -0
- package/src/components/chat/ncp/ncp-app-client-fetch.ts +3 -0
- package/src/components/chat/ncp/ncp-chat-input.manager.ts +13 -5
- package/src/components/chat/ncp/ncp-chat-page.tsx +23 -2
- package/src/components/chat/ncp/ncp-session-adapter.test.ts +1 -0
- package/src/components/chat/ncp/ncp-session-adapter.ts +3 -0
- package/src/components/chat/ncp/page/ncp-chat-derived-state.ts +10 -4
- package/src/components/chat/ncp/session-conversation/use-ncp-session-conversation.test.tsx +48 -4
- package/src/components/chat/ncp/session-conversation/use-ncp-session-conversation.ts +43 -5
- package/src/components/chat/ncp/tests/ncp-chat-input.manager.test.ts +51 -1
- package/src/components/chat/stores/chat-input.store.ts +2 -1
- package/src/components/chat/stores/chat-thread.store.ts +3 -1
- package/src/components/chat/useChatSessionTypeState.ts +10 -1
- package/src/components/chat/workspace/chat-session-workspace-file-breadcrumbs.tsx +86 -0
- package/src/components/common/BrandHeader.tsx +3 -1
- package/src/components/common/session-context-icon.tsx +15 -2
- package/src/components/common/{TagInput.tsx → tag-input.tsx} +25 -17
- package/src/components/config/ChannelForm.test.tsx +89 -3
- package/src/components/config/ChannelForm.tsx +157 -188
- package/src/components/config/ChannelsList.test.tsx +163 -119
- package/src/components/config/ChannelsList.tsx +90 -101
- package/src/components/config/ProviderForm.tsx +108 -146
- package/src/components/config/ProvidersList.tsx +100 -123
- package/src/components/config/SearchConfig.tsx +423 -393
- package/src/components/config/channel-form-fields-section.tsx +70 -37
- package/src/components/config/config-split-page.tsx +109 -0
- package/src/components/config/desktop-update-config.test.tsx +10 -4
- package/src/components/config/desktop-update-config.tsx +5 -3
- package/src/components/config/provider-enabled-field.tsx +17 -10
- package/src/components/config/runtime-control-card.test.tsx +136 -158
- package/src/components/config/runtime-control-card.tsx +43 -68
- package/src/components/config/runtime-presence-card.test.tsx +10 -14
- package/src/components/config/runtime-presence-card.tsx +97 -81
- package/src/components/layout/AppLayout.tsx +25 -37
- package/src/components/layout/Sidebar.tsx +4 -4
- package/src/components/layout/app-layout.test.tsx +46 -14
- package/src/components/layout/runtime-status-entry.test.tsx +101 -0
- package/src/components/layout/runtime-status-entry.tsx +95 -0
- package/src/components/layout/sidebar.layout.test.tsx +11 -5
- package/src/components/marketplace/marketplace-detail-doc.ts +93 -0
- package/src/components/marketplace/marketplace-list-card.tsx +288 -0
- package/src/components/marketplace/marketplace-page-data.ts +129 -0
- package/src/components/marketplace/marketplace-page.test.tsx +339 -0
- package/src/components/marketplace/marketplace-page.tsx +596 -0
- package/src/components/marketplace/mcp/mcp-marketplace-card.tsx +128 -0
- package/src/components/marketplace/mcp/mcp-marketplace-dialogs.tsx +191 -0
- package/src/components/marketplace/mcp/mcp-marketplace-doc.ts +152 -0
- package/src/components/marketplace/mcp/mcp-marketplace-page.test.tsx +223 -0
- package/src/components/marketplace/mcp/mcp-marketplace-page.tsx +414 -0
- package/src/components/ui/notice-card.tsx +129 -0
- package/src/components/ui/setting-row.tsx +51 -0
- package/src/components/ui/tag-chip.tsx +39 -0
- package/src/components/ui/textarea.tsx +19 -0
- package/src/features/account/components/account-panel.tsx +255 -0
- package/src/features/account/index.ts +6 -0
- package/src/{account → features/account}/managers/account.manager.ts +6 -5
- package/src/features/remote/components/remote-access-page.test.tsx +104 -0
- package/src/features/remote/components/remote-access-page.tsx +250 -0
- package/src/{hooks/useRemoteAccess.ts → features/remote/hooks/use-remote-access.ts} +1 -1
- package/src/features/remote/index.ts +27 -0
- package/src/{remote → features/remote}/managers/remote-access.manager.ts +3 -4
- package/src/{remote → features/remote/services}/remote-access-feedback.service.test.ts +1 -1
- package/src/features/system-status/hooks/use-system-status.ts +104 -0
- package/src/features/system-status/index.ts +12 -0
- package/src/features/system-status/managers/system-status.manager.bootstrap-polling.test.ts +126 -0
- package/src/features/system-status/managers/system-status.manager.test.ts +142 -0
- package/src/features/system-status/managers/system-status.manager.ts +511 -0
- package/src/features/system-status/stores/system-status.store.ts +32 -0
- package/src/features/system-status/types/system-status.types.ts +73 -0
- package/src/features/system-status/utils/system-status.utils.test.ts +132 -0
- package/src/features/system-status/utils/system-status.utils.ts +202 -0
- package/src/hooks/use-realtime-query-bridge.ts +34 -18
- package/src/hooks/useConfig.ts +2 -1
- package/src/index.css +24 -0
- package/src/lib/app-resource-uri.test.ts +20 -0
- package/src/lib/app-resource-uri.ts +29 -0
- package/src/lib/i18n.chat.ts +8 -0
- package/src/lib/i18n.remote.ts +1 -1
- package/src/lib/i18n.runtime-control.ts +31 -0
- package/src/lib/i18n.ts +5 -8
- package/src/lib/session-context.utils.test.ts +71 -0
- package/src/lib/session-context.utils.ts +28 -3
- package/src/lib/session-project/workspace-file-breadcrumb.test.ts +83 -0
- package/src/lib/session-project/workspace-file-breadcrumb.ts +188 -0
- package/src/platforms/desktop/index.ts +20 -0
- package/src/{desktop → platforms/desktop}/managers/desktop-presence.manager.ts +2 -2
- package/src/{desktop → platforms/desktop}/managers/desktop-update.manager.ts +2 -2
- package/src/{desktop → platforms/desktop}/stores/desktop-presence.store.ts +1 -1
- package/src/{desktop → platforms/desktop}/stores/desktop-update.store.ts +1 -1
- package/src/stores/ui.store.ts +0 -9
- package/src/transport/{app-client.ts → app-client.service.ts} +9 -9
- package/src/transport/app-client.test.ts +9 -5
- package/src/transport/index.ts +1 -1
- package/src/transport/{local.transport.ts → local-transport.service.ts} +14 -12
- package/dist/assets/ChannelsList-Ita2Zm1_.js +0 -8
- package/dist/assets/DocBrowser-BNwbPHf4.js +0 -1
- package/dist/assets/MarketplacePage-CjX2MWww.js +0 -1
- package/dist/assets/MarketplacePage-D0sDlYX4.js +0 -49
- package/dist/assets/McpMarketplacePage-BGKJm1sJ.js +0 -40
- package/dist/assets/ModelConfig-BzZenCH-.js +0 -1
- package/dist/assets/ProviderScopedModelInput-Da7khnBA.js +0 -1
- package/dist/assets/ProvidersList-BbVzRxjY.js +0 -1
- package/dist/assets/RemoteAccessPage-BaDH_X1Q.js +0 -1
- package/dist/assets/RuntimeConfig-F_XKGgLm.js +0 -1
- package/dist/assets/SearchConfig-BGkzXQP-.js +0 -1
- package/dist/assets/SecretsConfig-D281Rotl.js +0 -3
- package/dist/assets/app-query-client-VnFElj4E.js +0 -1
- package/dist/assets/chat-page-Doe0yTtB.js +0 -58
- package/dist/assets/chat-session-display-cw78aiI_.js +0 -1
- package/dist/assets/client-_i4MU2bB.js +0 -7
- package/dist/assets/config-DtIQwrHF.js +0 -1
- package/dist/assets/config-layout-CHs0mAaR.js +0 -1
- package/dist/assets/desktop-update-config-Dpcf4BKG.js +0 -1
- package/dist/assets/dist-ccBFUi-o.js +0 -9
- package/dist/assets/index-CF9xve0E.js +0 -6
- package/dist/assets/index-FgA52VBt.css +0 -1
- package/dist/assets/infiniteQueryBehavior-ZDS92Qpp.js +0 -1
- package/dist/assets/loader-circle-ACM1s51e.js +0 -1
- package/dist/assets/page-layout-vZnghcFy.js +0 -1
- package/dist/assets/play-CFUwCA2E.js +0 -1
- package/dist/assets/plus-rYsv72JG.js +0 -1
- package/dist/assets/popover-Bg1VoTZ6.js +0 -1
- package/dist/assets/refresh-ccw-DT98i__E.js +0 -1
- package/dist/assets/rotate-cw-JtFzpNn6.js +0 -1
- package/dist/assets/search-3kFR_zh9.js +0 -1
- package/dist/assets/security-config-BWaiARNk.js +0 -1
- package/dist/assets/select-DJ2MUjBB.js +0 -41
- package/dist/assets/skeleton-ByQepn0M.js +0 -1
- package/dist/assets/status-dot-vbanNPFU.js +0 -1
- package/dist/assets/use-infinite-scroll-loader-DkNhD-42.js +0 -1
- package/dist/assets/useConfirmDialog-BkvTN-vd.js +0 -1
- package/dist/assets/x-ByDbItbq.js +0 -1
- package/src/account/components/account-panel.tsx +0 -135
- package/src/components/agents/AgentDialogs.tsx +0 -400
- package/src/components/agents/AgentsPage.test.tsx +0 -217
- package/src/components/agents/AgentsPage.tsx +0 -352
- package/src/components/config/config-layout.ts +0 -10
- package/src/components/marketplace/MarketplacePage.test.tsx +0 -322
- package/src/components/marketplace/MarketplacePage.tsx +0 -827
- package/src/components/marketplace/mcp/McpMarketplacePage.test.tsx +0 -208
- package/src/components/marketplace/mcp/McpMarketplacePage.tsx +0 -580
- package/src/components/remote/RemoteAccessPage.test.tsx +0 -103
- package/src/components/remote/RemoteAccessPage.tsx +0 -144
- package/src/hooks/use-runtime-control.ts +0 -24
- package/src/presenter/app-presenter-context.tsx +0 -20
- package/src/presenter/app.presenter.ts +0 -12
- package/src/runtime-control/runtime-control.manager.ts +0 -118
- /package/dist/assets/{config-hints-BhTmc9P1.js → config-hints-DSQQbeOA.js} +0 -0
- /package/src/{account → features/account}/stores/account.store.ts +0 -0
- /package/src/{remote → features/remote/services}/remote-access-feedback.service.ts +0 -0
- /package/src/{remote/remote-access.query.ts → features/remote/services/remote-access-query.service.ts} +0 -0
- /package/src/{remote → features/remote}/stores/remote-access.store.ts +0 -0
- /package/src/{desktop → platforms/desktop/types}/desktop-update.types.ts +0 -0
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import { useQueryClient } from '@tanstack/react-query';
|
|
3
|
+
import { CircleDotDashed, Trash2 } from 'lucide-react';
|
|
4
|
+
import { toast } from 'sonner';
|
|
3
5
|
import {
|
|
4
6
|
useConfig,
|
|
5
7
|
useConfigMeta,
|
|
@@ -11,16 +13,20 @@ import {
|
|
|
11
13
|
useTestProviderConnection,
|
|
12
14
|
useUpdateProvider
|
|
13
15
|
} from '@/hooks/useConfig';
|
|
16
|
+
import { MaskedInput } from '@/components/common/MaskedInput';
|
|
14
17
|
import { Button } from '@/components/ui/button';
|
|
15
18
|
import { Input } from '@/components/ui/input';
|
|
16
19
|
import { Label } from '@/components/ui/label';
|
|
17
|
-
import { MaskedInput } from '@/components/common/MaskedInput';
|
|
18
|
-
import { getLanguage, t } from '@/lib/i18n';
|
|
19
20
|
import { hintForPath } from '@/lib/config-hints';
|
|
21
|
+
import { getLanguage, t } from '@/lib/i18n';
|
|
20
22
|
import type { ProviderConfigUpdate, ProviderConnectionTestRequest, ThinkingLevel } from '@/api/types';
|
|
21
|
-
import {
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
import {
|
|
24
|
+
ConfigSplitDetailPane,
|
|
25
|
+
ConfigSplitEmptyPane,
|
|
26
|
+
ConfigSplitPaneBody,
|
|
27
|
+
ConfigSplitPaneFooter,
|
|
28
|
+
ConfigSplitPaneHeader
|
|
29
|
+
} from './config-split-page';
|
|
24
30
|
import { ProviderAdvancedSettingsSection } from './provider-advanced-settings-section';
|
|
25
31
|
import { ProviderAuthSection } from './provider-auth-section';
|
|
26
32
|
import { ProviderEnabledField } from './provider-enabled-field';
|
|
@@ -86,7 +92,6 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
86
92
|
const resolvedProviderConfig = providerConfig ?? EMPTY_PROVIDER_CONFIG;
|
|
87
93
|
const uiHints = schema?.uiHints;
|
|
88
94
|
const isCustomProvider = Boolean(providerSpec?.isCustom);
|
|
89
|
-
|
|
90
95
|
const apiKeyHint = providerName ? hintForPath(`providers.${providerName}.apiKey`, uiHints) : undefined;
|
|
91
96
|
const apiBaseHint = providerName ? hintForPath(`providers.${providerName}.apiBase`, uiHints) : undefined;
|
|
92
97
|
const extraHeadersHint = providerName ? hintForPath(`providers.${providerName}.extraHeaders`, uiHints) : undefined;
|
|
@@ -95,12 +100,10 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
95
100
|
const currentDisplayName = (resolvedProviderConfig.displayName || '').trim();
|
|
96
101
|
const effectiveDisplayName = currentDisplayName || defaultDisplayName;
|
|
97
102
|
const currentEnabled = resolvedProviderConfig.enabled !== false;
|
|
98
|
-
|
|
99
103
|
const providerTitle = providerDisplayName.trim() || effectiveDisplayName || providerName || t('providersSelectPlaceholder');
|
|
100
|
-
const providerModelPrefix = providerSpec?.modelPrefix || providerName || '';
|
|
101
104
|
const providerModelAliases = useMemo(
|
|
102
|
-
() => normalizeModelList([
|
|
103
|
-
[
|
|
105
|
+
() => normalizeModelList([providerSpec?.modelPrefix || providerName || '', providerName || '']),
|
|
106
|
+
[providerName, providerSpec?.modelPrefix]
|
|
104
107
|
);
|
|
105
108
|
const defaultApiBase = providerSpec?.defaultApiBase || '';
|
|
106
109
|
const currentApiBase = resolvedProviderConfig.apiBase || defaultApiBase;
|
|
@@ -120,10 +123,7 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
120
123
|
),
|
|
121
124
|
[resolvedProviderConfig.models, providerModelAliases]
|
|
122
125
|
);
|
|
123
|
-
const currentEditableModels = useMemo(
|
|
124
|
-
() => resolveEditableModels(defaultModels, currentModels),
|
|
125
|
-
[defaultModels, currentModels]
|
|
126
|
-
);
|
|
126
|
+
const currentEditableModels = useMemo(() => resolveEditableModels(defaultModels, currentModels), [defaultModels, currentModels]);
|
|
127
127
|
const currentModelThinking = useMemo(
|
|
128
128
|
() =>
|
|
129
129
|
normalizeModelThinkingForModels(
|
|
@@ -134,15 +134,9 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
134
134
|
);
|
|
135
135
|
const language = getLanguage();
|
|
136
136
|
const apiBaseHelpText =
|
|
137
|
-
providerSpec?.apiBaseHelp?.[language] ||
|
|
138
|
-
providerSpec?.apiBaseHelp?.en ||
|
|
139
|
-
apiBaseHint?.help ||
|
|
140
|
-
t('providerApiBaseHelp');
|
|
137
|
+
providerSpec?.apiBaseHelp?.[language] || providerSpec?.apiBaseHelp?.en || apiBaseHint?.help || t('providerApiBaseHelp');
|
|
141
138
|
const providerAuth = providerSpec?.auth;
|
|
142
|
-
const providerAuthMethods =
|
|
143
|
-
() => providerAuth?.methods ?? [],
|
|
144
|
-
[providerAuth?.methods]
|
|
145
|
-
);
|
|
139
|
+
const providerAuthMethods = providerAuth?.methods ?? [];
|
|
146
140
|
const supportsWireApi = Boolean(providerSpec?.supportsWireApi) || isCustomProvider;
|
|
147
141
|
const providerAuthMethodOptions = useMemo(
|
|
148
142
|
() =>
|
|
@@ -153,12 +147,7 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
153
147
|
[providerAuthMethods, language]
|
|
154
148
|
);
|
|
155
149
|
const preferredAuthMethodId = useMemo(
|
|
156
|
-
() => resolvePreferredAuthMethodId({
|
|
157
|
-
providerName,
|
|
158
|
-
methods: providerAuthMethods,
|
|
159
|
-
defaultMethodId: providerAuth?.defaultMethodId,
|
|
160
|
-
language
|
|
161
|
-
}),
|
|
150
|
+
() => resolvePreferredAuthMethodId({ providerName, methods: providerAuthMethods, defaultMethodId: providerAuth?.defaultMethodId, language }),
|
|
162
151
|
[providerName, providerAuth?.defaultMethodId, providerAuthMethods, language]
|
|
163
152
|
);
|
|
164
153
|
const resolvedAuthMethodId = useMemo(() => {
|
|
@@ -180,8 +169,7 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
180
169
|
hasDefault: Boolean(providerAuth?.defaultMethodId?.trim()),
|
|
181
170
|
optionCount: providerAuthMethods.length
|
|
182
171
|
});
|
|
183
|
-
const
|
|
184
|
-
const wireApiSelectOptions: PillSelectOption[] = wireApiOptions.map((option) => ({
|
|
172
|
+
const wireApiSelectOptions: PillSelectOption[] = (providerSpec?.wireApiOptions || ['auto', 'chat', 'responses']).map((option) => ({
|
|
185
173
|
value: option,
|
|
186
174
|
label: option === 'chat' ? t('wireApiChat') : option === 'responses' ? t('wireApiResponses') : t('wireApiAuto')
|
|
187
175
|
}));
|
|
@@ -198,46 +186,46 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
198
186
|
}
|
|
199
187
|
}, []);
|
|
200
188
|
|
|
201
|
-
const scheduleProviderAuthPoll = useCallback(
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
try {
|
|
209
|
-
const result = await pollProviderAuth.mutateAsync({
|
|
210
|
-
provider: providerName,
|
|
211
|
-
data: { sessionId }
|
|
212
|
-
});
|
|
213
|
-
if (result.status === 'pending') {
|
|
214
|
-
setAuthStatusMessage(t('providerAuthWaitingBrowser'));
|
|
215
|
-
scheduleProviderAuthPoll(sessionId, result.nextPollMs ?? delayMs);
|
|
189
|
+
const scheduleProviderAuthPoll = useCallback(
|
|
190
|
+
(sessionId: string, delayMs: number) => {
|
|
191
|
+
clearAuthPollTimer();
|
|
192
|
+
authPollTimerRef.current = window.setTimeout(() => {
|
|
193
|
+
void (async () => {
|
|
194
|
+
if (!providerName) {
|
|
216
195
|
return;
|
|
217
196
|
}
|
|
218
|
-
|
|
197
|
+
try {
|
|
198
|
+
const result = await pollProviderAuth.mutateAsync({ provider: providerName, data: { sessionId } });
|
|
199
|
+
if (result.status === 'pending') {
|
|
200
|
+
setAuthStatusMessage(t('providerAuthWaitingBrowser'));
|
|
201
|
+
scheduleProviderAuthPoll(sessionId, result.nextPollMs ?? delayMs);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (result.status === 'authorized') {
|
|
205
|
+
setAuthSessionId(null);
|
|
206
|
+
clearAuthPollTimer();
|
|
207
|
+
setAuthStatusMessage(t('providerAuthCompleted'));
|
|
208
|
+
toast.success(t('providerAuthCompleted'));
|
|
209
|
+
queryClient.invalidateQueries({ queryKey: ['config'] });
|
|
210
|
+
queryClient.invalidateQueries({ queryKey: ['config-meta'] });
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
219
213
|
setAuthSessionId(null);
|
|
220
214
|
clearAuthPollTimer();
|
|
221
|
-
setAuthStatusMessage(
|
|
222
|
-
toast.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
215
|
+
setAuthStatusMessage(result.message || `Authorization ${result.status}.`);
|
|
216
|
+
toast.error(result.message || `Authorization ${result.status}.`);
|
|
217
|
+
} catch (error) {
|
|
218
|
+
setAuthSessionId(null);
|
|
219
|
+
clearAuthPollTimer();
|
|
220
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
221
|
+
setAuthStatusMessage(message);
|
|
222
|
+
toast.error(`Authorization failed: ${message}`);
|
|
226
223
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
setAuthSessionId(null);
|
|
233
|
-
clearAuthPollTimer();
|
|
234
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
235
|
-
setAuthStatusMessage(message);
|
|
236
|
-
toast.error(`Authorization failed: ${message}`);
|
|
237
|
-
}
|
|
238
|
-
})();
|
|
239
|
-
}, Math.max(1000, delayMs));
|
|
240
|
-
}, [clearAuthPollTimer, pollProviderAuth, providerName, queryClient]);
|
|
224
|
+
})();
|
|
225
|
+
}, Math.max(1000, delayMs));
|
|
226
|
+
},
|
|
227
|
+
[clearAuthPollTimer, pollProviderAuth, providerName, queryClient]
|
|
228
|
+
);
|
|
241
229
|
|
|
242
230
|
useEffect(() => {
|
|
243
231
|
if (!providerName) {
|
|
@@ -284,40 +272,24 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
284
272
|
]);
|
|
285
273
|
|
|
286
274
|
useEffect(() => () => clearAuthPollTimer(), [clearAuthPollTimer]);
|
|
287
|
-
|
|
288
|
-
useEffect(() => {
|
|
289
|
-
setModelThinking((prev) => normalizeModelThinkingForModels(prev, models));
|
|
290
|
-
}, [models]);
|
|
275
|
+
useEffect(() => setModelThinking((prev) => normalizeModelThinkingForModels(prev, models)), [models]);
|
|
291
276
|
|
|
292
277
|
const hasChanges = useMemo(() => {
|
|
293
278
|
if (!providerName) {
|
|
294
279
|
return false;
|
|
295
280
|
}
|
|
296
|
-
const apiKeyChanged = apiKey.trim().length > 0;
|
|
297
|
-
const apiBaseChanged = apiBase.trim() !== currentApiBase.trim();
|
|
298
|
-
const headersChanged = !headersEqual(extraHeaders, currentHeaders);
|
|
299
|
-
const wireApiChanged = supportsWireApi ? wireApi !== currentWireApi : false;
|
|
300
|
-
const modelsChanged = !modelListsEqual(models, currentEditableModels);
|
|
301
|
-
const modelThinkingChanged = !modelThinkingEqual(modelThinking, currentModelThinking);
|
|
302
|
-
const displayNameChanged = isCustomProvider
|
|
303
|
-
? providerDisplayName.trim() !== effectiveDisplayName
|
|
304
|
-
: false;
|
|
305
|
-
|
|
306
281
|
return (
|
|
307
|
-
|
|
282
|
+
apiKey.trim().length > 0 ||
|
|
308
283
|
enabled !== currentEnabled ||
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
284
|
+
apiBase.trim() !== currentApiBase.trim() ||
|
|
285
|
+
!headersEqual(extraHeaders, currentHeaders) ||
|
|
286
|
+
(supportsWireApi && wireApi !== currentWireApi) ||
|
|
287
|
+
!modelListsEqual(models, currentEditableModels) ||
|
|
288
|
+
!modelThinkingEqual(modelThinking, currentModelThinking) ||
|
|
289
|
+
(isCustomProvider && providerDisplayName.trim() !== effectiveDisplayName)
|
|
315
290
|
);
|
|
316
291
|
}, [
|
|
317
292
|
providerName,
|
|
318
|
-
isCustomProvider,
|
|
319
|
-
providerDisplayName,
|
|
320
|
-
effectiveDisplayName,
|
|
321
293
|
apiKey,
|
|
322
294
|
enabled,
|
|
323
295
|
currentEnabled,
|
|
@@ -331,7 +303,10 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
331
303
|
models,
|
|
332
304
|
currentEditableModels,
|
|
333
305
|
modelThinking,
|
|
334
|
-
currentModelThinking
|
|
306
|
+
currentModelThinking,
|
|
307
|
+
isCustomProvider,
|
|
308
|
+
providerDisplayName,
|
|
309
|
+
effectiveDisplayName
|
|
335
310
|
]);
|
|
336
311
|
|
|
337
312
|
const handleAddModel = () => {
|
|
@@ -379,16 +354,13 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
379
354
|
}
|
|
380
355
|
return {
|
|
381
356
|
...prev,
|
|
382
|
-
[modelName]: level
|
|
383
|
-
? { supported: currentEntry.supported, default: level }
|
|
384
|
-
: { supported: currentEntry.supported }
|
|
357
|
+
[modelName]: level ? { supported: currentEntry.supported, default: level } : { supported: currentEntry.supported }
|
|
385
358
|
};
|
|
386
359
|
});
|
|
387
360
|
};
|
|
388
361
|
|
|
389
362
|
const handleSubmit = (e: React.FormEvent) => {
|
|
390
363
|
e.preventDefault();
|
|
391
|
-
|
|
392
364
|
if (!providerName) {
|
|
393
365
|
return;
|
|
394
366
|
}
|
|
@@ -402,20 +374,16 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
402
374
|
if (isCustomProvider && trimmedDisplayName !== effectiveDisplayName) {
|
|
403
375
|
payload.displayName = trimmedDisplayName.length > 0 ? trimmedDisplayName : null;
|
|
404
376
|
}
|
|
405
|
-
|
|
406
377
|
if (trimmedApiKey.length > 0) {
|
|
407
378
|
payload.apiKey = trimmedApiKey;
|
|
408
379
|
}
|
|
409
380
|
applyEnabledPatch(payload, enabled, currentEnabled);
|
|
410
|
-
|
|
411
381
|
if (trimmedApiBase !== currentApiBase.trim()) {
|
|
412
382
|
payload.apiBase = trimmedApiBase.length > 0 && trimmedApiBase !== defaultApiBase ? trimmedApiBase : null;
|
|
413
383
|
}
|
|
414
|
-
|
|
415
384
|
if (!headersEqual(normalizedHeaders, currentHeaders)) {
|
|
416
385
|
payload.extraHeaders = normalizedHeaders;
|
|
417
386
|
}
|
|
418
|
-
|
|
419
387
|
if (supportsWireApi && wireApi !== currentWireApi) {
|
|
420
388
|
payload.wireApi = wireApi;
|
|
421
389
|
}
|
|
@@ -433,7 +401,6 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
433
401
|
if (!providerName) {
|
|
434
402
|
return;
|
|
435
403
|
}
|
|
436
|
-
|
|
437
404
|
const preferredModel = models.find((modelName) => modelName.trim().length > 0) ?? '';
|
|
438
405
|
const testModel = toProviderLocalModelId(preferredModel, providerModelAliases);
|
|
439
406
|
const payload: ProviderConnectionTestRequest = {
|
|
@@ -449,10 +416,7 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
449
416
|
}
|
|
450
417
|
|
|
451
418
|
try {
|
|
452
|
-
const result = await testProviderConnection.mutateAsync({
|
|
453
|
-
provider: providerName,
|
|
454
|
-
data: payload
|
|
455
|
-
});
|
|
419
|
+
const result = await testProviderConnection.mutateAsync({ provider: providerName, data: payload });
|
|
456
420
|
if (result.success) {
|
|
457
421
|
toast.success(`${t('providerTestConnectionSuccess')} (${result.latencyMs}ms)`);
|
|
458
422
|
return;
|
|
@@ -472,8 +436,7 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
472
436
|
if (!providerName || !isCustomProvider) {
|
|
473
437
|
return;
|
|
474
438
|
}
|
|
475
|
-
|
|
476
|
-
if (!confirmed) {
|
|
439
|
+
if (!window.confirm(t('providerDeleteConfirm'))) {
|
|
477
440
|
return;
|
|
478
441
|
}
|
|
479
442
|
try {
|
|
@@ -519,8 +482,7 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
519
482
|
clearAuthPollTimer();
|
|
520
483
|
setAuthSessionId(null);
|
|
521
484
|
const result = await importProviderAuthFromCli.mutateAsync({ provider: providerName });
|
|
522
|
-
|
|
523
|
-
setAuthStatusMessage(`${t('providerAuthImportStatusPrefix')}${expiresText}`);
|
|
485
|
+
setAuthStatusMessage(`${t('providerAuthImportStatusPrefix')}${result.expiresAt ? ` (expires: ${result.expiresAt})` : ''}`);
|
|
524
486
|
toast.success(t('providerAuthImportSuccess'));
|
|
525
487
|
queryClient.invalidateQueries({ queryKey: ['config'] });
|
|
526
488
|
queryClient.invalidateQueries({ queryKey: ['config-meta'] });
|
|
@@ -533,71 +495,71 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
533
495
|
|
|
534
496
|
if (!providerName || !providerSpec) {
|
|
535
497
|
return (
|
|
536
|
-
<
|
|
498
|
+
<ConfigSplitEmptyPane>
|
|
537
499
|
<div>
|
|
538
|
-
<h3 className=
|
|
539
|
-
<p className=
|
|
500
|
+
<h3 className='text-base font-semibold text-gray-900'>{t('providersSelectTitle')}</h3>
|
|
501
|
+
<p className='mt-2 text-sm text-gray-500'>{t('providersSelectDescription')}</p>
|
|
540
502
|
</div>
|
|
541
|
-
</
|
|
503
|
+
</ConfigSplitEmptyPane>
|
|
542
504
|
);
|
|
543
505
|
}
|
|
544
506
|
|
|
545
507
|
return (
|
|
546
|
-
<
|
|
547
|
-
<
|
|
548
|
-
<div className=
|
|
549
|
-
<h3 className=
|
|
550
|
-
<div className=
|
|
508
|
+
<ConfigSplitDetailPane>
|
|
509
|
+
<ConfigSplitPaneHeader className='px-6 py-4'>
|
|
510
|
+
<div className='flex items-center justify-between'>
|
|
511
|
+
<h3 className='truncate text-lg font-semibold text-gray-900'>{providerTitle}</h3>
|
|
512
|
+
<div className='flex items-center gap-3'>
|
|
551
513
|
{isCustomProvider && (
|
|
552
514
|
<button
|
|
553
|
-
type=
|
|
515
|
+
type='button'
|
|
554
516
|
onClick={handleDeleteProvider}
|
|
555
517
|
disabled={deleteProvider.isPending}
|
|
556
|
-
className=
|
|
518
|
+
className='text-gray-400 transition-colors hover:text-red-500'
|
|
557
519
|
title={t('providerDelete')}
|
|
558
520
|
>
|
|
559
|
-
<Trash2 className=
|
|
521
|
+
<Trash2 className='h-4 w-4' />
|
|
560
522
|
</button>
|
|
561
523
|
)}
|
|
562
524
|
<ProviderStatusBadge enabled={currentEnabled} apiKeySet={resolvedProviderConfig.apiKeySet} />
|
|
563
525
|
</div>
|
|
564
526
|
</div>
|
|
565
|
-
</
|
|
527
|
+
</ConfigSplitPaneHeader>
|
|
566
528
|
|
|
567
|
-
<form onSubmit={handleSubmit} className=
|
|
568
|
-
<
|
|
529
|
+
<form onSubmit={handleSubmit} className='flex min-h-0 flex-1 flex-col'>
|
|
530
|
+
<ConfigSplitPaneBody className='space-y-5 px-6 py-5'>
|
|
569
531
|
<ProviderEnabledField enabled={enabled} onChange={setEnabled} />
|
|
570
532
|
|
|
571
533
|
{isCustomProvider && (
|
|
572
|
-
<div className=
|
|
573
|
-
<Label htmlFor=
|
|
534
|
+
<div className='space-y-2'>
|
|
535
|
+
<Label htmlFor='providerDisplayName' className='text-sm font-medium text-gray-900'>
|
|
574
536
|
{t('providerDisplayName')}
|
|
575
537
|
</Label>
|
|
576
538
|
<Input
|
|
577
|
-
id=
|
|
578
|
-
type=
|
|
539
|
+
id='providerDisplayName'
|
|
540
|
+
type='text'
|
|
579
541
|
value={providerDisplayName}
|
|
580
542
|
onChange={(e) => setProviderDisplayName(e.target.value)}
|
|
581
543
|
placeholder={defaultDisplayName || t('providerDisplayNamePlaceholder')}
|
|
582
|
-
className=
|
|
544
|
+
className='rounded-xl'
|
|
583
545
|
/>
|
|
584
|
-
<p className=
|
|
546
|
+
<p className='text-xs text-gray-500'>{t('providerDisplayNameHelpShort')}</p>
|
|
585
547
|
</div>
|
|
586
548
|
)}
|
|
587
549
|
|
|
588
|
-
<div className=
|
|
589
|
-
<Label htmlFor=
|
|
550
|
+
<div className='space-y-2'>
|
|
551
|
+
<Label htmlFor='apiKey' className='text-sm font-medium text-gray-900'>
|
|
590
552
|
{apiKeyHint?.label ?? t('apiKey')}
|
|
591
553
|
</Label>
|
|
592
554
|
<MaskedInput
|
|
593
|
-
id=
|
|
555
|
+
id='apiKey'
|
|
594
556
|
value={apiKey}
|
|
595
557
|
isSet={resolvedProviderConfig.apiKeySet}
|
|
596
558
|
onChange={(e) => setApiKey(e.target.value)}
|
|
597
559
|
placeholder={apiKeyHint?.placeholder ?? t('enterApiKey')}
|
|
598
|
-
className=
|
|
560
|
+
className='rounded-xl'
|
|
599
561
|
/>
|
|
600
|
-
<p className=
|
|
562
|
+
<p className='text-xs text-gray-500'>{t('leaveBlankToKeepUnchanged')}</p>
|
|
601
563
|
</div>
|
|
602
564
|
|
|
603
565
|
<ProviderAuthSection
|
|
@@ -617,19 +579,19 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
617
579
|
authStatusMessage={authStatusMessage}
|
|
618
580
|
/>
|
|
619
581
|
|
|
620
|
-
<div className=
|
|
621
|
-
<Label htmlFor=
|
|
582
|
+
<div className='space-y-2'>
|
|
583
|
+
<Label htmlFor='apiBase' className='text-sm font-medium text-gray-900'>
|
|
622
584
|
{apiBaseHint?.label ?? t('apiBase')}
|
|
623
585
|
</Label>
|
|
624
586
|
<Input
|
|
625
|
-
id=
|
|
626
|
-
type=
|
|
587
|
+
id='apiBase'
|
|
588
|
+
type='text'
|
|
627
589
|
value={apiBase}
|
|
628
590
|
onChange={(e) => setApiBase(e.target.value)}
|
|
629
591
|
placeholder={defaultApiBase || apiBaseHint?.placeholder || 'https://api.example.com'}
|
|
630
|
-
className=
|
|
592
|
+
className='rounded-xl'
|
|
631
593
|
/>
|
|
632
|
-
<p className=
|
|
594
|
+
<p className='text-xs text-gray-500'>{apiBaseHelpText}</p>
|
|
633
595
|
</div>
|
|
634
596
|
|
|
635
597
|
<ProviderModelsSection
|
|
@@ -667,18 +629,18 @@ export function ProviderForm({ providerName, onProviderDeleted }: ProviderFormPr
|
|
|
667
629
|
extraHeaders={extraHeaders}
|
|
668
630
|
onExtraHeadersChange={setExtraHeaders}
|
|
669
631
|
/>
|
|
670
|
-
</
|
|
632
|
+
</ConfigSplitPaneBody>
|
|
671
633
|
|
|
672
|
-
<
|
|
673
|
-
<Button type=
|
|
674
|
-
<CircleDotDashed className=
|
|
634
|
+
<ConfigSplitPaneFooter className='flex items-center justify-between px-6 py-4'>
|
|
635
|
+
<Button type='button' variant='outline' size='sm' onClick={handleTestConnection} disabled={testProviderConnection.isPending}>
|
|
636
|
+
<CircleDotDashed className='mr-1.5 h-4 w-4' />
|
|
675
637
|
{testProviderConnection.isPending ? t('providerTestingConnection') : t('providerTestConnection')}
|
|
676
638
|
</Button>
|
|
677
|
-
<Button type=
|
|
639
|
+
<Button type='submit' disabled={updateProvider.isPending || !hasChanges}>
|
|
678
640
|
{updateProvider.isPending ? t('saving') : hasChanges ? t('save') : t('unchanged')}
|
|
679
641
|
</Button>
|
|
680
|
-
</
|
|
642
|
+
</ConfigSplitPaneFooter>
|
|
681
643
|
</form>
|
|
682
|
-
</
|
|
644
|
+
</ConfigSplitDetailPane>
|
|
683
645
|
);
|
|
684
646
|
}
|