diff --git a/ui/src/pages/Secrets.render.test.tsx b/ui/src/pages/Secrets.render.test.tsx index e80e31c68bb..ca75e981dd0 100644 --- a/ui/src/pages/Secrets.render.test.tsx +++ b/ui/src/pages/Secrets.render.test.tsx @@ -703,6 +703,42 @@ describe("Secrets page layout", () => { }); }); + it("opens the New secret dialog when provider queries fail", async () => { + mockSecretsApi.providers.mockRejectedValueOnce(new ApiError(403, "Providers unavailable")); + mockSecretsApi.providerConfigs.mockRejectedValueOnce(new ApiError(403, "Provider vaults unavailable")); + const root = createRoot(container); + const queryClient = new QueryClient({ + defaultOptions: { queries: { retry: false } }, + }); + + await act(async () => { + root.render( + + + + + , + ); + }); + await flushReact(); + await flushReact(); + + const newSecretButton = Array.from(container.querySelectorAll("button")).find( + (button) => button.textContent?.includes("New secret"), + ) as HTMLButtonElement | undefined; + await act(async () => { + newSecretButton?.click(); + }); + await flushReact(); + + expect(document.body.textContent).toContain("Create secret"); + expect(document.body.textContent).toContain("Select a provider."); + + await act(async () => { + root.unmount(); + }); + }); + it("opens the each-user detail sheet with coverage and set-my-value actions", async () => { const definition = makeUserSecretDefinition(); mockSecretsApi.listUserSecretDefinitions.mockResolvedValue([definition]); diff --git a/ui/src/pages/Secrets.tsx b/ui/src/pages/Secrets.tsx index 94ab638740a..d3924b7d850 100644 --- a/ui/src/pages/Secrets.tsx +++ b/ui/src/pages/Secrets.tsx @@ -143,6 +143,12 @@ type SafeProviderErrorDetails = { safeAlternative?: string; }; +const EMPTY_SECRETS: CompanySecret[] = []; +const EMPTY_USER_SECRET_DEFINITIONS: UserSecretDefinition[] = []; +const EMPTY_MY_USER_SECRETS: MyUserSecretEntry[] = []; +const EMPTY_SECRET_PROVIDERS: SecretProviderDescriptor[] = []; +const EMPTY_PROVIDER_CONFIGS: CompanySecretProviderConfig[] = []; + const PROVIDER_ORDER: SecretProvider[] = [ "local_encrypted", "aws_secrets_manager", @@ -693,11 +699,11 @@ export function Secrets() { retry: false, }); - const secrets = secretsQuery.data ?? []; - const userDefinitions = userDefinitionsQuery.data ?? []; - const myUserSecrets = myUserSecretsQuery.data ?? []; - const providers = providersQuery.data ?? []; - const providerConfigs = providerConfigsQuery.data ?? []; + const secrets = secretsQuery.data ?? EMPTY_SECRETS; + const userDefinitions = userDefinitionsQuery.data ?? EMPTY_USER_SECRET_DEFINITIONS; + const myUserSecrets = myUserSecretsQuery.data ?? EMPTY_MY_USER_SECRETS; + const providers = providersQuery.data ?? EMPTY_SECRET_PROVIDERS; + const providerConfigs = providerConfigsQuery.data ?? EMPTY_PROVIDER_CONFIGS; const selectedSecret = useMemo( () => secrets.find((secret) => secret.id === selectedSecretId) ?? null, [secrets, selectedSecretId], @@ -1199,9 +1205,11 @@ export function Secrets() { if (!createOpen) return; const current = providerConfigs.find((config) => config.id === createForm.providerConfigId); if (current?.provider === createForm.provider) return; + const nextProviderConfigId = getDefaultProviderConfigId(providerConfigs, createForm.provider); + if (nextProviderConfigId === createForm.providerConfigId) return; setCreateForm((form) => ({ ...form, - providerConfigId: getDefaultProviderConfigId(providerConfigs, form.provider), + providerConfigId: nextProviderConfigId, })); }, [createForm.provider, createForm.providerConfigId, createOpen, providerConfigs]);