/** * Ported from legacy henza_admin/src/components/x-table/model/{XTbl,Xtc}.js * and src/table/index.js (ColCreator). * * The fluent column API is preserved exactly — `new Xtc(key, title).filterText() * .renderSlot('x').noSort()` builds the same shape the legacy table schemas used, * so the 18 schema files port over with only their import path changed. * * Legacy had FOUR near-duplicate XTable forks (x-table/, x-table_select/, * custom-xtable-select/, backup-table/, ~1,300 LOC). Per the agreed decision this * port keeps ONE — the x-table/ variant, which is the most complete (it is the * only one with QuerySelectTableFilter). */ export type FilterType = 'default' | 'switch' | 'query' | 'date' | 'number' | 'select'; export interface ColumnSlots { customRender?: string; filterDropdown?: string; filterIcon?: string; } /** Port of legacy Xtc — one column definition. */ export class Xtc { key: string; title: string; dataIndex: string; show = true; /** legacy `__sorter`: sortable unless noSort() was called */ __sorter = true; filtered = false; filterType?: FilterType; filterAction?: string; /** legacy `filterItems`: a value -> label map for select filters */ filterItems?: Record; scopedSlots?: ColumnSlots; /** legacy filterKey()/master — filter against a different field than dataIndex */ __fkey?: string; width?: string | number; constructor(key: string, title: string) { this.key = key; this.title = title; this.dataIndex = key; } private __filter() { this.filtered = true; if (!this.scopedSlots) this.scopedSlots = {}; this.scopedSlots.filterDropdown = `${this.key}_filterDropdown`; this.scopedSlots.filterIcon = `${this.key}_filterIcon`; } /** legacy filterKey(key) */ filterKey(key: string) { this.__fkey = key; return this; } /** legacy renderSlot(name) — render this cell through a named slot */ renderSlot(name: string) { if (!this.scopedSlots) this.scopedSlots = {}; this.scopedSlots.customRender = name; return this; } filterText() { this.__filter(); this.filterType = 'default'; return this; } filterSwitch() { this.__filter(); this.filterType = 'switch'; return this; } filterQuery(action: string) { this.__filter(); this.filterType = 'query'; this.filterAction = action; return this; } filterDate() { this.__filter(); this.filterType = 'date'; return this; } filterNumber() { this.__filter(); this.filterType = 'number'; return this; } /** * legacy filterSelect(items) — `items` is an OBJECT MAP of value -> label, * e.g. { 0: 'معلق', 1: 'ثبت سفارش' }, stored on `filterItems`. The shape is * kept exactly so the ported table models pass their maps unchanged. * * Legacy also permitted calling it with no argument at all (TaminListModel does * this), which left filterItems undefined and rendered an empty dropdown. * Preserved: the parameter is optional here too. */ filterSelect(items?: Record) { this.__filter(); this.filterType = 'select'; this.filterItems = items; return this; } /** legacy noSort() */ noSort() { this.__sorter = false; return this; } /** legacy hidden() — column exists but starts unchecked in the column picker */ hidden() { this.show = false; return this; } setWidth(w: string | number) { this.width = w; return this; } } export interface DefaultFilter { field: string; op: string; value: unknown; } /** Port of legacy XTbl — a table definition: endpoint + title + columns. */ export class XTbl { url: string; title: string; cols: Xtc[] = []; defaultFilters?: DefaultFilter[]; _hidePagination = false; _hideSearch = false; _noFilters = false; constructor(url: string, title: string) { this.url = url; this.title = title; } add(col: Xtc) { this.cols.push(col); return this; } addDefaultFilter(filter: DefaultFilter) { if (!this.defaultFilters) this.defaultFilters = []; this.defaultFilters.push(filter); return this; } hidePagination() { this._hidePagination = true; return this; } /** * NOTE: legacy's hideSearch() set `_hidePageination` (sic) instead of a search * flag — a copy-paste bug, so calling it hid PAGINATION, not the search box. * Fixed here to set the intended flag; no ported schema calls it, so nothing * changes in behaviour. Recorded in docs/ADMIN-PORT-PLAN.md. */ hideSearch() { this._hideSearch = true; return this; } /** legacy noFilters(): hides the filter bar entirely (walletTbl uses this). */ noFilters() { this._noFilters = true; return this; } getSortFields() { return this.cols.filter((c) => c.__sorter); } } export default XTbl;