From c7d76e31412a0b21124d188cfd967dee9967bd01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Mon, 19 Apr 2021 00:18:22 +0300 Subject: [PATCH] Base listing (filter, search, select) for project listing & overview --- .../project-listing-screen.component.html | 16 +- .../project-listing-screen.component.ts | 107 +++++------- .../project-overview-screen.component.html | 35 ++-- .../project-overview-screen.component.ts | 152 ++++++------------ .../shared/base/base-listing.component.ts | 132 +++++++++++++++ .../src/app/modules/shared/shared.module.ts | 2 + 6 files changed, 239 insertions(+), 205 deletions(-) create mode 100644 apps/red-ui/src/app/modules/shared/base/base-listing.component.ts 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 13b48099b..580753ad9 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 @@ -48,7 +48,7 @@
- {{ 'project-listing.table-header.title' | translate: { length: displayedProjects.length || 0 } }} + {{ 'project-listing.table-header.title' | translate: { length: displayedEntities.length || 0 } }}
@@ -70,22 +70,18 @@
- +
- - diff --git a/apps/red-ui/src/app/modules/projects/screens/project-listing-screen/project-listing-screen.component.ts b/apps/red-ui/src/app/modules/projects/screens/project-listing-screen/project-listing-screen.component.ts index ba7d43e8f..cdeffd5a8 100644 --- a/apps/red-ui/src/app/modules/projects/screens/project-listing-screen/project-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/projects/screens/project-listing-screen/project-listing-screen.component.ts @@ -1,4 +1,4 @@ -import { ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { Component, Injector, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { FileManagementControllerService, Project, RuleSetModel } from '@redaction/red-ui-http'; import { AppStateService } from '../../../../state/app-state.service'; import { UserService } from '../../../../services/user.service'; @@ -7,7 +7,6 @@ import { groupBy } from '../../../../utils/functions'; import { FilterModel } from '../../../shared/components/filter/model/filter.model'; import { annotationFilterChecker, - getFilteredEntities, processFilters, projectMemberChecker, projectStatusChecker, @@ -23,21 +22,19 @@ import { TranslateChartService } from '../../../../services/translate-chart.serv import { RedactionFilterSorter } from '../../../../utils/sorters/redaction-filter-sorter'; import { StatusSorter } from '../../../../utils/sorters/status-sorter'; import { Router } from '@angular/router'; -import { FormBuilder, FormGroup } from '@angular/forms'; -import { debounce } from '../../../../utils/debounce'; import { FilterComponent } from '../../../shared/components/filter/filter.component'; import { ProjectsDialogService } from '../../services/projects-dialog.service'; +import { BaseListingComponent } from '../../../shared/base/base-listing.component'; @Component({ selector: 'redaction-project-listing-screen', templateUrl: './project-listing-screen.component.html', styleUrls: ['./project-listing-screen.component.scss'] }) -export class ProjectListingScreenComponent implements OnInit, OnDestroy { +export class ProjectListingScreenComponent extends BaseListingComponent implements OnInit, OnDestroy { public projectsChartData: DoughnutChartConfig[] = []; public documentsChartData: DoughnutChartConfig[] = []; - public searchForm: FormGroup; public actionMenuOpen: boolean; public statusFilters: FilterModel[]; @@ -51,7 +48,6 @@ export class ProjectListingScreenComponent implements OnInit, OnDestroy { statusFilters: [] }; - public displayedProjects: ProjectWrapper[] = []; private projectAutoUpdateTimer: Subscription; @ViewChild('statusFilter') private _statusFilterComponent: FilterComponent; @@ -60,36 +56,33 @@ export class ProjectListingScreenComponent implements OnInit, OnDestroy { @ViewChild('ruleSetFilter') private _ruleSetFilterComponent: FilterComponent; constructor( - public readonly appStateService: AppStateService, + private readonly _appStateService: AppStateService, public readonly userService: UserService, public readonly permissionsService: PermissionsService, - private readonly _changeDetectorRef: ChangeDetectorRef, private readonly _dialogService: ProjectsDialogService, private readonly _translateService: TranslateService, private readonly _router: Router, public readonly sortingService: SortingService, public readonly translateChartService: TranslateChartService, - private readonly _formBuilder: FormBuilder, - private readonly _fileManagementControllerService: FileManagementControllerService + private readonly _fileManagementControllerService: FileManagementControllerService, + protected readonly _injector: Injector ) { - this.appStateService.reset(); - this.searchForm = this._formBuilder.group({ - query: [''] - }); - - this.searchForm.valueChanges.subscribe((value) => this._executeSearch(value)); + super(_injector); + this._appStateService.reset(); + this._loadEntitiesFromState(); } public ngOnInit(): void { this.projectAutoUpdateTimer = timer(0, 10000) .pipe( tap(async () => { - await this.appStateService.loadAllProjects(); + await this._appStateService.loadAllProjects(); + this._loadEntitiesFromState(); }) ) .subscribe(); this._calculateData(); - this.appStateService.fileChanged.subscribe(() => { + this._appStateService.fileChanged.subscribe(() => { this._calculateData(); }); } @@ -98,37 +91,30 @@ export class ProjectListingScreenComponent implements OnInit, OnDestroy { this.projectAutoUpdateTimer.unsubscribe(); } - public get hasActiveFilters() { - return ( - this._statusFilterComponent?.hasActiveFilters || - this._peopleFilterComponent?.hasActiveFilters || - this._needsWorkFilterComponent?.hasActiveFilters || - this._ruleSetFilterComponent?.hasActiveFilters || - this.searchForm.get('query').value - ); + private _loadEntitiesFromState() { + this.allEntities = this._appStateService.allProjects; + } + + protected get _searchKey() { + return 'name'; } public get noData() { - return this.appStateService.allProjects?.length === 0; + return this.allEntities.length === 0; } - public resetFilters() { - this._statusFilterComponent.deactivateAllFilters(); - this._peopleFilterComponent.deactivateAllFilters(); - this._needsWorkFilterComponent.deactivateAllFilters(); - this._ruleSetFilterComponent.deactivateAllFilters(); - this.filtersChanged(); - this.searchForm.reset({ query: '' }); + protected get filterComponents(): FilterComponent[] { + return [this._statusFilterComponent, this._peopleFilterComponent, this._needsWorkFilterComponent, this._ruleSetFilterComponent]; } private _calculateData() { this._computeAllFilters(); - this._filterProjects(); + this._filterEntities(); this.projectsChartData = [ - { value: this.activeProjects, color: 'ACTIVE', label: 'active' }, - { value: this.inactiveProjects, color: 'DELETED', label: 'archived' } + { value: this.activeProjectsCount, color: 'ACTIVE', label: 'active' }, + { value: this.inactiveProjectsCount, color: 'DELETED', label: 'archived' } ]; - const groups = groupBy(this.appStateService.aggregatedFiles, 'status'); + const groups = groupBy(this._appStateService.aggregatedFiles, 'status'); this.documentsChartData = []; for (const key of Object.keys(groups)) { this.documentsChartData.push({ @@ -150,12 +136,12 @@ export class ProjectListingScreenComponent implements OnInit, OnDestroy { return this.sortingService.getSortingOption('project-listing'); } - public get activeProjects() { - return this.appStateService.allProjects.reduce((i, p) => i + (p.project.status === Project.StatusEnum.ACTIVE ? 1 : 0), 0); + public get activeProjectsCount() { + return this.allEntities.filter((p) => p.project.status === Project.StatusEnum.ACTIVE).length; } - public get inactiveProjects() { - return this.appStateService.allProjects.length - this.activeProjects; + public get inactiveProjectsCount() { + return this.allEntities.length - this.activeProjectsCount; } public documentCount(project: ProjectWrapper) { @@ -171,7 +157,7 @@ export class ProjectListingScreenComponent implements OnInit, OnDestroy { } public getRuleSet(pw: ProjectWrapper): RuleSetModel { - return this.appStateService.getRuleSetById(pw.project.ruleSetId); + return this._appStateService.getRuleSetById(pw.project.ruleSetId); } public openAddProjectDialog(): void { @@ -193,7 +179,7 @@ export class ProjectListingScreenComponent implements OnInit, OnDestroy { const allDistinctPeople = new Set(); const allDistinctNeedsWork = new Set(); const allDistinctRuleSets = new Set(); - this.appStateService.allProjects.forEach((entry) => { + this.allEntities.forEach((entry) => { // all people entry.project.memberIds.forEach((memberId) => allDistinctPeople.add(memberId)); // file statuses @@ -248,25 +234,14 @@ export class ProjectListingScreenComponent implements OnInit, OnDestroy { allDistinctRuleSets.forEach((ruleSetId) => { ruleSetFilters.push({ key: ruleSetId, - label: this.appStateService.getRuleSetById(ruleSetId).name + label: this._appStateService.getRuleSetById(ruleSetId).name }); }); this.ruleSetFilters = processFilters(this.ruleSetFilters, ruleSetFilters); } - filtersChanged(filters?: { [key: string]: FilterModel[] }): void { - if (filters) { - for (const key of Object.keys(filters)) { - for (let idx = 0; idx < this[key].length; ++idx) { - this[key][idx] = filters[key][idx]; - } - } - } - this._filterProjects(); - } - - private get _filteredProjects(): ProjectWrapper[] { - const filters = [ + protected get filters(): { values: FilterModel[]; checker: Function; matchAll?: boolean; checkerArgs?: any }[] { + return [ { values: this.statusFilters, checker: projectStatusChecker }, { values: this.peopleFilters, checker: projectMemberChecker }, { @@ -277,25 +252,15 @@ export class ProjectListingScreenComponent implements OnInit, OnDestroy { }, { values: this.ruleSetFilters, checker: ruleSetChecker } ]; - return getFilteredEntities(this.appStateService.allProjects, filters); } - private _filterProjects() { + protected preFilter() { this.detailsContainerFilters = { statusFilters: this.statusFilters.map((f) => ({ ...f })) }; - this.displayedProjects = this._filteredProjects.filter((project) => - project.name.toLowerCase().includes(this.searchForm.get('query').value.toLowerCase()) - ); - this._changeDetectorRef.detectChanges(); } - @debounce(200) - private _executeSearch(value: { query: string }) { - this.displayedProjects = this._filteredProjects.filter((project) => project.name.toLowerCase().includes(value.query.toLowerCase())); - } - - actionPerformed(pw: ProjectWrapper) { + public actionPerformed(pw: ProjectWrapper) { this._calculateData(); } } 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 c4f6ba38c..f8c08808d 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 @@ -1,4 +1,4 @@ -
+