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 extends AutoUnsubscribe implements OnDestroy { readonly filterService = this._injector.get(FilterService); readonly searchService = this._injector.get>(SearchService); readonly sortingService = this._injector.get>(SortingService); readonly entitiesService = this._injector.get>(EntitiesService); readonly listingService = this._injector.get>(ListingService); readonly noMatch$ = this._noMatch$; readonly noContent$ = this._noContent$; readonly sortedDisplayedEntities$ = this._sortedDisplayedEntities$; abstract readonly tableColumnConfigs: readonly TableColumnConfig[]; abstract readonly tableHeaderLabel: string; @ViewChild('tableItemTemplate') readonly tableItemTemplate?: TemplateRef; @ViewChild('workflowItemTemplate') readonly workflowItemTemplate?: TemplateRef; protected constructor(protected readonly _injector: Injector) { super(); } get allEntities(): T[] { return this.entitiesService.all; } private get _sortedDisplayedEntities$(): Observable { 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 { return combineLatest([this.entitiesService.allLength$, this.listingService.displayedLength$]).pipe( map(([hasEntities, hasDisplayedEntities]) => !!hasEntities && !hasDisplayedEntities), shareDistinctLast(), ); } private get _noContent$(): Observable { 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; } }