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),
]),
);