From e198edaeec1ed8fd0c6a25e9fab8f580f1b0fe18 Mon Sep 17 00:00:00 2001 From: Leslie Xiong Date: Tue, 27 Jan 2026 11:58:48 -0500 Subject: [PATCH] extended existing `item-footer` component --- .../cipher-form/item-footer.component.ts | 196 +----------------- 1 file changed, 9 insertions(+), 187 deletions(-) diff --git a/apps/desktop/src/vault/app/vault-v3/cipher-form/item-footer.component.ts b/apps/desktop/src/vault/app/vault-v3/cipher-form/item-footer.component.ts index 11f0648993f..a816288d5f5 100644 --- a/apps/desktop/src/vault/app/vault-v3/cipher-form/item-footer.component.ts +++ b/apps/desktop/src/vault/app/vault-v3/cipher-form/item-footer.component.ts @@ -1,36 +1,10 @@ import { CommonModule } from "@angular/common"; -import { - Input, - Output, - EventEmitter, - Component, - OnInit, - ViewChild, - OnChanges, - SimpleChanges, - input, -} from "@angular/core"; -import { combineLatest, firstValueFrom, switchMap } from "rxjs"; +import { Component } from "@angular/core"; import { JslibModule } from "@bitwarden/angular/jslib.module"; -import { AccountService } from "@bitwarden/common/auth/abstractions/account.service"; -import { getUserId } from "@bitwarden/common/auth/services/account.service"; -import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; -import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; -import { UserId } from "@bitwarden/common/types/guid"; -import { CipherArchiveService } from "@bitwarden/common/vault/abstractions/cipher-archive.service"; -import { CipherService } from "@bitwarden/common/vault/abstractions/cipher.service"; -import { CipherRepromptType } from "@bitwarden/common/vault/enums"; -import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view"; -import { CipherAuthorizationService } from "@bitwarden/common/vault/services/cipher-authorization.service"; -import { - ButtonComponent, - ButtonModule, - IconButtonModule, - DialogService, - ToastService, -} from "@bitwarden/components"; -import { ArchiveCipherUtilitiesService, PasswordRepromptService } from "@bitwarden/vault"; +import { ButtonModule, IconButtonModule } from "@bitwarden/components"; + +import { ItemFooterComponent as BaseItemFooterComponent } from "../../vault/item-footer.component"; // FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush // eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection @@ -39,166 +13,14 @@ import { ArchiveCipherUtilitiesService, PasswordRepromptService } from "@bitward templateUrl: "item-footer.component.html", imports: [ButtonModule, IconButtonModule, CommonModule, JslibModule], }) -export class ItemFooterComponent implements OnInit, OnChanges { - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-signals - @Input({ required: true }) cipher: CipherView = new CipherView(); - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-signals - @Input() collectionId: string | null = null; - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-signals - @Input({ required: true }) action: string = "view"; - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-signals - @Input() masterPasswordAlreadyPrompted: boolean = false; - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref - @Output() onEdit = new EventEmitter(); - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref - @Output() onClone = new EventEmitter(); - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref - @Output() onDelete = new EventEmitter(); - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref - @Output() onRestore = new EventEmitter(); - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref - @Output() onCancel = new EventEmitter(); - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref - @Output() onArchiveToggle = new EventEmitter(); - // FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals - // eslint-disable-next-line @angular-eslint/prefer-signals - @ViewChild("submitBtn", { static: false }) submitBtn: ButtonComponent | null = null; - - readonly submitButtonText = input(this.i18nService.t("save")); - - activeUserId: UserId | null = null; - passwordReprompted: boolean = false; - - protected showArchiveButton = false; - protected showUnarchiveButton = false; - - constructor( - protected cipherService: CipherService, - protected dialogService: DialogService, - protected passwordRepromptService: PasswordRepromptService, - protected cipherAuthorizationService: CipherAuthorizationService, - protected accountService: AccountService, - protected toastService: ToastService, - protected i18nService: I18nService, - protected logService: LogService, - protected cipherArchiveService: CipherArchiveService, - protected archiveCipherUtilitiesService: ArchiveCipherUtilitiesService, - ) {} - - async ngOnInit() { - this.activeUserId = await firstValueFrom(this.accountService.activeAccount$.pipe(getUserId)); - this.passwordReprompted = this.masterPasswordAlreadyPrompted; - await this.checkArchiveState(); - } - - async ngOnChanges(changes: SimpleChanges) { - if (changes.cipher) { - await this.checkArchiveState(); - } - } - - async clone() { - if (this.cipher.login?.hasFido2Credentials) { - const confirmed = await this.dialogService.openSimpleDialog({ - title: { key: "passkeyNotCopied" }, - content: { key: "passkeyNotCopiedAlert" }, - type: "info", - }); - - if (!confirmed) { - return false; - } - } - - if (await this.promptPassword()) { - this.onClone.emit(this.cipher); - return true; - } - - return false; - } - - protected edit() { - this.onEdit.emit(this.cipher); - } - - protected get hasFooterAction() { - return ( - this.showArchiveButton || - this.showUnarchiveButton || - (this.cipher.permissions?.delete && (this.action === "edit" || this.action === "view")) - ); - } - - cancel() { - this.onCancel.emit(this.cipher); - } - - async delete() { +export class ItemFooterComponent extends BaseItemFooterComponent { + async delete(): Promise { this.onDelete.emit(this.cipher); + return true; } - async restore() { + async restore(): Promise { this.onRestore.emit(this.cipher); - } - - protected deleteCipher(userId: UserId) { - return this.cipher.isDeleted - ? this.cipherService.deleteWithServer(this.cipher.id, userId) - : this.cipherService.softDeleteWithServer(this.cipher.id, userId); - } - - protected restoreCipher(userId: UserId) { - return this.cipherService.restoreWithServer(this.cipher.id, userId); - } - - protected async promptPassword() { - if (this.cipher.reprompt === CipherRepromptType.None || this.passwordReprompted) { - return true; - } - - return (this.passwordReprompted = await this.passwordRepromptService.showPasswordPrompt()); - } - - protected async archive() { - await this.archiveCipherUtilitiesService.archiveCipher(this.cipher); - this.onArchiveToggle.emit(); - } - - protected async unarchive() { - await this.archiveCipherUtilitiesService.unarchiveCipher(this.cipher); - this.onArchiveToggle.emit(); - } - - private async checkArchiveState() { - const cipherCanBeArchived = !this.cipher.isDeleted; - const [userCanArchive, hasArchiveFlagEnabled] = await firstValueFrom( - this.accountService.activeAccount$.pipe( - getUserId, - switchMap((id) => - combineLatest([ - this.cipherArchiveService.userCanArchive$(id), - this.cipherArchiveService.hasArchiveFlagEnabled$, - ]), - ), - ), - ); - - this.showArchiveButton = - cipherCanBeArchived && userCanArchive && this.action === "view" && !this.cipher.isArchived; - - // A user should always be able to unarchive an archived item - this.showUnarchiveButton = - hasArchiveFlagEnabled && this.action === "view" && this.cipher.isArchived; + return true; } }