@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,373 @@
|
|
|
1
|
+
import dateFormat from 'dateformat';
|
|
2
|
+
import { SvelteComponent } from 'svelte';
|
|
3
|
+
import type { Writable } from 'svelte/store';
|
|
4
|
+
|
|
5
|
+
import { Send, Receive } from '$models/Models';
|
|
6
|
+
import type { FilterOptionsEnum } from '$models/Enums';
|
|
7
|
+
import type { Columns, Filter, ServerColumn, ServerConfig } from '$models/Models';
|
|
8
|
+
|
|
9
|
+
// Function to determine minWidth for a column to simplify the logic in the HTML
|
|
10
|
+
export const minWidth = (id: string, columns: Columns | undefined) => {
|
|
11
|
+
if (columns && id in columns) {
|
|
12
|
+
return columns[id].minWidth ?? 0;
|
|
13
|
+
}
|
|
14
|
+
return 0;
|
|
15
|
+
};
|
|
16
|
+
// Function to determine fixedWidth for a column to simplify the logic in the HTML
|
|
17
|
+
export const fixedWidth = (id: string, columns: Columns | undefined) => {
|
|
18
|
+
if (columns && id in columns) {
|
|
19
|
+
return columns[id].fixedWidth ?? 0;
|
|
20
|
+
}
|
|
21
|
+
return 0;
|
|
22
|
+
};
|
|
23
|
+
// Function to create custom styles for the columns to simplify the logic in the HTML
|
|
24
|
+
export const cellStyle = (id: string, columns: Columns | undefined) => {
|
|
25
|
+
const minW = minWidth(id, columns);
|
|
26
|
+
const fixedW = fixedWidth(id, columns);
|
|
27
|
+
const styles: string[] = [];
|
|
28
|
+
|
|
29
|
+
// If minWidth is provided, add to styles
|
|
30
|
+
minW && styles.push(`min-width: ${minW}px`);
|
|
31
|
+
// If fixedWidth is provided, add to styles
|
|
32
|
+
fixedW && styles.push(`width: ${fixedW}px`);
|
|
33
|
+
// Create and return styles separated by ';'
|
|
34
|
+
return styles.join(';');
|
|
35
|
+
};
|
|
36
|
+
// Function to normalize the filters for back-end
|
|
37
|
+
export const normalizeFilters = (filters: {
|
|
38
|
+
[key: string]: { [key in FilterOptionsEnum]?: number | string | Date };
|
|
39
|
+
}) => {
|
|
40
|
+
let filter: Filter[] = [];
|
|
41
|
+
|
|
42
|
+
// Add filters to the request
|
|
43
|
+
Object.keys(filters).forEach((key) => {
|
|
44
|
+
Object.keys(filters[key])
|
|
45
|
+
.filter((k) => filters[key][k] !== undefined)
|
|
46
|
+
.forEach((k) => {
|
|
47
|
+
filter.push({
|
|
48
|
+
column: key,
|
|
49
|
+
filterBy: k as FilterOptionsEnum,
|
|
50
|
+
value: filters[key][k]
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return filter;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export const exportAsCsv = (tableId: string, exportedData: string) => {
|
|
59
|
+
// Creating a hidden anchor element to download the CSV file
|
|
60
|
+
const anchor = document.createElement('a');
|
|
61
|
+
anchor.style.display = 'none';
|
|
62
|
+
anchor.href = `data:text/csv;charset=utf-8,${encodeURIComponent(exportedData)}`;
|
|
63
|
+
anchor.download = `${tableId}.csv`;
|
|
64
|
+
document.body.appendChild(anchor);
|
|
65
|
+
anchor.click();
|
|
66
|
+
document.body.removeChild(anchor);
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const jsonToCsv = (data: string): string => {
|
|
70
|
+
const json = JSON.parse(data);
|
|
71
|
+
|
|
72
|
+
if (json.length === 0) return '';
|
|
73
|
+
|
|
74
|
+
// Extract headers (keys)
|
|
75
|
+
const headers = Object.keys(json[0]);
|
|
76
|
+
|
|
77
|
+
// Escape and format a single cell
|
|
78
|
+
const escapeCsvCell = (value: any): string => {
|
|
79
|
+
if (value === null || value === undefined) return '';
|
|
80
|
+
let cell = String(value);
|
|
81
|
+
// Escape quotes by doubling them, and wrap the value in quotes if it contains special characters
|
|
82
|
+
if (/[",\n]/.test(cell)) {
|
|
83
|
+
cell = `"${cell.replace(/"/g, '""')}"`;
|
|
84
|
+
}
|
|
85
|
+
return cell;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Create CSV rows
|
|
89
|
+
const rows = [
|
|
90
|
+
headers.join(','), // Header row
|
|
91
|
+
...json.map((row) =>
|
|
92
|
+
headers.map(header => escapeCsvCell(row[header])).join(',')
|
|
93
|
+
) // Data rows
|
|
94
|
+
];
|
|
95
|
+
|
|
96
|
+
// Join rows with newlines
|
|
97
|
+
return rows.join('\n');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Resetting the resized columns and/or rows
|
|
101
|
+
export const resetResize = (
|
|
102
|
+
headerRows: any,
|
|
103
|
+
pageRows: any,
|
|
104
|
+
tableId: string,
|
|
105
|
+
columns: Columns | undefined,
|
|
106
|
+
resizable: 'none' | 'rows' | 'columns' | 'both'
|
|
107
|
+
) => {
|
|
108
|
+
// Run only if resizable is not none
|
|
109
|
+
if (resizable === 'columns' || resizable === 'both') {
|
|
110
|
+
headerRows.forEach((row) => {
|
|
111
|
+
row.cells.forEach((cell) => {
|
|
112
|
+
const minW = minWidth(cell.id, columns);
|
|
113
|
+
const fixedW = fixedWidth(cell.id, columns);
|
|
114
|
+
// If a fixedWidth is provided for a column, then reset the width to that value
|
|
115
|
+
fixedW &&
|
|
116
|
+
document
|
|
117
|
+
.getElementById(`th-${tableId}-${cell.id}`)
|
|
118
|
+
?.style.setProperty('width', `${fixedW}px`);
|
|
119
|
+
// If a minWidth is provided for a column, then reset the width to that value
|
|
120
|
+
minW &&
|
|
121
|
+
document
|
|
122
|
+
.getElementById(`th-${tableId}-${cell.id}`)
|
|
123
|
+
?.style.setProperty('width', `${minW}px`);
|
|
124
|
+
// If neither minWidth nor fixedWidth provided for a column, then reset the width to auto
|
|
125
|
+
!minW &&
|
|
126
|
+
!fixedW &&
|
|
127
|
+
document.getElementById(`th-${tableId}-${cell.id}`)?.style.setProperty('width', 'auto');
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (resizable === 'rows' || resizable === 'both') {
|
|
133
|
+
pageRows.forEach((row) => {
|
|
134
|
+
row.cells.forEach((cell) => {
|
|
135
|
+
// Reset all row heights to auto
|
|
136
|
+
document
|
|
137
|
+
.getElementById(`${tableId}-${cell.id}-${row.id}`)
|
|
138
|
+
?.style.setProperty('height', 'auto');
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export const missingValuesFn = (
|
|
145
|
+
key: number | string,
|
|
146
|
+
missingValues: { [key: string | number]: string }
|
|
147
|
+
) => {
|
|
148
|
+
const foundKey =
|
|
149
|
+
typeof key === 'number' && key.toString().includes('e')
|
|
150
|
+
? Object.keys(missingValues).find((item) => {
|
|
151
|
+
return (item as string).toLowerCase() === key.toString().toLowerCase();
|
|
152
|
+
})
|
|
153
|
+
: typeof key === 'string' && parseInt(key).toString().length !== key.length && new Date(key)
|
|
154
|
+
? Object.keys(missingValues).find(
|
|
155
|
+
(item) => new Date(item).getTime() === new Date(key).getTime()
|
|
156
|
+
)
|
|
157
|
+
: key in missingValues
|
|
158
|
+
? key
|
|
159
|
+
: undefined;
|
|
160
|
+
|
|
161
|
+
return foundKey ? missingValues[foundKey] : key;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Function to update the server-side table data
|
|
165
|
+
export const updateTable = async (
|
|
166
|
+
pageSize: number,
|
|
167
|
+
pageIndex: number,
|
|
168
|
+
server: ServerConfig | undefined,
|
|
169
|
+
filters: {
|
|
170
|
+
[key: string]: { [key in FilterOptionsEnum]?: number | string | Date }
|
|
171
|
+
},
|
|
172
|
+
data: Writable<any[]>,
|
|
173
|
+
serverItems: Writable<number> | undefined,
|
|
174
|
+
columns: Columns | undefined,
|
|
175
|
+
dispatch: any
|
|
176
|
+
) => {
|
|
177
|
+
const { baseUrl, entityId, versionId, sendModel = new Send() } = server ?? {};
|
|
178
|
+
|
|
179
|
+
if (!sendModel) throw new Error('Server-side configuration is missing');
|
|
180
|
+
|
|
181
|
+
sendModel.limit = pageSize;
|
|
182
|
+
sendModel.offset = pageSize * pageIndex;
|
|
183
|
+
sendModel.version = versionId || -1;
|
|
184
|
+
sendModel.id = entityId || -1;
|
|
185
|
+
sendModel.filter = normalizeFilters(filters);
|
|
186
|
+
|
|
187
|
+
let fetchData;
|
|
188
|
+
|
|
189
|
+
try {
|
|
190
|
+
fetchData = await fetch(baseUrl || '', {
|
|
191
|
+
headers: {
|
|
192
|
+
'Content-Type': 'application/json'
|
|
193
|
+
},
|
|
194
|
+
method: 'POST',
|
|
195
|
+
body: JSON.stringify(sendModel)
|
|
196
|
+
});
|
|
197
|
+
} catch (error) {
|
|
198
|
+
throw new Error(`Network error: ${(error as Error).message}`);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (!fetchData.ok) {
|
|
202
|
+
throw new Error('Failed to fetch data');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const response: Receive = await fetchData.json();
|
|
206
|
+
|
|
207
|
+
// Format server columns to the client columns
|
|
208
|
+
if (response.columns !== undefined) {
|
|
209
|
+
columns = convertServerColumns(response.columns, columns);
|
|
210
|
+
|
|
211
|
+
const clientCols = response.columns.reduce((acc, col) => {
|
|
212
|
+
acc[col.key] = col.column;
|
|
213
|
+
return acc;
|
|
214
|
+
}, {});
|
|
215
|
+
|
|
216
|
+
const tmpArr: any[] = [];
|
|
217
|
+
|
|
218
|
+
response.data.forEach((row, index) => {
|
|
219
|
+
const tmp: { [key: string]: any } = {};
|
|
220
|
+
Object.keys(row).forEach((key) => {
|
|
221
|
+
tmp[clientCols[key]] = row[key];
|
|
222
|
+
});
|
|
223
|
+
tmpArr.push(tmp);
|
|
224
|
+
});
|
|
225
|
+
dispatch('fetch', columns);
|
|
226
|
+
data.set(tmpArr);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
serverItems?.set(response.count);
|
|
230
|
+
|
|
231
|
+
return response;
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
export const convertServerColumns = (
|
|
235
|
+
serverColumns: ServerColumn[],
|
|
236
|
+
columns: Columns | undefined
|
|
237
|
+
) => {
|
|
238
|
+
const columnsConfig: Columns = {};
|
|
239
|
+
|
|
240
|
+
serverColumns.forEach((col) => {
|
|
241
|
+
let instructions = {};
|
|
242
|
+
|
|
243
|
+
if (col.instructions?.displayPattern) {
|
|
244
|
+
let dp = col.instructions.displayPattern;
|
|
245
|
+
|
|
246
|
+
// Swap 'm' and 'M' to match the backend date format
|
|
247
|
+
for (let i = 0; i < col.instructions.displayPattern.length; i++) {
|
|
248
|
+
if (col.instructions.displayPattern[i] === 'm') {
|
|
249
|
+
dp = `${dp.slice(0, i)}M${dp.slice(i + 1)}`;
|
|
250
|
+
} else if (col.instructions.displayPattern[i] === 'M') {
|
|
251
|
+
dp = `${dp.slice(0, i)}m${dp.slice(i + 1)}`;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
instructions = {
|
|
256
|
+
toStringFn: (date: string) => {
|
|
257
|
+
if (col.instructions?.missingValues) {
|
|
258
|
+
const missingValue = missingValuesFn(date, col.instructions?.missingValues || {});
|
|
259
|
+
if (missingValue === date) {
|
|
260
|
+
return dateFormat(new Date(date), dp);
|
|
261
|
+
}
|
|
262
|
+
return missingValue;
|
|
263
|
+
} else {
|
|
264
|
+
return dateFormat(new Date(date), dp);
|
|
265
|
+
}
|
|
266
|
+
},
|
|
267
|
+
toSortableValueFn: (date: string) => new Date(date).getTime(),
|
|
268
|
+
toFilterableValueFn: (date: string) => new Date(date)
|
|
269
|
+
};
|
|
270
|
+
} else if (col.instructions?.missingValues) {
|
|
271
|
+
instructions = {
|
|
272
|
+
...instructions,
|
|
273
|
+
toStringFn: (key) => missingValuesFn(key, col.instructions?.missingValues || {})
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (columns && col.column in columns) {
|
|
278
|
+
columnsConfig[col.column] = {
|
|
279
|
+
...columns[col.column],
|
|
280
|
+
instructions
|
|
281
|
+
};
|
|
282
|
+
} else {
|
|
283
|
+
columnsConfig[col.column] = {
|
|
284
|
+
instructions
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
return columnsConfig;
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
// Calculates the maximum height of the cells in each row
|
|
293
|
+
export const getMaxCellHeightInRow = (
|
|
294
|
+
tableRef: HTMLTableElement,
|
|
295
|
+
resizable: 'columns' | 'rows' | 'none' | 'both',
|
|
296
|
+
optionsComponent: typeof SvelteComponent | undefined,
|
|
297
|
+
rowHeights: Writable<{ [key: number]: { max: number; min: number } }>,
|
|
298
|
+
tableId: string,
|
|
299
|
+
rowHeight: number | null
|
|
300
|
+
) => {
|
|
301
|
+
if (!tableRef || resizable === 'columns' || resizable === 'none') return;
|
|
302
|
+
|
|
303
|
+
tableRef.querySelectorAll('tbody tr').forEach((row, index) => {
|
|
304
|
+
const cells = row.querySelectorAll('td');
|
|
305
|
+
|
|
306
|
+
let maxHeight = optionsComponent ? 56 : 44;
|
|
307
|
+
let minHeight = optionsComponent ? 56 : 44;
|
|
308
|
+
|
|
309
|
+
cells.forEach((cell) => {
|
|
310
|
+
const cellHeight = cell.getBoundingClientRect().height;
|
|
311
|
+
// + 2 pixels for rendering borders correctly
|
|
312
|
+
if (cellHeight > maxHeight) {
|
|
313
|
+
maxHeight = cellHeight + 2;
|
|
314
|
+
}
|
|
315
|
+
if (cellHeight < minHeight) {
|
|
316
|
+
minHeight = cellHeight + 2;
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
rowHeights.update((rh) => {
|
|
321
|
+
const id = +row.id.split(`${tableId}-row-`)[1];
|
|
322
|
+
return {
|
|
323
|
+
...rh,
|
|
324
|
+
[id]: {
|
|
325
|
+
max: maxHeight - 24,
|
|
326
|
+
min: Math.max(minHeight - 24, rowHeight ?? 20)
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
// Calculates the minimum width of the cells in each column
|
|
334
|
+
export const getMinCellWidthInColumn = (
|
|
335
|
+
tableRef: HTMLTableElement,
|
|
336
|
+
colWidths: Writable<number[]>,
|
|
337
|
+
headerRowsLength: number,
|
|
338
|
+
resizable: 'columns' | 'rows' | 'none' | 'both'
|
|
339
|
+
) => {
|
|
340
|
+
if (!tableRef || resizable === 'rows' || resizable === 'none') return;
|
|
341
|
+
|
|
342
|
+
// Initialize the column widths if they are not already initialized
|
|
343
|
+
colWidths.update((cw) => {
|
|
344
|
+
if (cw.length === 0) {
|
|
345
|
+
return Array.from({ length: headerRowsLength }, () => 100);
|
|
346
|
+
}
|
|
347
|
+
return cw;
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
colWidths.update((cw) => {
|
|
351
|
+
tableRef?.querySelectorAll('thead tr th span').forEach((cell, index) => {
|
|
352
|
+
// + 12 pixels for padding and + 32 pixels for filter icon
|
|
353
|
+
// If the column width is 100, which means it has not been initialized, then calculate the width
|
|
354
|
+
cw[index] = cw[index] === 100 ? cell.getBoundingClientRect().width + 12 + 32 : cw[index];
|
|
355
|
+
});
|
|
356
|
+
return cw;
|
|
357
|
+
});
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
export const getResizeStyles = (
|
|
361
|
+
rowHeights: { [key: number]: { max: number; min: number } },
|
|
362
|
+
id: string | number,
|
|
363
|
+
index: number
|
|
364
|
+
) => {
|
|
365
|
+
return `
|
|
366
|
+
min-height: ${rowHeights && rowHeights[+id] ? `${rowHeights[+id].min}px` : 'auto'};
|
|
367
|
+
max-height: ${index !== 0 && rowHeights && rowHeights[+id]
|
|
368
|
+
? `${rowHeights[+id].max}px`
|
|
369
|
+
: 'auto'
|
|
370
|
+
};
|
|
371
|
+
height: ${rowHeights && rowHeights[+id] ? `${rowHeights[+id].min}px` : 'auto'};
|
|
372
|
+
`;
|
|
373
|
+
}
|
package/src/lib/models/Models.ts
CHANGED
|
@@ -117,6 +117,7 @@ export interface TableConfig<T> {
|
|
|
117
117
|
id: string;
|
|
118
118
|
data: Writable<T[]>;
|
|
119
119
|
resizable?: 'none' | 'rows' | 'columns' | 'both'; // none by default
|
|
120
|
+
showColumnsMenu?: boolean; // false by default
|
|
120
121
|
toggle?: boolean; // false by default
|
|
121
122
|
search?: boolean; // true by default
|
|
122
123
|
fitToScreen?: boolean; // true by default
|
|
@@ -126,6 +127,7 @@ export interface TableConfig<T> {
|
|
|
126
127
|
exportable?: boolean; // false by default
|
|
127
128
|
pageSizes?: number[]; // [5, 10, 20, 50, 100] by default
|
|
128
129
|
defaultPageSize?: number; // 10 by default
|
|
130
|
+
pageIndexStringType?: 'items' | 'pages'; // pages by default
|
|
129
131
|
optionsComponent?: typeof SvelteComponent;
|
|
130
132
|
|
|
131
133
|
server?: ServerConfig;
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { FilterOptionsEnum } from '../../models/Enums';
|
|
2
|
-
import type { Columns, Filter, ServerColumn } from '../../models/Models';
|
|
3
|
-
export declare const minWidth: (id: string, columns: Columns | undefined) => number;
|
|
4
|
-
export declare const fixedWidth: (id: string, columns: Columns | undefined) => number;
|
|
5
|
-
export declare const cellStyle: (id: string, columns: Columns | undefined) => string;
|
|
6
|
-
export declare const normalizeFilters: (filters: {
|
|
7
|
-
[key: string]: { [key in FilterOptionsEnum]?: number | string | Date; };
|
|
8
|
-
}) => Filter[];
|
|
9
|
-
export declare const exportAsCsv: (tableId: string, exportedData: string) => void;
|
|
10
|
-
export declare const resetResize: (headerRows: any, pageRows: any, tableId: string, columns: Columns | undefined, resizable: "none" | "rows" | "columns" | "both") => void;
|
|
11
|
-
export declare const missingValuesFn: (key: number | string, missingValues: {
|
|
12
|
-
[key: string | number]: string;
|
|
13
|
-
}) => string | number;
|
|
14
|
-
export declare const convertServerColumns: (serverColumns: ServerColumn[], columns: Columns | undefined) => Columns;
|
|
@@ -1,186 +0,0 @@
|
|
|
1
|
-
import dateFormat from 'dateformat';
|
|
2
|
-
|
|
3
|
-
import type { FilterOptionsEnum } from '$models/Enums';
|
|
4
|
-
import type { Columns, Filter, ServerColumn } from '$models/Models';
|
|
5
|
-
|
|
6
|
-
// Function to determine minWidth for a column to simplify the logic in the HTML
|
|
7
|
-
export const minWidth = (id: string, columns: Columns | undefined) => {
|
|
8
|
-
if (columns && id in columns) {
|
|
9
|
-
return columns[id].minWidth ?? 0;
|
|
10
|
-
}
|
|
11
|
-
return 0;
|
|
12
|
-
};
|
|
13
|
-
// Function to determine fixedWidth for a column to simplify the logic in the HTML
|
|
14
|
-
export const fixedWidth = (id: string, columns: Columns | undefined) => {
|
|
15
|
-
if (columns && id in columns) {
|
|
16
|
-
return columns[id].fixedWidth ?? 0;
|
|
17
|
-
}
|
|
18
|
-
return 0;
|
|
19
|
-
};
|
|
20
|
-
// Function to create custom styles for the columns to simplify the logic in the HTML
|
|
21
|
-
export const cellStyle = (id: string, columns: Columns | undefined) => {
|
|
22
|
-
const minW = minWidth(id, columns);
|
|
23
|
-
const fixedW = fixedWidth(id, columns);
|
|
24
|
-
const styles: string[] = [];
|
|
25
|
-
|
|
26
|
-
// If minWidth is provided, add to styles
|
|
27
|
-
minW && styles.push(`min-width: ${minW}px`);
|
|
28
|
-
// If fixedWidth is provided, add to styles
|
|
29
|
-
fixedW && styles.push(`width: ${fixedW}px`);
|
|
30
|
-
// Create and return styles separated by ';'
|
|
31
|
-
return styles.join(';');
|
|
32
|
-
};
|
|
33
|
-
// Function to normalize the filters for back-end
|
|
34
|
-
export const normalizeFilters = (filters: {
|
|
35
|
-
[key: string]: { [key in FilterOptionsEnum]?: number | string | Date };
|
|
36
|
-
}) => {
|
|
37
|
-
let filter: Filter[] = [];
|
|
38
|
-
|
|
39
|
-
// Add filters to the request
|
|
40
|
-
Object.keys(filters).forEach((key) => {
|
|
41
|
-
Object.keys(filters[key])
|
|
42
|
-
.filter((k) => filters[key][k] !== undefined)
|
|
43
|
-
.forEach((k) => {
|
|
44
|
-
filter.push({
|
|
45
|
-
column: key,
|
|
46
|
-
filterBy: k as FilterOptionsEnum,
|
|
47
|
-
value: filters[key][k]
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
return filter;
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
export const exportAsCsv = (tableId: string, exportedData: string) => {
|
|
56
|
-
// Creating a hidden anchor element to download the CSV file
|
|
57
|
-
const anchor = document.createElement('a');
|
|
58
|
-
anchor.style.display = 'none';
|
|
59
|
-
anchor.href = `data:text/csv;charset=utf-8,${encodeURIComponent(exportedData)}`;
|
|
60
|
-
anchor.download = `${tableId}.csv`;
|
|
61
|
-
document.body.appendChild(anchor);
|
|
62
|
-
anchor.click();
|
|
63
|
-
document.body.removeChild(anchor);
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
// Resetting the resized columns and/or rows
|
|
67
|
-
export const resetResize = (
|
|
68
|
-
headerRows: any,
|
|
69
|
-
pageRows: any,
|
|
70
|
-
tableId: string,
|
|
71
|
-
columns: Columns | undefined,
|
|
72
|
-
resizable: 'none' | 'rows' | 'columns' | 'both'
|
|
73
|
-
) => {
|
|
74
|
-
// Run only if resizable is not none
|
|
75
|
-
if (resizable === 'columns' || resizable === 'both') {
|
|
76
|
-
headerRows.forEach((row) => {
|
|
77
|
-
row.cells.forEach((cell) => {
|
|
78
|
-
const minW = minWidth(cell.id, columns);
|
|
79
|
-
const fixedW = fixedWidth(cell.id, columns);
|
|
80
|
-
// If a fixedWidth is provided for a column, then reset the width to that value
|
|
81
|
-
fixedW &&
|
|
82
|
-
document
|
|
83
|
-
.getElementById(`th-${tableId}-${cell.id}`)
|
|
84
|
-
?.style.setProperty('width', `${fixedW}px`);
|
|
85
|
-
// If a minWidth is provided for a column, then reset the width to that value
|
|
86
|
-
minW &&
|
|
87
|
-
document
|
|
88
|
-
.getElementById(`th-${tableId}-${cell.id}`)
|
|
89
|
-
?.style.setProperty('width', `${minW}px`);
|
|
90
|
-
// If neither minWidth nor fixedWidth provided for a column, then reset the width to auto
|
|
91
|
-
!minW &&
|
|
92
|
-
!fixedW &&
|
|
93
|
-
document.getElementById(`th-${tableId}-${cell.id}`)?.style.setProperty('width', 'auto');
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (resizable === 'rows' || resizable === 'both') {
|
|
99
|
-
pageRows.forEach((row) => {
|
|
100
|
-
row.cells.forEach((cell) => {
|
|
101
|
-
// Reset all row heights to auto
|
|
102
|
-
document
|
|
103
|
-
.getElementById(`${tableId}-${cell.id}-${row.id}`)
|
|
104
|
-
?.style.setProperty('height', 'auto');
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
export const missingValuesFn = (
|
|
111
|
-
key: number | string,
|
|
112
|
-
missingValues: { [key: string | number]: string }
|
|
113
|
-
) => {
|
|
114
|
-
const foundKey =
|
|
115
|
-
typeof key === 'number' && key.toString().includes('e')
|
|
116
|
-
? Object.keys(missingValues).find((item) => {
|
|
117
|
-
return (item as string).toLowerCase() === key.toString().toLowerCase();
|
|
118
|
-
})
|
|
119
|
-
: typeof key === 'string' && parseInt(key).toString().length !== key.length && new Date(key)
|
|
120
|
-
? Object.keys(missingValues).find(
|
|
121
|
-
(item) => new Date(item).getTime() === new Date(key).getTime()
|
|
122
|
-
)
|
|
123
|
-
: key in missingValues
|
|
124
|
-
? key
|
|
125
|
-
: undefined;
|
|
126
|
-
|
|
127
|
-
return foundKey ? missingValues[foundKey] : key;
|
|
128
|
-
};
|
|
129
|
-
|
|
130
|
-
export const convertServerColumns = (
|
|
131
|
-
serverColumns: ServerColumn[],
|
|
132
|
-
columns: Columns | undefined
|
|
133
|
-
) => {
|
|
134
|
-
const columnsConfig: Columns = {};
|
|
135
|
-
|
|
136
|
-
serverColumns.forEach((col) => {
|
|
137
|
-
let instructions = {};
|
|
138
|
-
|
|
139
|
-
if (col.instructions?.displayPattern) {
|
|
140
|
-
let dp = col.instructions.displayPattern;
|
|
141
|
-
|
|
142
|
-
// Swap 'm' and 'M' to match the backend date format
|
|
143
|
-
for (let i = 0; i < col.instructions.displayPattern.length; i++) {
|
|
144
|
-
if (col.instructions.displayPattern[i] === 'm') {
|
|
145
|
-
dp = `${dp.slice(0, i)}M${dp.slice(i + 1)}`;
|
|
146
|
-
} else if (col.instructions.displayPattern[i] === 'M') {
|
|
147
|
-
dp = `${dp.slice(0, i)}m${dp.slice(i + 1)}`;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
instructions = {
|
|
152
|
-
toStringFn: (date: string) => {
|
|
153
|
-
if (col.instructions?.missingValues) {
|
|
154
|
-
const missingValue = missingValuesFn(date, col.instructions?.missingValues || {});
|
|
155
|
-
if (missingValue === date) {
|
|
156
|
-
return dateFormat(new Date(date), dp);
|
|
157
|
-
}
|
|
158
|
-
return missingValue;
|
|
159
|
-
} else {
|
|
160
|
-
return dateFormat(new Date(date), dp);
|
|
161
|
-
}
|
|
162
|
-
},
|
|
163
|
-
toSortableValueFn: (date: string) => new Date(date).getTime(),
|
|
164
|
-
toFilterableValueFn: (date: string) => new Date(date)
|
|
165
|
-
};
|
|
166
|
-
} else if (col.instructions?.missingValues) {
|
|
167
|
-
instructions = {
|
|
168
|
-
...instructions,
|
|
169
|
-
toStringFn: (key) => missingValuesFn(key, col.instructions?.missingValues || {})
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (columns && col.column in columns) {
|
|
174
|
-
columnsConfig[col.column] = {
|
|
175
|
-
...columns[col.column],
|
|
176
|
-
instructions
|
|
177
|
-
};
|
|
178
|
-
} else {
|
|
179
|
-
columnsConfig[col.column] = {
|
|
180
|
-
instructions
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
return columnsConfig;
|
|
186
|
-
};
|