mirror of
https://github.com/bitwarden/browser
synced 2025-12-23 19:53:43 +00:00
[AC-1347] Allow editing of collections in individual vault (#6081)
* Rename Collection events to be more explicit * Implement edit collection for individual vault row * Implement edit and delete collection from individual vault header * Implement bulk delete for collections in individual vault * Clean up CollectionDialogResult properties * Centralize canEdit and canDelete logic to Collection models * Check orgId in canEdit and canDelete and add clarifying comments --------- Co-authored-by: Shane Melton <smelton@bitwarden.com>
This commit is contained in:
@@ -51,7 +51,7 @@ export interface CollectionDialogParams {
|
||||
|
||||
export interface CollectionDialogResult {
|
||||
action: CollectionDialogAction;
|
||||
collection: CollectionResponse;
|
||||
collection: CollectionResponse | CollectionView;
|
||||
}
|
||||
|
||||
export enum CollectionDialogAction {
|
||||
@@ -263,7 +263,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
this.i18nService.t("deletedCollectionId", this.collection?.name)
|
||||
);
|
||||
|
||||
this.close(CollectionDialogAction.Deleted);
|
||||
this.close(CollectionDialogAction.Deleted, this.collection);
|
||||
};
|
||||
|
||||
ngOnDestroy(): void {
|
||||
@@ -271,7 +271,7 @@ export class CollectionDialogComponent implements OnInit, OnDestroy {
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
private close(action: CollectionDialogAction, collection?: CollectionResponse) {
|
||||
private close(action: CollectionDialogAction, collection?: CollectionResponse | CollectionView) {
|
||||
this.dialogRef.close({ action, collection } as CollectionDialogResult);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,11 +60,11 @@ export class VaultCollectionRowComponent {
|
||||
}
|
||||
|
||||
protected edit() {
|
||||
this.onEvent.next({ type: "edit", item: this.collection });
|
||||
this.onEvent.next({ type: "editCollection", item: this.collection });
|
||||
}
|
||||
|
||||
protected access() {
|
||||
this.onEvent.next({ type: "viewAccess", item: this.collection });
|
||||
this.onEvent.next({ type: "viewCollectionAccess", item: this.collection });
|
||||
}
|
||||
|
||||
protected deleteCollection() {
|
||||
|
||||
@@ -6,9 +6,9 @@ import { VaultItem } from "./vault-item";
|
||||
export type VaultItemEvent =
|
||||
| { type: "viewAttachments"; item: CipherView }
|
||||
| { type: "viewCollections"; item: CipherView }
|
||||
| { type: "viewAccess"; item: CollectionView }
|
||||
| { type: "viewCollectionAccess"; item: CollectionView }
|
||||
| { type: "viewEvents"; item: CipherView }
|
||||
| { type: "edit"; item: CollectionView }
|
||||
| { type: "editCollection"; item: CollectionView }
|
||||
| { type: "clone"; item: CipherView }
|
||||
| { type: "restore"; items: CipherView[] }
|
||||
| { type: "delete"; items: VaultItem[] }
|
||||
|
||||
@@ -30,12 +30,12 @@
|
||||
appA11yTitle="{{ 'options' | i18n }}"
|
||||
></button>
|
||||
<bit-menu #headerMenu>
|
||||
<button *ngIf="showBulkMove" type="button" bitMenuItem (click)="bulkMoveToFolder()">
|
||||
<button *ngIf="bulkMoveAllowed" type="button" bitMenuItem (click)="bulkMoveToFolder()">
|
||||
<i class="bwi bwi-fw bwi-folder" aria-hidden="true"></i>
|
||||
{{ "moveSelected" | i18n }}
|
||||
</button>
|
||||
<button
|
||||
*ngIf="showBulkMove"
|
||||
*ngIf="bulkMoveAllowed"
|
||||
type="button"
|
||||
bitMenuItem
|
||||
(click)="bulkMoveToOrganization()"
|
||||
|
||||
@@ -7,7 +7,6 @@ import { CollectionView } from "@bitwarden/common/vault/models/view/collection.v
|
||||
import { TableDataSource } from "@bitwarden/components";
|
||||
|
||||
import { GroupView } from "../../../admin-console/organizations/core";
|
||||
import { CollectionAdminView } from "../../core/views/collection-admin.view";
|
||||
import { Unassigned } from "../../individual-vault/vault-filter/shared/models/routed-vault-filter.model";
|
||||
|
||||
import { VaultItem } from "./vault-item";
|
||||
@@ -33,7 +32,6 @@ export class VaultItemsComponent {
|
||||
@Input() showCollections: boolean;
|
||||
@Input() showGroups: boolean;
|
||||
@Input() useEvents: boolean;
|
||||
@Input() editableCollections: boolean;
|
||||
@Input() cloneableOrganizationCiphers: boolean;
|
||||
@Input() showPremiumFeatures: boolean;
|
||||
@Input() showBulkMove: boolean;
|
||||
@@ -80,44 +78,30 @@ export class VaultItemsComponent {
|
||||
return this.dataSource.data.length === 0;
|
||||
}
|
||||
|
||||
protected canEditCollection(collection: CollectionView): boolean {
|
||||
// We currently don't support editing collections from individual vault
|
||||
if (!(collection instanceof CollectionAdminView)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow allow deletion if collection editing is enabled and not deleting "Unassigned"
|
||||
if (!this.editableCollections || collection.id === Unassigned) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const organization = this.allOrganizations.find((o) => o.id === collection.organizationId);
|
||||
|
||||
// Otherwise, check if we can edit the specified collection
|
||||
get bulkMoveAllowed() {
|
||||
return (
|
||||
organization?.canEditAnyCollection ||
|
||||
(organization?.canEditAssignedCollections && collection.assigned)
|
||||
this.showBulkMove && this.selection.selected.filter((item) => item.collection).length === 0
|
||||
);
|
||||
}
|
||||
|
||||
protected canDeleteCollection(collection: CollectionView): boolean {
|
||||
// We currently don't support editing collections from individual vault
|
||||
if (!(collection instanceof CollectionAdminView)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected canEditCollection(collection: CollectionView): boolean {
|
||||
// Only allow allow deletion if collection editing is enabled and not deleting "Unassigned"
|
||||
if (!this.editableCollections || collection.id === Unassigned) {
|
||||
if (collection.id === Unassigned) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const organization = this.allOrganizations.find((o) => o.id === collection.organizationId);
|
||||
return collection.canEdit(organization);
|
||||
}
|
||||
|
||||
// Otherwise, check if we can delete the specified collection
|
||||
return (
|
||||
organization?.canDeleteAnyCollection ||
|
||||
(organization?.canDeleteAssignedCollections && collection.assigned)
|
||||
);
|
||||
protected canDeleteCollection(collection: CollectionView): boolean {
|
||||
// Only allow allow deletion if collection editing is enabled and not deleting "Unassigned"
|
||||
if (collection.id === Unassigned) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const organization = this.allOrganizations.find((o) => o.id === collection.organizationId);
|
||||
return collection.canDelete(organization);
|
||||
}
|
||||
|
||||
protected toggleAll() {
|
||||
|
||||
@@ -125,7 +125,6 @@ Individual.args = {
|
||||
showBulkMove: true,
|
||||
showBulkTrashOptions: false,
|
||||
useEvents: false,
|
||||
editableCollections: false,
|
||||
cloneableOrganizationCiphers: false,
|
||||
};
|
||||
|
||||
@@ -141,7 +140,6 @@ IndividualDisabled.args = {
|
||||
showBulkMove: true,
|
||||
showBulkTrashOptions: false,
|
||||
useEvents: false,
|
||||
editableCollections: false,
|
||||
cloneableOrganizationCiphers: false,
|
||||
};
|
||||
|
||||
@@ -156,7 +154,6 @@ IndividualTrash.args = {
|
||||
showBulkMove: false,
|
||||
showBulkTrashOptions: true,
|
||||
useEvents: false,
|
||||
editableCollections: false,
|
||||
cloneableOrganizationCiphers: false,
|
||||
};
|
||||
|
||||
@@ -171,7 +168,6 @@ IndividualTopLevelCollection.args = {
|
||||
showBulkMove: false,
|
||||
showBulkTrashOptions: false,
|
||||
useEvents: false,
|
||||
editableCollections: false,
|
||||
cloneableOrganizationCiphers: false,
|
||||
};
|
||||
|
||||
@@ -186,7 +182,6 @@ IndividualSecondLevelCollection.args = {
|
||||
showBulkMove: true,
|
||||
showBulkTrashOptions: false,
|
||||
useEvents: false,
|
||||
editableCollections: false,
|
||||
cloneableOrganizationCiphers: false,
|
||||
};
|
||||
|
||||
@@ -201,7 +196,6 @@ OrganizationVault.args = {
|
||||
showBulkMove: false,
|
||||
showBulkTrashOptions: false,
|
||||
useEvents: true,
|
||||
editableCollections: true,
|
||||
cloneableOrganizationCiphers: true,
|
||||
};
|
||||
|
||||
@@ -216,7 +210,6 @@ OrganizationTrash.args = {
|
||||
showBulkMove: false,
|
||||
showBulkTrashOptions: true,
|
||||
useEvents: true,
|
||||
editableCollections: true,
|
||||
cloneableOrganizationCiphers: true,
|
||||
};
|
||||
|
||||
@@ -234,7 +227,6 @@ OrganizationTopLevelCollection.args = {
|
||||
showBulkMove: false,
|
||||
showBulkTrashOptions: false,
|
||||
useEvents: true,
|
||||
editableCollections: true,
|
||||
cloneableOrganizationCiphers: true,
|
||||
};
|
||||
|
||||
@@ -249,7 +241,6 @@ OrganizationSecondLevelCollection.args = {
|
||||
showBulkMove: false,
|
||||
showBulkTrashOptions: false,
|
||||
useEvents: true,
|
||||
editableCollections: true,
|
||||
cloneableOrganizationCiphers: true,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user