remove filter string pipe, performance improvements (#10231)

This commit is contained in:
Denys Vuika 2024-09-30 10:44:15 -04:00 committed by GitHub
parent dd2bbd0a4b
commit 0139273914
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 64 additions and 111 deletions

View File

@ -37,21 +37,17 @@
</div> </div>
<div class="adf-columns-selector-list-container"> <div class="adf-columns-selector-list-container">
<ng-container *ngFor="let column of columnItems"> <div *ngFor="let column of columnItems" class="adf-columns-selector-list-item">
<div <mat-checkbox
*ngIf="(column.title | translate | filterString:searchQuery) as translatedTitle" color="primary"
class="adf-columns-selector-list-item"> class="adf-columns-selector-column-checkbox"
<mat-checkbox [attr.data-automation-id]="'adf-columns-selector-column-checkbox-' + column.title"
color="primary" [checked]="!column.isHidden"
class="adf-columns-selector-column-checkbox" [disabled]="isCheckboxDisabled(column)"
[attr.data-automation-id]="'adf-columns-selector-column-checkbox-' + column.title" (change)="changeColumnVisibility(column)">
[checked]="!column.isHidden" <div class="adf-columns-selector-list-content">{{column.title | translate}}</div>
[disabled]="isCheckboxDisabled(column)" </mat-checkbox>
(change)="changeColumnVisibility(column)"> </div>
<div class="adf-columns-selector-list-content">{{translatedTitle}}</div>
</mat-checkbox>
</div>
</ng-container>
</div> </div>
<mat-divider class="adf-columns-selector-divider"></mat-divider> <mat-divider class="adf-columns-selector-divider"></mat-divider>

View File

@ -24,7 +24,7 @@ import { By } from '@angular/platform-browser';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { HarnessLoader } from '@angular/cdk/testing'; import { HarnessLoader } from '@angular/cdk/testing';
import { MatCheckboxHarness } from '@angular/material/checkbox/testing'; import { MatCheckboxHarness } from '@angular/material/checkbox/testing';
import { NoopTranslateModule } from '@alfresco/adf-core'; import { NoopTranslateModule } from '../../../testing/noop-translate.module';
describe('ColumnsSelectorComponent', () => { describe('ColumnsSelectorComponent', () => {
let fixture: ComponentFixture<ColumnsSelectorComponent>; let fixture: ComponentFixture<ColumnsSelectorComponent>;
@ -91,6 +91,8 @@ describe('ColumnsSelectorComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
}); });
afterEach(() => fixture.destroy());
it('should clear search after closing menu', fakeAsync(() => { it('should clear search after closing menu', fakeAsync(() => {
menuOpenedTrigger.next(); menuOpenedTrigger.next();
fixture.detectChanges(); fixture.detectChanges();

View File

@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { Component, EventEmitter, Input, OnDestroy, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, inject, Input, OnDestroy, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { ReactiveFormsModule, UntypedFormControl } from '@angular/forms'; import { ReactiveFormsModule, UntypedFormControl } from '@angular/forms';
import { MatMenuTrigger } from '@angular/material/menu'; import { MatMenuTrigger } from '@angular/material/menu';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
@ -27,25 +27,19 @@ import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatDividerModule } from '@angular/material/divider'; import { MatDividerModule } from '@angular/material/divider';
import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatCheckboxModule } from '@angular/material/checkbox';
import { FilterStringPipe } from '../../../pipes'; import { TranslationService } from '../../../translation';
@Component({ @Component({
selector: 'adf-datatable-column-selector', selector: 'adf-datatable-column-selector',
standalone: true, standalone: true,
imports: [ imports: [CommonModule, TranslateModule, MatButtonModule, MatIconModule, MatDividerModule, ReactiveFormsModule, MatCheckboxModule],
CommonModule,
TranslateModule,
MatButtonModule,
MatIconModule,
MatDividerModule,
ReactiveFormsModule,
MatCheckboxModule,
FilterStringPipe
],
templateUrl: './columns-selector.component.html', templateUrl: './columns-selector.component.html',
styleUrls: ['./columns-selector.component.scss'], styleUrls: ['./columns-selector.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class ColumnsSelectorComponent implements OnInit, OnDestroy { export class ColumnsSelectorComponent implements OnInit, OnDestroy {
private translationService = inject(TranslationService);
@Input() @Input()
columns: DataColumn[] = []; columns: DataColumn[] = [];
@ -68,8 +62,7 @@ export class ColumnsSelectorComponent implements OnInit, OnDestroy {
ngOnInit(): void { ngOnInit(): void {
this.mainMenuTrigger.menuOpened.pipe(takeUntil(this.onDestroy$)).subscribe(() => { this.mainMenuTrigger.menuOpened.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
const columns = this.columns.map((column) => ({ ...column })); this.updateColumnItems();
this.columnItems = this.columnsSorting ? this.sortColumns(columns) : columns;
}); });
this.mainMenuTrigger.menuClosed.pipe(takeUntil(this.onDestroy$)).subscribe(() => { this.mainMenuTrigger.menuClosed.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
@ -78,9 +71,17 @@ export class ColumnsSelectorComponent implements OnInit, OnDestroy {
this.searchInputControl.valueChanges.pipe(debounceTime(300), takeUntil(this.onDestroy$)).subscribe((searchQuery) => { this.searchInputControl.valueChanges.pipe(debounceTime(300), takeUntil(this.onDestroy$)).subscribe((searchQuery) => {
this.searchQuery = searchQuery; this.searchQuery = searchQuery;
this.updateColumnItems();
}); });
} }
private updateColumnItems(): void {
let columns = this.columns.map((column) => ({ ...column }));
columns = this.filterColumnItems(columns, this.searchQuery);
columns = this.sortColumns(columns);
this.columnItems = columns;
}
ngOnDestroy() { ngOnDestroy() {
this.onDestroy$.next(true); this.onDestroy$.next(true);
this.onDestroy$.complete(); this.onDestroy$.complete();
@ -90,6 +91,34 @@ export class ColumnsSelectorComponent implements OnInit, OnDestroy {
this.mainMenuTrigger.closeMenu(); this.mainMenuTrigger.closeMenu();
} }
private filterString(value: string = '', filterBy: string = ''): string {
const testResult = filterBy ? value.toLowerCase().indexOf(filterBy.toLowerCase()) > -1 : true;
return testResult ? value : '';
}
private filterColumnItems(columns: DataColumn[], query: string): DataColumn[] {
const result = [];
for (const column of columns) {
if (!column.title) {
continue;
}
if (!query) {
result.push(column);
continue;
}
const title = this.translationService.instant(column.title);
if (this.filterString(title, query)) {
result.push(column);
}
}
return result;
}
changeColumnVisibility(column: DataColumn): void { changeColumnVisibility(column: DataColumn): void {
column.isHidden = !column.isHidden; column.isHidden = !column.isHidden;
} }
@ -103,14 +132,17 @@ export class ColumnsSelectorComponent implements OnInit, OnDestroy {
return ( return (
this.maxColumnsVisible && this.maxColumnsVisible &&
column.isHidden && column.isHidden &&
this.maxColumnsVisible === this.columnItems.filter((dataColumn) => !dataColumn.isHidden).length this.maxColumnsVisible >= this.columnItems.filter((dataColumn) => !dataColumn.isHidden).length
); );
} }
private sortColumns(columns: DataColumn[]): DataColumn[] { private sortColumns(columns: DataColumn[]): DataColumn[] {
const shownColumns = columns.filter((column) => !column.isHidden); if (this.columnsSorting) {
const hiddenColumns = columns.filter((column) => column.isHidden); const shownColumns = columns.filter((column) => !column.isHidden);
const hiddenColumns = columns.filter((column) => column.isHidden);
return [...shownColumns, ...hiddenColumns]; return [...shownColumns, ...hiddenColumns];
}
return columns;
} }
} }

View File

@ -1,44 +0,0 @@
/*!
* @license
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { FilterStringPipe } from './filter-string.pipe';
describe('FilterStringPipe', () => {
let pipe: FilterStringPipe;
beforeEach(() => {
pipe = new FilterStringPipe();
});
it('should left string', () => {
const result = pipe.transform('ABC', 'B');
expect(result).toBe('ABC');
});
it('should filter out string', () => {
const result = pipe.transform('ABC', 'D');
expect(result).toBe('');
});
it('should left string when no query string is passed', () => {
const result = pipe.transform('ABC');
expect(result).toBe('ABC');
});
});

View File

@ -1,30 +0,0 @@
/*!
* @license
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'filterString',
standalone: true
})
export class FilterStringPipe implements PipeTransform {
transform(value: string = '', filterBy: string = ''): string {
const testResult = filterBy ? value.toLowerCase().indexOf(filterBy.toLowerCase()) > -1 : true;
return testResult ? value : '';
}
}

View File

@ -29,7 +29,6 @@ import { LocalizedDatePipe } from './localized-date.pipe';
import { DecimalNumberPipe } from './decimal-number.pipe'; import { DecimalNumberPipe } from './decimal-number.pipe';
import { MomentDatePipe } from './moment-date.pipe'; import { MomentDatePipe } from './moment-date.pipe';
import { MomentDateTimePipe } from './moment-datetime.pipe'; import { MomentDateTimePipe } from './moment-datetime.pipe';
import { FilterStringPipe } from './filter-string.pipe';
import { DateTimePipe } from './date-time.pipe'; import { DateTimePipe } from './date-time.pipe';
export const CORE_PIPES = [ export const CORE_PIPES = [
@ -45,7 +44,6 @@ export const CORE_PIPES = [
MomentDatePipe, MomentDatePipe,
MomentDateTimePipe, MomentDateTimePipe,
DateTimePipe, DateTimePipe,
FilterStringPipe,
InitialUsernamePipe InitialUsernamePipe
] as const; ] as const;

View File

@ -29,4 +29,3 @@ export * from './pipe.module';
export * from './moment-date.pipe'; export * from './moment-date.pipe';
export * from './moment-datetime.pipe'; export * from './moment-datetime.pipe';
export * from './date-time.pipe'; export * from './date-time.pipe';
export * from './filter-string.pipe';