From 04207647dea53dd822867e69a918d8f6821cd018 Mon Sep 17 00:00:00 2001 From: cd-bitwarden <106776772+cd-bitwarden@users.noreply.github.com> Date: Sat, 8 Jul 2023 09:59:35 -0400 Subject: [PATCH] [SM-650] Updating search and select all to work together properly (#5510) * Updating search and select all to work together properly * adding comment and moving filtered data below private variables * thomas suggested changes * making service-accounts-list the same as projects and secrest list * changes * Update service-accounts-list.component.ts * removing unnecessary code * setting active filter on set data, adding comment * removing unused field * Update libs/components/src/table/table-data-source.ts Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> --------- Co-authored-by: Thomas Avery <43214426+Thomas-Avery@users.noreply.github.com> --- .../service-accounts-list.component.ts | 18 ++++++---- .../shared/projects-list.component.ts | 18 ++++++---- .../shared/secrets-list.component.ts | 18 ++++++---- .../components/src/table/table-data-source.ts | 35 ++++++++++++++----- 4 files changed, 63 insertions(+), 26 deletions(-) diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-accounts-list.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-accounts-list.component.ts index 3ff6ad760e..1d79ae0685 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-accounts-list.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/service-accounts/service-accounts-list.component.ts @@ -28,6 +28,7 @@ export class ServiceAccountsListComponent implements OnDestroy { @Input() set search(search: string) { + this.selection.clear(); this.dataSource.filter = search; } @@ -55,15 +56,20 @@ export class ServiceAccountsListComponent implements OnDestroy { } isAllSelected() { - const numSelected = this.selection.selected.length; - const numRows = this.serviceAccounts.length; - return numSelected === numRows; + if (this.selection.selected?.length > 0) { + const numSelected = this.selection.selected.length; + const numRows = this.dataSource.filteredData.length; + return numSelected === numRows; + } + return false; } toggleAll() { - this.isAllSelected() - ? this.selection.clear() - : this.selection.select(...this.serviceAccounts.map((s) => s.id)); + if (this.isAllSelected()) { + this.selection.clear(); + } else { + this.selection.select(...this.dataSource.filteredData.map((s) => s.id)); + } } delete(serviceAccount: ServiceAccountView) { diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/shared/projects-list.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/shared/projects-list.component.ts index 2c4836934d..426af07591 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/shared/projects-list.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/shared/projects-list.component.ts @@ -26,6 +26,7 @@ export class ProjectsListComponent { @Input() set search(search: string) { + this.selection.clear(); this.dataSource.filter = search; } @@ -45,15 +46,20 @@ export class ProjectsListComponent { ) {} isAllSelected() { - const numSelected = this.selection.selected.length; - const numRows = this.projects.length; - return numSelected === numRows; + if (this.selection.selected?.length > 0) { + const numSelected = this.selection.selected.length; + const numRows = this.dataSource.filteredData.length; + return numSelected === numRows; + } + return false; } toggleAll() { - this.isAllSelected() - ? this.selection.clear() - : this.selection.select(...this.projects.map((s) => s.id)); + if (this.isAllSelected()) { + this.selection.clear(); + } else { + this.selection.select(...this.dataSource.filteredData.map((s) => s.id)); + } } deleteProject(projectId: string) { diff --git a/bitwarden_license/bit-web/src/app/secrets-manager/shared/secrets-list.component.ts b/bitwarden_license/bit-web/src/app/secrets-manager/shared/secrets-list.component.ts index 301a4f9c2a..59a99bb1e3 100644 --- a/bitwarden_license/bit-web/src/app/secrets-manager/shared/secrets-list.component.ts +++ b/bitwarden_license/bit-web/src/app/secrets-manager/shared/secrets-list.component.ts @@ -29,6 +29,7 @@ export class SecretsListComponent implements OnDestroy { @Input() set search(search: string) { + this.selection.clear(); this.dataSource.filter = search; } @@ -61,15 +62,20 @@ export class SecretsListComponent implements OnDestroy { } isAllSelected() { - const numSelected = this.selection.selected.length; - const numRows = this.secrets.length; - return numSelected === numRows; + if (this.selection.selected?.length > 0) { + const numSelected = this.selection.selected.length; + const numRows = this.dataSource.filteredData.length; + return numSelected === numRows; + } + return false; } toggleAll() { - this.isAllSelected() - ? this.selection.clear() - : this.selection.select(...this.secrets.map((s) => s.id)); + if (this.isAllSelected()) { + this.selection.clear(); + } else { + this.selection.select(...this.dataSource.filteredData.map((s) => s.id)); + } } bulkDeleteSecrets() { diff --git a/libs/components/src/table/table-data-source.ts b/libs/components/src/table/table-data-source.ts index 71e8b8318e..9565d48d00 100644 --- a/libs/components/src/table/table-data-source.ts +++ b/libs/components/src/table/table-data-source.ts @@ -17,9 +17,16 @@ export class TableDataSource extends DataSource { private readonly _sort: BehaviorSubject; private readonly _filter = new BehaviorSubject(""); private readonly _renderData = new BehaviorSubject([]); - private _renderChangesSubscription: Subscription | null = null; + /** + * The filtered set of data that has been matched by the filter string, or all the data if there + * is no filter. Useful for knowing the set of data the table represents. + * For example, a 'selectAll()' function would likely want to select the set of filtered data + * shown to the user rather than all the data. + */ + filteredData: T[]; + constructor() { super(); this._data = new BehaviorSubject([]); @@ -31,7 +38,13 @@ export class TableDataSource extends DataSource { } set data(data: T[]) { - this._data.next(data ? [...data] : []); + data = Array.isArray(data) ? data : []; + this._data.next(data); + // Normally the `filteredData` is updated by the re-render + // subscription, but that won't happen if it's inactive. + if (!this._renderChangesSubscription) { + this.filterData(data); + } } set sort(sort: Sort) { @@ -48,6 +61,11 @@ export class TableDataSource extends DataSource { set filter(filter: string) { this._filter.next(filter); + // Normally the `filteredData` is updated by the re-render + // subscription, but that won't happen if it's inactive. + if (!this._renderChangesSubscription) { + this.filterData(this.data); + } } connect(): Observable { @@ -65,7 +83,7 @@ export class TableDataSource extends DataSource { private updateChangeSubscription() { const filteredData = combineLatest([this._data, this._filter]).pipe( - map(([data, filter]) => this.filterData(data, filter)) + map(([data]) => this.filterData(data)) ); const orderedData = combineLatest([filteredData, this._sort]).pipe( @@ -76,12 +94,13 @@ export class TableDataSource extends DataSource { this._renderChangesSubscription = orderedData.subscribe((data) => this._renderData.next(data)); } - private filterData(data: T[], filter: string): T[] { - if (filter == null || filter == "") { - return data; - } + private filterData(data: T[]): T[] { + this.filteredData = + this.filter == null || this.filter === "" + ? data + : data.filter((obj) => this.filterPredicate(obj, this.filter)); - return data.filter((obj) => this.filterPredicate(obj, filter)); + return this.filteredData; } private orderData(data: T[], sort: Sort): T[] {