@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
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { SvelteComponent } from 'svelte';
|
|
2
|
+
import type { Writable } from 'svelte/store';
|
|
3
|
+
import { Receive } from '../../models/Models';
|
|
4
|
+
import type { FilterOptionsEnum } from '../../models/Enums';
|
|
5
|
+
import type { Columns, Filter, ServerColumn, ServerConfig } from '../../models/Models';
|
|
6
|
+
export declare const minWidth: (id: string, columns: Columns | undefined) => number;
|
|
7
|
+
export declare const fixedWidth: (id: string, columns: Columns | undefined) => number;
|
|
8
|
+
export declare const cellStyle: (id: string, columns: Columns | undefined) => string;
|
|
9
|
+
export declare const normalizeFilters: (filters: {
|
|
10
|
+
[key: string]: { [key in FilterOptionsEnum]?: number | string | Date; };
|
|
11
|
+
}) => Filter[];
|
|
12
|
+
export declare const exportAsCsv: (tableId: string, exportedData: string) => void;
|
|
13
|
+
export declare const jsonToCsv: (data: string) => string;
|
|
14
|
+
export declare const resetResize: (headerRows: any, pageRows: any, tableId: string, columns: Columns | undefined, resizable: "none" | "rows" | "columns" | "both") => void;
|
|
15
|
+
export declare const missingValuesFn: (key: number | string, missingValues: {
|
|
16
|
+
[key: string | number]: string;
|
|
17
|
+
}) => string | number;
|
|
18
|
+
export declare const updateTable: (pageSize: number, pageIndex: number, server: ServerConfig | undefined, filters: {
|
|
19
|
+
[key: string]: { [key in FilterOptionsEnum]?: number | string | Date; };
|
|
20
|
+
}, data: Writable<any[]>, serverItems: Writable<number> | undefined, columns: Columns | undefined, dispatch: any) => Promise<Receive>;
|
|
21
|
+
export declare const convertServerColumns: (serverColumns: ServerColumn[], columns: Columns | undefined) => Columns;
|
|
22
|
+
export declare const getMaxCellHeightInRow: (tableRef: HTMLTableElement, resizable: "columns" | "rows" | "none" | "both", optionsComponent: typeof SvelteComponent | undefined, rowHeights: Writable<{
|
|
23
|
+
[key: number]: {
|
|
24
|
+
max: number;
|
|
25
|
+
min: number;
|
|
26
|
+
};
|
|
27
|
+
}>, tableId: string, rowHeight: number | null) => void;
|
|
28
|
+
export declare const getMinCellWidthInColumn: (tableRef: HTMLTableElement, colWidths: Writable<number[]>, headerRowsLength: number, resizable: "columns" | "rows" | "none" | "both") => void;
|
|
29
|
+
export declare const getResizeStyles: (rowHeights: {
|
|
30
|
+
[key: number]: {
|
|
31
|
+
max: number;
|
|
32
|
+
min: number;
|
|
33
|
+
};
|
|
34
|
+
}, id: string | number, index: number) => string;
|
|
@@ -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) {
|
|
@@ -52,6 +54,31 @@ export const exportAsCsv = (tableId, exportedData) => {
|
|
|
52
54
|
anchor.click();
|
|
53
55
|
document.body.removeChild(anchor);
|
|
54
56
|
};
|
|
57
|
+
export const jsonToCsv = (data) => {
|
|
58
|
+
const json = JSON.parse(data);
|
|
59
|
+
if (json.length === 0)
|
|
60
|
+
return '';
|
|
61
|
+
// Extract headers (keys)
|
|
62
|
+
const headers = Object.keys(json[0]);
|
|
63
|
+
// Escape and format a single cell
|
|
64
|
+
const escapeCsvCell = (value) => {
|
|
65
|
+
if (value === null || value === undefined)
|
|
66
|
+
return '';
|
|
67
|
+
let cell = String(value);
|
|
68
|
+
// Escape quotes by doubling them, and wrap the value in quotes if it contains special characters
|
|
69
|
+
if (/[",\n]/.test(cell)) {
|
|
70
|
+
cell = `"${cell.replace(/"/g, '""')}"`;
|
|
71
|
+
}
|
|
72
|
+
return cell;
|
|
73
|
+
};
|
|
74
|
+
// Create CSV rows
|
|
75
|
+
const rows = [
|
|
76
|
+
headers.join(','), // Header row
|
|
77
|
+
...json.map((row) => headers.map(header => escapeCsvCell(row[header])).join(',')) // Data rows
|
|
78
|
+
];
|
|
79
|
+
// Join rows with newlines
|
|
80
|
+
return rows.join('\n');
|
|
81
|
+
};
|
|
55
82
|
// Resetting the resized columns and/or rows
|
|
56
83
|
export const resetResize = (headerRows, pageRows, tableId, columns, resizable) => {
|
|
57
84
|
// Run only if resizable is not none
|
|
@@ -100,6 +127,54 @@ export const missingValuesFn = (key, missingValues) => {
|
|
|
100
127
|
: undefined;
|
|
101
128
|
return foundKey ? missingValues[foundKey] : key;
|
|
102
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
|
+
};
|
|
103
178
|
export const convertServerColumns = (serverColumns, columns) => {
|
|
104
179
|
const columnsConfig = {};
|
|
105
180
|
serverColumns.forEach((col) => {
|
|
@@ -152,3 +227,62 @@ export const convertServerColumns = (serverColumns, columns) => {
|
|
|
152
227
|
});
|
|
153
228
|
return columnsConfig;
|
|
154
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,4 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import Fa from 'svelte-fa';
|
|
3
|
+
import { faEye } from '@fortawesome/free-solid-svg-icons';
|
|
2
4
|
import { popup } from '@skeletonlabs/skeleton';
|
|
3
5
|
import type { PopupSettings } from '@skeletonlabs/skeleton';
|
|
4
6
|
|
|
@@ -8,29 +10,55 @@
|
|
|
8
10
|
const popupCombobox: PopupSettings = {
|
|
9
11
|
event: 'click',
|
|
10
12
|
target: `${tableId}-columns-menu`,
|
|
11
|
-
placement: 'bottom'
|
|
13
|
+
placement: 'bottom',
|
|
14
|
+
closeQuery: ''
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const selectAll = () => {
|
|
18
|
+
columns = columns.map((column) => ({ ...column, visible: true }));
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const deselectAll = () => {
|
|
22
|
+
columns = columns.map((column) => ({ ...column, visible: false }));
|
|
23
|
+
columns[0].visible = true;
|
|
12
24
|
};
|
|
13
25
|
</script>
|
|
14
26
|
|
|
15
27
|
<button
|
|
16
28
|
type="button"
|
|
17
|
-
|
|
18
|
-
class="btn btn-sm variant-filled-primary rounded-full order-last"
|
|
29
|
+
class="btn btn-sm variant-filled-primary rounded-full order-last gap-2"
|
|
19
30
|
aria-label="Open menu to hide/show columns"
|
|
20
|
-
use:popup={popupCombobox}
|
|
31
|
+
use:popup={popupCombobox}><Fa icon={faEye} /> Columns</button
|
|
21
32
|
>
|
|
22
|
-
|
|
23
33
|
<div
|
|
24
|
-
class="bg-white dark:bg-surface-500 p-4 rounded-md shadow-md z-10"
|
|
34
|
+
class="bg-white dark:bg-surface-500 p-4 px-5 rounded-md shadow-md z-10 border border-primary-500"
|
|
25
35
|
data-popup="{tableId}-columns-menu"
|
|
26
36
|
>
|
|
37
|
+
<div class="flex items-center gap-4 pb-5 grow justify-between">
|
|
38
|
+
<button
|
|
39
|
+
on:click|preventDefault={selectAll}
|
|
40
|
+
type="button"
|
|
41
|
+
class="btn p-0 text-sm grow underline text-primary-600"
|
|
42
|
+
>
|
|
43
|
+
Select All
|
|
44
|
+
</button>
|
|
45
|
+
<div class="border border-r border-neutral-200 h-6" />
|
|
46
|
+
<button
|
|
47
|
+
on:click|preventDefault={deselectAll}
|
|
48
|
+
type="button"
|
|
49
|
+
class="btn p-0 text-sm grow underline text-neutral-500"
|
|
50
|
+
>
|
|
51
|
+
Deselect All
|
|
52
|
+
</button>
|
|
53
|
+
</div>
|
|
27
54
|
{#each columns as column}
|
|
28
55
|
<div class="flex gap-3 items-center">
|
|
29
56
|
<label for={column.id} class="cursor-pointer" title={column.label}></label>
|
|
30
57
|
<input
|
|
31
58
|
aria-label={`${column.visible ? 'Hide' : 'Show'} ${column.label} column`}
|
|
32
59
|
type="checkbox"
|
|
33
|
-
|
|
60
|
+
class="checkbox"
|
|
61
|
+
id={column.id}
|
|
34
62
|
bind:checked={column.visible}
|
|
35
63
|
title={`${column.visible ? 'Hide' : 'Show'} ${column.label} column`}
|
|
36
64
|
disabled={columns.filter((c) => c.visible).length === 1 && column.visible}
|
|
@@ -39,5 +67,5 @@
|
|
|
39
67
|
</div>
|
|
40
68
|
{/each}
|
|
41
69
|
|
|
42
|
-
<div class="arrow bg-white dark:bg-surface-500" />
|
|
70
|
+
<div class="arrow bg-white dark:bg-surface-500 border-l border-t border-primary-500" />
|
|
43
71
|
</div>
|