@bexis2/bexis2-core-ui 0.4.23 → 0.4.24
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.
- package/README.md +9 -0
- package/dist/components/Facets/Facets.svelte +13 -9
- package/dist/components/Table/TableContent.svelte +74 -141
- package/dist/components/Table/TableContent.svelte.d.ts +0 -1
- package/dist/components/Table/TablePagination.svelte +15 -7
- package/dist/components/Table/TablePagination.svelte.d.ts +2 -0
- package/dist/components/Table/TablePaginationServer.svelte +11 -9
- package/dist/components/Table/TablePaginationServer.svelte.d.ts +1 -0
- package/dist/components/Table/utils.d.ts +34 -0
- package/dist/components/Table/{shared.js → utils.js} +109 -0
- package/dist/models/Models.d.ts +2 -0
- package/package.json +1 -1
- package/src/lib/components/Facets/Facets.svelte +13 -9
- package/src/lib/components/Table/TableContent.svelte +81 -167
- package/src/lib/components/Table/TablePagination.svelte +17 -7
- package/src/lib/components/Table/TablePaginationServer.svelte +16 -9
- package/src/lib/components/Table/{shared.ts → utils.ts} +157 -1
- package/src/lib/models/Models.ts +2 -0
- package/dist/components/Table/shared.d.ts +0 -15
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import dateFormat from 'dateformat';
|
|
2
|
+
import { SvelteComponent } from 'svelte';
|
|
3
|
+
import { Send, Receive } from '../../models/Models';
|
|
2
4
|
// Function to determine minWidth for a column to simplify the logic in the HTML
|
|
3
5
|
export const minWidth = (id, columns) => {
|
|
4
6
|
if (columns && id in columns) {
|
|
@@ -125,6 +127,54 @@ export const missingValuesFn = (key, missingValues) => {
|
|
|
125
127
|
: undefined;
|
|
126
128
|
return foundKey ? missingValues[foundKey] : key;
|
|
127
129
|
};
|
|
130
|
+
// Function to update the server-side table data
|
|
131
|
+
export const updateTable = async (pageSize, pageIndex, server, filters, data, serverItems, columns, dispatch) => {
|
|
132
|
+
const { baseUrl, entityId, versionId, sendModel = new Send() } = server ?? {};
|
|
133
|
+
if (!sendModel)
|
|
134
|
+
throw new Error('Server-side configuration is missing');
|
|
135
|
+
sendModel.limit = pageSize;
|
|
136
|
+
sendModel.offset = pageSize * pageIndex;
|
|
137
|
+
sendModel.version = versionId || -1;
|
|
138
|
+
sendModel.id = entityId || -1;
|
|
139
|
+
sendModel.filter = normalizeFilters(filters);
|
|
140
|
+
let fetchData;
|
|
141
|
+
try {
|
|
142
|
+
fetchData = await fetch(baseUrl || '', {
|
|
143
|
+
headers: {
|
|
144
|
+
'Content-Type': 'application/json'
|
|
145
|
+
},
|
|
146
|
+
method: 'POST',
|
|
147
|
+
body: JSON.stringify(sendModel)
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
throw new Error(`Network error: ${error.message}`);
|
|
152
|
+
}
|
|
153
|
+
if (!fetchData.ok) {
|
|
154
|
+
throw new Error('Failed to fetch data');
|
|
155
|
+
}
|
|
156
|
+
const response = await fetchData.json();
|
|
157
|
+
// Format server columns to the client columns
|
|
158
|
+
if (response.columns !== undefined) {
|
|
159
|
+
columns = convertServerColumns(response.columns, columns);
|
|
160
|
+
const clientCols = response.columns.reduce((acc, col) => {
|
|
161
|
+
acc[col.key] = col.column;
|
|
162
|
+
return acc;
|
|
163
|
+
}, {});
|
|
164
|
+
const tmpArr = [];
|
|
165
|
+
response.data.forEach((row, index) => {
|
|
166
|
+
const tmp = {};
|
|
167
|
+
Object.keys(row).forEach((key) => {
|
|
168
|
+
tmp[clientCols[key]] = row[key];
|
|
169
|
+
});
|
|
170
|
+
tmpArr.push(tmp);
|
|
171
|
+
});
|
|
172
|
+
dispatch('fetch', columns);
|
|
173
|
+
data.set(tmpArr);
|
|
174
|
+
}
|
|
175
|
+
serverItems?.set(response.count);
|
|
176
|
+
return response;
|
|
177
|
+
};
|
|
128
178
|
export const convertServerColumns = (serverColumns, columns) => {
|
|
129
179
|
const columnsConfig = {};
|
|
130
180
|
serverColumns.forEach((col) => {
|
|
@@ -177,3 +227,62 @@ export const convertServerColumns = (serverColumns, columns) => {
|
|
|
177
227
|
});
|
|
178
228
|
return columnsConfig;
|
|
179
229
|
};
|
|
230
|
+
// Calculates the maximum height of the cells in each row
|
|
231
|
+
export const getMaxCellHeightInRow = (tableRef, resizable, optionsComponent, rowHeights, tableId, rowHeight) => {
|
|
232
|
+
if (!tableRef || resizable === 'columns' || resizable === 'none')
|
|
233
|
+
return;
|
|
234
|
+
tableRef.querySelectorAll('tbody tr').forEach((row, index) => {
|
|
235
|
+
const cells = row.querySelectorAll('td');
|
|
236
|
+
let maxHeight = optionsComponent ? 56 : 44;
|
|
237
|
+
let minHeight = optionsComponent ? 56 : 44;
|
|
238
|
+
cells.forEach((cell) => {
|
|
239
|
+
const cellHeight = cell.getBoundingClientRect().height;
|
|
240
|
+
// + 2 pixels for rendering borders correctly
|
|
241
|
+
if (cellHeight > maxHeight) {
|
|
242
|
+
maxHeight = cellHeight + 2;
|
|
243
|
+
}
|
|
244
|
+
if (cellHeight < minHeight) {
|
|
245
|
+
minHeight = cellHeight + 2;
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
rowHeights.update((rh) => {
|
|
249
|
+
const id = +row.id.split(`${tableId}-row-`)[1];
|
|
250
|
+
return {
|
|
251
|
+
...rh,
|
|
252
|
+
[id]: {
|
|
253
|
+
max: maxHeight - 24,
|
|
254
|
+
min: Math.max(minHeight - 24, rowHeight ?? 20)
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
};
|
|
260
|
+
// Calculates the minimum width of the cells in each column
|
|
261
|
+
export const getMinCellWidthInColumn = (tableRef, colWidths, headerRowsLength, resizable) => {
|
|
262
|
+
if (!tableRef || resizable === 'rows' || resizable === 'none')
|
|
263
|
+
return;
|
|
264
|
+
// Initialize the column widths if they are not already initialized
|
|
265
|
+
colWidths.update((cw) => {
|
|
266
|
+
if (cw.length === 0) {
|
|
267
|
+
return Array.from({ length: headerRowsLength }, () => 100);
|
|
268
|
+
}
|
|
269
|
+
return cw;
|
|
270
|
+
});
|
|
271
|
+
colWidths.update((cw) => {
|
|
272
|
+
tableRef?.querySelectorAll('thead tr th span').forEach((cell, index) => {
|
|
273
|
+
// + 12 pixels for padding and + 32 pixels for filter icon
|
|
274
|
+
// If the column width is 100, which means it has not been initialized, then calculate the width
|
|
275
|
+
cw[index] = cw[index] === 100 ? cell.getBoundingClientRect().width + 12 + 32 : cw[index];
|
|
276
|
+
});
|
|
277
|
+
return cw;
|
|
278
|
+
});
|
|
279
|
+
};
|
|
280
|
+
export const getResizeStyles = (rowHeights, id, index) => {
|
|
281
|
+
return `
|
|
282
|
+
min-height: ${rowHeights && rowHeights[+id] ? `${rowHeights[+id].min}px` : 'auto'};
|
|
283
|
+
max-height: ${index !== 0 && rowHeights && rowHeights[+id]
|
|
284
|
+
? `${rowHeights[+id].max}px`
|
|
285
|
+
: 'auto'};
|
|
286
|
+
height: ${rowHeights && rowHeights[+id] ? `${rowHeights[+id].min}px` : 'auto'};
|
|
287
|
+
`;
|
|
288
|
+
};
|
package/dist/models/Models.d.ts
CHANGED
|
@@ -90,6 +90,7 @@ export interface TableConfig<T> {
|
|
|
90
90
|
id: string;
|
|
91
91
|
data: Writable<T[]>;
|
|
92
92
|
resizable?: 'none' | 'rows' | 'columns' | 'both';
|
|
93
|
+
showColumnsMenu?: boolean;
|
|
93
94
|
toggle?: boolean;
|
|
94
95
|
search?: boolean;
|
|
95
96
|
fitToScreen?: boolean;
|
|
@@ -99,6 +100,7 @@ export interface TableConfig<T> {
|
|
|
99
100
|
exportable?: boolean;
|
|
100
101
|
pageSizes?: number[];
|
|
101
102
|
defaultPageSize?: number;
|
|
103
|
+
pageIndexStringType?: 'items' | 'pages';
|
|
102
104
|
optionsComponent?: typeof SvelteComponent;
|
|
103
105
|
server?: ServerConfig;
|
|
104
106
|
}
|
package/package.json
CHANGED
|
@@ -191,10 +191,14 @@
|
|
|
191
191
|
hyphenOpacity="opacity-0"
|
|
192
192
|
bind:checked={selectedGroups[group.name]}
|
|
193
193
|
bind:group={selectedGroups}
|
|
194
|
+
regionSymbol="shrink-0"
|
|
194
195
|
>
|
|
195
|
-
<
|
|
196
|
-
|
|
197
|
-
|
|
196
|
+
<div class="grid grid-flow-col gap-2">
|
|
197
|
+
<p class="font-semibold whitespace-nowrap truncate" title={group.displayName}>
|
|
198
|
+
{group.displayName}
|
|
199
|
+
</p>
|
|
200
|
+
<span>{group.count !== undefined ? ` (${group.count})` : ''}</span>
|
|
201
|
+
</div>
|
|
198
202
|
|
|
199
203
|
<svelte:fragment slot="children">
|
|
200
204
|
<!-- If more than 5 choices, show the remaining in the Modal -->
|
|
@@ -210,9 +214,9 @@
|
|
|
210
214
|
selection
|
|
211
215
|
multiple
|
|
212
216
|
>
|
|
213
|
-
<div class="
|
|
214
|
-
<p class="
|
|
215
|
-
<span title={item.displayName}>{item.displayName}</span>
|
|
217
|
+
<div class="grid grid-flow-col gap-2">
|
|
218
|
+
<p class="truncate">
|
|
219
|
+
<span class="" title={item.displayName}>{item.displayName}</span>
|
|
216
220
|
</p>
|
|
217
221
|
<span>({item.count})</span>
|
|
218
222
|
</div>
|
|
@@ -237,9 +241,9 @@
|
|
|
237
241
|
selection
|
|
238
242
|
multiple
|
|
239
243
|
>
|
|
240
|
-
<div class="
|
|
241
|
-
<p class="
|
|
242
|
-
<span title={item.displayName}>{item.displayName}</span>
|
|
244
|
+
<div class="grid grid-flow-col gap-2">
|
|
245
|
+
<p class="truncate">
|
|
246
|
+
<span class="" title={item.displayName}>{item.displayName}</span>
|
|
243
247
|
</p>
|
|
244
248
|
<span>({item.count})</span>
|
|
245
249
|
</div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { afterUpdate,
|
|
2
|
+
import { afterUpdate, createEventDispatcher, onDestroy } from 'svelte';
|
|
3
3
|
import { readable, writable } from 'svelte/store';
|
|
4
4
|
|
|
5
5
|
import Fa from 'svelte-fa';
|
|
@@ -26,18 +26,9 @@
|
|
|
26
26
|
import TablePagination from './TablePagination.svelte';
|
|
27
27
|
import TablePaginationServer from './TablePaginationServer.svelte';
|
|
28
28
|
import ColumnsMenu from './ColumnsMenu.svelte';
|
|
29
|
+
import * as utils from './utils';
|
|
29
30
|
import { columnFilter, searchFilter } from './filter';
|
|
30
|
-
import {
|
|
31
|
-
cellStyle,
|
|
32
|
-
exportAsCsv,
|
|
33
|
-
jsonToCsv,
|
|
34
|
-
fixedWidth,
|
|
35
|
-
normalizeFilters,
|
|
36
|
-
resetResize,
|
|
37
|
-
convertServerColumns,
|
|
38
|
-
minWidth
|
|
39
|
-
} from './shared';
|
|
40
|
-
import { Receive, Send } from '$models/Models';
|
|
31
|
+
import { Send } from '$models/Models';
|
|
41
32
|
import type { TableConfig } from '$models/Models';
|
|
42
33
|
import type { FilterOptionsEnum } from '$models/Enums';
|
|
43
34
|
|
|
@@ -48,6 +39,7 @@
|
|
|
48
39
|
id: tableId, // Unique table ID
|
|
49
40
|
data, // Data store
|
|
50
41
|
columns, // Column configuration
|
|
42
|
+
showColumnsMenu = false, // Whether to display the columns menu
|
|
51
43
|
resizable = 'none', // Resizability config
|
|
52
44
|
height = null, // Table height
|
|
53
45
|
rowHeight = null, // Row height
|
|
@@ -56,6 +48,7 @@
|
|
|
56
48
|
toggle = false, // Whether to display the fitToScreen toggle
|
|
57
49
|
search = true, // Whether to display the search input
|
|
58
50
|
pageSizes = [5, 10, 20, 50, 100], // Page sizes to display in the pagination component
|
|
51
|
+
pageIndexStringType = 'pages', // pages by default
|
|
59
52
|
fitToScreen = true, // Whether to fit the table to the screen,
|
|
60
53
|
exportable = false, // Whether to display the export button and enable export functionality
|
|
61
54
|
server
|
|
@@ -66,7 +59,7 @@
|
|
|
66
59
|
let tableRef: HTMLTableElement;
|
|
67
60
|
|
|
68
61
|
const serverSide = server !== undefined;
|
|
69
|
-
const {
|
|
62
|
+
const { sendModel = new Send() } = server ?? {};
|
|
70
63
|
|
|
71
64
|
const filters = writable<{
|
|
72
65
|
[key: string]: { [key in FilterOptionsEnum]?: number | string | Date };
|
|
@@ -84,7 +77,7 @@
|
|
|
84
77
|
const colWidths = writable<number[]>([]);
|
|
85
78
|
|
|
86
79
|
// Server-side variables
|
|
87
|
-
const serverItems = serverSide ? writable<
|
|
80
|
+
const serverItems = serverSide ? writable<number>(0) : undefined;
|
|
88
81
|
const serverItemCount = serverSide
|
|
89
82
|
? readable<Number>(0, (set) => {
|
|
90
83
|
serverItems!.subscribe((val) => set(val));
|
|
@@ -207,7 +200,7 @@
|
|
|
207
200
|
id,
|
|
208
201
|
tableId,
|
|
209
202
|
values,
|
|
210
|
-
updateTable,
|
|
203
|
+
updateTable: updateTableWithParams,
|
|
211
204
|
pageIndex,
|
|
212
205
|
toFilterableValueFn,
|
|
213
206
|
filters,
|
|
@@ -241,7 +234,7 @@
|
|
|
241
234
|
accessor: accessor,
|
|
242
235
|
cell: ({ value }) => {
|
|
243
236
|
// If null or undefined, return an empty string
|
|
244
|
-
return value
|
|
237
|
+
return value ?? '';
|
|
245
238
|
},
|
|
246
239
|
plugins: {
|
|
247
240
|
// Sorting enabled by default
|
|
@@ -255,7 +248,7 @@
|
|
|
255
248
|
id,
|
|
256
249
|
tableId,
|
|
257
250
|
values,
|
|
258
|
-
updateTable,
|
|
251
|
+
updateTable: updateTableWithParams,
|
|
259
252
|
pageIndex,
|
|
260
253
|
filters
|
|
261
254
|
})
|
|
@@ -299,7 +292,7 @@
|
|
|
299
292
|
// Creating the table columns
|
|
300
293
|
const createdTableColumns = table.createColumns(tableColumns);
|
|
301
294
|
// Creating the table view model
|
|
302
|
-
const { headerRows, pageRows, tableAttrs, tableBodyAttrs, pluginStates } =
|
|
295
|
+
const { headerRows, pageRows, tableAttrs, tableBodyAttrs, pluginStates, rows } =
|
|
303
296
|
table.createViewModel(createdTableColumns);
|
|
304
297
|
// Extracting filterValue to bind it for the search input and search immediately on input
|
|
305
298
|
const { filterValue } = pluginStates.tableFilter;
|
|
@@ -310,65 +303,6 @@
|
|
|
310
303
|
// Column visibility configuration
|
|
311
304
|
const { hiddenColumnIds } = pluginStates.hideColumns;
|
|
312
305
|
|
|
313
|
-
const updateTable = async () => {
|
|
314
|
-
if (!sendModel) throw new Error('Server-side configuration is missing');
|
|
315
|
-
|
|
316
|
-
sendModel.limit = $pageSize;
|
|
317
|
-
sendModel.offset = $pageSize * $pageIndex;
|
|
318
|
-
sendModel.version = versionId || -1;
|
|
319
|
-
sendModel.id = entityId || -1;
|
|
320
|
-
sendModel.filter = normalizeFilters($filters);
|
|
321
|
-
|
|
322
|
-
let fetchData;
|
|
323
|
-
|
|
324
|
-
try {
|
|
325
|
-
isFetching = true;
|
|
326
|
-
fetchData = await fetch(baseUrl || '', {
|
|
327
|
-
headers: {
|
|
328
|
-
'Content-Type': 'application/json'
|
|
329
|
-
},
|
|
330
|
-
method: 'POST',
|
|
331
|
-
body: JSON.stringify(sendModel)
|
|
332
|
-
});
|
|
333
|
-
} catch (error) {
|
|
334
|
-
throw new Error(`Network error: ${(error as Error).message}`);
|
|
335
|
-
} finally {
|
|
336
|
-
isFetching = false;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
if (!fetchData.ok) {
|
|
340
|
-
throw new Error('Failed to fetch data');
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
const response: Receive = await fetchData.json();
|
|
344
|
-
|
|
345
|
-
// Format server columns to the client columns
|
|
346
|
-
if (response.columns !== undefined) {
|
|
347
|
-
columns = convertServerColumns(response.columns, columns);
|
|
348
|
-
|
|
349
|
-
const clientCols = response.columns.reduce((acc, col) => {
|
|
350
|
-
acc[col.key] = col.column;
|
|
351
|
-
return acc;
|
|
352
|
-
}, {});
|
|
353
|
-
|
|
354
|
-
const tmpArr: any[] = [];
|
|
355
|
-
|
|
356
|
-
response.data.forEach((row, index) => {
|
|
357
|
-
const tmp: { [key: string]: any } = {};
|
|
358
|
-
Object.keys(row).forEach((key) => {
|
|
359
|
-
tmp[clientCols[key]] = row[key];
|
|
360
|
-
});
|
|
361
|
-
tmpArr.push(tmp);
|
|
362
|
-
});
|
|
363
|
-
dispatch('fetch', columns);
|
|
364
|
-
$data = tmpArr;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
$serverItems = response.count;
|
|
368
|
-
|
|
369
|
-
return response;
|
|
370
|
-
};
|
|
371
|
-
|
|
372
306
|
const sortServer = (order: 'asc' | 'desc' | undefined, id: string) => {
|
|
373
307
|
if (!sendModel) throw new Error('Server-side configuration is missing');
|
|
374
308
|
// Set parameter for sorting
|
|
@@ -381,83 +315,70 @@
|
|
|
381
315
|
// Reset pagination
|
|
382
316
|
$pageIndex = 0;
|
|
383
317
|
|
|
384
|
-
|
|
318
|
+
updateTableWithParams();
|
|
385
319
|
};
|
|
386
320
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
321
|
+
// Function to update the table with the provided parameters for easily passing to other components
|
|
322
|
+
const updateTableWithParams = async () => {
|
|
323
|
+
isFetching = true;
|
|
324
|
+
const result = await utils.updateTable(
|
|
325
|
+
$pageSize,
|
|
326
|
+
$pageIndex,
|
|
327
|
+
server,
|
|
328
|
+
$filters,
|
|
329
|
+
data,
|
|
330
|
+
serverItems,
|
|
331
|
+
columns,
|
|
332
|
+
dispatch
|
|
333
|
+
);
|
|
334
|
+
isFetching = false;
|
|
395
335
|
|
|
396
|
-
|
|
397
|
-
const cellHeight = cell.getBoundingClientRect().height;
|
|
398
|
-
// + 2 pixels for rendering borders correctly
|
|
399
|
-
if (cellHeight > maxHeight) {
|
|
400
|
-
maxHeight = cellHeight + 2;
|
|
401
|
-
}
|
|
402
|
-
if (cellHeight < minHeight) {
|
|
403
|
-
minHeight = cellHeight + 2;
|
|
404
|
-
}
|
|
405
|
-
});
|
|
406
|
-
|
|
407
|
-
rowHeights.update((rh) => {
|
|
408
|
-
const id = +row.id.split(`${tableId}-row-`)[1];
|
|
409
|
-
return {
|
|
410
|
-
...rh,
|
|
411
|
-
[id]: {
|
|
412
|
-
max: maxHeight - 24,
|
|
413
|
-
min: Math.max(minHeight - 24, rowHeight ?? 20)
|
|
414
|
-
}
|
|
415
|
-
};
|
|
416
|
-
});
|
|
417
|
-
});
|
|
336
|
+
return result;
|
|
418
337
|
};
|
|
419
338
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
if (
|
|
425
|
-
|
|
339
|
+
// Initializes observers for rows and columns
|
|
340
|
+
const getDimensions = () => {
|
|
341
|
+
if (!tableRef) return;
|
|
342
|
+
if (resizable === 'none') return;
|
|
343
|
+
else if (resizable === 'columns') {
|
|
344
|
+
observeHeaderColumns();
|
|
345
|
+
} else if (resizable === 'rows') {
|
|
346
|
+
observeFirstCells();
|
|
347
|
+
} else {
|
|
348
|
+
observeHeaderColumns();
|
|
349
|
+
observeFirstCells();
|
|
426
350
|
}
|
|
427
|
-
|
|
428
|
-
colWidths.update((cw) => {
|
|
429
|
-
tableRef?.querySelectorAll('thead tr th span').forEach((cell, index) => {
|
|
430
|
-
// + 12 pixels for padding and + 32 pixels for filter icon
|
|
431
|
-
// If the column width is 100, which means it has not been initialized, then calculate the width
|
|
432
|
-
cw[index] = cw[index] === 100 ? cell.getBoundingClientRect().width + 12 + 32 : cw[index];
|
|
433
|
-
});
|
|
434
|
-
return cw;
|
|
435
|
-
});
|
|
436
351
|
};
|
|
437
352
|
|
|
353
|
+
// Resize observer for rows
|
|
438
354
|
const resizeRowsObserver = new ResizeObserver(() => {
|
|
439
|
-
getMaxCellHeightInRow(
|
|
355
|
+
utils.getMaxCellHeightInRow(
|
|
356
|
+
tableRef,
|
|
357
|
+
resizable,
|
|
358
|
+
optionsComponent,
|
|
359
|
+
rowHeights,
|
|
360
|
+
tableId,
|
|
361
|
+
rowHeight
|
|
362
|
+
);
|
|
440
363
|
});
|
|
441
364
|
|
|
365
|
+
// Resize observers for columns
|
|
442
366
|
const resizeColumnsObserver = new ResizeObserver(() => {
|
|
443
|
-
getMinCellWidthInColumn();
|
|
367
|
+
utils.getMinCellWidthInColumn(tableRef, colWidths, $headerRows[0].cells.length, resizable);
|
|
444
368
|
});
|
|
445
369
|
|
|
370
|
+
// Adds observers on the first cells of each row to resize rows
|
|
446
371
|
const observeFirstCells = () => {
|
|
447
372
|
if (!tableRef) return;
|
|
448
373
|
|
|
449
|
-
$pageRows.forEach((row) => {
|
|
450
|
-
const cell = tableRef.querySelector(`#${tableId}-row-${row.id}`);
|
|
451
|
-
if (cell) {
|
|
452
|
-
resizeRowsObserver.observe(cell);
|
|
453
|
-
}
|
|
454
|
-
});
|
|
455
|
-
|
|
456
374
|
tableRef.querySelectorAll('tbody tr td:first-child').forEach((cell) => {
|
|
457
375
|
resizeRowsObserver.observe(cell);
|
|
458
376
|
});
|
|
377
|
+
|
|
378
|
+
return resizeRowsObserver;
|
|
459
379
|
};
|
|
460
380
|
|
|
381
|
+
// Adds observers on the header columns to resize columns
|
|
461
382
|
const observeHeaderColumns = () => {
|
|
462
383
|
if (!tableRef) return;
|
|
463
384
|
|
|
@@ -467,6 +388,7 @@
|
|
|
467
388
|
};
|
|
468
389
|
|
|
469
390
|
afterUpdate(() => {
|
|
391
|
+
// If not resizable, return
|
|
470
392
|
if (resizable !== 'rows' && resizable !== 'both') {
|
|
471
393
|
return;
|
|
472
394
|
}
|
|
@@ -478,27 +400,13 @@
|
|
|
478
400
|
}
|
|
479
401
|
});
|
|
480
402
|
|
|
481
|
-
// Remove the resize observer when the component is destroyed for performance reasons
|
|
482
403
|
onDestroy(() => {
|
|
483
|
-
resizeRowsObserver.disconnect();
|
|
484
404
|
resizeColumnsObserver.disconnect();
|
|
405
|
+
resizeRowsObserver.disconnect();
|
|
485
406
|
});
|
|
486
407
|
|
|
487
|
-
const getDimensions = () => {
|
|
488
|
-
if (!tableRef) return;
|
|
489
|
-
if (resizable === 'none') return;
|
|
490
|
-
else if (resizable === 'columns') {
|
|
491
|
-
observeHeaderColumns();
|
|
492
|
-
} else if (resizable === 'rows') {
|
|
493
|
-
observeFirstCells();
|
|
494
|
-
} else {
|
|
495
|
-
observeHeaderColumns();
|
|
496
|
-
observeFirstCells();
|
|
497
|
-
}
|
|
498
|
-
};
|
|
499
|
-
|
|
500
408
|
$: sortKeys = pluginStates.sort.sortKeys;
|
|
501
|
-
$: serverSide &&
|
|
409
|
+
$: serverSide && updateTableWithParams();
|
|
502
410
|
$: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
|
|
503
411
|
$: $hiddenColumnIds = shownColumns.filter((col) => !col.visible).map((col) => col.id);
|
|
504
412
|
</script>
|
|
@@ -598,20 +506,23 @@
|
|
|
598
506
|
class="btn btn-sm variant-filled-primary rounded-full order-last flex gap-2 items-center"
|
|
599
507
|
aria-label="Reset sizing of columns and rows"
|
|
600
508
|
on:click|preventDefault={() =>
|
|
601
|
-
resetResize($headerRows, $pageRows, tableId, columns, resizable)}
|
|
509
|
+
utils.resetResize($headerRows, $pageRows, tableId, columns, resizable)}
|
|
602
510
|
><Fa icon={faCompress} /> Reset sizing</button
|
|
603
511
|
>
|
|
604
512
|
{/if}
|
|
513
|
+
<!-- Enable export as CSV button if exportable === true -->
|
|
605
514
|
{#if exportable}
|
|
606
515
|
<button
|
|
607
516
|
type="button"
|
|
608
517
|
class="btn btn-sm variant-filled-primary rounded-full order-last flex items-center gap-2"
|
|
609
518
|
aria-label="Export table data as CSV"
|
|
610
|
-
on:click|preventDefault={() =>
|
|
519
|
+
on:click|preventDefault={() =>
|
|
520
|
+
utils.exportAsCsv(tableId, utils.jsonToCsv($exportedData))}
|
|
611
521
|
><Fa icon={faDownload} /> Export as CSV</button
|
|
612
522
|
>
|
|
613
523
|
{/if}
|
|
614
|
-
|
|
524
|
+
<!-- Enable show/hide columns menu if showColumnsMenu === true -->
|
|
525
|
+
{#if showColumnsMenu && shownColumns.length > 0}
|
|
615
526
|
<ColumnsMenu bind:columns={shownColumns} {tableId} />
|
|
616
527
|
{/if}
|
|
617
528
|
</div>
|
|
@@ -644,16 +555,20 @@
|
|
|
644
555
|
{...attrs}
|
|
645
556
|
style={`
|
|
646
557
|
width: ${cell.isData() ? 'auto' : '0'};
|
|
647
|
-
${cellStyle(cell.id, columns)}
|
|
558
|
+
${utils.cellStyle(cell.id, columns)}
|
|
648
559
|
`}
|
|
649
560
|
>
|
|
650
561
|
<div
|
|
651
562
|
class="overflow-auto"
|
|
652
563
|
class:resize-x={(resizable === 'columns' || resizable === 'both') &&
|
|
653
|
-
!fixedWidth(cell.id, columns)}
|
|
564
|
+
!utils.fixedWidth(cell.id, columns)}
|
|
654
565
|
id="th-{tableId}-{cell.id}"
|
|
655
566
|
style={`
|
|
656
|
-
min-width: ${
|
|
567
|
+
min-width: ${
|
|
568
|
+
utils.minWidth(cell.id, columns)
|
|
569
|
+
? utils.minWidth(cell.id, columns)
|
|
570
|
+
: $colWidths[index]
|
|
571
|
+
}px;
|
|
657
572
|
`}
|
|
658
573
|
>
|
|
659
574
|
<div class="flex justify-between items-center">
|
|
@@ -712,15 +627,7 @@
|
|
|
712
627
|
? 'resize-y overflow-auto'
|
|
713
628
|
: 'block'}"
|
|
714
629
|
id="{tableId}-{cell.id}-{row.id}"
|
|
715
|
-
style={
|
|
716
|
-
min-height: ${$rowHeights && $rowHeights[+row.id] ? `${$rowHeights[+row.id].min}px` : 'auto'};
|
|
717
|
-
max-height: ${
|
|
718
|
-
index !== 0 && $rowHeights && $rowHeights[+row.id]
|
|
719
|
-
? `${$rowHeights[+row.id].max}px`
|
|
720
|
-
: 'auto'
|
|
721
|
-
};
|
|
722
|
-
height: ${$rowHeights && $rowHeights[+row.id] ? `${$rowHeights[+row.id].min}px` : 'auto'};
|
|
723
|
-
`}
|
|
630
|
+
style={utils.getResizeStyles($rowHeights, row.id, index)}
|
|
724
631
|
>
|
|
725
632
|
<!-- Adding config for initial rowHeight, if provided -->
|
|
726
633
|
<div
|
|
@@ -733,8 +640,8 @@
|
|
|
733
640
|
class="grow overflow-auto"
|
|
734
641
|
style={cell.isData()
|
|
735
642
|
? `width: ${
|
|
736
|
-
minWidth(cell.id, columns)
|
|
737
|
-
? minWidth(cell.id, columns)
|
|
643
|
+
utils.minWidth(cell.id, columns)
|
|
644
|
+
? utils.minWidth(cell.id, columns)
|
|
738
645
|
: $colWidths[index]
|
|
739
646
|
}px;`
|
|
740
647
|
: 'max-width: min-content;'}
|
|
@@ -777,12 +684,19 @@
|
|
|
777
684
|
{pageIndex}
|
|
778
685
|
{pageSize}
|
|
779
686
|
{serverItemCount}
|
|
780
|
-
{
|
|
687
|
+
updateTable={updateTableWithParams}
|
|
781
688
|
{pageSizes}
|
|
689
|
+
{pageIndexStringType}
|
|
782
690
|
id={tableId}
|
|
783
691
|
/>
|
|
784
692
|
{:else}
|
|
785
|
-
<TablePagination
|
|
693
|
+
<TablePagination
|
|
694
|
+
itemCount={$rows.length}
|
|
695
|
+
pageConfig={pluginStates.page}
|
|
696
|
+
{pageSizes}
|
|
697
|
+
id={tableId}
|
|
698
|
+
{pageIndexStringType}
|
|
699
|
+
/>
|
|
786
700
|
{/if}
|
|
787
701
|
{/if}
|
|
788
702
|
</div>
|
|
@@ -9,10 +9,14 @@
|
|
|
9
9
|
} from '@fortawesome/free-solid-svg-icons';
|
|
10
10
|
import { ListBox, ListBoxItem, popup, type PopupSettings } from '@skeletonlabs/skeleton';
|
|
11
11
|
|
|
12
|
+
export let itemCount;
|
|
12
13
|
export let pageConfig;
|
|
13
14
|
export let pageSizes;
|
|
15
|
+
export let pageIndexStringType;
|
|
14
16
|
export let id;
|
|
15
17
|
|
|
18
|
+
let indexInformation = '';
|
|
19
|
+
|
|
16
20
|
const { pageIndex, pageCount, pageSize, hasNextPage, hasPreviousPage } = pageConfig;
|
|
17
21
|
|
|
18
22
|
const goToFirstPage = () => ($pageIndex = 0);
|
|
@@ -42,11 +46,23 @@
|
|
|
42
46
|
closeQuery: '.listbox-item'
|
|
43
47
|
};
|
|
44
48
|
|
|
49
|
+
const getIndexInfomationString = () => {
|
|
50
|
+
if (pageIndexStringType === 'pages') {
|
|
51
|
+
return $pageCount > 0 ? `Page ${$pageIndex + 1} of ${$pageCount}` : 'No pages';
|
|
52
|
+
} else {
|
|
53
|
+
return itemCount === 0 ? 'No items' : `Displaying items ${$pageIndex * $pageSize + 1} - ${Math.min(
|
|
54
|
+
($pageIndex + 1) * $pageSize,
|
|
55
|
+
itemCount
|
|
56
|
+
)} of ${Math.min($pageCount * $pageSize, itemCount)}`;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
45
60
|
$: goToFirstPageDisabled = !$pageIndex;
|
|
46
61
|
$: goToLastPageDisabled = $pageIndex == $pageCount - 1;
|
|
47
62
|
$: goToNextPageDisabled = !$hasNextPage;
|
|
48
63
|
$: goToPreviousPageDisabled = !$hasPreviousPage;
|
|
49
64
|
$: $pageSize = pageSizeDropdownValue;
|
|
65
|
+
$: $pageCount, $pageIndex, $pageSize, (indexInformation = getIndexInfomationString());
|
|
50
66
|
</script>
|
|
51
67
|
|
|
52
68
|
<div class="flex justify-between w-full items-stretch gap-10">
|
|
@@ -124,12 +140,6 @@
|
|
|
124
140
|
>
|
|
125
141
|
</div>
|
|
126
142
|
<div class="flex justify-end items-center">
|
|
127
|
-
<span class="text-sm text-gray-500">
|
|
128
|
-
{#if $pageCount > 0}
|
|
129
|
-
Page {$pageIndex + 1} of {$pageCount}
|
|
130
|
-
{:else}
|
|
131
|
-
No pages
|
|
132
|
-
{/if}
|
|
133
|
-
</span>
|
|
143
|
+
<span class="text-sm text-gray-500">{indexInformation}</span>
|
|
134
144
|
</div>
|
|
135
145
|
</div>
|