From a8001fc05a4e1da4c7b9d255cf49a1fa9c333fb6 Mon Sep 17 00:00:00 2001 From: Sawyer Date: Wed, 30 Sep 2026 00:03:31 -0700 Subject: [PATCH] fix(web): Settings lists only inference providers, and the Settings connect dialog has no Skip (CL-9609) --- .../src/onboarding/provider-connect-step.tsx | 11 +- apps/web/src/settings/credentials-section.tsx | 113 +++++++++--------- apps/web/src/settings/inference-providers.ts | 18 +++ apps/web/src/settings/models-section.tsx | 5 +- 4 files changed, 86 insertions(+), 61 deletions(-) create mode 100644 apps/web/src/settings/inference-providers.ts diff --git a/apps/web/src/onboarding/provider-connect-step.tsx b/apps/web/src/onboarding/provider-connect-step.tsx index 8eb4d1ac5..022086f3a 100644 --- a/apps/web/src/onboarding/provider-connect-step.tsx +++ b/apps/web/src/onboarding/provider-connect-step.tsx @@ -222,7 +222,8 @@ export function ProviderConnectStep({ readonly tenantId: string; readonly onConnected: (offering: ExistingOffering) => void; readonly onError: (message: string) => void; - readonly onSkip: () => void; + /** Omitted outside onboarding: only the first-run flow can be skipped. */ + readonly onSkip?: () => void; }) { const [selected, setSelected] = useState(null); const [apiKey, setApiKey] = useState(""); @@ -523,9 +524,11 @@ export function ProviderConnectStep({ - + {onSkip === undefined ? null : ( + + )} ); diff --git a/apps/web/src/settings/credentials-section.tsx b/apps/web/src/settings/credentials-section.tsx index 9f1424e27..a0b4600c5 100644 --- a/apps/web/src/settings/credentials-section.tsx +++ b/apps/web/src/settings/credentials-section.tsx @@ -49,6 +49,7 @@ import { SETTINGS_STRINGS } from "./strings"; import { ConfirmButton } from "../components/confirm-button"; import { ProviderConnectStep } from "../onboarding/provider-connect-step"; import { SettingsGroup, SettingsRow } from "./rows"; +import { inferenceProviders, providerLabel } from "./inference-providers"; type CatalogProvider = typeof ModelProviderResponse.infer; type CatalogOffering = typeof ModelOfferingResponse.infer; @@ -279,66 +280,73 @@ export function CredentialsSection({ tenantId }: { readonly tenantId: string | n return ( - {({ credentials }) => ( - setCreateOpen(true)}> - {SETTINGS_STRINGS.credentialsCreateAction} - - } - > - {del.error === null || del.error === undefined ? null : ( -

- {SETTINGS_STRINGS.credentialsDeleteError} -

- )} - {signIn.error === null || signIn.error === undefined ? null : ( -

- {SETTINGS_STRINGS.credentialsSignInAgainError} -

- )} - del.mutate(credential)} - onSignIn={(credential) => signIn.mutate(credential)} - /> - { - setCreateOpen(false); - reload(); - }} - /> - { - if (!open) setEditing(null); - }} - onSave={(input) => update.mutate(input)} - submitting={update.isPending} - error={update.error === null ? null : SETTINGS_STRINGS.credentialsEditError} - /> -
- )} + {({ credentials: all, providers }) => { + const inference = inferenceProviders(providers); + const credentials = all.filter((row) => inference.some((p) => p.id === row.providerId)); + return ( + setCreateOpen(true)}> + {SETTINGS_STRINGS.credentialsCreateAction} + + } + > + {del.error === null || del.error === undefined ? null : ( +

+ {SETTINGS_STRINGS.credentialsDeleteError} +

+ )} + {signIn.error === null || signIn.error === undefined ? null : ( +

+ {SETTINGS_STRINGS.credentialsSignInAgainError} +

+ )} + del.mutate(credential)} + onSignIn={(credential) => signIn.mutate(credential)} + /> + { + setCreateOpen(false); + reload(); + }} + /> + { + if (!open) setEditing(null); + }} + onSave={(input) => update.mutate(input)} + submitting={update.isPending} + error={update.error === null ? null : SETTINGS_STRINGS.credentialsEditError} + /> +
+ ); + }}
); } function CredentialsTable({ credentials, + providers, signingIn, onEdit, onDelete, onSignIn, }: { readonly credentials: readonly Credential[]; + readonly providers: readonly Provider[]; readonly signingIn: boolean; readonly onEdit: (credential: Credential) => void; readonly onDelete: (credential: Credential) => void; @@ -357,7 +365,7 @@ function CredentialsTable({ {credentials.map((credential) => ( p.id === credential.providerId))} meta={ <> {credential.type} @@ -424,12 +432,7 @@ function AddProviderDialog({ - onOpenChange(false)} - /> + {error !== null && (

{error} diff --git a/apps/web/src/settings/inference-providers.ts b/apps/web/src/settings/inference-providers.ts new file mode 100644 index 000000000..a6fea9555 --- /dev/null +++ b/apps/web/src/settings/inference-providers.ts @@ -0,0 +1,18 @@ +import { ModelProviderPlugin } from "@intx/types"; + +import { PROVIDER_OPTIONS } from "../onboarding/provider-connect-step"; +import type { Provider } from "./credentials-api"; + +/** Model providers only: MCP servers and hub-internal credentials hang off + * providers with other plugins and are managed elsewhere. */ +export function inferenceProviders(providers: readonly Provider[]): readonly Provider[] { + return providers.filter((provider) => ModelProviderPlugin.allows(provider.plugin)); +} + +/** The picker's label when the row was created from it, else the row's own name. */ +export function providerLabel(provider: Provider | undefined): string { + if (provider === undefined) return "Provider"; + const name = provider.name.toLowerCase(); + const option = PROVIDER_OPTIONS.find((candidate) => candidate.label.toLowerCase() === name); + return option?.label ?? provider.name; +} diff --git a/apps/web/src/settings/models-section.tsx b/apps/web/src/settings/models-section.tsx index 14de1a7cc..7f2a1b383 100644 --- a/apps/web/src/settings/models-section.tsx +++ b/apps/web/src/settings/models-section.tsx @@ -8,6 +8,7 @@ import { QueryView, toAPIQuery } from "@/lib/api-query"; import { listProviders, type Provider } from "./credentials-api"; import { getResolvedCatalog, type ModelInfo } from "./inference"; import { SettingsGroup, SettingsRow } from "./rows"; +import { inferenceProviders, providerLabel } from "./inference-providers"; import { SETTINGS_STRINGS } from "./strings"; type ModelsData = { @@ -48,7 +49,7 @@ export function ModelsSection({ tenantId }: { readonly tenantId: string | null } description={SETTINGS_STRINGS.modelsSectionDescription} >

{SETTINGS_STRINGS.modelsProvidersHeading}

- +

{SETTINGS_STRINGS.modelsCatalogHeading}

@@ -69,7 +70,7 @@ function ProvidersTable({ providers }: { readonly providers: readonly Provider[] return ( <> {providers.map((provider) => ( - + ))} );