@bexis2/bexis2-core-ui 0.4.96 → 0.4.97

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/README.md +99 -25
  2. package/dist/components/CodeEditor/CodeEditor.svelte +2 -2
  3. package/dist/components/Facets/ShowMore.svelte +4 -6
  4. package/dist/components/File/FileUploader.svelte +6 -3
  5. package/dist/components/Table/Table.svelte +26 -5
  6. package/dist/components/Table/TableContent.svelte +226 -27
  7. package/dist/components/Table/TablePaginationServer.svelte +27 -8
  8. package/dist/components/Table/clientDB.d.ts +22 -0
  9. package/dist/components/Table/clientDB.js +236 -0
  10. package/dist/components/Table/filter.js +5 -1
  11. package/dist/components/Table/tableWorker.d.ts +1 -0
  12. package/dist/components/Table/tableWorker.js +179 -0
  13. package/dist/components/Table/utils.d.ts +1 -2
  14. package/dist/components/Table/utils.js +45 -26
  15. package/dist/components/form/CheckboxKvPList.svelte +15 -15
  16. package/dist/components/form/CheckboxList.svelte +1 -1
  17. package/dist/components/form/DateInput.svelte +12 -1
  18. package/dist/components/form/DatePickerInput.svelte +51 -29
  19. package/dist/components/form/Dropdown.svelte +14 -3
  20. package/dist/components/form/DropdownKvP.svelte +13 -2
  21. package/dist/components/form/InputContainer.svelte +17 -15
  22. package/dist/components/form/MultiSelect.svelte +30 -29
  23. package/dist/components/form/NumberInput.svelte +12 -1
  24. package/dist/components/form/TextArea.svelte +12 -1
  25. package/dist/components/form/TextInput.svelte +12 -1
  26. package/dist/components/page/Alert.svelte +5 -1
  27. package/dist/components/page/BackToTop.svelte +3 -1
  28. package/dist/components/page/Docs.svelte +9 -2
  29. package/dist/components/page/GoToTop.svelte +14 -15
  30. package/dist/components/page/Page.svelte +50 -56
  31. package/dist/components/page/breadcrumb/BreadcrumbDataCaller.js +11 -15
  32. package/dist/components/page/menu/MenuAccountBar.svelte +1 -5
  33. package/dist/components/page/menu/MenuDataCaller.js +1 -1
  34. package/dist/components/page/menu/MenuItem.svelte +9 -7
  35. package/dist/components/page/menu/MenuSublist.svelte +7 -5
  36. package/dist/components/page/menu/SettingsBar.svelte +4 -1
  37. package/dist/components/toggle/Toggle.svelte +9 -9
  38. package/dist/css/core.ui.postcss +1 -2
  39. package/dist/services/Api.js +4 -4
  40. package/dist/services/BaseCaller.js +1 -1
  41. package/package.json +114 -114
  42. package/src/lib/components/CodeEditor/CodeEditor.svelte +4 -4
  43. package/src/lib/components/Facets/Facets.svelte +2 -2
  44. package/src/lib/components/Facets/ShowMore.svelte +4 -6
  45. package/src/lib/components/File/FileUploader.svelte +17 -14
  46. package/src/lib/components/Table/Table.svelte +31 -10
  47. package/src/lib/components/Table/TableContent.svelte +261 -38
  48. package/src/lib/components/Table/TableFilter.svelte +7 -2
  49. package/src/lib/components/Table/TablePagination.svelte +6 -2
  50. package/src/lib/components/Table/TablePaginationServer.svelte +36 -10
  51. package/src/lib/components/Table/clientDB.js +236 -0
  52. package/src/lib/components/Table/filter.ts +27 -23
  53. package/src/lib/components/Table/tableWorker.js +179 -0
  54. package/src/lib/components/Table/utils.ts +75 -56
  55. package/src/lib/components/form/Checkbox.svelte +1 -1
  56. package/src/lib/components/form/CheckboxKvPList.svelte +15 -16
  57. package/src/lib/components/form/CheckboxList.svelte +1 -1
  58. package/src/lib/components/form/DateInput.svelte +13 -2
  59. package/src/lib/components/form/DatePickerInput.svelte +51 -29
  60. package/src/lib/components/form/Dropdown.svelte +14 -3
  61. package/src/lib/components/form/DropdownKvP.svelte +13 -2
  62. package/src/lib/components/form/InputContainer.svelte +18 -17
  63. package/src/lib/components/form/MultiSelect.svelte +30 -29
  64. package/src/lib/components/form/NumberInput.svelte +21 -12
  65. package/src/lib/components/form/TextArea.svelte +13 -2
  66. package/src/lib/components/form/TextInput.svelte +13 -2
  67. package/src/lib/components/page/Alert.svelte +5 -1
  68. package/src/lib/components/page/BackToTop.svelte +3 -1
  69. package/src/lib/components/page/Docs.svelte +9 -2
  70. package/src/lib/components/page/GoToTop.svelte +14 -15
  71. package/src/lib/components/page/Notification.svelte +1 -1
  72. package/src/lib/components/page/Page.svelte +67 -78
  73. package/src/lib/components/page/breadcrumb/Breadcrumb.svelte +2 -3
  74. package/src/lib/components/page/breadcrumb/BreadcrumbDataCaller.js +11 -15
  75. package/src/lib/components/page/menu/MenuAccountBar.svelte +1 -6
  76. package/src/lib/components/page/menu/MenuDataCaller.js +1 -1
  77. package/src/lib/components/page/menu/MenuItem.svelte +10 -8
  78. package/src/lib/components/page/menu/MenuSublist.svelte +35 -41
  79. package/src/lib/components/page/menu/SettingsBar.svelte +5 -2
  80. package/src/lib/components/toggle/Toggle.svelte +28 -30
  81. package/src/lib/css/core.ui.postcss +1 -2
  82. package/src/lib/index.ts +1 -2
  83. package/src/lib/services/Api.ts +21 -20
  84. package/src/lib/services/BaseCaller.js +1 -1
  85. package/src/lib/stores/apiStores.ts +1 -5
  86. package/src/lib/stores/pageStores.ts +0 -2
@@ -0,0 +1,236 @@
1
+ // Simple client-side DB wrapper using IndexedDB directly (no worker)
2
+ const DB_PREFIX = 'table-db-';
3
+
4
+ function openDB(name) {
5
+ return new Promise((resolve, reject) => {
6
+ const req = indexedDB.open(DB_PREFIX + name, 1);
7
+ req.onupgradeneeded = () => {
8
+ const db = req.result;
9
+ if (!db.objectStoreNames.contains('rows')) {
10
+ db.createObjectStore('rows', { keyPath: '__id', autoIncrement: true });
11
+ }
12
+ };
13
+ req.onsuccess = () => resolve(req.result);
14
+ req.onerror = () => reject(req.error);
15
+ });
16
+ }
17
+
18
+ function clearStore(db) {
19
+ return new Promise((resolve, reject) => {
20
+ const tx = db.transaction('rows', 'readwrite');
21
+ const store = tx.objectStore('rows');
22
+ const req = store.clear();
23
+ req.onsuccess = () => resolve(undefined);
24
+ req.onerror = () => reject(req.error);
25
+ });
26
+ }
27
+
28
+ function bulkInsert(db, rows) {
29
+ return new Promise((resolve, reject) => {
30
+ const tx = db.transaction('rows', 'readwrite');
31
+ const store = tx.objectStore('rows');
32
+ for (let i = 0; i < rows.length; i++) {
33
+ store.add({ __r: rows[i] });
34
+ }
35
+ tx.oncomplete = () => resolve(undefined);
36
+ tx.onerror = () => reject(tx.error);
37
+ });
38
+ }
39
+
40
+ function matches(rowObj, q, filters) {
41
+ const row = rowObj.__r || rowObj;
42
+
43
+ if (q && q.length > 0) {
44
+ const ql = String(q).toLowerCase();
45
+ let found = false;
46
+ for (const k in row) {
47
+ const v = row[k];
48
+ if (v == null) continue;
49
+ if (typeof v === 'string' && v.toLowerCase().includes(ql)) {
50
+ found = true;
51
+ break;
52
+ }
53
+ if (typeof v === 'number' && String(v).includes(ql)) {
54
+ found = true;
55
+ break;
56
+ }
57
+ }
58
+ if (!found) return false;
59
+ }
60
+
61
+ const normalizeKey = (k) => String(k || '').replaceAll('%%%', '.');
62
+ const getValue = (column) => {
63
+ const dot = normalizeKey(column);
64
+ return row[dot] ?? row[column] ?? row[dot.replaceAll('.', '%%%')];
65
+ };
66
+
67
+ const asComparableNumber = (v) => {
68
+ if (typeof v === 'number') return v;
69
+ if (typeof v === 'bigint') return Number(v);
70
+ const n = Number(v);
71
+ return Number.isNaN(n) ? null : n;
72
+ };
73
+
74
+ const asTime = (v) => {
75
+ if (v instanceof Date) return v.getTime();
76
+ const d = new Date(v);
77
+ const t = d.getTime();
78
+ return Number.isNaN(t) ? null : t;
79
+ };
80
+
81
+ if (filters && filters.length > 0) {
82
+ for (const f of filters) {
83
+ const op = f.filterBy;
84
+ const val = f.value;
85
+ const actual = getValue(f.column);
86
+ if (val == null) continue;
87
+
88
+ const aStr = String(actual ?? '').toLowerCase();
89
+ const vStr = String(val ?? '').toLowerCase();
90
+ const aNum = asComparableNumber(actual);
91
+ const vNum = asComparableNumber(val);
92
+ const aDate = asTime(actual);
93
+ const vDate = asTime(val);
94
+
95
+ if (op === 'c' && !aStr.includes(vStr)) return false;
96
+ if (op === 'nc' && aStr.includes(vStr)) return false;
97
+ if (op === 'sw' && !aStr.startsWith(vStr)) return false;
98
+ if (op === 'ew' && !aStr.endsWith(vStr)) return false;
99
+
100
+ if (op === 'e' && actual != val) return false;
101
+ if (op === 'ne' && actual == val) return false;
102
+
103
+ if (op === 'gt') {
104
+ if (aNum == null || vNum == null || !(aNum > vNum)) return false;
105
+ }
106
+ if (op === 'lt') {
107
+ if (aNum == null || vNum == null || !(aNum < vNum)) return false;
108
+ }
109
+ if (op === 'gte') {
110
+ if (aNum == null || vNum == null || !(aNum >= vNum)) return false;
111
+ }
112
+ if (op === 'lte') {
113
+ if (aNum == null || vNum == null || !(aNum <= vNum)) return false;
114
+ }
115
+
116
+ if (op === 'o') {
117
+ if (aDate == null || vDate == null || aDate !== vDate) return false;
118
+ }
119
+ if (op === 'sf' || op === 'a') {
120
+ if (aDate == null || vDate == null || !(aDate > vDate || aDate === vDate)) return false;
121
+ }
122
+ if (op === 'u' || op === 'b') {
123
+ if (aDate == null || vDate == null || !(aDate < vDate || aDate === vDate)) return false;
124
+ }
125
+ if (op === 'no') {
126
+ if (aDate == null || vDate == null || aDate === vDate) return false;
127
+ }
128
+ }
129
+ }
130
+
131
+ return true;
132
+ }
133
+
134
+ export default class ClientDB {
135
+ constructor(tableId) {
136
+ this.tableId = tableId;
137
+ this.db = null;
138
+ }
139
+
140
+ async init(rows) {
141
+ this.db = this.db || (await openDB(this.tableId));
142
+ await clearStore(this.db);
143
+
144
+ const CHUNK = 1000;
145
+ for (let i = 0; i < rows.length; i += CHUNK) {
146
+ const chunk = rows.slice(i, i + CHUNK);
147
+ await bulkInsert(this.db, chunk);
148
+ // Yield to keep the UI responsive while importing
149
+ await new Promise((r) => setTimeout(r, 0));
150
+ }
151
+
152
+ return { tableId: this.tableId, count: rows.length };
153
+ }
154
+
155
+ async query({ q = '', filters = [], order = [], offset = 0, limit = 100 } = {}) {
156
+ this.db = this.db || (await openDB(this.tableId));
157
+
158
+ const tx = this.db.transaction('rows', 'readonly');
159
+ const store = tx.objectStore('rows');
160
+ const req = store.openCursor();
161
+
162
+ const matched = [];
163
+
164
+ await new Promise((resolve, reject) => {
165
+ req.onsuccess = (evt) => {
166
+ const cursor = evt.target.result;
167
+ if (!cursor) {
168
+ resolve(undefined);
169
+ return;
170
+ }
171
+
172
+ const rec = cursor.value;
173
+ if (matches(rec, q, filters)) {
174
+ matched.push(rec.__r || rec);
175
+ }
176
+
177
+ cursor.continue();
178
+ };
179
+ req.onerror = () => reject(req.error);
180
+ });
181
+
182
+ const getValue = (row, column) => {
183
+ const dot = String(column || '').replaceAll('%%%', '.');
184
+ return row[dot] ?? row[column] ?? row[dot.replaceAll('.', '%%%')];
185
+ };
186
+
187
+ if (order && order.length > 0) {
188
+ const { column, direction } = order[0];
189
+ const dir = direction === 'desc' ? -1 : 1;
190
+ matched.sort((a, b) => {
191
+ const av = getValue(a, column);
192
+ const bv = getValue(b, column);
193
+
194
+ if (av == null && bv == null) return 0;
195
+ if (av == null) return -1 * dir;
196
+ if (bv == null) return 1 * dir;
197
+
198
+ if (typeof av === 'number' && typeof bv === 'number') {
199
+ return (av - bv) * dir;
200
+ }
201
+
202
+ if (typeof av === 'bigint' || typeof bv === 'bigint') {
203
+ const ai = BigInt(av);
204
+ const bi = BigInt(bv);
205
+ if (ai === bi) return 0;
206
+ return ai > bi ? dir : -dir;
207
+ }
208
+
209
+ const ad = new Date(av).getTime();
210
+ const bd = new Date(bv).getTime();
211
+ if (!Number.isNaN(ad) && !Number.isNaN(bd)) {
212
+ return (ad - bd) * dir;
213
+ }
214
+
215
+ return String(av).localeCompare(String(bv)) * dir;
216
+ });
217
+ }
218
+
219
+ const total = matched.length;
220
+ const rows = matched.slice(offset, offset + limit);
221
+
222
+ return { tableId: this.tableId, rows, total };
223
+ }
224
+
225
+ async clear() {
226
+ this.db = this.db || (await openDB(this.tableId));
227
+ await clearStore(this.db);
228
+ }
229
+
230
+ destroy() {
231
+ if (this.db) {
232
+ this.db.close();
233
+ this.db = null;
234
+ }
235
+ }
236
+ }
@@ -67,7 +67,11 @@ const applyFilter = (filterValue, value, filterFn) => {
67
67
  value: filterValue[key]
68
68
  }));
69
69
  filters.forEach((filter) => {
70
- result = result && (filter.value !== undefined && filter.value !== '' && filter.value !== null ? filterFn(filter.option, filter.value, value) : true);
70
+ result =
71
+ result &&
72
+ (filter.value !== undefined && filter.value !== '' && filter.value !== null
73
+ ? filterFn(filter.option, filter.value, value)
74
+ : true);
71
75
  });
72
76
  return result;
73
77
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,179 @@
1
+ // @ts-nocheck
2
+ // Lightweight web worker that stores rows in IndexedDB and answers simple queries
3
+ const DB_PREFIX = 'table-db-';
4
+
5
+ function openDB(name) {
6
+ return new Promise((resolve, reject) => {
7
+ const req = indexedDB.open(DB_PREFIX + name, 1);
8
+ req.onupgradeneeded = () => {
9
+ const db = req.result;
10
+ if (!db.objectStoreNames.contains('rows')) {
11
+ db.createObjectStore('rows', { keyPath: '__id', autoIncrement: true });
12
+ }
13
+ };
14
+ req.onsuccess = () => resolve(req.result);
15
+ req.onerror = () => reject(req.error);
16
+ });
17
+ }
18
+
19
+ async function clearStore(db) {
20
+ return new Promise((res, rej) => {
21
+ const tx = db.transaction('rows', 'readwrite');
22
+ const store = tx.objectStore('rows');
23
+ const r = store.clear();
24
+ r.onsuccess = () => res(undefined);
25
+ r.onerror = () => rej(r.error);
26
+ });
27
+ }
28
+
29
+ async function bulkInsert(db, rows) {
30
+ return new Promise((res, rej) => {
31
+ const tx = db.transaction('rows', 'readwrite');
32
+ const store = tx.objectStore('rows');
33
+ for (let i = 0; i < rows.length; i++) {
34
+ // wrap row to avoid clashes with internal __id
35
+ const toPut = { __r: rows[i] };
36
+ store.add(toPut);
37
+ }
38
+ tx.oncomplete = () => res(undefined);
39
+ tx.onerror = () => rej(tx.error);
40
+ });
41
+ }
42
+
43
+ function matches(rowObj, q, filters) {
44
+ const row = rowObj.__r || rowObj;
45
+ // full text query
46
+ if (q && q.length > 0) {
47
+ const ql = String(q).toLowerCase();
48
+ let found = false;
49
+ for (const k in row) {
50
+ const v = row[k];
51
+ if (v == null) continue;
52
+ if (typeof v === 'string' && v.toLowerCase().includes(ql)) {
53
+ found = true;
54
+ break;
55
+ }
56
+ if (typeof v === 'number' && String(v).includes(ql)) {
57
+ found = true;
58
+ break;
59
+ }
60
+ }
61
+ if (!found) return false;
62
+ }
63
+
64
+ // simple equality filters: filters is array of {column, filterBy, value}
65
+ if (filters && filters.length > 0) {
66
+ for (const f of filters) {
67
+ const col = (f.column || '').replaceAll('%%%', '.');
68
+ const val = f.value;
69
+ const actual = row[col] ?? row[f.column] ?? row[col.replaceAll('.', '%%%')];
70
+ if (val == null) continue;
71
+ if (typeof actual === 'string') {
72
+ if (!String(actual).toLowerCase().includes(String(val).toLowerCase())) return false;
73
+ } else if (typeof actual === 'number') {
74
+ if (Number(val) !== actual) return false;
75
+ } else {
76
+ if (actual !== val) return false;
77
+ }
78
+ }
79
+ }
80
+
81
+ return true;
82
+ }
83
+
84
+ // handle messages
85
+ let dbs = {};
86
+ let initCounts = {};
87
+ self.addEventListener('message', async (e) => {
88
+ const { type, payload } = e.data;
89
+ try {
90
+ if (type === 'init-start') {
91
+ const { tableId } = payload;
92
+ const db = await openDB(tableId);
93
+ await clearStore(db);
94
+ dbs[tableId] = db;
95
+ initCounts[tableId] = 0;
96
+ postMessage({ type: 'init-ack', payload: { tableId } });
97
+ return;
98
+ }
99
+
100
+ if (type === 'init-chunk') {
101
+ const { tableId, rows } = payload;
102
+ const db = dbs[tableId] || (await openDB(tableId));
103
+ await bulkInsert(db, rows);
104
+ initCounts[tableId] = (initCounts[tableId] || 0) + rows.length;
105
+ postMessage({ type: 'init-progress', payload: { tableId, inserted: initCounts[tableId] } });
106
+ return;
107
+ }
108
+
109
+ if (type === 'init-done') {
110
+ const { tableId } = payload;
111
+ const total = initCounts[tableId] || 0;
112
+ postMessage({ type: 'inited', payload: { tableId, count: total } });
113
+ delete initCounts[tableId];
114
+ return;
115
+ }
116
+
117
+ if (type === 'init') {
118
+ const { tableId, rows } = payload;
119
+ const db = await openDB(tableId);
120
+ await clearStore(db);
121
+ // insert in chunks to avoid blocking
122
+ const CHUNK = 1000;
123
+ for (let i = 0; i < rows.length; i += CHUNK) {
124
+ const chunk = rows.slice(i, i + CHUNK);
125
+ await bulkInsert(db, chunk);
126
+ }
127
+ dbs[tableId] = db;
128
+ postMessage({ type: 'inited', payload: { tableId, count: rows.length } });
129
+ }
130
+
131
+ if (type === 'query') {
132
+ const { tableId, q, filters = [], offset = 0, limit = 100 } = payload;
133
+ const db = dbs[tableId] || (await openDB(tableId));
134
+ dbs[tableId] = db;
135
+
136
+ const tx = db.transaction('rows', 'readonly');
137
+ const store = tx.objectStore('rows');
138
+ const req = store.openCursor();
139
+
140
+ const results = [];
141
+ let total = 0;
142
+ let skipped = 0;
143
+
144
+ await new Promise((res, rej) => {
145
+ req.onsuccess = (evt) => {
146
+ const cursor = evt.target.result;
147
+ if (!cursor) {
148
+ res();
149
+ return;
150
+ }
151
+ const rec = cursor.value;
152
+ if (matches(rec, q, filters)) {
153
+ total++;
154
+ if (skipped < offset) {
155
+ skipped++;
156
+ } else if (results.length < limit) {
157
+ results.push(rec.__r || rec);
158
+ }
159
+ }
160
+ cursor.continue();
161
+ };
162
+ req.onerror = () => rej(req.error);
163
+ });
164
+
165
+ postMessage({ type: 'result', payload: { tableId, rows: results, total } });
166
+ }
167
+
168
+ if (type === 'clear') {
169
+ const { tableId } = payload;
170
+ const db = dbs[tableId] || (await openDB(tableId));
171
+ await clearStore(db);
172
+ postMessage({ type: 'cleared', payload: { tableId } });
173
+ }
174
+ } catch (err) {
175
+ postMessage({ type: 'error', payload: { message: err?.message ?? String(err) } });
176
+ }
177
+ });
178
+
179
+ export {};
@@ -1,6 +1,5 @@
1
1
  import { SvelteComponent } from 'svelte';
2
2
  import type { Writable } from 'svelte/store';
3
- import { Receive } from '../../models/Models';
4
3
  import type { FilterOptionsEnum } from '../../models/Enums';
5
4
  import type { Columns, Filter, OrderBy, ServerColumn, ServerConfig } from '../../models/Models';
6
5
  export declare const minWidth: (id: string, columns: Columns | undefined) => number;
@@ -23,7 +22,7 @@ export declare const missingValuesFn: (key: number | string, missingValues: {
23
22
  }) => string | number;
24
23
  export declare const updateTable: (pageSize: number, pageIndex: number, server: ServerConfig | undefined, filters: {
25
24
  [key: string]: { [key in FilterOptionsEnum]?: number | string | Date; };
26
- }, data: Writable<any[]>, serverItems: Writable<number> | undefined, columns: Columns | undefined, dispatch: any, order?: OrderBy[]) => Promise<Receive | Writable<any[]>>;
25
+ }, data: Writable<any[]>, serverItems: Writable<number> | undefined, columns: Columns | undefined, dispatch: any, order?: OrderBy[]) => Promise<Writable<any[]>>;
27
26
  export declare const convertServerColumns: (serverColumns: ServerColumn[], columns: Columns | undefined) => Columns;
28
27
  export declare const getMaxCellHeightInRow: (tableRef: HTMLTableElement, resizable: "columns" | "rows" | "none" | "both", optionsComponent: typeof SvelteComponent | undefined, rowHeights: Writable<{
29
28
  [key: number]: {
@@ -31,9 +31,7 @@ export const cellStyle = (id, columns) => {
31
31
  export const getResizeStyles = (rowHeights, id, index) => {
32
32
  return `
33
33
  min-height: ${rowHeights && rowHeights[+id] ? `${rowHeights[+id].min}px` : 'auto'};
34
- max-height: ${index !== 0 && rowHeights && rowHeights[+id]
35
- ? `${rowHeights[+id].max}px`
36
- : 'auto'};
34
+ max-height: ${index !== 0 && rowHeights && rowHeights[+id] ? `${rowHeights[+id].max}px` : 'auto'};
37
35
  height: ${rowHeights && rowHeights[+id] ? `${rowHeights[+id].min}px` : 'auto'};
38
36
  `;
39
37
  };
@@ -86,7 +84,7 @@ export const jsonToCsv = (data) => {
86
84
  // Create CSV rows
87
85
  const rows = [
88
86
  headers.join(','), // Header row
89
- ...json.map((row) => headers.map(header => escapeCsvCell(row[header])).join(',')) // Data rows
87
+ ...json.map((row) => headers.map((header) => escapeCsvCell(row[header])).join(',')) // Data rows
90
88
  ];
91
89
  // Join rows with newlines
92
90
  return rows.join('\n');
@@ -154,7 +152,7 @@ export const updateTable = async (pageSize, pageIndex, server, filters, data, se
154
152
  // remove %%% from the columns object
155
153
  if (sendModel.order) {
156
154
  sendModel.order.forEach((order) => {
157
- if (order.column.includes("%%%")) {
155
+ if (order.column.includes('%%%')) {
158
156
  const newKey = order.column.replaceAll('%%%', '.');
159
157
  order.column = newKey;
160
158
  }
@@ -190,6 +188,19 @@ export const updateTable = async (pageSize, pageIndex, server, filters, data, se
190
188
  }
191
189
  return value;
192
190
  });
191
+ const rawCount = response.count;
192
+ const hasRawCount = rawCount !== undefined && rawCount !== null && String(rawCount).trim().length > 0;
193
+ const parsedServerCount = hasRawCount
194
+ ? typeof rawCount === 'number'
195
+ ? rawCount
196
+ : Number(String(rawCount).replace(/[^0-9.-]/g, ''))
197
+ : Number.NaN;
198
+ const hasServerCount = hasRawCount && Number.isFinite(parsedServerCount) && parsedServerCount >= 0;
199
+ const normalizedCount = hasServerCount
200
+ ? parsedServerCount
201
+ : Array.isArray(response.data)
202
+ ? response.data.length
203
+ : 0;
193
204
  // console.log('Server response', response);
194
205
  // Format server columns to the client columns
195
206
  if (response.columns !== undefined) {
@@ -201,8 +212,8 @@ export const updateTable = async (pageSize, pageIndex, server, filters, data, se
201
212
  //const key = col.key.replaceAll('.' ,'');
202
213
  ///console.log(key, col.column);
203
214
  // set the key to the columns object
204
- col.column = col.column.replaceAll('.', "%%%");
205
- col.key = col.key.replaceAll('.', "%%%");
215
+ col.column = col.column.replaceAll('.', '%%%');
216
+ col.key = col.key.replaceAll('.', '%%%');
206
217
  acc[col.key] = col.column;
207
218
  //acc[col.column] = col.column;
208
219
  return acc;
@@ -212,20 +223,23 @@ export const updateTable = async (pageSize, pageIndex, server, filters, data, se
212
223
  response.data.forEach((row, index) => {
213
224
  const tmp = {};
214
225
  Object.keys(row).forEach((key) => {
215
- tmp[clientCols[key.replaceAll('.', "%%%")]] = row[key];
226
+ tmp[clientCols[key.replaceAll('.', '%%%')]] = row[key];
216
227
  });
217
228
  tmpArr.push(tmp);
218
229
  });
219
- dispatch('fetch', columns);
230
+ dispatch('fetch', {
231
+ columns,
232
+ count: hasServerCount ? parsedServerCount : tmpArr.length
233
+ });
234
+ serverItems?.set(hasServerCount ? parsedServerCount : tmpArr.length);
220
235
  data.set(tmpArr);
221
236
  // console.log('Server data', tmpArr);
222
237
  return data;
223
238
  }
224
- serverItems?.set(response.count);
225
- // console.log('Server data updated');
226
- // log the columns object
227
- console.log(response);
228
- return response;
239
+ serverItems?.set(normalizedCount);
240
+ // If backend does not provide column metadata, still render returned rows.
241
+ data.set(response.data ?? []);
242
+ return data;
229
243
  };
230
244
  // Function to convert server data to client data
231
245
  export const convertServerColumns = (serverColumns, columns) => {
@@ -267,13 +281,13 @@ export const convertServerColumns = (serverColumns, columns) => {
267
281
  };
268
282
  }
269
283
  if (columns && col.column in columns) {
270
- columnsConfig[col.column.replaceAll('.', "%%%")] = {
271
- ...columns[col.column.replaceAll('.', "%%%")],
284
+ columnsConfig[col.column.replaceAll('.', '%%%')] = {
285
+ ...columns[col.column.replaceAll('.', '%%%')],
272
286
  instructions
273
287
  };
274
288
  }
275
289
  else {
276
- columnsConfig[col.column.replaceAll('.', "%%%")] = {
290
+ columnsConfig[col.column.replaceAll('.', '%%%')] = {
277
291
  instructions
278
292
  };
279
293
  }
@@ -285,6 +299,7 @@ export const convertServerColumns = (serverColumns, columns) => {
285
299
  export const getMaxCellHeightInRow = (tableRef, resizable, optionsComponent, rowHeights, tableId, rowHeight) => {
286
300
  if (!tableRef || resizable === 'columns' || resizable === 'none')
287
301
  return;
302
+ const measuredHeights = {};
288
303
  tableRef.querySelectorAll('tbody tr').forEach((row, index) => {
289
304
  const cells = row.querySelectorAll('td');
290
305
  let maxHeight = optionsComponent ? 56 : 44;
@@ -299,17 +314,21 @@ export const getMaxCellHeightInRow = (tableRef, resizable, optionsComponent, row
299
314
  minHeight = cellHeight + 2;
300
315
  }
301
316
  });
302
- rowHeights.update((rh) => {
303
- const id = +row.id.split(`${tableId}-row-`)[1];
304
- return {
305
- ...rh,
306
- [id]: {
307
- max: maxHeight - 24,
308
- min: Math.max(minHeight - 24, rowHeight ?? 20)
309
- }
317
+ const id = +row.id.split(`${tableId}-row-`)[1];
318
+ if (Number.isFinite(id)) {
319
+ measuredHeights[id] = {
320
+ max: maxHeight - 24,
321
+ min: Math.max(minHeight - 24, rowHeight ?? 20)
310
322
  };
311
- });
323
+ }
312
324
  });
325
+ if (Object.keys(measuredHeights).length === 0) {
326
+ return;
327
+ }
328
+ rowHeights.update((rh) => ({
329
+ ...rh,
330
+ ...measuredHeights
331
+ }));
313
332
  };
314
333
  // Calculates the minimum width of the cells in each column
315
334
  export const getMinCellWidthInColumn = (tableRef, colWidths, headerRowsLength, resizable) => {
@@ -12,19 +12,19 @@ export let feedback;
12
12
  </script>
13
13
 
14
14
  <InputContainer {id} label={title} {feedback} {required} {help} {description}>
15
- <div class="flex gap-2" class:flex-col={vertical} >
16
- {#each source as item}
17
- <label class="flex items-center space-x-2" for={item.key}>
18
- <input
19
- class="checkbox"
20
- type="checkbox"
21
- bind:group={target}
22
- checked={item.key}
23
- value={item.key}
24
- id={item.key}
25
- />
26
- <p>{item.value}</p>
27
- </label>
28
- {/each}
29
- </div>
15
+ <div class="flex gap-2" class:flex-col={vertical}>
16
+ {#each source as item}
17
+ <label class="flex items-center space-x-2" for={item.key}>
18
+ <input
19
+ class="checkbox"
20
+ type="checkbox"
21
+ bind:group={target}
22
+ checked={item.key}
23
+ value={item.key}
24
+ id={item.key}
25
+ />
26
+ <p>{item.value}</p>
27
+ </label>
28
+ {/each}
29
+ </div>
30
30
  </InputContainer>
@@ -11,7 +11,7 @@ export let feedback;
11
11
  <InputContainer label={title} {feedback} {required} {description}>
12
12
  {#each source as item}
13
13
  <label class="flex items-center space-x-2" for={item}>
14
- <input class="checkbox" type="checkbox" bind:group={target} value={item} id={item}/>
14
+ <input class="checkbox" type="checkbox" bind:group={target} value={item} id={item} />
15
15
  <p>{item}</p>
16
16
  </label>
17
17
  {/each}
@@ -13,7 +13,18 @@ export let showDescription = false;
13
13
  export let showIcon = false;
14
14
  </script>
15
15
 
16
- <InputContainer {id} {label} {feedback} {required} {help} {description} {showDescription} {showIcon} on:showDescription on:hideDescription>
16
+ <InputContainer
17
+ {id}
18
+ {label}
19
+ {feedback}
20
+ {required}
21
+ {help}
22
+ {description}
23
+ {showDescription}
24
+ {showIcon}
25
+ on:showDescription
26
+ on:hideDescription
27
+ >
17
28
  <input
18
29
  {id}
19
30
  class="input variant-form-material bg-zinc-50 dark:bg-zinc-700 placeholder:text-gray-400"