diff --git a/frontend/src/pages/settings/settings-provider.tsx b/frontend/src/pages/settings/settings-provider.tsx index afee537a..3329c086 100644 --- a/frontend/src/pages/settings/settings-provider.tsx +++ b/frontend/src/pages/settings/settings-provider.tsx @@ -1065,8 +1065,10 @@ const extractAgentTypes = (agents: unknown): null | string[] => { return types.length > 0 ? types : null; }; -interface DeleteProviderDialogProps - extends Pick, 'handleConfirm' | 'handleOpenChange' | 'isOpen'> { +interface DeleteProviderDialogProps extends Pick< + ComponentProps, + 'handleConfirm' | 'handleOpenChange' | 'isOpen' +> { control: Control; } @@ -1258,6 +1260,16 @@ function SettingsProvider() { const queryType = formQueryParams.type ?? undefined; const queryId = formQueryParams.id; + // A hand-typed ?type= URL bypasses the create menu's enabled-only filter; an + // unknown or disabled type would otherwise create a dead provider or dump a raw + // zod error on submit. Bounce it to the list. (Clone-by-id, below, is exempt.) + if (!queryId && queryType && !providers.enabled[queryType as keyof typeof providers.enabled]) { + toast.error(`Provider type "${queryType}" is not available`); + navigate(routes.settings.providers, { replace: true }); + + return; + } + if (queryId && data?.settingsProviders?.userDefined) { const sourceProvider = data.settingsProviders.userDefined.find((p: Provider) => p.id == queryId); diff --git a/frontend/src/pages/settings/settings-providers.tsx b/frontend/src/pages/settings/settings-providers.tsx index c312e0b4..acb81b8f 100644 --- a/frontend/src/pages/settings/settings-providers.tsx +++ b/frontend/src/pages/settings/settings-providers.tsx @@ -452,6 +452,9 @@ function SettingsProviders() { function SettingsProvidersHeader() { const navigate = useNavigate(); + // Cached: the list above already fetched this query, so the read is local. + const { data } = useQuery(SettingsProvidersDocument); + const enabled = data?.settingsProviders?.enabled; const handleProviderCreate = (providerType: string) => { navigate(routes.settings.newProvider({ type: providerType })); @@ -486,19 +489,24 @@ function SettingsProvidersHeader() { width: 'var(--radix-dropdown-menu-trigger-width)', }} > - {providerTypes.map(({ label, type }) => { - const Icon = providerIcons[type]?.icon; + {/* Only offer types whose API key is configured — creating a provider of a + disabled type yields one that's unusable for flows (the create form guards + the same against a hand-typed ?type=). */} + {providerTypes + .filter(({ type }) => enabled?.[type as keyof typeof enabled]) + .map(({ label, type }) => { + const Icon = providerIcons[type]?.icon; - return ( - handleProviderCreate(type)} - > - {Icon && } - {label} - - ); - })} + return ( + handleProviderCreate(type)} + > + {Icon && } + {label} + + ); + })}