1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-10 21:33:27 +00:00

[PM-25216] - handle extension already installed on new user creation (#16650)

* handle extension already installed on new user creation

* fix tests

* remove comment
This commit is contained in:
Jordan Aasen
2025-10-01 13:21:11 -07:00
committed by GitHub
parent 5de8a145ec
commit 688647b2c6
6 changed files with 32 additions and 33 deletions

View File

@@ -29,15 +29,32 @@
</div>
</section>
<section *ngIf="state === SetupExtensionState.Success" class="tw-flex tw-flex-col tw-items-center">
<section
*ngIf="state === SetupExtensionState.Success || state === SetupExtensionState.AlreadyInstalled"
class="tw-flex tw-flex-col tw-items-center"
>
<div class="tw-size-[90px]">
<bit-icon [icon]="PartyIcon"></bit-icon>
</div>
<h1 bitTypography="h2" class="tw-mb-6 tw-mt-4">{{ "bitwardenExtensionInstalled" | i18n }}</h1>
<h1 bitTypography="h2" class="tw-mb-6 tw-mt-4 tw-text-center">
{{
(state === SetupExtensionState.Success
? "bitwardenExtensionInstalled"
: "openTheBitwardenExtension"
) | i18n
}}
</h1>
<div
class="tw-flex tw-flex-col tw-rounded-2xl tw-bg-background tw-border tw-border-solid tw-border-secondary-300 tw-p-8"
class="tw-flex tw-flex-col tw-rounded-2xl tw-bg-background tw-border tw-border-solid tw-border-secondary-300 tw-p-8 tw-max-w-md tw-text-center"
>
<p>{{ "openExtensionToAutofill" | i18n }}</p>
<p>
{{
(state === SetupExtensionState.Success
? "openExtensionToAutofill"
: "bitwardenExtensionInstalledOpenExtension"
) | i18n
}}
</p>
<button type="button" bitButton buttonType="primary" class="tw-mb-2" (click)="openExtension()">
{{ "openBitwardenExtension" | i18n }}
</button>

View File

@@ -93,14 +93,9 @@ describe("SetupExtensionComponent", () => {
});
describe("extensionInstalled$", () => {
it("redirects the user to the vault when the first emitted value is true", () => {
extensionInstalled$.next(true);
expect(navigate).toHaveBeenCalledWith(["/vault"]);
});
describe("success state", () => {
beforeEach(() => {
update.mockClear();
// avoid initial redirect
extensionInstalled$.next(false);

View File

@@ -36,6 +36,7 @@ export const SetupExtensionState = {
Loading: "loading",
NeedsExtension: "needs-extension",
Success: "success",
AlreadyInstalled: "already-installed",
ManualOpen: "manual-open",
} as const;
@@ -99,9 +100,10 @@ export class SetupExtensionComponent implements OnInit, OnDestroy {
this.webBrowserExtensionInteractionService.extensionInstalled$
.pipe(takeUntilDestroyed(this.destroyRef), startWith(null), pairwise())
.subscribe(([previousState, currentState]) => {
// Initial state transitioned to extension installed, redirect the user
// User landed on the page and the extension is already installed, show already installed state
if (previousState === null && currentState) {
void this.router.navigate(["/vault"]);
void this.dismissExtensionPage();
this.state = SetupExtensionState.AlreadyInstalled;
}
// Extension was not installed and now it is, show success state

View File

@@ -82,13 +82,6 @@ describe("setupExtensionRedirectGuard", () => {
expect(await setupExtensionGuard()).toBe(true);
});
it("returns `true` when the user has the extension installed", async () => {
state$.next(false);
extensionInstalled$.next(true);
expect(await setupExtensionGuard()).toBe(true);
});
it('redirects the user to "/setup-extension" when all criteria do not pass', async () => {
state$.next(false);
extensionInstalled$.next(false);

View File

@@ -11,8 +11,6 @@ import {
UserKeyDefinition,
} from "@bitwarden/common/platform/state";
import { WebBrowserInteractionService } from "../services/web-browser-interaction.service";
export const SETUP_EXTENSION_DISMISSED = new UserKeyDefinition<boolean>(
SETUP_EXTENSION_DISMISSED_DISK,
"setupExtensionDismissed",
@@ -27,7 +25,6 @@ export const setupExtensionRedirectGuard: CanActivateFn = async () => {
const accountService = inject(AccountService);
const vaultProfileService = inject(VaultProfileService);
const stateProvider = inject(StateProvider);
const webBrowserInteractionService = inject(WebBrowserInteractionService);
const isMobile = Utils.isMobileBrowser;
@@ -43,10 +40,6 @@ export const setupExtensionRedirectGuard: CanActivateFn = async () => {
return router.createUrlTree(["/login"]);
}
const hasExtensionInstalledPromise = firstValueFrom(
webBrowserInteractionService.extensionInstalled$,
);
const dismissedExtensionPage = await firstValueFrom(
stateProvider
.getUser(currentAcct.id, SETUP_EXTENSION_DISMISSED)
@@ -66,13 +59,6 @@ export const setupExtensionRedirectGuard: CanActivateFn = async () => {
return true;
}
// Checking for the extension is a more expensive operation, do it last to avoid unnecessary delays.
const hasExtensionInstalled = await hasExtensionInstalledPromise;
if (hasExtensionInstalled) {
return true;
}
return router.createUrlTree(["/setup-extension"]);
};

View File

@@ -11199,6 +11199,12 @@
"bitwardenExtensionInstalled": {
"message": "Bitwarden extension installed!"
},
"openTheBitwardenExtension": {
"message": "Open the Bitwarden extension"
},
"bitwardenExtensionInstalledOpenExtension": {
"message": "The Bitwarden extension is installed! Open the extension to log in and start autofilling."
},
"openExtensionToAutofill": {
"message": "Open the extension to log in and start autofilling."
},