From 4e611a7907fae9da1e66d60f6b88a59076f9bd0e Mon Sep 17 00:00:00 2001 From: hannahwestra25 Date: Wed, 12 Aug 2026 16:45:21 -0400 Subject: [PATCH] fix(gui): keep saved initializer settings visible when catalog loading fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use Promise.allSettled instead of Promise.all so a catalog endpoint failure does not prevent successfully fetched settings from rendering. Each fetch result is handled independently — settings remain visible even when the catalog is unavailable, and errors are surfaced in the status message bar. Fixes #2348 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../Initializers/Initializers.test.tsx | 10 +++++ .../components/Initializers/Initializers.tsx | 44 +++++++++++-------- 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/frontend/src/components/Initializers/Initializers.test.tsx b/frontend/src/components/Initializers/Initializers.test.tsx index 08f6cd4d14..8f312137d1 100644 --- a/frontend/src/components/Initializers/Initializers.test.tsx +++ b/frontend/src/components/Initializers/Initializers.test.tsx @@ -259,6 +259,16 @@ describe('Initializers', () => { expect(within(baselineRow).queryByRole('button', { name: 'Apply now' })).not.toBeInTheDocument() }) + it('should keep saved settings visible when catalog loading fails', async () => { + mockedInitializersApi.listRegistered.mockRejectedValue(new Error('Service Unavailable')) + + renderInitializers() + + expect(await screen.findByTestId('baseline-initializer-row-target')).toBeInTheDocument() + expect(screen.getByTestId('initializer-row-additional-1')).toBeInTheDocument() + expect(screen.getByText('Service Unavailable')).toBeInTheDocument() + }) + it('should remove an additional initializer and show success feedback', async () => { const user = userEvent.setup() renderInitializers() diff --git a/frontend/src/components/Initializers/Initializers.tsx b/frontend/src/components/Initializers/Initializers.tsx index bbd655dfa2..684f085675 100644 --- a/frontend/src/components/Initializers/Initializers.tsx +++ b/frontend/src/components/Initializers/Initializers.tsx @@ -38,26 +38,32 @@ export default function Initializers() { let cancelled = false const loadInitializersAsync = async (): Promise => { - try { - const [settingsResponse, registeredResponse] = await Promise.all([ - initializersApi.getSettings(), - initializersApi.listRegistered(), - ]) - if (cancelled) { - return - } - setSettings(settingsResponse) - setRegisteredInitializers(registeredResponse.items) - } catch (error) { - if (cancelled) { - return - } - setStatusMessage({ intent: 'error', text: toApiError(error).detail }) - } finally { - if (!cancelled) { - setLoading(false) - } + const [settingsResult, registeredResult] = await Promise.allSettled([ + initializersApi.getSettings(), + initializersApi.listRegistered(), + ]) + if (cancelled) { + return } + + if (settingsResult.status === 'fulfilled') { + setSettings(settingsResult.value) + } else { + setStatusMessage({ intent: 'error', text: toApiError(settingsResult.reason).detail }) + } + + if (registeredResult.status === 'fulfilled') { + setRegisteredInitializers(registeredResult.value.items) + } else { + const catalogError = toApiError(registeredResult.reason).detail + setStatusMessage((current: StatusMessage | null) => + current + ? { intent: 'error', text: `${current.text} ${catalogError}` } + : { intent: 'error', text: catalogError }, + ) + } + + setLoading(false) } void loadInitializersAsync()