From 093091a74bab1ebdf2bfb7b072bed9fe30e2d9a9 Mon Sep 17 00:00:00 2001 From: Isaac Ivins Date: Wed, 21 Jan 2026 16:37:14 -0500 Subject: [PATCH] wip - added milestone 3 FF --- .../src/auth/delete-account.component.html | 22 +++++--- .../src/auth/delete-account.component.ts | 51 +++++++++++++++---- libs/common/src/enums/feature-flag.enum.ts | 8 +++ 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/apps/desktop/src/auth/delete-account.component.html b/apps/desktop/src/auth/delete-account.component.html index 0d5eec29bf4..08448e2422d 100644 --- a/apps/desktop/src/auth/delete-account.component.html +++ b/apps/desktop/src/auth/delete-account.component.html @@ -6,14 +6,22 @@ {{ "deleteAccountWarning" | i18n }} - -
- -
+ verificationType="server" + [invalidSecret]="invalidSecret" + > + } @else { + +
+ +
+ }

{{ "confirmIdentity" | i18n }}

diff --git a/apps/desktop/src/auth/delete-account.component.ts b/apps/desktop/src/auth/delete-account.component.ts index 5cd73896e07..b3bad0eba96 100644 --- a/apps/desktop/src/auth/delete-account.component.ts +++ b/apps/desktop/src/auth/delete-account.component.ts @@ -1,13 +1,15 @@ // FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore -import { Component } from "@angular/core"; +import { Component, OnInit } from "@angular/core"; import { FormBuilder, ReactiveFormsModule } from "@angular/forms"; import { JslibModule } from "@bitwarden/angular/jslib.module"; +import { UserVerificationFormInputComponent } from "@bitwarden/auth/angular"; import { AccountApiService } from "@bitwarden/common/auth/abstractions/account-api.service"; import { VerificationWithSecret } from "@bitwarden/common/auth/types/verification"; +import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum"; +import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service"; import { DialogRef, AsyncActionsModule, @@ -27,6 +29,7 @@ import { UserVerificationComponent } from "../app/components/user-verification.c templateUrl: "delete-account.component.html", imports: [ JslibModule, + UserVerificationFormInputComponent, UserVerificationComponent, ButtonModule, CalloutModule, @@ -35,19 +38,36 @@ import { UserVerificationComponent } from "../app/components/user-verification.c ReactiveFormsModule, ], }) -export class DeleteAccountComponent { +export class DeleteAccountComponent implements OnInit { deleteForm = this.formBuilder.group({ verification: undefined as VerificationWithSecret | undefined, }); + /** + * Tracks whether the verification failed due to invalid credentials. + * Used to show inline error messages in the verification component. + */ + protected invalidSecret = false; + + /** + * Feature flag for UI Migration Milestone 3 + */ + protected migrationMilestone3 = false; + constructor( private i18nService: I18nService, - private platformUtilsService: PlatformUtilsService, private formBuilder: FormBuilder, private accountApiService: AccountApiService, private toastService: ToastService, + private configService: ConfigService, ) {} + async ngOnInit() { + this.migrationMilestone3 = await this.configService.getFeatureFlag( + FeatureFlag.DesktopUiMigrationMilestone3, + ); + } + static open(dialogService: DialogService): DialogRef { return dialogService.open(DeleteAccountComponent); } @@ -57,12 +77,21 @@ export class DeleteAccountComponent { } submit = async () => { - const verification = this.deleteForm.get("verification").value; - await this.accountApiService.deleteAccount(verification); - this.toastService.showToast({ - variant: "success", - title: this.i18nService.t("accountDeleted"), - message: this.i18nService.t("accountDeletedDesc"), - }); + try { + if (this.migrationMilestone3) { + this.invalidSecret = false; // Reset error state before attempting + } + const verification = this.deleteForm.get("verification").value; + await this.accountApiService.deleteAccount(verification); + this.toastService.showToast({ + variant: "success", + title: this.i18nService.t("accountDeleted"), + message: this.i18nService.t("accountDeletedDesc"), + }); + } catch { + if (this.migrationMilestone3) { + this.invalidSecret = true; + } + } }; } diff --git a/libs/common/src/enums/feature-flag.enum.ts b/libs/common/src/enums/feature-flag.enum.ts index 9f6beb5f81e..65346113fcd 100644 --- a/libs/common/src/enums/feature-flag.enum.ts +++ b/libs/common/src/enums/feature-flag.enum.ts @@ -76,6 +76,7 @@ export enum FeatureFlag { /* Desktop */ DesktopUiMigrationMilestone1 = "desktop-ui-migration-milestone-1", + DesktopUiMigrationMilestone3 = "desktop-ui-migration-milestone-3", /* UIF */ RouterFocusManagement = "router-focus-management", @@ -164,6 +165,7 @@ export const DefaultFeatureFlagValue = { /* Desktop */ [FeatureFlag.DesktopUiMigrationMilestone1]: FALSE, + [FeatureFlag.DesktopUiMigrationMilestone3]: FALSE, /* UIF */ [FeatureFlag.RouterFocusManagement]: FALSE, @@ -180,6 +182,12 @@ export function getFeatureFlagValue( serverConfig: ServerConfig | null, flag: Flag, ) { + if (flag === FeatureFlag.DesktopUiMigrationMilestone1) { + return true; + } + if (flag === FeatureFlag.DesktopUiMigrationMilestone3) { + return true; + } if (serverConfig?.featureStates == null || serverConfig.featureStates[flag] == null) { return DefaultFeatureFlagValue[flag]; }