From c4f70244ca15f1971dc01a150adb65f2cf88d07e Mon Sep 17 00:00:00 2001 From: Ajit Mehrotra Date: Mon, 30 Mar 2026 16:49:29 -0400 Subject: [PATCH 1/2] fix(onboarding): reload after https hostname apply - Purpose: move the unavoidable HTTPS certificate interruption to immediately after a successful hostname change in onboarding - Before: users applied settings, advanced normally, and only hit the cert warning later when leaving onboarding for the dashboard - Problem: the interruption happened at the wrong moment, which made the flow feel broken and could leave users re-running apply after refresh - Change: when onboarding successfully renames the server during an HTTPS session, the Summary result confirmation now advances to NEXT_STEPS first, then reloads - How: arm a reload flag only after a successful HTTPS hostname change, consume it when the result dialog is confirmed, await step advancement, then reload and cover the flow with a regression test --- .../Onboarding/OnboardingSummaryStep.test.ts | 28 +++++++++++++++++-- .../steps/OnboardingSummaryStep.vue | 24 +++++++++++++--- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/web/__test__/components/Onboarding/OnboardingSummaryStep.test.ts b/web/__test__/components/Onboarding/OnboardingSummaryStep.test.ts index 1cb8b99d9a..43ca634fb2 100644 --- a/web/__test__/components/Onboarding/OnboardingSummaryStep.test.ts +++ b/web/__test__/components/Onboarding/OnboardingSummaryStep.test.ts @@ -295,7 +295,7 @@ interface SummaryVm { applyResultSeverity: 'success' | 'warning' | 'error'; handleBootDriveWarningConfirm: () => Promise; handleBootDriveWarningCancel: () => void; - handleApplyResultConfirm: () => void; + handleApplyResultConfirm: () => Promise; } const getSummaryVm = (wrapper: ReturnType['wrapper']) => @@ -332,7 +332,7 @@ const clickButtonByText = async ( } else if (normalizedTarget === 'cancel') { vm.handleBootDriveWarningCancel(); } else if (normalizedTarget === 'ok') { - vm.handleApplyResultConfirm(); + await vm.handleApplyResultConfirm(); } else { expect(button).toBeTruthy(); } @@ -1015,6 +1015,30 @@ describe('OnboardingSummaryStep', () => { expect(onComplete).not.toHaveBeenCalled(); }); + it('advances to next steps before reloading after a successful HTTPS server rename', async () => { + draftStore.serverName = 'Newtower'; + const protocolSpy = vi.spyOn(window.location, 'protocol', 'get').mockReturnValue('https:'); + const reloadSpy = vi.spyOn(window.location, 'reload').mockImplementation(() => undefined); + const { wrapper, onComplete } = mountComponent(); + + await clickApply(wrapper); + + expect(updateServerIdentityMock).toHaveBeenCalledWith({ + name: 'Newtower', + comment: '', + sysModel: undefined, + }); + expect(onComplete).not.toHaveBeenCalled(); + + await clickButtonByText(wrapper, 'OK'); + + expect(onComplete).toHaveBeenCalledTimes(1); + expect(reloadSpy).toHaveBeenCalledTimes(1); + + protocolSpy.mockRestore(); + reloadSpy.mockRestore(); + }); + it('retries final identity update after transient network errors when SSH changed', async () => { draftStore.useSsh = true; draftStore.serverDescription = 'Primary host'; diff --git a/web/src/components/Onboarding/steps/OnboardingSummaryStep.vue b/web/src/components/Onboarding/steps/OnboardingSummaryStep.vue index 86a1e89625..ddceae80f1 100644 --- a/web/src/components/Onboarding/steps/OnboardingSummaryStep.vue +++ b/web/src/components/Onboarding/steps/OnboardingSummaryStep.vue @@ -1,5 +1,5 @@