65 lines
2.6 KiB
TypeScript
65 lines
2.6 KiB
TypeScript
import { Directive, inject, OnDestroy, TemplateRef, ViewChild } from '@angular/core';
|
|
import { combineLatest, Observable } from 'rxjs';
|
|
import { map, switchMap } 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';
|
|
import { Id } from './models/trackable';
|
|
|
|
@Directive()
|
|
export abstract class ListingComponent<Class extends IListable<PrimaryKey>, PrimaryKey extends Id = Class['id']>
|
|
extends AutoUnsubscribe
|
|
implements OnDestroy
|
|
{
|
|
readonly filterService = inject(FilterService);
|
|
readonly searchService = inject<SearchService<Class>>(SearchService);
|
|
readonly sortingService = inject<SortingService<Class>>(SortingService);
|
|
readonly entitiesService = inject<EntitiesService<Class, Class>>(EntitiesService);
|
|
readonly listingService = inject<ListingService<Class>>(ListingService);
|
|
|
|
// TODO: Move to table content component
|
|
readonly noMatch$ = this.#noMatch$;
|
|
// TODO: Move to table content component
|
|
readonly noContent$ = this.#noContent$;
|
|
readonly sortedDisplayedEntities$ = this.#sortedDisplayedEntities$;
|
|
|
|
abstract readonly tableColumnConfigs: readonly TableColumnConfig<Class>[];
|
|
abstract readonly tableHeaderLabel: string;
|
|
|
|
@ViewChild('tableItemTemplate') readonly tableItemTemplate?: TemplateRef<unknown>;
|
|
|
|
get allEntities(): Class[] {
|
|
return this.entitiesService.all;
|
|
}
|
|
|
|
get #sortedDisplayedEntities$(): Observable<Class[]> {
|
|
const sort = (entities: Class[]) => this.sortingService.defaultSort(entities);
|
|
const sortedEntities$ = this.listingService.displayed$.pipe(map(sort));
|
|
return this.sortingService.sortingOption$.pipe(
|
|
switchMap(() => sortedEntities$),
|
|
shareDistinctLast(),
|
|
);
|
|
}
|
|
|
|
get #noMatch$(): Observable<boolean> {
|
|
return combineLatest([this.entitiesService.allLength$, this.listingService.displayedLength$]).pipe(
|
|
map(([hasEntities, hasDisplayedEntities]) => !!hasEntities && !hasDisplayedEntities),
|
|
shareDistinctLast(),
|
|
);
|
|
}
|
|
|
|
get #noContent$(): Observable<boolean> {
|
|
return combineLatest([this.noMatch$, this.entitiesService.noData$]).pipe(
|
|
map(([noMatch, noData]) => noMatch || noData),
|
|
shareDistinctLast(),
|
|
);
|
|
}
|
|
|
|
cast(entity: unknown): Class {
|
|
return entity as Class;
|
|
}
|
|
}
|