From 68f4c2e8797fea99fbe2fc40e11e832680b43359 Mon Sep 17 00:00:00 2001 From: Shane Melton Date: Mon, 7 Oct 2024 07:23:00 -0700 Subject: [PATCH] [PM-12389] Vault Item Dialog Fixes (#11374) * [PM-12389] Hide delete button when there is no cipher to delete * [PM-12389] Ensure decrypted collections and folders are available before building cipher form config * [PM-12389] Hide the delete button when cloning ciphers --- .../vault-item-dialog.component.html | 3 ++- .../vault-item-dialog.component.ts | 13 +++++++++++-- .../vault/abstractions/collection.service.ts | 1 + .../default-cipher-form-config.service.ts | 18 +++++++++++++++--- 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.html b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.html index 521665496a..740264713c 100644 --- a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.html +++ b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.html @@ -65,7 +65,7 @@ > {{ "cancel" | i18n }} -
+
diff --git a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts index d3d0703605..c1878e2dcb 100644 --- a/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts +++ b/apps/web/src/app/vault/components/vault-item-dialog/vault-item-dialog.component.ts @@ -179,6 +179,15 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy { return this.cipher?.edit ?? false; } + protected get showDelete() { + // Don't show the delete button when cloning a cipher + if (this.params.mode == "form" && this.formConfig.mode === "clone") { + return false; + } + // Never show the delete button for new ciphers + return this.cipher != null; + } + protected get showCipherView() { return this.cipher != undefined && (this.params.mode === "view" || this.loadingForm); } @@ -332,8 +341,8 @@ export class VaultItemDialogComponent implements OnInit, OnDestroy { }; cancel = async () => { - // We're in View mode, or we don't have a cipher, close the dialog. - if (this.params.mode === "view" || this.cipher == null) { + // We're in View mode, we don't have a cipher, or we were cloning, close the dialog. + if (this.params.mode === "view" || this.cipher == null || this.formConfig.mode === "clone") { this.dialogRef.close(this._cipherModified ? VaultItemDialogResult.Saved : undefined); return; } diff --git a/libs/common/src/vault/abstractions/collection.service.ts b/libs/common/src/vault/abstractions/collection.service.ts index 81ae76729a..1f3e95a019 100644 --- a/libs/common/src/vault/abstractions/collection.service.ts +++ b/libs/common/src/vault/abstractions/collection.service.ts @@ -8,6 +8,7 @@ import { TreeNode } from "../models/domain/tree-node"; import { CollectionView } from "../models/view/collection.view"; export abstract class CollectionService { + encryptedCollections$: Observable; decryptedCollections$: Observable; clearActiveUserCache: () => Promise; diff --git a/libs/vault/src/cipher-form/services/default-cipher-form-config.service.ts b/libs/vault/src/cipher-form/services/default-cipher-form-config.service.ts index 4171f153ec..977cee8156 100644 --- a/libs/vault/src/cipher-form/services/default-cipher-form-config.service.ts +++ b/libs/vault/src/cipher-form/services/default-cipher-form-config.service.ts @@ -1,5 +1,5 @@ import { inject, Injectable } from "@angular/core"; -import { combineLatest, firstValueFrom, map } from "rxjs"; +import { combineLatest, filter, firstValueFrom, map, switchMap } from "rxjs"; import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction"; import { PolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction"; @@ -39,9 +39,21 @@ export class DefaultCipherFormConfigService implements CipherFormConfigService { await firstValueFrom( combineLatest([ this.organizations$, - this.collectionService.decryptedCollections$, + this.collectionService.encryptedCollections$.pipe( + switchMap((c) => + this.collectionService.decryptedCollections$.pipe( + filter((d) => d.length === c.length), // Ensure all collections have been decrypted + ), + ), + ), this.allowPersonalOwnership$, - this.folderService.folderViews$, + this.folderService.folders$.pipe( + switchMap((f) => + this.folderService.folderViews$.pipe( + filter((d) => d.length - 1 === f.length), // -1 for "No Folder" in folderViews$ + ), + ), + ), this.getCipher(cipherId), ]), );