mirror of
https://github.com/bitwarden/browser
synced 2026-02-07 20:24:01 +00:00
[PM-2014] feat: add delete dialog
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Injectable, Optional } from "@angular/core";
|
||||
import { BehaviorSubject, from, map, Observable, shareReplay, switchMap, tap } from "rxjs";
|
||||
import { BehaviorSubject, filter, from, map, Observable, shareReplay, switchMap, tap } from "rxjs";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/abstractions/i18n.service";
|
||||
import { LogService } from "@bitwarden/common/abstractions/log.service";
|
||||
@@ -105,6 +105,15 @@ export class WebauthnService {
|
||||
}
|
||||
}
|
||||
|
||||
getCredential$(credentialId: string): Observable<WebauthnCredentialView> {
|
||||
return this.credentials$.pipe(
|
||||
map(
|
||||
(credentials) => credentials.find((c) => c.id === credentialId),
|
||||
filter((c) => c !== undefined)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private getCredentials$(): Observable<WebauthnCredentialView[]> {
|
||||
return from(this.apiService.getCredentials()).pipe(map((response) => response.data));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<form [formGroup]="formGroup" [bitSubmit]="submit">
|
||||
<bit-dialog dialogSize="large">
|
||||
<span bitDialogTitle
|
||||
>{{ "removePasskey" | i18n }}
|
||||
<span *ngIf="credential" class="tw-text-sm tw-normal-case tw-text-muted">{{
|
||||
credential.name
|
||||
}}</span>
|
||||
</span>
|
||||
<ng-container bitDialogContent>
|
||||
<ng-container *ngIf="!credential">
|
||||
<i class="bwi bwi-spinner bwi-spin tw-ml-1" aria-hidden="true"></i>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="credential">
|
||||
<p bitTypography="body1">{{ "removePasskeyInfo" | i18n }}</p>
|
||||
|
||||
<bit-form-field disableMargin>
|
||||
<bit-label>{{ "masterPassword" | i18n }}</bit-label>
|
||||
<input type="password" bitInput formControlName="masterPassword" />
|
||||
<button type="button" bitIconButton bitSuffix bitPasswordInputToggle></button>
|
||||
<bit-hint>{{ "confirmIdentity" | i18n }}</bit-hint>
|
||||
</bit-form-field>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<ng-container bitDialogFooter>
|
||||
<button type="submit" bitButton bitFormButton buttonType="primary">
|
||||
{{ "remove" | i18n }}
|
||||
</button>
|
||||
<button type="button" bitButton bitFormButton buttonType="secondary" bitDialogClose>
|
||||
{{ "cancel" | i18n }}
|
||||
</button>
|
||||
</ng-container>
|
||||
</bit-dialog>
|
||||
</form>
|
||||
@@ -0,0 +1,60 @@
|
||||
import { DialogConfig, DialogRef, DIALOG_DATA } from "@angular/cdk/dialog";
|
||||
import { Component, Inject, OnDestroy, OnInit } from "@angular/core";
|
||||
import { FormBuilder, Validators } from "@angular/forms";
|
||||
import { Subject, takeUntil } from "rxjs";
|
||||
|
||||
import { DialogServiceAbstraction } from "@bitwarden/angular/services/dialog";
|
||||
|
||||
import { WebauthnService } from "../../../core";
|
||||
import { WebauthnCredentialView } from "../../../core/views/webauth-credential.view";
|
||||
|
||||
export interface DeleteCredentialDialogParams {
|
||||
credentialId: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: "delete-credential-dialog.component.html",
|
||||
})
|
||||
export class DeleteCredentialDialogComponent implements OnInit, OnDestroy {
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
protected formGroup = this.formBuilder.group({
|
||||
masterPassword: ["", [Validators.required]],
|
||||
});
|
||||
protected credential?: WebauthnCredentialView;
|
||||
|
||||
constructor(
|
||||
@Inject(DIALOG_DATA) private params: DeleteCredentialDialogParams,
|
||||
private formBuilder: FormBuilder,
|
||||
private dialogRef: DialogRef,
|
||||
private webauthnService: WebauthnService
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.webauthnService
|
||||
.getCredential$(this.params.credentialId)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe((credential) => (this.credential = credential));
|
||||
}
|
||||
|
||||
submit = async () => {
|
||||
// empty
|
||||
};
|
||||
|
||||
ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strongly typed helper to open a DeleteCredentialDialogComponent
|
||||
* @param dialogService Instance of the dialog service that will be used to open the dialog
|
||||
* @param config Configuration for the dialog
|
||||
*/
|
||||
export const openDeleteCredentialDialogComponent = (
|
||||
dialogService: DialogServiceAbstraction,
|
||||
config: DialogConfig<DeleteCredentialDialogParams>
|
||||
) => {
|
||||
return dialogService.open<unknown>(DeleteCredentialDialogComponent, config);
|
||||
};
|
||||
@@ -29,6 +29,7 @@
|
||||
bitLink
|
||||
[disabled]="loading"
|
||||
[attr.aria-label]="('remove' | i18n) + ' ' + credential.name"
|
||||
(click)="deleteCredential(credential.id)"
|
||||
>
|
||||
{{ "remove" | i18n }}
|
||||
</button>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { WebauthnService } from "../../core";
|
||||
import { WebauthnCredentialView } from "../../core/views/webauth-credential.view";
|
||||
|
||||
import { openCreateCredentialDialog } from "./create-credential-dialog/create-credential-dialog.component";
|
||||
import { openDeleteCredentialDialogComponent } from "./delete-credential-dialog/delete-credential-dialog.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-fido2-login-settings",
|
||||
@@ -54,7 +55,11 @@ export class Fido2LoginSettingsComponent implements OnInit, OnDestroy {
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
protected async createCredential() {
|
||||
protected createCredential() {
|
||||
openCreateCredentialDialog(this.dialogService, {});
|
||||
}
|
||||
|
||||
protected deleteCredential(credentialId: string) {
|
||||
openDeleteCredentialDialogComponent(this.dialogService, { data: { credentialId } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,16 @@ import { FormsModule, ReactiveFormsModule } from "@angular/forms";
|
||||
import { SharedModule } from "../../../shared/shared.module";
|
||||
|
||||
import { CreateCredentialDialogComponent } from "./create-credential-dialog/create-credential-dialog.component";
|
||||
import { DeleteCredentialDialogComponent } from "./delete-credential-dialog/delete-credential-dialog.component";
|
||||
import { Fido2LoginSettingsComponent } from "./fido2-login-settings.component";
|
||||
|
||||
@NgModule({
|
||||
imports: [SharedModule, FormsModule, ReactiveFormsModule],
|
||||
declarations: [Fido2LoginSettingsComponent, CreateCredentialDialogComponent],
|
||||
declarations: [
|
||||
Fido2LoginSettingsComponent,
|
||||
CreateCredentialDialogComponent,
|
||||
DeleteCredentialDialogComponent,
|
||||
],
|
||||
exports: [Fido2LoginSettingsComponent],
|
||||
})
|
||||
export class Fido2LoginSettingsModule {}
|
||||
|
||||
@@ -673,6 +673,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"removePasskey": {
|
||||
"message": "Remove passkey"
|
||||
},
|
||||
"removePasskeyInfo": {
|
||||
"message": "If all passkeys are removed, you will be unable to log into new devices without your master password."
|
||||
},
|
||||
"tryAgain": {
|
||||
"message": "Try again"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user