mirror of
https://github.com/bitwarden/browser
synced 2025-12-23 03:33:54 +00:00
* Add initial view cipher dialog. * Add working view cipher modal dialog markup. * Cleanup dialog markup and allow edit from dialog. * Cleanup unused imports. * Begin adding org-vault view-cipher functionality. * Refactor to remove loose-components usage and use DialogService. * Add edit and delete button functionality. * Add delete functionality. * Remove addition to loose components. * Remove unused modal-dialog artifacts. * Ensure dialog closes and URL updates properly on edit or close. * Disable edit/delete buttons instead of hiding them. * Add simple tests for view.component.ts. * Adjust import order. * Remove now unnecessary ng-template. * Decrypt cipher to cipher view. * Add cleanup function and additional delete test. * Remove boolean return from delete promise. * Remove fake timers. * Remove unnecessary TestBed.inject calls. * Add code comments. * Hide new view cipher dialog behind feature flag. * Keep "else if" statement intact. * Simplify getting cipherTypeString. * Add comments to vault.component.ts files. * Change button type to "danger" Update apps/web/src/app/vault/individual-vault/view.component.html Co-authored-by: Nick Krantz <125900171+nick-livefront@users.noreply.github.com> * Add a11y title to delete button. * Simplify OrganizationService testing. * Update comment to better reflect function. * Use large dialog to better match designs. * Add aria-haspopup to cipher row button. * Add deleteCipher to messages.json. * Remove extra argument from canEditAllCiphers. * Use 'delete' instead of 'delete cipher' for a11y title. * Remove 'bitFormButton' from non-form buttons. * Rework view cipher view delete functionality. * Add translations for cipher types. * Remove unecesarry test. * Add additional test coverage to ensure dialogs close. * Add back delete functionality in view.component.ts. * Update "secure note" to "note". --------- Co-authored-by: Nick Krantz <125900171+nick-livefront@users.noreply.github.com>
194 lines
6.3 KiB
TypeScript
194 lines
6.3 KiB
TypeScript
import { DIALOG_DATA, DialogConfig, DialogRef } from "@angular/cdk/dialog";
|
|
import { CommonModule } from "@angular/common";
|
|
import { Component, Inject, OnInit, EventEmitter, OnDestroy } from "@angular/core";
|
|
import { Router } from "@angular/router";
|
|
import { Subject } from "rxjs";
|
|
|
|
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
|
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
|
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 { LogService } from "@bitwarden/common/platform/abstractions/log.service";
|
|
import { MessagingService } from "@bitwarden/common/platform/abstractions/messaging.service";
|
|
import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service";
|
|
import { CipherType } from "@bitwarden/common/vault/enums/cipher-type";
|
|
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
|
import {
|
|
AsyncActionsModule,
|
|
DialogModule,
|
|
DialogService,
|
|
ToastService,
|
|
} from "@bitwarden/components";
|
|
|
|
import { CipherViewComponent } from "../../../../../../libs/vault/src/cipher-view/cipher-view.component";
|
|
import { SharedModule } from "../../shared/shared.module";
|
|
|
|
export interface ViewCipherDialogParams {
|
|
cipher: CipherView;
|
|
}
|
|
|
|
export enum ViewCipherDialogResult {
|
|
edited = "edited",
|
|
deleted = "deleted",
|
|
}
|
|
|
|
export interface ViewCipherDialogCloseResult {
|
|
action: ViewCipherDialogResult;
|
|
}
|
|
|
|
/**
|
|
* Component for viewing a cipher, presented in a dialog.
|
|
*/
|
|
@Component({
|
|
selector: "app-vault-view",
|
|
templateUrl: "view.component.html",
|
|
standalone: true,
|
|
imports: [CipherViewComponent, CommonModule, AsyncActionsModule, DialogModule, SharedModule],
|
|
})
|
|
export class ViewComponent implements OnInit, OnDestroy {
|
|
cipher: CipherView;
|
|
onDeletedCipher = new EventEmitter<CipherView>();
|
|
cipherTypeString: string;
|
|
cipherEditUrl: string;
|
|
organization: Organization;
|
|
restrictProviderAccess = false;
|
|
|
|
protected destroy$ = new Subject<void>();
|
|
|
|
constructor(
|
|
@Inject(DIALOG_DATA) public params: ViewCipherDialogParams,
|
|
private dialogRef: DialogRef<ViewCipherDialogCloseResult>,
|
|
private i18nService: I18nService,
|
|
private dialogService: DialogService,
|
|
private messagingService: MessagingService,
|
|
private logService: LogService,
|
|
private cipherService: CipherService,
|
|
private toastService: ToastService,
|
|
private organizationService: OrganizationService,
|
|
private router: Router,
|
|
private configService: ConfigService,
|
|
) {}
|
|
|
|
/**
|
|
* Lifecycle hook for component initialization.
|
|
*/
|
|
async ngOnInit() {
|
|
this.cipher = this.params.cipher;
|
|
this.cipherTypeString = this.getCipherViewTypeString();
|
|
if (this.cipher.organizationId) {
|
|
this.organization = await this.organizationService.get(this.cipher.organizationId);
|
|
}
|
|
this.restrictProviderAccess = await this.configService.getFeatureFlag(
|
|
FeatureFlag.RestrictProviderAccess,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Lifecycle hook for component destruction.
|
|
*/
|
|
ngOnDestroy(): void {
|
|
this.destroy$.next();
|
|
this.destroy$.complete();
|
|
}
|
|
|
|
/**
|
|
* Method to handle cipher deletion. Called when a user clicks the delete button.
|
|
*/
|
|
delete = async () => {
|
|
const confirmed = await this.dialogService.openSimpleDialog({
|
|
title: { key: "deleteItem" },
|
|
content: {
|
|
key: this.cipher.isDeleted ? "permanentlyDeleteItemConfirmation" : "deleteItemConfirmation",
|
|
},
|
|
type: "warning",
|
|
});
|
|
|
|
if (!confirmed) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await this.deleteCipher();
|
|
this.toastService.showToast({
|
|
variant: "success",
|
|
title: this.i18nService.t("success"),
|
|
message: this.i18nService.t(
|
|
this.cipher.isDeleted ? "permanentlyDeletedItem" : "deletedItem",
|
|
),
|
|
});
|
|
this.onDeletedCipher.emit(this.cipher);
|
|
this.messagingService.send(
|
|
this.cipher.isDeleted ? "permanentlyDeletedCipher" : "deletedCipher",
|
|
);
|
|
} catch (e) {
|
|
this.logService.error(e);
|
|
}
|
|
|
|
this.dialogRef.close({ action: ViewCipherDialogResult.deleted });
|
|
};
|
|
|
|
/**
|
|
* Helper method to delete cipher.
|
|
*/
|
|
protected async deleteCipher(): Promise<void> {
|
|
const asAdmin = this.organization?.canEditAllCiphers(this.restrictProviderAccess);
|
|
if (this.cipher.isDeleted) {
|
|
await this.cipherService.deleteWithServer(this.cipher.id, asAdmin);
|
|
} else {
|
|
await this.cipherService.softDeleteWithServer(this.cipher.id, asAdmin);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method to handle cipher editing. Called when a user clicks the edit button.
|
|
*/
|
|
async edit(): Promise<void> {
|
|
this.dialogRef.close({ action: ViewCipherDialogResult.edited });
|
|
await this.router.navigate([], {
|
|
queryParams: {
|
|
itemId: this.cipher.id,
|
|
action: "edit",
|
|
organizationId: this.cipher.organizationId,
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Method to get cipher view type string, used for the dialog title.
|
|
* E.g. "View login" or "View note".
|
|
* @returns The localized string for the cipher type
|
|
*/
|
|
getCipherViewTypeString(): string {
|
|
if (!this.cipher) {
|
|
return null;
|
|
}
|
|
|
|
switch (this.cipher.type) {
|
|
case CipherType.Login:
|
|
return this.i18nService.t("viewItemType", this.i18nService.t("typeLogin").toLowerCase());
|
|
case CipherType.SecureNote:
|
|
return this.i18nService.t("viewItemType", this.i18nService.t("note").toLowerCase());
|
|
case CipherType.Card:
|
|
return this.i18nService.t("viewItemType", this.i18nService.t("typeCard").toLowerCase());
|
|
case CipherType.Identity:
|
|
return this.i18nService.t("viewItemType", this.i18nService.t("typeIdentity").toLowerCase());
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Strongly typed helper to open a cipher view dialog
|
|
* @param dialogService Instance of the dialog service that will be used to open the dialog
|
|
* @param config Configuration for the dialog
|
|
* @returns A reference to the opened dialog
|
|
*/
|
|
export function openViewCipherDialog(
|
|
dialogService: DialogService,
|
|
config: DialogConfig<ViewCipherDialogParams>,
|
|
): DialogRef<ViewCipherDialogCloseResult> {
|
|
return dialogService.open(ViewComponent, config);
|
|
}
|