69 lines
2.9 KiB
TypeScript
69 lines
2.9 KiB
TypeScript
import { Directive, Injector, OnDestroy, TemplateRef, ViewChild } from '@angular/core';
|
|
import { combineLatest, Observable } from 'rxjs';
|
|
import { map, switchMapTo } from 'rxjs/operators';
|
|
import { FilterService } from '../filtering';
|
|
import { SortingService } from '../sorting';
|
|
import { AutoUnsubscribe, shareDistinctLast } from '../utils';
|
|
import { SearchService } from '../search';
|
|
import { EntitiesService, ListingService } from './services';
|
|
import { IListable, TableColumnConfig } from './models';
|
|
|
|
export const DefaultListingServicesTmp = [FilterService, SearchService, SortingService, ListingService] as const;
|
|
export const DefaultListingServices = [...DefaultListingServicesTmp, EntitiesService] as const;
|
|
|
|
@Directive()
|
|
export abstract class ListingComponent<T extends IListable> extends AutoUnsubscribe implements OnDestroy {
|
|
readonly filterService = this._injector.get(FilterService);
|
|
readonly searchService = this._injector.get<SearchService<T>>(SearchService);
|
|
readonly sortingService = this._injector.get<SortingService<T>>(SortingService);
|
|
readonly entitiesService = this._injector.get<EntitiesService<T>>(EntitiesService);
|
|
readonly listingService = this._injector.get<ListingService<T>>(ListingService);
|
|
|
|
readonly noMatch$ = this._noMatch$;
|
|
readonly noContent$ = this._noContent$;
|
|
readonly sortedDisplayedEntities$ = this._sortedDisplayedEntities$;
|
|
|
|
abstract readonly tableColumnConfigs: readonly TableColumnConfig<T>[];
|
|
abstract readonly tableHeaderLabel: string;
|
|
|
|
@ViewChild('tableItemTemplate') readonly tableItemTemplate?: TemplateRef<unknown>;
|
|
@ViewChild('workflowItemTemplate') readonly workflowItemTemplate?: TemplateRef<unknown>;
|
|
|
|
protected constructor(protected readonly _injector: Injector) {
|
|
super();
|
|
}
|
|
|
|
get allEntities(): T[] {
|
|
return this.entitiesService.all;
|
|
}
|
|
|
|
private get _sortedDisplayedEntities$(): Observable<T[]> {
|
|
const sort = (entities: T[]) => this.sortingService.defaultSort(entities);
|
|
const sortedEntities$ = this.listingService.displayed$.pipe(map(sort));
|
|
return this.sortingService.sortingOption$.pipe(switchMapTo(sortedEntities$), shareDistinctLast());
|
|
}
|
|
|
|
private get _noMatch$(): Observable<boolean> {
|
|
return combineLatest([this.entitiesService.allLength$, this.listingService.displayedLength$]).pipe(
|
|
map(([hasEntities, hasDisplayedEntities]) => !!hasEntities && !hasDisplayedEntities),
|
|
shareDistinctLast(),
|
|
);
|
|
}
|
|
|
|
private get _noContent$(): Observable<boolean> {
|
|
return combineLatest([this._noMatch$, this.entitiesService.noData$]).pipe(
|
|
map(([noMatch, noData]) => noMatch || noData),
|
|
shareDistinctLast(),
|
|
);
|
|
}
|
|
|
|
toggleEntitySelected(event: MouseEvent, entity: T): void {
|
|
event.stopPropagation();
|
|
this.listingService.select(entity);
|
|
}
|
|
|
|
cast(entity: unknown): T {
|
|
return entity as T;
|
|
}
|
|
}
|