1
0
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:
Robyn MacCallum
2023-10-04 17:15:20 -04:00
committed by GitHub
parent f43c3220dc
commit d40f996e71
17 changed files with 302 additions and 107 deletions

View File

@@ -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);
}
}

View File

@@ -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() {

View File

@@ -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[] }

View File

@@ -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()"

View File

@@ -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() {

View File

@@ -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,
};