From 7951e2e2cf06c5ad87d57373d5ce060b021f29cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Mon, 19 Apr 2021 21:55:44 +0300 Subject: [PATCH] Sorting logic, added for rulesets listing --- .../rule-sets-listing-screen.component.html | 24 ++--- .../rule-sets-listing-screen.component.ts | 78 +++------------- .../project-listing-screen.component.html | 2 +- .../project-listing-screen.component.ts | 13 +-- .../project-overview-screen.component.html | 2 + .../project-overview-screen.component.ts | 22 +---- .../shared/base/base-listing.component.ts | 93 ++++++++++++------- .../src/app/services/sorting.service.ts | 6 +- 8 files changed, 100 insertions(+), 140 deletions(-) diff --git a/apps/red-ui/src/app/modules/admin/screens/rule-sets-listing/rule-sets-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/rule-sets-listing/rule-sets-listing-screen.component.html index 72be0a00e..452c1d81b 100644 --- a/apps/red-ui/src/app/modules/admin/screens/rule-sets-listing/rule-sets-listing-screen.component.html +++ b/apps/red-ui/src/app/modules/admin/screens/rule-sets-listing/rule-sets-listing-screen.component.html @@ -30,13 +30,13 @@
- + - {{ 'project-templates-listing.table-header.title' | translate: { length: displayedRuleSets.length } }} + {{ 'project-templates-listing.table-header.title' | translate: { length: displayedEntities.length } }}
-
+
- + @@ -87,12 +87,12 @@
-
-
- +
+
+
diff --git a/apps/red-ui/src/app/modules/admin/screens/rule-sets-listing/rule-sets-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/rule-sets-listing/rule-sets-listing-screen.component.ts index 105a1afd6..5b227b3d8 100644 --- a/apps/red-ui/src/app/modules/admin/screens/rule-sets-listing/rule-sets-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/rule-sets-listing/rule-sets-listing-screen.component.ts @@ -1,57 +1,43 @@ -import { Component, OnInit } from '@angular/core'; -import { SortingOption, SortingService } from '../../../../services/sorting.service'; +import { Component, Injector, OnInit } from '@angular/core'; import { AppStateService } from '../../../../state/app-state.service'; import { PermissionsService } from '../../../../services/permissions.service'; -import { FormBuilder, FormGroup } from '@angular/forms'; -import { debounce } from '../../../../utils/debounce'; -import { RuleSetModel } from '@redaction/red-ui-http'; import { UserPreferenceService } from '../../../../services/user-preference.service'; import { AdminDialogService } from '../../services/admin-dialog.service'; +import { BaseListingComponent } from '../../../shared/base/base-listing.component'; @Component({ selector: 'redaction-rule-sets-listing-screen', templateUrl: './rule-sets-listing-screen.component.html', styleUrls: ['./rule-sets-listing-screen.component.scss'] }) -export class RuleSetsListingScreenComponent implements OnInit { - public ruleSets: RuleSetModel[]; - public displayedRuleSets: RuleSetModel[]; - public selectedRuleSetIds: string[] = []; - public searchForm: FormGroup; +export class RuleSetsListingScreenComponent extends BaseListingComponent implements OnInit { + protected readonly _searchKey = 'name'; + protected readonly _selectionKey = 'ruleSetId'; + protected readonly _sortKey = 'rule-sets-listing'; constructor( private readonly _dialogService: AdminDialogService, - private readonly _sortingService: SortingService, - private readonly _formBuilder: FormBuilder, private readonly _appStateService: AppStateService, public readonly permissionsService: PermissionsService, - public readonly userPreferenceService: UserPreferenceService + public readonly userPreferenceService: UserPreferenceService, + protected readonly _injector: Injector ) { - this.searchForm = this._formBuilder.group({ - query: [''] - }); - - this.searchForm.valueChanges.subscribe((value) => this._executeSearch(value)); + super(_injector); } ngOnInit(): void { this.loadRuleSetsData(); } - @debounce(200) - private _executeSearch(value: { query: string }) { - this.displayedRuleSets = this.ruleSets.filter((pt) => pt.name.toLowerCase().includes(value.query.toLowerCase())); - } - public loadRuleSetsData() { this._appStateService.reset(); - this.ruleSets = this._appStateService.ruleSets; - this.displayedRuleSets = [...this.ruleSets]; + this.allEntities = this._appStateService.ruleSets; + this._executeSearch(); this._loadRuleSetStats(); } private _loadRuleSetStats() { - this.ruleSets.forEach((rs) => { + this.allEntities.forEach((rs) => { const dictionaries = this._appStateService.dictionaryData[rs.ruleSetId]; if (dictionaries) { rs.dictionariesCount = Object.keys(dictionaries) @@ -64,45 +50,7 @@ export class RuleSetsListingScreenComponent implements OnInit { }); } - public get sortingOption(): SortingOption { - return this._sortingService.getSortingOption('rule-sets-listing'); - } - - public toggleSort($event) { - this._sortingService.toggleSort('rule-sets-listing', $event); - } - - toggleTemplateSelected($event: MouseEvent, ruleSet: RuleSetModel) { - $event.stopPropagation(); - const idx = this.selectedRuleSetIds.indexOf(ruleSet.ruleSetId); - if (idx === -1) { - this.selectedRuleSetIds.push(ruleSet.ruleSetId); - } else { - this.selectedRuleSetIds.splice(idx, 1); - } - } - - public toggleSelectAll() { - if (this.areSomeRuleSetsSelected) { - this.selectedRuleSetIds = []; - } else { - this.selectedRuleSetIds = this.displayedRuleSets.map((rs) => rs.ruleSetId); - } - } - - public get areAllRuleSetsSelected() { - return this.displayedRuleSets.length !== 0 && this.selectedRuleSetIds.length === this.displayedRuleSets.length; - } - - public get areSomeRuleSetsSelected() { - return this.selectedRuleSetIds.length > 0; - } - - public isRuleSetSelected(ruleSet: RuleSetModel) { - return this.selectedRuleSetIds.indexOf(ruleSet.ruleSetId) !== -1; - } - - openAddRuleSetDialog() { + public openAddRuleSetDialog() { this._dialogService.openAddEditRuleSetDialog(null, async (newRuleSet) => { if (newRuleSet) { this.loadRuleSetsData(); diff --git a/apps/red-ui/src/app/modules/projects/screens/project-listing-screen/project-listing-screen.component.html b/apps/red-ui/src/app/modules/projects/screens/project-listing-screen/project-listing-screen.component.html index 580753ad9..c037ce2a2 100644 --- a/apps/red-ui/src/app/modules/projects/screens/project-listing-screen/project-listing-screen.component.html +++ b/apps/red-ui/src/app/modules/projects/screens/project-listing-screen/project-listing-screen.component.html @@ -54,7 +54,7 @@
implements OnInit, OnDestroy { + protected readonly _searchKey = 'name'; + protected readonly _sortKey = 'project-listing'; + public projectsChartData: DoughnutChartConfig[] = []; public documentsChartData: DoughnutChartConfig[] = []; @@ -62,7 +64,6 @@ export class ProjectListingScreenComponent extends BaseListingComponent p.project.status === Project.StatusEnum.ACTIVE).length; } diff --git a/apps/red-ui/src/app/modules/projects/screens/project-overview-screen/project-overview-screen.component.html b/apps/red-ui/src/app/modules/projects/screens/project-overview-screen/project-overview-screen.component.html index f8c08808d..01b8ba998 100644 --- a/apps/red-ui/src/app/modules/projects/screens/project-overview-screen/project-overview-screen.component.html +++ b/apps/red-ui/src/app/modules/projects/screens/project-overview-screen/project-overview-screen.component.html @@ -108,6 +108,8 @@ [selectedFileIds]="selectedEntitiesIds" (reload)="bulkActionPerformed()" > + + {{ selectedEntitiesIds.length }} selected
diff --git a/apps/red-ui/src/app/modules/projects/screens/project-overview-screen/project-overview-screen.component.ts b/apps/red-ui/src/app/modules/projects/screens/project-overview-screen/project-overview-screen.component.ts index a5519513b..c68cd34d4 100644 --- a/apps/red-ui/src/app/modules/projects/screens/project-overview-screen/project-overview-screen.component.ts +++ b/apps/red-ui/src/app/modules/projects/screens/project-overview-screen/project-overview-screen.component.ts @@ -13,7 +13,6 @@ import * as moment from 'moment'; import { ProjectDetailsComponent } from '../../components/project-details/project-details.component'; import { FileStatusWrapper } from '../../../../models/file/file-status.wrapper'; import { annotationFilterChecker, keyChecker, processFilters } from '../../../shared/components/filter/utils/filter-utils'; -import { SortingOption, SortingService } from '../../../../services/sorting.service'; import { PermissionsService } from '../../../../services/permissions.service'; import { UserService } from '../../../../services/user.service'; import { FileManagementControllerService, FileStatus } from '@redaction/red-ui-http'; @@ -34,6 +33,10 @@ import { ProjectWrapper } from '../../../../state/model/project.wrapper'; styleUrls: ['./project-overview-screen.component.scss'] }) export class ProjectOverviewScreenComponent extends BaseListingComponent implements OnInit, OnDestroy { + protected readonly _searchKey = 'filename'; + protected readonly _selectionKey = 'fileId'; + protected readonly _sortKey = 'project-overview'; + public statusFilters: FilterModel[]; public peopleFilters: FilterModel[]; public needsWorkFilters: FilterModel[]; @@ -56,7 +59,6 @@ export class ProjectOverviewScreenComponent extends BaseListingComponent { @@ -17,37 +20,57 @@ export class BaseListingComponent { protected readonly _formBuilder: FormBuilder; protected readonly _changeDetectorRef: ChangeDetectorRef; + protected readonly _sortingService: SortingService; // ---- // Overwrite in child class: - protected get _searchKey(): string { - throw new Error('Not implemented.'); - } - - protected get _selectionKey(): string { - throw new Error('Not implemented.'); - } + protected readonly _searchKey: string; + protected readonly _selectionKey: string; + protected readonly _sortKey: ScreenName; protected get filters(): { values: FilterModel[]; checker: Function; matchAll?: boolean; checkerArgs?: any }[] { - throw new Error('Not implemented.'); + return []; } protected preFilter() { - throw new Error('Not implemented.'); + return; } protected get filterComponents(): FilterComponent[] { - throw new Error('Not implemented.'); + return []; } - // ---- constructor(protected readonly _injector: Injector) { this._formBuilder = this._injector.get(FormBuilder); this._changeDetectorRef = this._injector.get(ChangeDetectorRef); + this._sortingService = this._injector.get(SortingService); this._initSearch(); } + private get searchKey(): string { + if (!this._searchKey) { + throw new Error('Not implemented.'); + } + return this._searchKey; + } + + private get selectionKey(): string { + if (!this._selectionKey) { + throw new Error('Not implemented.'); + } + return this._selectionKey; + } + + private get sortKey(): ScreenName { + if (!this._sortKey) { + throw new Error('Not implemented.'); + } + return this._sortKey; + } + + // Search + private _initSearch() { this.searchForm = this._formBuilder.group({ query: [''] @@ -56,6 +79,16 @@ export class BaseListingComponent { this.searchForm.valueChanges.subscribe(() => this._executeSearch()); } + @debounce(200) + protected _executeSearch() { + this.displayedEntities = (this.filters.length ? this.filteredEntities : this.allEntities).filter((entity) => + entity[this.searchKey].toLowerCase().includes(this.searchForm.get('query').value.toLowerCase()) + ); + this.selectedEntitiesIds = this.displayedEntities.map((entity) => entity[this.selectionKey]).filter((id) => this.selectedEntitiesIds.includes(id)); + } + + // Filter + public filtersChanged(filters?: { [key: string]: FilterModel[] }): void { if (filters) { for (const key of Object.keys(filters)) { @@ -67,15 +100,9 @@ export class BaseListingComponent { this._filterEntities(); } - private get _filteredEntities(): T[] { - const filters = this.filters; - return getFilteredEntities(this.allEntities, filters); - } - protected _filterEntities() { this.preFilter(); - this.filteredEntities = this._filteredEntities; - this.selectedEntitiesIds = this.displayedEntities.map((entity) => entity[this._selectionKey]).filter((id) => this.selectedEntitiesIds.includes(id)); + this.filteredEntities = getFilteredEntities(this.allEntities, this.filters); this._executeSearch(); this._changeDetectorRef.detectChanges(); } @@ -92,19 +119,13 @@ export class BaseListingComponent { return this.filterComponents.reduce((prev, component) => prev || component?.hasActiveFilters, false) || this.searchForm.get('query').value; } - @debounce(200) - protected _executeSearch() { - this.displayedEntities = this.filteredEntities.filter((entity) => - entity[this._searchKey].toLowerCase().includes(this.searchForm.get('query').value.toLowerCase()) - ); - } + // Selection toggleEntitySelected($event: MouseEvent, entity: T) { - console.log({ entity, key: entity[this._selectionKey] }); $event.stopPropagation(); - const idx = this.selectedEntitiesIds.indexOf(entity[this._selectionKey]); + const idx = this.selectedEntitiesIds.indexOf(entity[this.selectionKey]); if (idx === -1) { - this.selectedEntitiesIds.push(entity[this._selectionKey]); + this.selectedEntitiesIds.push(entity[this.selectionKey]); } else { this.selectedEntitiesIds.splice(idx, 1); } @@ -114,7 +135,7 @@ export class BaseListingComponent { if (this.areSomeEntitiesSelected) { this.selectedEntitiesIds = []; } else { - this.selectedEntitiesIds = this.displayedEntities.map((entity) => entity[this._selectionKey]); + this.selectedEntitiesIds = this.displayedEntities.map((entity) => entity[this.selectionKey]); } } @@ -127,6 +148,16 @@ export class BaseListingComponent { } public isEntitySelected(entity: T) { - return this.selectedEntitiesIds.indexOf(entity[this._selectionKey]) !== -1; + return this.selectedEntitiesIds.indexOf(entity[this.selectionKey]) !== -1; + } + + // Sort + + public get sortingOption(): SortingOption { + return this._sortingService.getSortingOption(this.sortKey); + } + + public toggleSort($event) { + this._sortingService.toggleSort(this.sortKey, $event); } } diff --git a/apps/red-ui/src/app/services/sorting.service.ts b/apps/red-ui/src/app/services/sorting.service.ts index b73629bdb..58eeb969e 100644 --- a/apps/red-ui/src/app/services/sorting.service.ts +++ b/apps/red-ui/src/app/services/sorting.service.ts @@ -5,7 +5,7 @@ export class SortingOption { column: string; } -type Screen = 'project-listing' | 'project-overview' | 'dictionary-listing' | 'rule-sets-listing' | 'default-colors' | 'file-attributes-listing'; +export type ScreenName = 'project-listing' | 'project-overview' | 'dictionary-listing' | 'rule-sets-listing' | 'default-colors' | 'file-attributes-listing'; @Injectable({ providedIn: 'root' @@ -22,7 +22,7 @@ export class SortingService { constructor() {} - public toggleSort(screen: Screen, column: string) { + public toggleSort(screen: ScreenName, column: string) { if (this._options[screen].column === column) { const currentOrder = this._options[screen].order; this._options[screen].order = currentOrder === 'asc' ? 'desc' : 'asc'; @@ -31,7 +31,7 @@ export class SortingService { } } - public getSortingOption(screen: Screen) { + public getSortingOption(screen: ScreenName) { return this._options[screen]; } }