import { Context } from "koa"; import { BaseListPageFields, DEFAULT_ITEMS_PER_PAGE, ListPage, } from "./list.js"; import { Collection, CollectionItem, ItemList, Context as SealiousContext, CollectionInput, } from "sealious"; import { FlatTemplatable, Templatable, tempstream } from "tempstream"; import { peopleWhoCan } from "./access-control.js"; import qs from "qs"; import { is, predicates } from "@sealcode/ts-predicates"; export abstract class SealiousItemListPage< C extends Collection, F extends typeof BaseListPageFields, > extends ListPage, F> { constructor(public collection: C) { super(); } async getContextForList(ctx: Context): Promise { return ctx.$context; } async getTotalPages(ctx: Context, itemsPerPage: number): Promise { const query = this.collection.list(await this.getContextForList(ctx)); await this.addFilter(ctx, query); const { items } = await query.fetch(); return Math.ceil(items.length / itemsPerPage); } protected async addFilter(ctx: Context, list: ItemList): Promise { const filters = await this.getFilterValues(ctx); for (const key in filters) { if (filters[key] === undefined || filters[key] == "") { delete filters[key]; } } if (Object.keys(filters).length) { list.filter(filters as Partial>); } } async makeQuery(ctx: Context): Promise> { const query = this.collection.list(await this.getContextForList(ctx)); const sort = await this.getSort(ctx); if (sort) { // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any query.sort({ [sort.field]: sort.order } as any); } return query; } async getItems( ctx: Context, page: number, itemsPerPage: number | null ): Promise[]> { const query = await this.makeQuery(ctx); await this.addFilter(ctx, query); const { items } = await query .paginate({ items: itemsPerPage || DEFAULT_ITEMS_PER_PAGE, page }) .fetch(); return items; } async getFilterValues(ctx: Context) { const query_params = qs.parse(ctx.search.slice(1)); const _filter_values = query_params?.filter || {}; const filter_values: Record = is( _filter_values, predicates.record(predicates.string, predicates.string) ) ? _filter_values : {}; for (const key in filter_values) { if (filter_values[key] == "") { delete filter_values[key]; } } return filter_values; } renderListContainer(_: Context, content: Templatable): FlatTemplatable { return tempstream`
${content}
`; } async renderItem( _: Context, item: CollectionItem, _index: number ): Promise { return `
${item.id}
`; } canAccess = peopleWhoCan("list", this.collection); }