@bexis2/bexis2-core-ui 0.4.22 → 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 +16 -0
- package/dist/components/Facets/Facets.svelte +13 -9
- package/dist/components/Table/ColumnsMenu.svelte +35 -9
- package/dist/components/Table/TableContent.svelte +146 -87
- 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} +134 -0
- package/dist/components/form/MultiSelect.svelte +1 -1
- 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/ColumnsMenu.svelte +36 -8
- package/src/lib/components/Table/TableContent.svelte +166 -97
- package/src/lib/components/Table/TablePagination.svelte +17 -7
- package/src/lib/components/Table/TablePaginationServer.svelte +16 -9
- package/src/lib/components/Table/utils.ts +373 -0
- package/src/lib/components/form/MultiSelect.svelte +1 -1
- package/src/lib/models/Models.ts +2 -0
- package/dist/components/Table/shared.d.ts +0 -14
- package/src/lib/components/Table/shared.ts +0 -186
package/README.md
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
# bexis-core-ui
|
|
2
|
+
## 0.4.24
|
|
3
|
+
- Table
|
|
4
|
+
- Adds option for enabling/disabling show/hide column menu in table.
|
|
5
|
+
- Adds option to show number of items displayed instead of number of pages.
|
|
6
|
+
- Fixes an issue where "0" values return empty string.
|
|
7
|
+
|
|
8
|
+
- Facets
|
|
9
|
+
- Fixes an issue with truncation of text in Facet headers and options.
|
|
10
|
+
|
|
11
|
+
## 0.4.23
|
|
12
|
+
- Table
|
|
13
|
+
- fix resizing issues after page size or page index changes
|
|
14
|
+
- Add Select All and Deselect All in columns menu
|
|
15
|
+
- Convert JSON to CSV and export as CSV
|
|
16
|
+
- Export as JSON to fix special characters and encoding issues
|
|
17
|
+
|
|
2
18
|
## 0.4.22
|
|
3
19
|
- Facets
|
|
4
20
|
- Replace column class function with more efficient solution
|
|
@@ -147,10 +147,14 @@ $: selectedGroups, mapSelected("groups");
|
|
|
147
147
|
hyphenOpacity="opacity-0"
|
|
148
148
|
bind:checked={selectedGroups[group.name]}
|
|
149
149
|
bind:group={selectedGroups}
|
|
150
|
+
regionSymbol="shrink-0"
|
|
150
151
|
>
|
|
151
|
-
<
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
<div class="grid grid-flow-col gap-2">
|
|
153
|
+
<p class="font-semibold whitespace-nowrap truncate" title={group.displayName}>
|
|
154
|
+
{group.displayName}
|
|
155
|
+
</p>
|
|
156
|
+
<span>{group.count !== undefined ? ` (${group.count})` : ''}</span>
|
|
157
|
+
</div>
|
|
154
158
|
|
|
155
159
|
<svelte:fragment slot="children">
|
|
156
160
|
<!-- If more than 5 choices, show the remaining in the Modal -->
|
|
@@ -166,9 +170,9 @@ $: selectedGroups, mapSelected("groups");
|
|
|
166
170
|
selection
|
|
167
171
|
multiple
|
|
168
172
|
>
|
|
169
|
-
<div class="
|
|
170
|
-
<p class="
|
|
171
|
-
<span title={item.displayName}>{item.displayName}</span>
|
|
173
|
+
<div class="grid grid-flow-col gap-2">
|
|
174
|
+
<p class="truncate">
|
|
175
|
+
<span class="" title={item.displayName}>{item.displayName}</span>
|
|
172
176
|
</p>
|
|
173
177
|
<span>({item.count})</span>
|
|
174
178
|
</div>
|
|
@@ -193,9 +197,9 @@ $: selectedGroups, mapSelected("groups");
|
|
|
193
197
|
selection
|
|
194
198
|
multiple
|
|
195
199
|
>
|
|
196
|
-
<div class="
|
|
197
|
-
<p class="
|
|
198
|
-
<span title={item.displayName}>{item.displayName}</span>
|
|
200
|
+
<div class="grid grid-flow-col gap-2">
|
|
201
|
+
<p class="truncate">
|
|
202
|
+
<span class="" title={item.displayName}>{item.displayName}</span>
|
|
199
203
|
</p>
|
|
200
204
|
<span>({item.count})</span>
|
|
201
205
|
</div>
|
|
@@ -1,32 +1,58 @@
|
|
|
1
|
-
<script>import
|
|
1
|
+
<script>import Fa from "svelte-fa";
|
|
2
|
+
import { faEye } from "@fortawesome/free-solid-svg-icons";
|
|
3
|
+
import { popup } from "@skeletonlabs/skeleton";
|
|
2
4
|
export let columns = [];
|
|
3
5
|
export let tableId;
|
|
4
6
|
const popupCombobox = {
|
|
5
7
|
event: "click",
|
|
6
8
|
target: `${tableId}-columns-menu`,
|
|
7
|
-
placement: "bottom"
|
|
9
|
+
placement: "bottom",
|
|
10
|
+
closeQuery: ""
|
|
11
|
+
};
|
|
12
|
+
const selectAll = () => {
|
|
13
|
+
columns = columns.map((column) => ({ ...column, visible: true }));
|
|
14
|
+
};
|
|
15
|
+
const deselectAll = () => {
|
|
16
|
+
columns = columns.map((column) => ({ ...column, visible: false }));
|
|
17
|
+
columns[0].visible = true;
|
|
8
18
|
};
|
|
9
19
|
</script>
|
|
10
20
|
|
|
11
21
|
<button
|
|
12
22
|
type="button"
|
|
13
|
-
|
|
14
|
-
class="btn btn-sm variant-filled-primary rounded-full order-last"
|
|
23
|
+
class="btn btn-sm variant-filled-primary rounded-full order-last gap-2"
|
|
15
24
|
aria-label="Open menu to hide/show columns"
|
|
16
|
-
use:popup={popupCombobox}
|
|
25
|
+
use:popup={popupCombobox}><Fa icon={faEye} /> Columns</button
|
|
17
26
|
>
|
|
18
|
-
|
|
19
27
|
<div
|
|
20
|
-
class="bg-white dark:bg-surface-500 p-4 rounded-md shadow-md z-10"
|
|
28
|
+
class="bg-white dark:bg-surface-500 p-4 px-5 rounded-md shadow-md z-10 border border-primary-500"
|
|
21
29
|
data-popup="{tableId}-columns-menu"
|
|
22
30
|
>
|
|
31
|
+
<div class="flex items-center gap-4 pb-5 grow justify-between">
|
|
32
|
+
<button
|
|
33
|
+
on:click|preventDefault={selectAll}
|
|
34
|
+
type="button"
|
|
35
|
+
class="btn p-0 text-sm grow underline text-primary-600"
|
|
36
|
+
>
|
|
37
|
+
Select All
|
|
38
|
+
</button>
|
|
39
|
+
<div class="border border-r border-neutral-200 h-6" />
|
|
40
|
+
<button
|
|
41
|
+
on:click|preventDefault={deselectAll}
|
|
42
|
+
type="button"
|
|
43
|
+
class="btn p-0 text-sm grow underline text-neutral-500"
|
|
44
|
+
>
|
|
45
|
+
Deselect All
|
|
46
|
+
</button>
|
|
47
|
+
</div>
|
|
23
48
|
{#each columns as column}
|
|
24
49
|
<div class="flex gap-3 items-center">
|
|
25
50
|
<label for={column.id} class="cursor-pointer" title={column.label}></label>
|
|
26
51
|
<input
|
|
27
52
|
aria-label={`${column.visible ? 'Hide' : 'Show'} ${column.label} column`}
|
|
28
53
|
type="checkbox"
|
|
29
|
-
|
|
54
|
+
class="checkbox"
|
|
55
|
+
id={column.id}
|
|
30
56
|
bind:checked={column.visible}
|
|
31
57
|
title={`${column.visible ? 'Hide' : 'Show'} ${column.label} column`}
|
|
32
58
|
disabled={columns.filter((c) => c.visible).length === 1 && column.visible}
|
|
@@ -35,5 +61,5 @@ const popupCombobox = {
|
|
|
35
61
|
</div>
|
|
36
62
|
{/each}
|
|
37
63
|
|
|
38
|
-
<div class="arrow bg-white dark:bg-surface-500" />
|
|
64
|
+
<div class="arrow bg-white dark:bg-surface-500 border-l border-t border-primary-500" />
|
|
39
65
|
</div>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
<script>import { createEventDispatcher } from "svelte";
|
|
1
|
+
<script>import { afterUpdate, createEventDispatcher, onDestroy } from "svelte";
|
|
2
2
|
import { readable, writable } from "svelte/store";
|
|
3
3
|
import Fa from "svelte-fa";
|
|
4
|
-
import { faXmark } from "@fortawesome/free-solid-svg-icons";
|
|
4
|
+
import { faCompress, faDownload, faXmark } from "@fortawesome/free-solid-svg-icons";
|
|
5
5
|
import { createTable, Subscribe, Render, createRender } from "svelte-headless-table";
|
|
6
6
|
import {
|
|
7
7
|
addSortBy,
|
|
@@ -21,16 +21,9 @@ import TableFilterServer from "./TableFilterServer.svelte";
|
|
|
21
21
|
import TablePagination from "./TablePagination.svelte";
|
|
22
22
|
import TablePaginationServer from "./TablePaginationServer.svelte";
|
|
23
23
|
import ColumnsMenu from "./ColumnsMenu.svelte";
|
|
24
|
+
import * as utils from "./utils";
|
|
24
25
|
import { columnFilter, searchFilter } from "./filter";
|
|
25
|
-
import {
|
|
26
|
-
cellStyle,
|
|
27
|
-
exportAsCsv,
|
|
28
|
-
fixedWidth,
|
|
29
|
-
normalizeFilters,
|
|
30
|
-
resetResize,
|
|
31
|
-
convertServerColumns
|
|
32
|
-
} from "./shared";
|
|
33
|
-
import { Receive, Send } from "../../models/Models";
|
|
26
|
+
import { Send } from "../../models/Models";
|
|
34
27
|
export let config;
|
|
35
28
|
let {
|
|
36
29
|
id: tableId,
|
|
@@ -39,6 +32,8 @@ let {
|
|
|
39
32
|
// Data store
|
|
40
33
|
columns,
|
|
41
34
|
// Column configuration
|
|
35
|
+
showColumnsMenu = false,
|
|
36
|
+
// Whether to display the columns menu
|
|
42
37
|
resizable = "none",
|
|
43
38
|
// Resizability config
|
|
44
39
|
height = null,
|
|
@@ -55,6 +50,8 @@ let {
|
|
|
55
50
|
// Whether to display the search input
|
|
56
51
|
pageSizes = [5, 10, 20, 50, 100],
|
|
57
52
|
// Page sizes to display in the pagination component
|
|
53
|
+
pageIndexStringType = "pages",
|
|
54
|
+
// pages by default
|
|
58
55
|
fitToScreen = true,
|
|
59
56
|
// Whether to fit the table to the screen,
|
|
60
57
|
exportable = false,
|
|
@@ -63,11 +60,14 @@ let {
|
|
|
63
60
|
} = config;
|
|
64
61
|
let searchValue = "";
|
|
65
62
|
let isFetching = false;
|
|
63
|
+
let tableRef;
|
|
66
64
|
const serverSide = server !== void 0;
|
|
67
|
-
const {
|
|
65
|
+
const { sendModel = new Send() } = server ?? {};
|
|
68
66
|
const filters = writable({});
|
|
69
67
|
const dispatch = createEventDispatcher();
|
|
70
68
|
const actionDispatcher = (obj) => dispatch("action", obj);
|
|
69
|
+
const rowHeights = writable({});
|
|
70
|
+
const colWidths = writable([]);
|
|
71
71
|
const serverItems = serverSide ? writable(0) : void 0;
|
|
72
72
|
const serverItemCount = serverSide ? readable(0, (set) => {
|
|
73
73
|
serverItems.subscribe((val) => set(val));
|
|
@@ -89,7 +89,7 @@ const table = createTable(data, {
|
|
|
89
89
|
serverItemCount
|
|
90
90
|
}),
|
|
91
91
|
expand: addExpandedRows(),
|
|
92
|
-
export: addDataExport({ format: "
|
|
92
|
+
export: addDataExport({ format: "json" })
|
|
93
93
|
});
|
|
94
94
|
const allCols = {};
|
|
95
95
|
$data.forEach((item) => {
|
|
@@ -165,7 +165,7 @@ const tableColumns = [
|
|
|
165
165
|
id,
|
|
166
166
|
tableId,
|
|
167
167
|
values,
|
|
168
|
-
updateTable,
|
|
168
|
+
updateTable: updateTableWithParams,
|
|
169
169
|
pageIndex,
|
|
170
170
|
toFilterableValueFn,
|
|
171
171
|
filters,
|
|
@@ -195,7 +195,7 @@ const tableColumns = [
|
|
|
195
195
|
header: key,
|
|
196
196
|
accessor,
|
|
197
197
|
cell: ({ value }) => {
|
|
198
|
-
return value
|
|
198
|
+
return value ?? "";
|
|
199
199
|
},
|
|
200
200
|
plugins: {
|
|
201
201
|
// Sorting enabled by default
|
|
@@ -208,7 +208,7 @@ const tableColumns = [
|
|
|
208
208
|
id,
|
|
209
209
|
tableId,
|
|
210
210
|
values,
|
|
211
|
-
updateTable,
|
|
211
|
+
updateTable: updateTableWithParams,
|
|
212
212
|
pageIndex,
|
|
213
213
|
filters
|
|
214
214
|
}) : createRender(TableFilter, {
|
|
@@ -246,57 +246,11 @@ if (optionsComponent !== void 0) {
|
|
|
246
246
|
);
|
|
247
247
|
}
|
|
248
248
|
const createdTableColumns = table.createColumns(tableColumns);
|
|
249
|
-
const { headerRows, pageRows, tableAttrs, tableBodyAttrs, pluginStates } = table.createViewModel(createdTableColumns);
|
|
249
|
+
const { headerRows, pageRows, tableAttrs, tableBodyAttrs, pluginStates, rows } = table.createViewModel(createdTableColumns);
|
|
250
250
|
const { filterValue } = pluginStates.tableFilter;
|
|
251
251
|
const { exportedData } = pluginStates.export;
|
|
252
252
|
const { pageIndex, pageSize } = pluginStates.page;
|
|
253
253
|
const { hiddenColumnIds } = pluginStates.hideColumns;
|
|
254
|
-
const updateTable = async () => {
|
|
255
|
-
if (!sendModel) throw new Error("Server-side configuration is missing");
|
|
256
|
-
sendModel.limit = $pageSize;
|
|
257
|
-
sendModel.offset = $pageSize * $pageIndex;
|
|
258
|
-
sendModel.version = versionId || -1;
|
|
259
|
-
sendModel.id = entityId || -1;
|
|
260
|
-
sendModel.filter = normalizeFilters($filters);
|
|
261
|
-
let fetchData;
|
|
262
|
-
try {
|
|
263
|
-
isFetching = true;
|
|
264
|
-
fetchData = await fetch(baseUrl || "", {
|
|
265
|
-
headers: {
|
|
266
|
-
"Content-Type": "application/json"
|
|
267
|
-
},
|
|
268
|
-
method: "POST",
|
|
269
|
-
body: JSON.stringify(sendModel)
|
|
270
|
-
});
|
|
271
|
-
} catch (error) {
|
|
272
|
-
throw new Error(`Network error: ${error.message}`);
|
|
273
|
-
} finally {
|
|
274
|
-
isFetching = false;
|
|
275
|
-
}
|
|
276
|
-
if (!fetchData.ok) {
|
|
277
|
-
throw new Error("Failed to fetch data");
|
|
278
|
-
}
|
|
279
|
-
const response = await fetchData.json();
|
|
280
|
-
if (response.columns !== void 0) {
|
|
281
|
-
columns = convertServerColumns(response.columns, columns);
|
|
282
|
-
const clientCols = response.columns.reduce((acc, col) => {
|
|
283
|
-
acc[col.key] = col.column;
|
|
284
|
-
return acc;
|
|
285
|
-
}, {});
|
|
286
|
-
const tmpArr = [];
|
|
287
|
-
response.data.forEach((row, index) => {
|
|
288
|
-
const tmp = {};
|
|
289
|
-
Object.keys(row).forEach((key) => {
|
|
290
|
-
tmp[clientCols[key]] = row[key];
|
|
291
|
-
});
|
|
292
|
-
tmpArr.push(tmp);
|
|
293
|
-
});
|
|
294
|
-
dispatch("fetch", columns);
|
|
295
|
-
$data = tmpArr;
|
|
296
|
-
}
|
|
297
|
-
$serverItems = response.count;
|
|
298
|
-
return response;
|
|
299
|
-
};
|
|
300
254
|
const sortServer = (order, id) => {
|
|
301
255
|
if (!sendModel) throw new Error("Server-side configuration is missing");
|
|
302
256
|
if (order === void 0) {
|
|
@@ -305,10 +259,76 @@ const sortServer = (order, id) => {
|
|
|
305
259
|
sendModel.order = [{ column: id, direction: order }];
|
|
306
260
|
}
|
|
307
261
|
$pageIndex = 0;
|
|
308
|
-
|
|
262
|
+
updateTableWithParams();
|
|
309
263
|
};
|
|
264
|
+
const updateTableWithParams = async () => {
|
|
265
|
+
isFetching = true;
|
|
266
|
+
const result = await utils.updateTable(
|
|
267
|
+
$pageSize,
|
|
268
|
+
$pageIndex,
|
|
269
|
+
server,
|
|
270
|
+
$filters,
|
|
271
|
+
data,
|
|
272
|
+
serverItems,
|
|
273
|
+
columns,
|
|
274
|
+
dispatch
|
|
275
|
+
);
|
|
276
|
+
isFetching = false;
|
|
277
|
+
return result;
|
|
278
|
+
};
|
|
279
|
+
const getDimensions = () => {
|
|
280
|
+
if (!tableRef) return;
|
|
281
|
+
if (resizable === "none") return;
|
|
282
|
+
else if (resizable === "columns") {
|
|
283
|
+
observeHeaderColumns();
|
|
284
|
+
} else if (resizable === "rows") {
|
|
285
|
+
observeFirstCells();
|
|
286
|
+
} else {
|
|
287
|
+
observeHeaderColumns();
|
|
288
|
+
observeFirstCells();
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
const resizeRowsObserver = new ResizeObserver(() => {
|
|
292
|
+
utils.getMaxCellHeightInRow(
|
|
293
|
+
tableRef,
|
|
294
|
+
resizable,
|
|
295
|
+
optionsComponent,
|
|
296
|
+
rowHeights,
|
|
297
|
+
tableId,
|
|
298
|
+
rowHeight
|
|
299
|
+
);
|
|
300
|
+
});
|
|
301
|
+
const resizeColumnsObserver = new ResizeObserver(() => {
|
|
302
|
+
utils.getMinCellWidthInColumn(tableRef, colWidths, $headerRows[0].cells.length, resizable);
|
|
303
|
+
});
|
|
304
|
+
const observeFirstCells = () => {
|
|
305
|
+
if (!tableRef) return;
|
|
306
|
+
tableRef.querySelectorAll("tbody tr td:first-child").forEach((cell) => {
|
|
307
|
+
resizeRowsObserver.observe(cell);
|
|
308
|
+
});
|
|
309
|
+
return resizeRowsObserver;
|
|
310
|
+
};
|
|
311
|
+
const observeHeaderColumns = () => {
|
|
312
|
+
if (!tableRef) return;
|
|
313
|
+
tableRef.querySelectorAll("thead tr th").forEach((cell) => {
|
|
314
|
+
resizeColumnsObserver.observe(cell);
|
|
315
|
+
});
|
|
316
|
+
};
|
|
317
|
+
afterUpdate(() => {
|
|
318
|
+
if (resizable !== "rows" && resizable !== "both") {
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const e = tableRef?.querySelector(`#${tableId}-row-${$pageRows[0].id}`);
|
|
322
|
+
if (e) {
|
|
323
|
+
getDimensions();
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
onDestroy(() => {
|
|
327
|
+
resizeColumnsObserver.disconnect();
|
|
328
|
+
resizeRowsObserver.disconnect();
|
|
329
|
+
});
|
|
310
330
|
$: sortKeys = pluginStates.sort.sortKeys;
|
|
311
|
-
$: serverSide &&
|
|
331
|
+
$: serverSide && updateTableWithParams();
|
|
312
332
|
$: serverSide && sortServer($sortKeys[0]?.order, $sortKeys[0]?.id);
|
|
313
333
|
$: $hiddenColumnIds = shownColumns.filter((col) => !col.visible).map((col) => col.id);
|
|
314
334
|
</script>
|
|
@@ -377,7 +397,8 @@ $: $hiddenColumnIds = shownColumns.filter((col) => !col.visible).map((col) => co
|
|
|
377
397
|
{/if}
|
|
378
398
|
|
|
379
399
|
<div
|
|
380
|
-
class="flex justify-between items-center w-full {search &&
|
|
400
|
+
class="flex justify-between overflow-x-auto items-center w-full {search &&
|
|
401
|
+
'py-2'} {!search &&
|
|
381
402
|
(shownColumns.length > 0 || toggle || resizable !== 'none' || exportable) &&
|
|
382
403
|
'pb-2'}"
|
|
383
404
|
>
|
|
@@ -404,25 +425,26 @@ $: $hiddenColumnIds = shownColumns.filter((col) => !col.visible).map((col) => co
|
|
|
404
425
|
{#if resizable !== 'none'}
|
|
405
426
|
<button
|
|
406
427
|
type="button"
|
|
407
|
-
|
|
408
|
-
class="btn btn-sm variant-filled-primary rounded-full order-last"
|
|
428
|
+
class="btn btn-sm variant-filled-primary rounded-full order-last flex gap-2 items-center"
|
|
409
429
|
aria-label="Reset sizing of columns and rows"
|
|
410
430
|
on:click|preventDefault={() =>
|
|
411
|
-
resetResize($headerRows, $pageRows, tableId, columns, resizable)}
|
|
412
|
-
|
|
431
|
+
utils.resetResize($headerRows, $pageRows, tableId, columns, resizable)}
|
|
432
|
+
><Fa icon={faCompress} /> Reset sizing</button
|
|
413
433
|
>
|
|
414
434
|
{/if}
|
|
435
|
+
<!-- Enable export as CSV button if exportable === true -->
|
|
415
436
|
{#if exportable}
|
|
416
437
|
<button
|
|
417
438
|
type="button"
|
|
418
|
-
|
|
419
|
-
class="btn btn-sm variant-filled-primary rounded-full order-last"
|
|
439
|
+
class="btn btn-sm variant-filled-primary rounded-full order-last flex items-center gap-2"
|
|
420
440
|
aria-label="Export table data as CSV"
|
|
421
|
-
on:click|preventDefault={() =>
|
|
422
|
-
|
|
441
|
+
on:click|preventDefault={() =>
|
|
442
|
+
utils.exportAsCsv(tableId, utils.jsonToCsv($exportedData))}
|
|
443
|
+
><Fa icon={faDownload} /> Export as CSV</button
|
|
423
444
|
>
|
|
424
445
|
{/if}
|
|
425
|
-
|
|
446
|
+
<!-- Enable show/hide columns menu if showColumnsMenu === true -->
|
|
447
|
+
{#if showColumnsMenu && shownColumns.length > 0}
|
|
426
448
|
<ColumnsMenu bind:columns={shownColumns} {tableId} />
|
|
427
449
|
{/if}
|
|
428
450
|
</div>
|
|
@@ -430,6 +452,7 @@ $: $hiddenColumnIds = shownColumns.filter((col) => !col.visible).map((col) => co
|
|
|
430
452
|
|
|
431
453
|
<div class="overflow-auto" style="height: {height}px">
|
|
432
454
|
<table
|
|
455
|
+
bind:this={tableRef}
|
|
433
456
|
{...$tableAttrs}
|
|
434
457
|
class="table table-auto table-compact bg-tertiary-500/30 dark:bg-tertiary-900/10 overflow-clip"
|
|
435
458
|
id="{tableId}-table"
|
|
@@ -446,14 +469,29 @@ $: $hiddenColumnIds = shownColumns.filter((col) => !col.visible).map((col) => co
|
|
|
446
469
|
let:rowProps
|
|
447
470
|
>
|
|
448
471
|
<tr {...rowAttrs} class="bg-primary-300 dark:bg-primary-800">
|
|
449
|
-
{#each headerRow.cells as cell (cell.id)}
|
|
472
|
+
{#each headerRow.cells as cell, index (cell.id)}
|
|
450
473
|
<Subscribe attrs={cell.attrs()} props={cell.props()} let:props let:attrs>
|
|
451
|
-
<th
|
|
474
|
+
<th
|
|
475
|
+
scope="col"
|
|
476
|
+
class="!p-2"
|
|
477
|
+
{...attrs}
|
|
478
|
+
style={`
|
|
479
|
+
width: ${cell.isData() ? 'auto' : '0'};
|
|
480
|
+
${utils.cellStyle(cell.id, columns)}
|
|
481
|
+
`}
|
|
482
|
+
>
|
|
452
483
|
<div
|
|
453
484
|
class="overflow-auto"
|
|
454
485
|
class:resize-x={(resizable === 'columns' || resizable === 'both') &&
|
|
455
|
-
!fixedWidth(cell.id, columns)}
|
|
486
|
+
!utils.fixedWidth(cell.id, columns)}
|
|
456
487
|
id="th-{tableId}-{cell.id}"
|
|
488
|
+
style={`
|
|
489
|
+
min-width: ${
|
|
490
|
+
utils.minWidth(cell.id, columns)
|
|
491
|
+
? utils.minWidth(cell.id, columns)
|
|
492
|
+
: $colWidths[index]
|
|
493
|
+
}px;
|
|
494
|
+
`}
|
|
457
495
|
>
|
|
458
496
|
<div class="flex justify-between items-center">
|
|
459
497
|
<div class="flex gap-1 whitespace-pre-wrap">
|
|
@@ -504,20 +542,34 @@ $: $hiddenColumnIds = shownColumns.filter((col) => !col.visible).map((col) => co
|
|
|
504
542
|
<tr {...rowAttrs} id="{tableId}-row-{row.id}" class="">
|
|
505
543
|
{#each row.cells as cell, index (cell?.id)}
|
|
506
544
|
<Subscribe attrs={cell.attrs()} let:attrs>
|
|
507
|
-
<td {...attrs} class="
|
|
545
|
+
<td {...attrs} class="">
|
|
508
546
|
<div
|
|
509
|
-
class="
|
|
547
|
+
class=" h-full {index === 0 &&
|
|
510
548
|
(resizable === 'rows' || resizable === 'both')
|
|
511
|
-
? 'resize-y'
|
|
512
|
-
: ''}"
|
|
549
|
+
? 'resize-y overflow-auto'
|
|
550
|
+
: 'block'}"
|
|
513
551
|
id="{tableId}-{cell.id}-{row.id}"
|
|
552
|
+
style={utils.getResizeStyles($rowHeights, row.id, index)}
|
|
514
553
|
>
|
|
515
554
|
<!-- Adding config for initial rowHeight, if provided -->
|
|
516
555
|
<div
|
|
517
|
-
class="flex items-
|
|
518
|
-
style=
|
|
556
|
+
class="flex items-start overflow-auto"
|
|
557
|
+
style={`
|
|
558
|
+
max-height: ${$rowHeights && $rowHeights[+row.id] ? `${$rowHeights[+row.id].max}px` : 'auto'};
|
|
559
|
+
`}
|
|
519
560
|
>
|
|
520
|
-
<div
|
|
561
|
+
<div
|
|
562
|
+
class="grow overflow-auto"
|
|
563
|
+
style={cell.isData()
|
|
564
|
+
? `width: ${
|
|
565
|
+
utils.minWidth(cell.id, columns)
|
|
566
|
+
? utils.minWidth(cell.id, columns)
|
|
567
|
+
: $colWidths[index]
|
|
568
|
+
}px;`
|
|
569
|
+
: 'max-width: min-content;'}
|
|
570
|
+
>
|
|
571
|
+
<Render of={cell.render()} />
|
|
572
|
+
</div>
|
|
521
573
|
</div>
|
|
522
574
|
</div>
|
|
523
575
|
</td>
|
|
@@ -554,12 +606,19 @@ $: $hiddenColumnIds = shownColumns.filter((col) => !col.visible).map((col) => co
|
|
|
554
606
|
{pageIndex}
|
|
555
607
|
{pageSize}
|
|
556
608
|
{serverItemCount}
|
|
557
|
-
{
|
|
609
|
+
updateTable={updateTableWithParams}
|
|
558
610
|
{pageSizes}
|
|
611
|
+
{pageIndexStringType}
|
|
559
612
|
id={tableId}
|
|
560
613
|
/>
|
|
561
614
|
{:else}
|
|
562
|
-
<TablePagination
|
|
615
|
+
<TablePagination
|
|
616
|
+
itemCount={$rows.length}
|
|
617
|
+
pageConfig={pluginStates.page}
|
|
618
|
+
{pageSizes}
|
|
619
|
+
id={tableId}
|
|
620
|
+
{pageIndexStringType}
|
|
621
|
+
/>
|
|
563
622
|
{/if}
|
|
564
623
|
{/if}
|
|
565
624
|
</div>
|
|
@@ -7,9 +7,12 @@ import {
|
|
|
7
7
|
faChevronDown
|
|
8
8
|
} from "@fortawesome/free-solid-svg-icons";
|
|
9
9
|
import { ListBox, ListBoxItem, popup } from "@skeletonlabs/skeleton";
|
|
10
|
+
export let itemCount;
|
|
10
11
|
export let pageConfig;
|
|
11
12
|
export let pageSizes;
|
|
13
|
+
export let pageIndexStringType;
|
|
12
14
|
export let id;
|
|
15
|
+
let indexInformation = "";
|
|
13
16
|
const { pageIndex, pageCount, pageSize, hasNextPage, hasPreviousPage } = pageConfig;
|
|
14
17
|
const goToFirstPage = () => $pageIndex = 0;
|
|
15
18
|
const goToLastPage = () => $pageIndex = $pageCount - 1;
|
|
@@ -32,11 +35,22 @@ const pageSizePopup = {
|
|
|
32
35
|
placement: "bottom",
|
|
33
36
|
closeQuery: ".listbox-item"
|
|
34
37
|
};
|
|
38
|
+
const getIndexInfomationString = () => {
|
|
39
|
+
if (pageIndexStringType === "pages") {
|
|
40
|
+
return $pageCount > 0 ? `Page ${$pageIndex + 1} of ${$pageCount}` : "No pages";
|
|
41
|
+
} else {
|
|
42
|
+
return itemCount === 0 ? "No items" : `Displaying items ${$pageIndex * $pageSize + 1} - ${Math.min(
|
|
43
|
+
($pageIndex + 1) * $pageSize,
|
|
44
|
+
itemCount
|
|
45
|
+
)} of ${Math.min($pageCount * $pageSize, itemCount)}`;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
35
48
|
$: goToFirstPageDisabled = !$pageIndex;
|
|
36
49
|
$: goToLastPageDisabled = $pageIndex == $pageCount - 1;
|
|
37
50
|
$: goToNextPageDisabled = !$hasNextPage;
|
|
38
51
|
$: goToPreviousPageDisabled = !$hasPreviousPage;
|
|
39
52
|
$: $pageSize = pageSizeDropdownValue;
|
|
53
|
+
$: $pageCount, $pageIndex, $pageSize, indexInformation = getIndexInfomationString();
|
|
40
54
|
</script>
|
|
41
55
|
|
|
42
56
|
<div class="flex justify-between w-full items-stretch gap-10">
|
|
@@ -114,12 +128,6 @@ $: $pageSize = pageSizeDropdownValue;
|
|
|
114
128
|
>
|
|
115
129
|
</div>
|
|
116
130
|
<div class="flex justify-end items-center">
|
|
117
|
-
<span class="text-sm text-gray-500">
|
|
118
|
-
{#if $pageCount > 0}
|
|
119
|
-
Page {$pageIndex + 1} of {$pageCount}
|
|
120
|
-
{:else}
|
|
121
|
-
No pages
|
|
122
|
-
{/if}
|
|
123
|
-
</span>
|
|
131
|
+
<span class="text-sm text-gray-500">{indexInformation}</span>
|
|
124
132
|
</div>
|
|
125
133
|
</div>
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
export let id;
|
|
9
9
|
export let pageIndex;
|
|
10
10
|
export let pageSize;
|
|
11
|
+
export let pageIndexStringType;
|
|
11
12
|
export let pageSizes;
|
|
12
13
|
export let serverItemCount;
|
|
13
14
|
export let updateTable;
|
|
@@ -15,6 +16,7 @@ let goToFirstPageDisabled = true;
|
|
|
15
16
|
let goToLastPageDisabled = true;
|
|
16
17
|
let goToNextPageDisabled = true;
|
|
17
18
|
let goToPreviousPageDisabled = true;
|
|
19
|
+
let indexInformation = "";
|
|
18
20
|
const handleChange = (e) => {
|
|
19
21
|
const value = e.target.value;
|
|
20
22
|
if (value > pageCount) {
|
|
@@ -45,12 +47,20 @@ const goTo = (dst) => {
|
|
|
45
47
|
}
|
|
46
48
|
updateTable();
|
|
47
49
|
};
|
|
50
|
+
const getIndexInfomationString = () => {
|
|
51
|
+
if (pageIndexStringType === "pages") {
|
|
52
|
+
return pageCount > 0 ? `Page ${$pageIndex + 1} of ${pageCount}` : "No pages";
|
|
53
|
+
} else {
|
|
54
|
+
return `Showing ${$pageIndex * $pageSize + 1} - ${($pageIndex + 1) * $pageSize} of ${pageCount * $pageSize} items`;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
48
57
|
$: pageCount = Math.ceil($serverItemCount / $pageSize);
|
|
49
58
|
$: goToFirstPageDisabled = !$pageIndex;
|
|
50
59
|
$: goToLastPageDisabled = $pageIndex == pageCount - 1;
|
|
51
60
|
$: goToNextPageDisabled = $pageIndex == pageCount - 1;
|
|
52
61
|
$: goToPreviousPageDisabled = !$pageIndex;
|
|
53
62
|
$: $pageSize && updateTable();
|
|
63
|
+
$: pageCount, $pageIndex, $pageSize, indexInformation = getIndexInfomationString();
|
|
54
64
|
updateTable();
|
|
55
65
|
</script>
|
|
56
66
|
|
|
@@ -113,15 +123,7 @@ updateTable();
|
|
|
113
123
|
</div>
|
|
114
124
|
<div class="flex justify-end items-center">
|
|
115
125
|
<span class="text-sm text-gray-500">
|
|
116
|
-
{
|
|
117
|
-
{#if pageCount == 1}
|
|
118
|
-
1 page
|
|
119
|
-
{:else}
|
|
120
|
-
{pageCount} pages
|
|
121
|
-
{/if}
|
|
122
|
-
{:else}
|
|
123
|
-
No pages
|
|
124
|
-
{/if}
|
|
126
|
+
{indexInformation}
|
|
125
127
|
</span>
|
|
126
128
|
</div>
|
|
127
129
|
</div>
|