mirror of
https://github.com/bitwarden/browser
synced 2025-12-21 10:43:35 +00:00
[AC-974] [Technical Dependency] Refactor Vault Tables (#4967)
* [EC-974] feat: scaffold new vault-items component * [EC-974] feat: add basic mocked data to story * [EC-974] feat: add initial table version * [EC-974] chore: split rows into separate components * [EC-974] chore: rename item row to cipher row * [EC-974] feat: create common vault item interface * [EC-974] feat: use cdk virtual scrolling * [EC-974] fix: tweak `itemSize` * [EC-974] chore: move vault-items component to app/vault folder * [EC-974] feat: initial support for extra column * [EC-974] feat: start adding org badge Having issues with modules import * [EC-974] feat: add working owner column on collections row * [EC-974] feat: add owner to ciphers * [EC-974] fix: org name badge bugs when reused * [EC-974] feat: fix and translate columns * [EC-974] feat: allow collections to be non-editable * [EC-974] feat: use data source * [EC-974] fix: remove profile name from vault items * [EC-974] feat: add events * [EC-974] feat: add support for copy event * [EC-974] feat: add support for collections column * [EC-974] feat: add support for group badges * [EC-974] chore: rename for consistency * [EC-974] feat: change story to use template * [EC-974] feat: add support for launching * [EC-974] feat: add support for attachements * [EC-974] feat: add stories for all use-cases * [EC-974] feat: add support for cloning * [EC-974] feat: add support for moving to organization * [EC-974] feat: add support for editing cipher collections * [EC-974] feat: add support for event logs * [EC-974] feat: add support for trash/delete/restore * [EC-974] feat: add support for editing collections * [EC-974] feat: add support for access and delete collections * [EC-974] feat: don't show menu if it's empty * [EC-974] feat: initial buggy implementation of selection * [EC-974] feat: implement bulk move * [EC-974] feat: add support for bulk moving to org * [EC-974] feat: add support for bulk restore * [EC-974] feat: add support for bulk delete * [EC-974] feat: add ability to disable the table * [EC-974] feat: create new filter function based on routed model * [EC-974] wip: start replacing vault items component * [EC-974] feat: add support for fetching ciphers * [EC-974] feat: hide trash by default * [EC-974] feat: add support for the rest of the data * [EC-974] feat: implement organization filtering using org badge * [EC-974] feat: fix navigation to "my vault" * [EC-974] feat: don't show bulk move options when filtering on org items * [EC-974] feat: prepare for disabling table * [EC-974] fix: add missing router link to collections * [EC-974] feat: connect all outputs * [EC-974] fix: list not properly refreshing after delete * [EC-974] feat: limit selection to top 500 items * [EC-974] feat: implement refresh tracker * [EC-974] feat: use refresh tracker to disable vault items * [EC-974] feat: add empty list message * [AC-974] feat: add initial load with spinner and fix empty -> show list bug * [EC-974] feat: replace action promise with simple loading boolean * [EC-974] feat: refactor individual vault header * [EC-974] feat: cache and make observables long lived * [EC-974] feat: implement searching * [EC-974] feat: add support for showing collections * [EC-974] feat: add ciphers to org vault list * [EC-974] feat: show group column * [EC-974] feat: tweak settings for org vault * [EC-974] feat: implement search using query params * [EC-974] feat: add support for events that are common with individual vault * [EC-974] feat: add support for all events * [EC-974] feat: add support for empty list message and no permission message * [EC-974] feat: always show table * [EC-974] feat: fix layout issues due to incorrect row height * [EC-974] feat: disable list if empty * [EC-974] feat: improve sync handling * [EC-974] feat: improve initial loading sequence * [EC-974] feat: improve initial load sequence in org vault * [EC-974] refactor: simplify and optimize data fetching * [EC-974] feat: use observables from org service * [EC-974] feat: refactor org vault header * [EC-974] fix: data not refreshing properly * [EC-974] fix: avoid collection double fetching * [EC-974] chore: clean up refresh tracker * [EC-974] chore: clean up old vault-items components * [EC-974] chore: clean up old code in vault component * [EC-974] fix: reduce rows in story The story ends up too big for chromatic. * [EC-974] docs: tweak and typo fixes of asyncToObservable docs comment * [EC-974] fix: `attachements` typo * [EC-974] chore: remove review question comment * [EC-974] chore: remove unused `securityCode` if statement * [EC-974] fix: use `takeUntill` for legacy dialogs * [EC-974] fix: use CollectionDialogTabType instead of custom strings * [EC-974] fix: copy implementation * [EC-974] fix: use `useTotp` to check for premium features * [EC-974] fix: use `tw-sr-only` * [EC-974] chore: remove unecessary eslint disable * [EC-974] fix: clarify vault item event naming * [EC-974] fix: remove `new` from `app-new-vault-items` * [EC-974] fix: collection row not disabled during loading * [EC-974] chore: simplify router links without path changes * [EC-974] feat: invert filter function to get rid of `cipherPassesFilter` * [EC-974] fix: move `NestingDelimiter` to collection view Nesting is currently only a presentational construct, and the concept does not exist in our domain. * [EC-974] fix: org vault header not updating when switching org * [EC-974] fix: table sizing jumping around * [EC-974] fix: list not refreshing after restoring item * [EC-974] fix: re-add missing unassigned collection * [EC-974] fix don't show new item button in unassigned collection * [EC-974] fix: navigations always leading to individual vault * [EC-974] fix: remove checkbox when collections are not editable * [EC-974] fix: null reference blocking collections from refreshing after delete * [EC-974] fix: don't show checbox for collections that user does not have permissions to delete * [EC-974] fix: navigate away from deleted folder * [EC-974] chore: clean up un-used output * [EC-974] fix: org badge changing color randomly * [EC-974] fix: lint issues after merge * [EC-974] fix: lower amount of ciphers in story chromatic doesn't like large snapshots * [EC-974] fix: "all collections" not taking `organizationId` filter into account * [EC-974] fix: make sure unassigned appears in table too * [EC-974] feat: add unassigned to storybook * [EC-974] fix: forced row height not being applied properly * [EC-974] fix: hopefully fix table jumping once and for all * [EC-974] fix: attachemnts getting hidden * [EC-974] feat: extract collection editable logic to parent component * [EC-974] feat: separately track editable items * [EC-974] feat: optimize permission checks * [EC-974] fix: bulk menu hidden on chrome :lolcry: * [EC-974] fix: don't show groups column if org doesnt use groups * [EC-974] feat: make entire row clickable * [EC-974] fix: typo resulting in non-editable collections
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
import { SelectionModel } from "@angular/cdk/collections";
|
||||
import { Component, EventEmitter, Input, Output } from "@angular/core";
|
||||
|
||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
||||
import { CollectionView } from "@bitwarden/common/admin-console/models/view/collection.view";
|
||||
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
|
||||
import { TableDataSource } from "@bitwarden/components";
|
||||
|
||||
import { CollectionAdminView, GroupView } from "../../../admin-console/organizations/core";
|
||||
import { Unassigned } from "../../individual-vault/vault-filter/shared/models/routed-vault-filter.model";
|
||||
|
||||
import { VaultItem } from "./vault-item";
|
||||
import { VaultItemEvent } from "./vault-item-event";
|
||||
|
||||
// Fixed manual row height required due to how cdk-virtual-scroll works
|
||||
export const RowHeight = 65;
|
||||
export const RowHeightClass = `tw-h-[65px]`;
|
||||
|
||||
const MaxSelectionCount = 500;
|
||||
|
||||
@Component({
|
||||
selector: "app-vault-items",
|
||||
templateUrl: "vault-items.component.html",
|
||||
// TODO: Improve change detection, see: https://bitwarden.atlassian.net/browse/TDL-220
|
||||
// changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class VaultItemsComponent {
|
||||
protected RowHeight = RowHeight;
|
||||
|
||||
@Input() disabled: boolean;
|
||||
@Input() showOwner: boolean;
|
||||
@Input() showCollections: boolean;
|
||||
@Input() showGroups: boolean;
|
||||
@Input() useEvents: boolean;
|
||||
@Input() editableCollections: boolean;
|
||||
@Input() cloneableOrganizationCiphers: boolean;
|
||||
@Input() showPremiumFeatures: boolean;
|
||||
@Input() showBulkMove: boolean;
|
||||
@Input() showBulkTrashOptions: boolean;
|
||||
@Input() allOrganizations: Organization[] = [];
|
||||
@Input() allCollections: CollectionView[] = [];
|
||||
@Input() allGroups: GroupView[] = [];
|
||||
|
||||
private _ciphers?: CipherView[] = [];
|
||||
@Input() get ciphers(): CipherView[] {
|
||||
return this._ciphers;
|
||||
}
|
||||
set ciphers(value: CipherView[] | undefined) {
|
||||
this._ciphers = value ?? [];
|
||||
this.refreshItems();
|
||||
}
|
||||
|
||||
private _collections?: CollectionView[] = [];
|
||||
@Input() get collections(): CollectionView[] {
|
||||
return this._collections;
|
||||
}
|
||||
set collections(value: CollectionView[] | undefined) {
|
||||
this._collections = value ?? [];
|
||||
this.refreshItems();
|
||||
}
|
||||
|
||||
@Output() onEvent = new EventEmitter<VaultItemEvent>();
|
||||
|
||||
protected editableItems: VaultItem[] = [];
|
||||
protected dataSource = new TableDataSource<VaultItem>();
|
||||
protected selection = new SelectionModel<VaultItem>(true, [], true);
|
||||
|
||||
get showExtraColumn() {
|
||||
return this.showCollections || this.showGroups || this.showOwner;
|
||||
}
|
||||
|
||||
get isAllSelected() {
|
||||
return this.editableItems
|
||||
.slice(0, MaxSelectionCount)
|
||||
.every((item) => this.selection.isSelected(item));
|
||||
}
|
||||
|
||||
get isEmpty() {
|
||||
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
|
||||
return (
|
||||
organization?.canEditAnyCollection ||
|
||||
(organization?.canEditAssignedCollections && collection.assigned)
|
||||
);
|
||||
}
|
||||
|
||||
protected canDeleteCollection(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 delete the specified collection
|
||||
return (
|
||||
organization?.canDeleteAnyCollection ||
|
||||
(organization?.canDeleteAssignedCollections && collection.assigned)
|
||||
);
|
||||
}
|
||||
|
||||
protected toggleAll() {
|
||||
this.isAllSelected
|
||||
? this.selection.clear()
|
||||
: this.selection.select(...this.editableItems.slice(0, MaxSelectionCount));
|
||||
}
|
||||
|
||||
protected event(event: VaultItemEvent) {
|
||||
this.onEvent.emit(event);
|
||||
}
|
||||
|
||||
protected bulkMoveToFolder() {
|
||||
this.event({
|
||||
type: "moveToFolder",
|
||||
items: this.selection.selected
|
||||
.filter((item) => item.cipher !== undefined)
|
||||
.map((item) => item.cipher),
|
||||
});
|
||||
}
|
||||
|
||||
protected bulkMoveToOrganization() {
|
||||
this.event({
|
||||
type: "moveToOrganization",
|
||||
items: this.selection.selected
|
||||
.filter((item) => item.cipher !== undefined)
|
||||
.map((item) => item.cipher),
|
||||
});
|
||||
}
|
||||
|
||||
protected bulkRestore() {
|
||||
this.event({
|
||||
type: "restore",
|
||||
items: this.selection.selected
|
||||
.filter((item) => item.cipher !== undefined)
|
||||
.map((item) => item.cipher),
|
||||
});
|
||||
}
|
||||
|
||||
protected bulkDelete() {
|
||||
this.event({
|
||||
type: "delete",
|
||||
items: this.selection.selected,
|
||||
});
|
||||
}
|
||||
|
||||
private refreshItems() {
|
||||
const collections: VaultItem[] = this.collections.map((collection) => ({ collection }));
|
||||
const ciphers: VaultItem[] = this.ciphers.map((cipher) => ({ cipher }));
|
||||
const items: VaultItem[] = [].concat(collections).concat(ciphers);
|
||||
|
||||
this.selection.clear();
|
||||
this.editableItems = items.filter(
|
||||
(item) =>
|
||||
item.cipher !== undefined ||
|
||||
(item.collection !== undefined && this.canDeleteCollection(item.collection))
|
||||
);
|
||||
this.dataSource.data = items;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user