refactor sorting service

This commit is contained in:
Dan Percic 2021-07-09 19:24:15 +03:00
parent 3e400e6dd2
commit 5ba302bd83
13 changed files with 144 additions and 115 deletions

View File

@ -10,11 +10,16 @@ import {
import { BaseListingComponent } from '@shared/base/base-listing.component';
import { Field } from '../file-attributes-csv-import-dialog.component';
import { FileAttributeConfig } from '@redaction/red-ui-http';
import { FilterService } from '../../../../shared/services/filter.service';
import { SearchService } from '../../../../shared/services/search.service';
import { ScreenStateService } from '../../../../shared/services/screen-state.service';
import { SortingService } from '../../../../../services/sorting.service';
@Component({
selector: 'redaction-active-fields-listing',
templateUrl: './active-fields-listing.component.html',
styleUrls: ['./active-fields-listing.component.scss']
styleUrls: ['./active-fields-listing.component.scss'],
providers: [FilterService, SearchService, ScreenStateService, SortingService]
})
export class ActiveFieldsListingComponent extends BaseListingComponent<Field> implements OnChanges {
@Input() allEntities: Field[];

View File

@ -13,6 +13,10 @@ import { map, startWith } from 'rxjs/operators';
import { BaseListingComponent } from '@shared/base/base-listing.component';
import { NotificationService, NotificationType } from '@services/notification.service';
import { TranslateService } from '@ngx-translate/core';
import { FilterService } from '../../../shared/services/filter.service';
import { SearchService } from '../../../shared/services/search.service';
import { ScreenStateService } from '../../../shared/services/screen-state.service';
import { SortingService } from '../../../../services/sorting.service';
export interface Field {
id?: string;
@ -28,7 +32,8 @@ export interface Field {
@Component({
selector: 'redaction-file-attributes-csv-import-dialog',
templateUrl: './file-attributes-csv-import-dialog.component.html',
styleUrls: ['./file-attributes-csv-import-dialog.component.scss']
styleUrls: ['./file-attributes-csv-import-dialog.component.scss'],
providers: [FilterService, SearchService, ScreenStateService, SortingService]
})
export class FileAttributesCsvImportDialogComponent extends BaseListingComponent<Field> {
csvFile: File;

View File

@ -6,11 +6,15 @@ import { PermissionsService } from '@services/permissions.service';
import { AdminDialogService } from '../../services/admin-dialog.service';
import { BaseListingComponent } from '@shared/base/base-listing.component';
import { LoadingService } from '../../../../services/loading.service';
import { FilterService } from '../../../shared/services/filter.service';
import { SearchService } from '../../../shared/services/search.service';
import { ScreenStateService } from '../../../shared/services/screen-state.service';
import { SortingService } from '../../../../services/sorting.service';
@Component({
selector: 'redaction-default-colors-screen',
templateUrl: './default-colors-screen.component.html',
styleUrls: ['./default-colors-screen.component.scss']
styleUrls: ['./default-colors-screen.component.scss'],
providers: [FilterService, SearchService, ScreenStateService, SortingService]
})
export class DefaultColorsScreenComponent
extends BaseListingComponent<{
@ -19,7 +23,6 @@ export class DefaultColorsScreenComponent
}>
implements OnInit
{
protected readonly _sortKey = 'default-colors';
private _colorsObj: Colors;
constructor(
@ -32,6 +35,7 @@ export class DefaultColorsScreenComponent
protected readonly _injector: Injector
) {
super(_injector);
this._sortingService.screenName = 'default-colors';
_appStateService.activateDossierTemplate(_activatedRoute.snapshot.params.dossierTemplateId);
}

View File

@ -11,6 +11,10 @@ import { BaseListingComponent } from '@shared/base/base-listing.component';
import { TypeValueWrapper } from '../../../../models/file/type-value.wrapper';
import { TranslateService } from '@ngx-translate/core';
import { LoadingService } from '../../../../services/loading.service';
import { FilterService } from '../../../shared/services/filter.service';
import { SearchService } from '../../../shared/services/search.service';
import { ScreenStateService } from '../../../shared/services/screen-state.service';
import { SortingService } from '../../../../services/sorting.service';
const toChartConfig = (dict: TypeValueWrapper): DoughnutChartConfig => ({
value: dict.entries ? dict.entries.length : 0,
@ -20,9 +24,9 @@ const toChartConfig = (dict: TypeValueWrapper): DoughnutChartConfig => ({
});
@Component({
selector: 'redaction-dictionary-listing-screen',
templateUrl: './dictionary-listing-screen.component.html',
styleUrls: ['./dictionary-listing-screen.component.scss']
styleUrls: ['./dictionary-listing-screen.component.scss'],
providers: [FilterService, SearchService, ScreenStateService, SortingService]
})
export class DictionaryListingScreenComponent
extends BaseListingComponent<TypeValueWrapper>
@ -31,7 +35,6 @@ export class DictionaryListingScreenComponent
chartData: DoughnutChartConfig[] = [];
protected readonly _searchKey = 'label';
protected readonly _selectionKey = 'type';
protected readonly _sortKey = 'dictionary-listing';
constructor(
private readonly _dialogService: AdminDialogService,
@ -45,6 +48,7 @@ export class DictionaryListingScreenComponent
) {
super(_injector);
_loadingService.start();
this._sortingService.screenName = 'dictionary-listing';
_appStateService.activateDossierTemplate(_activatedRoute.snapshot.params.dossierTemplateId);
}

View File

@ -7,11 +7,15 @@ import { BaseListingComponent } from '@shared/base/base-listing.component';
import { DossierTemplateModelWrapper } from '../../../../models/file/dossier-template-model.wrapper';
import { LoadingService } from '../../../../services/loading.service';
import { DossierTemplateControllerService } from '@redaction/red-ui-http';
import { FilterService } from '../../../shared/services/filter.service';
import { SearchService } from '../../../shared/services/search.service';
import { ScreenStateService } from '../../../shared/services/screen-state.service';
import { SortingService } from '../../../../services/sorting.service';
@Component({
selector: 'redaction-dossier-templates-listing-screen',
templateUrl: './dossier-templates-listing-screen.component.html',
styleUrls: ['./dossier-templates-listing-screen.component.scss']
styleUrls: ['./dossier-templates-listing-screen.component.scss'],
providers: [FilterService, SearchService, ScreenStateService, SortingService]
})
export class DossierTemplatesListingScreenComponent
extends BaseListingComponent<DossierTemplateModelWrapper>
@ -19,7 +23,6 @@ export class DossierTemplatesListingScreenComponent
{
protected readonly _searchKey = 'name';
protected readonly _selectionKey = 'dossierTemplateId';
protected readonly _sortKey = 'dossier-templates-listing';
constructor(
private readonly _dialogService: AdminDialogService,
@ -31,6 +34,7 @@ export class DossierTemplatesListingScreenComponent
readonly userPreferenceService: UserPreferenceService
) {
super(_injector);
this._sortingService.screenName = 'dossier-templates-listing';
}
ngOnInit(): void {

View File

@ -6,16 +6,19 @@ import { ActivatedRoute } from '@angular/router';
import { AdminDialogService } from '../../services/admin-dialog.service';
import { BaseListingComponent } from '@shared/base/base-listing.component';
import { LoadingService } from '../../../../services/loading.service';
import { FilterService } from '../../../shared/services/filter.service';
import { SearchService } from '../../../shared/services/search.service';
import { ScreenStateService } from '../../../shared/services/screen-state.service';
import { SortingService } from '../../../../services/sorting.service';
@Component({
selector: 'redaction-file-attributes-listing-screen',
templateUrl: './file-attributes-listing-screen.component.html',
styleUrls: ['./file-attributes-listing-screen.component.scss']
styleUrls: ['./file-attributes-listing-screen.component.scss'],
providers: [FilterService, SearchService, ScreenStateService, SortingService]
})
export class FileAttributesListingScreenComponent extends BaseListingComponent<FileAttributeConfig> implements OnInit {
protected readonly _searchKey = 'label';
protected readonly _selectionKey = 'id';
protected readonly _sortKey = 'file-attributes-listing';
private _existingConfiguration: FileAttributesConfig;
@ViewChild('fileInput') private _fileInput: ElementRef;
@ -30,7 +33,10 @@ export class FileAttributesListingScreenComponent extends BaseListingComponent<F
protected readonly _injector: Injector
) {
super(_injector);
this._appStateService.activateDossierTemplate(_activatedRoute.snapshot.params.dossierTemplateId);
this._sortingService.screenName = 'file-attributes-listing';
this._appStateService.activateDossierTemplate(
_activatedRoute.snapshot.params.dossierTemplateId
);
}
async ngOnInit() {

View File

@ -7,10 +7,15 @@ import { LoadingService } from '../../../../services/loading.service';
import { AppConfigKey, AppConfigService } from '../../../app-config/app-config.service';
import * as moment from 'moment';
import { TranslateService } from '@ngx-translate/core';
import { FilterService } from '../../../shared/services/filter.service';
import { SearchService } from '../../../shared/services/search.service';
import { ScreenStateService } from '../../../shared/services/screen-state.service';
import { SortingService } from '../../../../services/sorting.service';
@Component({
templateUrl: './trash-screen.component.html',
styleUrls: ['./trash-screen.component.scss']
styleUrls: ['./trash-screen.component.scss'],
providers: [FilterService, SearchService, ScreenStateService, SortingService]
})
export class TrashScreenComponent extends BaseListingComponent<Dossier> implements OnInit {
readonly itemSize = 85;
@ -20,7 +25,6 @@ export class TrashScreenComponent extends BaseListingComponent<Dossier> implemen
protected readonly _searchKey = 'dossierName';
protected readonly _selectionKey = 'dossierId';
protected readonly _sortKey = 'dossier-listing';
constructor(
private readonly _appStateService: AppStateService,
@ -32,6 +36,7 @@ export class TrashScreenComponent extends BaseListingComponent<Dossier> implemen
private readonly _translateService: TranslateService
) {
super(_injector);
this._sortingService.screenName = 'dossier-listing';
}
async ngOnInit(): Promise<void> {
@ -51,7 +56,7 @@ export class TrashScreenComponent extends BaseListingComponent<Dossier> implemen
}
getRestoreDate(softDeletedTime: string) {
return moment(softDeletedTime).add(5, 'hours').format();
return moment(softDeletedTime).add(this._deleteRetentionHours, 'hours').format();
}
async restore(dossier: Dossier) {

View File

@ -9,10 +9,15 @@ import { TranslateChartService } from '@services/translate-chart.service';
import { BaseListingComponent } from '@shared/base/base-listing.component';
import { LoadingService } from '../../../../services/loading.service';
import { InitialsAvatarComponent } from '../../../shared/components/initials-avatar/initials-avatar.component';
import { FilterService } from '../../../shared/services/filter.service';
import { SearchService } from '../../../shared/services/search.service';
import { ScreenStateService } from '../../../shared/services/screen-state.service';
import { SortingService } from '../../../../services/sorting.service';
@Component({
templateUrl: './user-listing-screen.component.html',
styleUrls: ['./user-listing-screen.component.scss']
styleUrls: ['./user-listing-screen.component.scss'],
providers: [FilterService, SearchService, ScreenStateService, SortingService]
})
export class UserListingScreenComponent extends BaseListingComponent<User> implements OnInit {
collapsedDetails = false;

View File

@ -30,11 +30,13 @@ import { FilterService } from '../../../shared/services/filter.service';
import { SearchService } from '../../../shared/services/search.service';
import { ScreenStateService } from '../../../shared/services/screen-state.service';
import { NewBaseListingComponent } from '../../../shared/base/new-base-listing.component';
import { FilterWrapper } from '../../../shared/components/filters/popup-filter/model/filter-wrapper.model';
import { SortingService } from '../../../../services/sorting.service';
@Component({
templateUrl: './dossier-listing-screen.component.html',
styleUrls: ['./dossier-listing-screen.component.scss'],
providers: [FilterService, SearchService, ScreenStateService]
providers: [FilterService, SearchService, ScreenStateService, SortingService]
})
export class DossierListingScreenComponent
extends NewBaseListingComponent<DossierWrapper>
@ -65,8 +67,6 @@ export class DossierListingScreenComponent
readonly itemSize = 85;
protected readonly _sortKey = 'dossier-listing';
private _dossierAutoUpdateTimer: Subscription;
private _lastScrollPosition: number;
private _routerEventsScrollPositionSub: Subscription;
@ -87,6 +87,7 @@ export class DossierListingScreenComponent
protected readonly _injector: Injector
) {
super(_injector);
this._sortingService.screenName = 'dossier-listing';
this._appStateService.reset();
this._searchService.searchKey = 'name';
this._loadEntitiesFromState();
@ -110,12 +111,7 @@ export class DossierListingScreenComponent
return this._screenStateService.entities$;
}
protected get _filters(): {
values: FilterModel[];
checker: Function;
matchAll?: boolean;
checkerArgs?: any;
}[] {
protected get _filters(): FilterWrapper[] {
return [
{ values: this.statusFilters, checker: dossierStatusChecker },
{ values: this.peopleFilters, checker: dossierMemberChecker },
@ -135,37 +131,32 @@ export class DossierListingScreenComponent
}
ngOnInit(): void {
try {
this._calculateData();
this._dossierAutoUpdateTimer = timer(0, 10000)
.pipe(
tap(async () => {
await this._appStateService.loadAllDossiers();
this._loadEntitiesFromState();
})
)
.subscribe();
this._fileChangedSub = this._appStateService.fileChanged.subscribe(() => {
this._calculateData();
});
this._dossierAutoUpdateTimer = timer(0, 10000)
.pipe(
tap(async () => {
await this._appStateService.loadAllDossiers();
this._loadEntitiesFromState();
})
this._routerEventsScrollPositionSub = this._router.events
.pipe(
filter(
events => events instanceof NavigationStart || events instanceof NavigationEnd
)
.subscribe();
this._fileChangedSub = this._appStateService.fileChanged.subscribe(() => {
this._calculateData();
)
.subscribe(event => {
if (event instanceof NavigationStart && event.url !== '/main/dossiers') {
this._lastScrollPosition = this.scrollViewport.measureScrollOffset('top');
}
});
this._routerEventsScrollPositionSub = this._router.events
.pipe(
filter(
events =>
events instanceof NavigationStart || events instanceof NavigationEnd
)
)
.subscribe(event => {
if (event instanceof NavigationStart && event.url !== '/main/dossiers') {
this._lastScrollPosition = this.scrollViewport.measureScrollOffset('top');
}
});
} catch (e) {
console.log(e);
}
}
ngOnAttach() {

View File

@ -41,12 +41,14 @@ import { AppConfigKey, AppConfigService } from '../../../app-config/app-config.s
import { FilterConfig } from '@shared/components/page-header/models/filter-config.model';
import { ActionConfig } from '@shared/components/page-header/models/action-config.model';
import { FilterService } from '../../../shared/services/filter.service';
import { SearchService } from '../../../shared/services/search.service';
import { ScreenStateService } from '../../../shared/services/screen-state.service';
import { SortingService } from '../../../../services/sorting.service';
@Component({
selector: 'redaction-dossier-overview-screen',
templateUrl: './dossier-overview-screen.component.html',
styleUrls: ['./dossier-overview-screen.component.scss'],
providers: [FilterService]
providers: [FilterService, SearchService, ScreenStateService, SortingService]
})
export class DossierOverviewScreenComponent
extends BaseListingComponent<FileStatusWrapper>
@ -67,7 +69,6 @@ export class DossierOverviewScreenComponent
protected readonly _searchKey = 'searchField';
protected readonly _selectionKey = 'fileId';
protected readonly _sortKey = 'dossier-overview';
@ViewChild(DossierDetailsComponent, { static: false })
private readonly _dossierDetailsComponent: DossierDetailsComponent;
@ -97,6 +98,7 @@ export class DossierOverviewScreenComponent
protected readonly _injector: Injector
) {
super(_injector);
this._sortingService.screenName = 'dossier-overview';
this._loadEntitiesFromState();
}

View File

@ -1,6 +1,6 @@
import { ChangeDetectorRef, Component, Injector, ViewChild } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { ScreenName, SortingOption, SortingService } from '@services/sorting.service';
import { SortingOption, SortingService } from '@services/sorting.service';
import { FilterModel } from '../components/filters/popup-filter/model/filter.model';
import { QuickFiltersComponent } from '../components/filters/quick-filters/quick-filters.component';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
@ -35,7 +35,6 @@ export abstract class BaseListingComponent<T = any> {
// Overwrite in child class:
protected readonly _searchKey: string;
protected readonly _selectionKey: string;
protected readonly _sortKey: ScreenName;
// Overwrite this in ngOnInit
@ViewChild(QuickFiltersComponent)
protected _quickFilters: QuickFiltersComponent;
@ -63,7 +62,7 @@ export abstract class BaseListingComponent<T = any> {
}
get sortingOption(): SortingOption {
return this._sortingService.getSortingOption(this._getSortKey);
return this._sortingService.getSortingOption();
}
protected get _filters(): {
@ -91,12 +90,6 @@ export abstract class BaseListingComponent<T = any> {
return this._selectionKey;
}
private get _getSortKey(): ScreenName {
if (!this._sortKey) throw new Error('Not implemented');
return this._sortKey;
}
filtersChanged(filters?: { [key: string]: FilterModel[] } | FilterModel[]): void {
if (filters instanceof Array) this.showResetFilters = !!filters.find(f => f.checked);
else
@ -141,7 +134,7 @@ export abstract class BaseListingComponent<T = any> {
}
toggleSort($event) {
this._sortingService.toggleSort(this._getSortKey, $event);
this._sortingService.toggleSort($event);
}
// Selection

View File

@ -1,4 +1,4 @@
import { ChangeDetectorRef, Component, Injector, ViewChild } from '@angular/core';
import { Component, Injector, ViewChild } from '@angular/core';
import { ScreenName, SortingOption, SortingService } from '@services/sorting.service';
import { FilterModel } from '../components/filters/popup-filter/model/filter.model';
import { QuickFiltersComponent } from '../components/filters/quick-filters/quick-filters.component';
@ -6,26 +6,22 @@ import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import { FilterService } from '../services/filter.service';
import { SearchService } from '../services/search.service';
import { ScreenStateService } from '../services/screen-state.service';
import { FilterWrapper } from '../components/filters/popup-filter/model/filter-wrapper.model';
@Component({ template: '' })
export abstract class NewBaseListingComponent<T = any> {
@ViewChild(CdkVirtualScrollViewport) scrollViewport: CdkVirtualScrollViewport;
protected readonly _changeDetectorRef: ChangeDetectorRef;
protected readonly _sortingService: SortingService;
protected readonly _filterService: FilterService<T>;
protected readonly _searchService: SearchService<T>;
protected readonly _screenStateService: ScreenStateService<T>;
// ----
// Overwrite in child class:
protected readonly _sortKey: ScreenName;
// Overwrite this in ngOnInit
@ViewChild(QuickFiltersComponent)
protected _quickFilters: QuickFiltersComponent;
protected constructor(protected readonly _injector: Injector) {
this._changeDetectorRef = this._injector.get<ChangeDetectorRef>(ChangeDetectorRef);
this._sortingService = this._injector.get<SortingService>(SortingService);
this._filterService = this._injector.get<FilterService<T>>(FilterService);
this._searchService = this._injector.get<SearchService<T>>(SearchService);
@ -33,37 +29,19 @@ export abstract class NewBaseListingComponent<T = any> {
}
get sortingOption(): SortingOption {
return this._sortingService.getSortingOption(this._getSortKey);
return this._sortingService.getSortingOption();
}
protected get _filters(): {
values: FilterModel[];
checker: Function;
matchAll?: boolean;
checkerArgs?: any;
}[] {
protected get _filters(): FilterWrapper[] {
return [];
}
private get _getSortKey(): ScreenName {
if (!this._sortKey) throw new Error('Not implemented');
return this._sortKey;
}
resetFilters() {
this._quickFilters.deactivateFilters();
this._filterService.reset();
}
toggleSort($event) {
this._sortingService.toggleSort(this._getSortKey, $event);
this._sortingService.toggleSort($event);
}
// protected _filterEntities() {
// this._preFilter();
// this.filteredEntities = getFilteredEntities(this.allEntities, this._filters);
// this.executeSearch(this._searchValue);
// this._changeDetectorRef.detectChanges();
// }
}

View File

@ -1,7 +1,14 @@
import { Injectable } from '@angular/core';
export class SortingOption {
order: 'asc' | 'desc';
export type SortingOrder = 'asc' | 'desc';
export enum SortingOrders {
ASC = 'asc',
DESC = 'desc'
}
export interface SortingOption {
order: SortingOrder;
column: string;
}
@ -14,30 +21,50 @@ export type ScreenName =
| 'file-attributes-listing'
| 'dossier-attributes-listing';
@Injectable({
providedIn: 'root'
})
export enum ScreenNames {
DOSSIER_LISTING = 'dossier-listing',
DOSSIER_OVERVIEW = 'dossier-overview',
DICTIONARY_LISTING = 'dictionary-listing',
DICTIONARY_TEMPLATES_LISTING = 'dossier-templates-listing',
DEFAULT_COLORS = 'default-colors',
FILE_ATTRIBUTES_LISTING = 'file-attributes-listing',
DOSSIER_ATTRIBUTES_LISTING = 'dossier-attributes-listing'
}
@Injectable()
export class SortingService {
private readonly _options: { [key: string]: SortingOption } = {
'dossier-listing': { column: 'dossier.dossierName', order: 'asc' },
'dossier-overview': { column: 'filename', order: 'asc' },
'dictionary-listing': { column: 'label', order: 'asc' },
'dossier-templates-listing': { column: 'name', order: 'asc' },
'default-colors': { column: 'key', order: 'asc' },
'file-attributes-listing': { column: 'label', order: 'asc' },
'dossier-attributes-listing': { column: 'label', order: 'asc' }
private _currentScreenName: string;
private readonly _options: { [key in ScreenName]: SortingOption } = {
[ScreenNames.DOSSIER_LISTING]: { column: 'dossier.dossierName', order: SortingOrders.ASC },
[ScreenNames.DOSSIER_OVERVIEW]: { column: 'filename', order: SortingOrders.ASC },
[ScreenNames.DICTIONARY_LISTING]: { column: 'label', order: SortingOrders.ASC },
[ScreenNames.DICTIONARY_TEMPLATES_LISTING]: { column: 'name', order: SortingOrders.ASC },
[ScreenNames.DEFAULT_COLORS]: { column: 'key', order: SortingOrders.ASC },
[ScreenNames.FILE_ATTRIBUTES_LISTING]: { column: 'label', order: SortingOrders.ASC },
[ScreenNames.DOSSIER_ATTRIBUTES_LISTING]: { column: 'label', order: 'asc' }
};
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';
set screenName(value: string) {
this._currentScreenName = value;
}
toggleSort(column: string) {
if (this._options[this._currentScreenName].column === column) {
this._currentOrder = this._currentOrder === SortingOrders.ASC ? SortingOrders.DESC : SortingOrders.ASC;
} else {
this._options[screen] = { column, order: 'asc' };
this._options[this._currentScreenName] = { column, order: SortingOrders.ASC };
}
}
getSortingOption(screen: ScreenName) {
return this._options[screen];
getSortingOption() {
return this._options[this._currentScreenName];
}
private get _currentOrder(): string {
return this._options[this._currentScreenName].order;
}
private set _currentOrder(value: string) {
this._options[this._currentScreenName].order = value;
}
}