1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-20 18:23:31 +00:00
Files
browser/libs/vault/src/cipher-view/cipher-view.component.ts
Shane Melton 0d877c4e77 [PM-12389] Combined web vault item dialog (#11345)
* [PM-12389] Cleanup attachment dialog UI bugs

* [PM-12389] Add formReady event to CipherForm

* [PM-12389] Use ngOnChanges for CipherView component initialization

* [PM-12389] Cleanup web specific services and components

* [PM-12389] Introduce combined Vault Item Dialog component

* [PM-12389] Use the new VaultItemDialog in the Individual Vault

* [PM-12389] Deprecate the AddEditV2 and View dialogs in Web

* [PM-12389] Fix failing test

* [PM-12389] Fix broken imports after move

* [PM-12389] Remove messages.json addition that is taken care of in another PR
2024-10-02 14:34:46 -07:00

121 lines
4.4 KiB
TypeScript

import { CommonModule } from "@angular/common";
import { Component, Input, OnChanges, OnDestroy } from "@angular/core";
import { firstValueFrom, Observable, Subject, takeUntil } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
import { isCardExpired } from "@bitwarden/common/autofill/utils";
import { CollectionId } from "@bitwarden/common/types/guid";
import { CollectionService } from "@bitwarden/common/vault/abstractions/collection.service";
import { FolderService } from "@bitwarden/common/vault/abstractions/folder/folder.service.abstraction";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import { CollectionView } from "@bitwarden/common/vault/models/view/collection.view";
import { FolderView } from "@bitwarden/common/vault/models/view/folder.view";
import { CalloutModule, SearchModule } from "@bitwarden/components";
import { AdditionalOptionsComponent } from "./additional-options/additional-options.component";
import { AttachmentsV2ViewComponent } from "./attachments/attachments-v2-view.component";
import { AutofillOptionsViewComponent } from "./autofill-options/autofill-options-view.component";
import { CardDetailsComponent } from "./card-details/card-details-view.component";
import { CustomFieldV2Component } from "./custom-fields/custom-fields-v2.component";
import { ItemDetailsV2Component } from "./item-details/item-details-v2.component";
import { ItemHistoryV2Component } from "./item-history/item-history-v2.component";
import { LoginCredentialsViewComponent } from "./login-credentials/login-credentials-view.component";
import { ViewIdentitySectionsComponent } from "./view-identity-sections/view-identity-sections.component";
@Component({
selector: "app-cipher-view",
templateUrl: "cipher-view.component.html",
standalone: true,
imports: [
CalloutModule,
CommonModule,
SearchModule,
JslibModule,
ItemDetailsV2Component,
AdditionalOptionsComponent,
AttachmentsV2ViewComponent,
ItemHistoryV2Component,
CustomFieldV2Component,
CardDetailsComponent,
ViewIdentitySectionsComponent,
LoginCredentialsViewComponent,
AutofillOptionsViewComponent,
],
})
export class CipherViewComponent implements OnChanges, OnDestroy {
@Input({ required: true }) cipher: CipherView;
/**
* Optional list of collections the cipher is assigned to. If none are provided, they will be fetched using the
* `CipherService` and the `collectionIds` property of the cipher.
*/
@Input() collections: CollectionView[];
organization$: Observable<Organization>;
folder$: Observable<FolderView>;
private destroyed$: Subject<void> = new Subject();
cardIsExpired: boolean = false;
constructor(
private organizationService: OrganizationService,
private collectionService: CollectionService,
private folderService: FolderService,
) {}
async ngOnChanges() {
if (this.cipher == null) {
return;
}
await this.loadCipherData();
this.cardIsExpired = isCardExpired(this.cipher.card);
}
ngOnDestroy(): void {
this.destroyed$.next();
this.destroyed$.complete();
}
get hasCard() {
const { cardholderName, code, expMonth, expYear, number } = this.cipher.card;
return cardholderName || code || expMonth || expYear || number;
}
get hasLogin() {
const { username, password, totp } = this.cipher.login;
return username || password || totp;
}
get hasAutofill() {
return this.cipher.login?.uris.length > 0;
}
async loadCipherData() {
// Load collections if not provided and the cipher has collectionIds
if (
this.cipher.collectionIds.length > 0 &&
(!this.collections || this.collections.length === 0)
) {
this.collections = await firstValueFrom(
this.collectionService.decryptedCollectionViews$(
this.cipher.collectionIds as CollectionId[],
),
);
}
if (this.cipher.organizationId) {
this.organization$ = this.organizationService
.get$(this.cipher.organizationId)
.pipe(takeUntil(this.destroyed$));
}
if (this.cipher.folderId) {
this.folder$ = this.folderService
.getDecrypted$(this.cipher.folderId)
.pipe(takeUntil(this.destroyed$));
}
}
}