diff --git a/packages/frontend/editor-ui/src/features/settings/usage/views/SettingsUsageAndPlan.test.ts b/packages/frontend/editor-ui/src/features/settings/usage/views/SettingsUsageAndPlan.test.ts index c649c020b1e..5e6ef8d3616 100644 --- a/packages/frontend/editor-ui/src/features/settings/usage/views/SettingsUsageAndPlan.test.ts +++ b/packages/frontend/editor-ui/src/features/settings/usage/views/SettingsUsageAndPlan.test.ts @@ -257,6 +257,63 @@ describe('SettingsUsageAndPlan', () => { expect(usageStore.activateLicense).toHaveBeenCalledTimes(1); }); + it('should preserve activation key during EULA flow and send it with acceptance', async () => { + usageStore.isLoading = false; + usageStore.planName = 'Community'; + usersStore.currentUser = { + globalScopes: ['license:manage'], + } as IUser; + rbacStore.setGlobalScopes(['license:manage']); + usageStore.activateLicense + .mockRejectedValueOnce({ + httpStatusCode: 400, + meta: { eulaUrl: 'https://example.com/eula.pdf' }, + }) + .mockResolvedValueOnce(undefined); + + const { getByRole, findByTestId } = renderComponent(); + + // Open activation modal and enter key + await userEvent.click(getByRole('button', { name: /activation/i })); + const input = document.querySelector('input') as HTMLInputElement; + await userEvent.type(input, 'test-key-123'); + + // Click activate - this should trigger EULA modal + await userEvent.click(getByRole('button', { name: /activate/i })); + + // EULA modal should appear + const eulaModal = await findByTestId('eula-acceptance-modal'); + expect(eulaModal).toBeInTheDocument(); + + // Accept EULA + const checkbox = (await findByTestId('eula-checkbox')).querySelector( + 'input[type="checkbox"]', + ) as HTMLInputElement; + await userEvent.click(checkbox); + + const acceptButton = await findByTestId('eula-accept-button'); + await userEvent.click(acceptButton); + + // Verify the activation key was preserved and sent with EULA acceptance + await waitFor(() => { + expect(usageStore.activateLicense).toHaveBeenCalledTimes(2); + // First call without EULA + expect(usageStore.activateLicense).toHaveBeenNthCalledWith(1, 'test-key-123', undefined); + // Second call with EULA URL - key should still be present + expect(usageStore.activateLicense).toHaveBeenNthCalledWith( + 2, + 'test-key-123', + 'https://example.com/eula.pdf', + ); + }); + + expect(mockToast.showMessage).toHaveBeenCalledWith( + expect.objectContaining({ + type: 'success', + }), + ); + }); + it('should show error when activation fails without EULA requirement', async () => { usageStore.isLoading = false; usageStore.planName = 'Community'; @@ -424,5 +481,41 @@ describe('SettingsUsageAndPlan', () => { expect(reopenedInput).toBeInTheDocument(); }); }); + + it('should clear activation key when cancel button is clicked', async () => { + usageStore.isLoading = false; + usersStore.currentUser = { + globalScopes: ['license:manage'], + } as IUser; + rbacStore.setGlobalScopes(['license:manage']); + + const { getByRole, findByPlaceholderText } = renderComponent(); + + await waitAllPromises(); + + // Open activation modal + await userEvent.click(getByRole('button', { name: /activation/i })); + const input = await findByPlaceholderText('Activation key'); + expect(input).toBeInTheDocument(); + + // Enter activation key + await userEvent.type(input, 'test-key-should-be-cleared'); + expect(input).toHaveValue('test-key-should-be-cleared'); + + // Click cancel + const cancelButton = getByRole('button', { name: /cancel/i }); + await userEvent.click(cancelButton); + + await waitAllPromises(); + + // Reopen modal + await userEvent.click(getByRole('button', { name: /activation/i })); + + // Input should be cleared + await waitFor(async () => { + const reopenedInput = await findByPlaceholderText('Activation key'); + expect(reopenedInput).toHaveValue(''); + }); + }); }); }); diff --git a/packages/frontend/editor-ui/src/features/settings/usage/views/SettingsUsageAndPlan.vue b/packages/frontend/editor-ui/src/features/settings/usage/views/SettingsUsageAndPlan.vue index 1a5a38e229f..5c0beb4043b 100644 --- a/packages/frontend/editor-ui/src/features/settings/usage/views/SettingsUsageAndPlan.vue +++ b/packages/frontend/editor-ui/src/features/settings/usage/views/SettingsUsageAndPlan.vue @@ -111,9 +111,9 @@ const onLicenseActivation = async (eulaUri?: string) => { } catch (error: unknown) { // Check if error requires EULA acceptance using type guard if (isEulaError(error)) { - activationKeyModal.value = false; eulaUrl.value = error.meta.eulaUrl; eulaModal.value = true; + activationKeyModal.value = false; return; } @@ -138,6 +138,18 @@ const onEulaCancel = () => { activationKey.value = ''; }; +const onActivationCancel = () => { + activationKeyModal.value = false; + activationKey.value = ''; +}; + +const onActivationModalClose = () => { + // Only clear key if not transitioning to EULA flow + if (!eulaModal.value) { + onActivationCancel(); + } +}; + onMounted(async () => { documentTitle.set(locale.baseText('settings.usageAndPlan.title')); usageStore.setLoading(true); @@ -187,10 +199,6 @@ const onManagePlan = () => { sendUsageTelemetry('manage_plan'); }; -const onDialogClosed = () => { - activationKey.value = ''; -}; - const onDialogOpened = () => { activationKeyInput.value?.focus(); }; @@ -307,7 +315,7 @@ const openCommunityRegisterModal = () => { top="0" :title="locale.baseText('settings.usageAndPlan.dialog.activation.title')" :modal-class="$style.center" - @closed="onDialogClosed" + @closed="onActivationModalClose" @opened="onDialogOpened" >