import { gettext } from "django"; import { CSSResult, html, LitElement, property, TemplateResult } from "lit-element"; import { AKResponse } from "../../api/Client"; import PFBase from "@patternfly/patternfly/patternfly-base.css"; import PFTable from "@patternfly/patternfly/components/Table/table.css"; import PFBullseye from "@patternfly/patternfly/layouts/Bullseye/bullseye.css"; import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFToolbar from "@patternfly/patternfly/components/Toolbar/toolbar.css"; import PFDropdown from "@patternfly/patternfly/components/Dropdown/dropdown.css"; import PFPagination from "@patternfly/patternfly/components/Pagination/pagination.css"; import AKGlobal from "../../authentik.css"; import "./TablePagination"; import "../EmptyState"; export class TableColumn { title: string; orderBy?: string; onClick?: () => void; constructor(title: string, orderBy?: string) { this.title = title; this.orderBy = orderBy; } headerClickHandler(table: Table): void { if (!this.orderBy) { return; } if (table.order === this.orderBy) { table.order = `-${this.orderBy}`; } else { table.order = this.orderBy; } table.fetch(); } private getSortIndicator(table: Table): string { switch (table.order) { case this.orderBy: return "fa-long-arrow-alt-down"; case `-${this.orderBy}`: return "fa-long-arrow-alt-up"; default: return "fa-arrows-alt-v"; } } renderSortable(table: Table): TemplateResult { return html` `; } render(table: Table): TemplateResult { return html` ${this.orderBy ? this.renderSortable(table) : html`${gettext(this.title)}`} `; } } export abstract class Table extends LitElement { abstract apiEndpoint(page: number): Promise>; abstract columns(): TableColumn[]; abstract row(item: T): TemplateResult[]; private isLoading = false; // eslint-disable-next-line @typescript-eslint/no-unused-vars renderExpanded(item: T): TemplateResult { if (this.expandable) { throw new Error("Expandable is enabled but renderExpanded is not overridden!"); } return html``; } @property({attribute: false}) data?: AKResponse; @property({type: Number}) page = 1; @property({type: String}) order?: string; @property({type: String}) search?: string; @property({type: Boolean}) checkbox = false; @property({attribute: false}) selectedElements: T[] = []; @property({type: Boolean}) expandable = false; @property({attribute: false}) expandedRows: boolean[] = []; static get styles(): CSSResult[] { return [PFBase, PFTable, PFBullseye, PFButton, PFToolbar, PFDropdown, PFPagination, AKGlobal]; } constructor() { super(); this.addEventListener("ak-refresh", () => { this.fetch(); }); } public fetch(): void { if (this.isLoading) { return; } this.isLoading = true; this.apiEndpoint(this.page).then((r) => { this.data = r; this.page = r.pagination.current; this.expandedRows = []; this.isLoading = false; }).catch(() => { this.isLoading = false; }); } private renderLoading(): TemplateResult { return html`
`; } renderEmpty(inner?: TemplateResult): TemplateResult { return html`
${inner ? inner : html``}
`; } private renderRows(): TemplateResult[] | undefined { if (!this.data) { return; } if (this.data.pagination.count === 0) { return [this.renderEmpty()]; } return this.data.results.map((item: T, idx: number) => { if ((this.expandedRows.length - 1) < idx) { this.expandedRows[idx] = false; } return html` ${this.checkbox ? html` = 0} @input=${(ev: InputEvent) => { if ((ev.target as HTMLInputElement).checked) { // Add item to selected this.selectedElements.push(item); } else { // Get index of item and remove if selected const index = this.selectedElements.indexOf(item); if (index <= -1) return; this.selectedElements.splice(index, 1); } }} /> ` : html``} ${this.expandable ? html` ` : html``} ${this.row(item).map((col) => { return html`${col}`; })} ${this.expandedRows[idx] ? this.renderExpanded(item) : html``} `; }); } renderToolbar(): TemplateResult { return html``; } renderToolbarAfter(): TemplateResult { return html``; } renderSearch(): TemplateResult { return html``; } firstUpdated(): void { this.fetch(); } renderTable(): TemplateResult { return html`
${this.renderSearch()}
${this.renderToolbar()}
${this.renderToolbarAfter()} { this.page = page; this.fetch(); }}>
${this.checkbox ? html`` : html``} ${this.expandable ? html`` : html``} ${this.columns().map((col) => col.render(this))} ${(this.isLoading || !this.data) ? this.renderLoading() : this.renderRows()}
{ if ((ev.target as HTMLInputElement).checked) { this.selectedElements = this.data?.results || []; } else { this.selectedElements = []; } }} />
{ this.page = page; this.fetch(); }}>
`; } render(): TemplateResult { return this.renderTable(); } }