mig-schema-table 4.0.5 → 4.0.7

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.
@@ -1,715 +0,0 @@
1
- var __rest = (this && this.__rest) || function (s, e) {
2
- var t = {};
3
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
4
- t[p] = s[p];
5
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
6
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
7
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
8
- t[p[i]] = s[p[i]];
9
- }
10
- return t;
11
- };
12
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
- import React from "react";
14
- import { createPortal } from "react-dom";
15
- import { VariableSizeGrid, VariableSizeList } from "react-window";
16
- import { localeFormat } from "../inc/date";
17
- import { defaultTranslate } from "../inc/string";
18
- import { SELECT_ALL_COLUMN_NAME, SELECT_ALL_COLUMN_WIDTH } from "./constants";
19
- import Td from "./Td";
20
- import { DEFAULT_DATE_FORMAT, DEFAULT_DATE_TIME_FORMAT, ENumberColumnFilterOperation, MINIMUM_COLUMN_WIDTH, } from "../inc/constant";
21
- import { parseLocationHash, serializeLocationHash } from "../inc/data";
22
- import Th, { EColumnFilterStatus } from "./Th";
23
- import ThMenu from "./ThMenu";
24
- import { saveAs } from "file-saver";
25
- import ColumnResizers from "./ColumnResizers";
26
- import { difference, isFinite, sum } from "lodash";
27
- import { Workbook } from "exceljs";
28
- const startOfTheWorldDate = new Date("1000-01-01 00:00:00Z");
29
- const numberFormatter = new Intl.NumberFormat("nl-NL");
30
- const currencyFormatter = new Intl.NumberFormat("nl-NL", {
31
- style: "currency",
32
- currency: "EUR",
33
- });
34
- function getSortByValue(propSchema, propConfig) {
35
- const { TdBody, sortByValue } = propConfig || {};
36
- if (sortByValue !== undefined) {
37
- return sortByValue;
38
- }
39
- if (!propSchema) {
40
- return false;
41
- }
42
- const { format, type } = propSchema;
43
- const isDate = format === null || format === void 0 ? void 0 : format.startsWith("date");
44
- return isDate || type === "boolean" || type === "integer" || !!TdBody;
45
- }
46
- function getIsColumnSortable(isTableSortable, propSchema, propConfig) {
47
- return !!(isTableSortable &&
48
- (propConfig === null || propConfig === void 0 ? void 0 : propConfig.isSortable) !== false &&
49
- (propSchema || (propConfig === null || propConfig === void 0 ? void 0 : propConfig.renderData) || (propConfig === null || propConfig === void 0 ? void 0 : propConfig.sort)));
50
- }
51
- function SchemaTable({ Heading = VariableSizeList, checkedIndexes, config, customElement, data, defaultColumnFilters, defaultSortAsc = false, defaultSortColumn, disabledCheckedIndexes, enableAutoFocus = true, enableRowCounter = true, getRowClassName, getRowSelected, isColumnFilterable = true, isExportable = true, isResizable = true, isSearchable = true, isSortable = true, maxHeight, onCheckedIndexesChange, onRowClick, onRowDoubleClick, onSearchEnter, rowHeight = 36, schema, searchPlaceholder, settingsStorageKey, style, translate = defaultTranslate, useFilterStateHash, width, tableRef, }) {
52
- var _a;
53
- const [columnNames, setColumnNames] = React.useState();
54
- const [resizeColumnIndex, setResizeColumnIndex] = React.useState(-1);
55
- const [sortColumn, setSortColumn] = React.useState(defaultSortColumn);
56
- const [sortAsc, setSortAsc] = React.useState(defaultSortAsc);
57
- const [thMenuConfig, setThMenuConfig] = React.useState();
58
- const isDataFunction = data instanceof Function;
59
- const [sourceData, setSourceData] = React.useState(isDataFunction ? undefined : data);
60
- const [columnWidths, setColumnWidths] = React.useState();
61
- const [locationHash, setLocationHash] = React.useState(useFilterStateHash ? parseLocationHash(window.location.hash) : null);
62
- const [searchQuery, setSearchQuery] = React.useState((locationHash === null || locationHash === void 0 ? void 0 : locationHash.searchQuery) || "");
63
- const [columnFilterMap, setColumnFilterMap] = React.useState((locationHash === null || locationHash === void 0 ? void 0 : locationHash.columnFilterMap) || defaultColumnFilters || {});
64
- const [isDirty, setIsDirty] = React.useState(false);
65
- React.useEffect(() => {
66
- const removeThMenuConfig = () => {
67
- setThMenuConfig(undefined);
68
- };
69
- window.addEventListener("resize", removeThMenuConfig);
70
- window.addEventListener("scroll", removeThMenuConfig);
71
- return () => {
72
- window.removeEventListener("resize", removeThMenuConfig);
73
- window.removeEventListener("scroll", removeThMenuConfig);
74
- };
75
- }, []);
76
- React.useEffect(() => {
77
- if (isDataFunction) {
78
- return;
79
- }
80
- setSourceData(data);
81
- }, [data, isDataFunction]);
82
- React.useEffect(() => {
83
- if (!isDataFunction || sourceData !== undefined) {
84
- return;
85
- }
86
- data({
87
- searchQuery,
88
- columnFilterMap,
89
- sortColumn,
90
- sortAsc,
91
- }).then(setSourceData);
92
- }, [
93
- columnFilterMap,
94
- data,
95
- isDataFunction,
96
- searchQuery,
97
- sortAsc,
98
- sortColumn,
99
- sourceData,
100
- ]);
101
- const { properties = {}, required = [] } = schema;
102
- const serializedStoredColumnNames = settingsStorageKey
103
- ? localStorage.getItem(`${settingsStorageKey}.columnNames`)
104
- : null;
105
- const serializedStoredColumnWidths = settingsStorageKey
106
- ? localStorage.getItem(`${settingsStorageKey}.columnWidths`)
107
- : null;
108
- React.useEffect(() => {
109
- const storedColumnNames = serializedStoredColumnNames
110
- ? JSON.parse(serializedStoredColumnNames)
111
- : undefined;
112
- let freshColumnNames = Object.keys(properties);
113
- if (onCheckedIndexesChange) {
114
- freshColumnNames.unshift(SELECT_ALL_COLUMN_NAME);
115
- }
116
- if (config) {
117
- Object.keys(config).forEach((configKey) => {
118
- if (!freshColumnNames.includes(configKey)) {
119
- freshColumnNames.push(configKey);
120
- }
121
- });
122
- const invisibleColumns = Object.entries(config).reduce((prev, [propName, propConfig]) => {
123
- if (propConfig.hidden) {
124
- prev.push(propName);
125
- }
126
- return prev;
127
- }, []);
128
- freshColumnNames = freshColumnNames
129
- .filter((key) => !invisibleColumns.includes(key))
130
- .sort((columnA, columnB) => {
131
- let orderA = config[columnA] ? config[columnA].order : undefined;
132
- if (orderA === undefined) {
133
- orderA = Object.keys(properties).findIndex((propName) => propName === columnA);
134
- }
135
- let orderB = config[columnB] ? config[columnB].order : undefined;
136
- if (orderB === undefined) {
137
- orderB = Object.keys(properties).findIndex((propName) => propName === columnB);
138
- }
139
- if (columnB === SELECT_ALL_COLUMN_NAME ||
140
- columnA === SELECT_ALL_COLUMN_NAME) {
141
- return 0;
142
- }
143
- if (orderA === -1) {
144
- return 1;
145
- }
146
- if (orderB === -1) {
147
- return -1;
148
- }
149
- return orderA - orderB;
150
- });
151
- }
152
- setColumnNames((storedColumnNames === null || storedColumnNames === void 0 ? void 0 : storedColumnNames.length) === freshColumnNames.length
153
- ? storedColumnNames
154
- : freshColumnNames);
155
- }, [config, onCheckedIndexesChange, properties, serializedStoredColumnNames]);
156
- const renderData = React.useMemo(() => sourceData && columnNames
157
- ? sourceData.map((object, rowIndex) => columnNames.reduce((prev, propName) => {
158
- var _a;
159
- const schema = properties[propName];
160
- const propConfig = config ? config[propName] : undefined;
161
- if (propConfig === null || propConfig === void 0 ? void 0 : propConfig.renderData) {
162
- prev[propName] = propConfig.renderData(object, rowIndex);
163
- return prev;
164
- }
165
- if (!schema || propName === SELECT_ALL_COLUMN_NAME) {
166
- prev[propName] = "";
167
- return prev;
168
- }
169
- const rawValue = object[propName];
170
- switch (schema.type) {
171
- case "array":
172
- prev[propName] =
173
- ((_a = schema.items) === null || _a === void 0 ? void 0 : _a.type) === "string" &&
174
- rawValue
175
- ? rawValue.map(translate).join(", ")
176
- : JSON.stringify(rawValue);
177
- return prev;
178
- case "boolean":
179
- prev[propName] = rawValue ? "✓" : "✕";
180
- return prev;
181
- case "number":
182
- case "integer":
183
- if (rawValue === undefined) {
184
- prev[propName] = "";
185
- return prev;
186
- }
187
- prev[propName] =
188
- schema.format === "currency"
189
- ? currencyFormatter.format(rawValue)
190
- : numberFormatter.format(rawValue);
191
- return prev;
192
- // @ts-ignore
193
- case "string":
194
- if (schema.format === "date" && rawValue) {
195
- prev[propName] = ["2999-12-31", "1970-01-01"].includes(rawValue)
196
- ? "-"
197
- : localeFormat(new Date(rawValue), (propConfig === null || propConfig === void 0 ? void 0 : propConfig.dateFormat) || DEFAULT_DATE_FORMAT);
198
- return prev;
199
- }
200
- if (schema.format === "date-time" && rawValue) {
201
- prev[propName] = localeFormat(new Date(rawValue), (propConfig === null || propConfig === void 0 ? void 0 : propConfig.dateFormat) || DEFAULT_DATE_TIME_FORMAT);
202
- return prev;
203
- }
204
- if (schema.enum) {
205
- prev[propName] = rawValue ? translate(rawValue) : "";
206
- return prev;
207
- }
208
- // fallthrough
209
- default:
210
- prev[propName] = rawValue ? `${rawValue}` : "";
211
- return prev;
212
- }
213
- }, { _index: rowIndex }))
214
- : undefined, [sourceData, columnNames, properties, config, translate]);
215
- const columnCount = columnNames ? columnNames.length : 0;
216
- const { dynamicWidthColumnCount, fixedWidthColumnsWidth } = React.useMemo(() => {
217
- let fixedWidthColumnsWidth = 0;
218
- let dynamicWidthColumnCount = 0;
219
- (columnNames || []).forEach((propName) => {
220
- if (propName === SELECT_ALL_COLUMN_NAME) {
221
- fixedWidthColumnsWidth += SELECT_ALL_COLUMN_WIDTH;
222
- return;
223
- }
224
- const propConfig = config ? config[propName] : undefined;
225
- if (propConfig === null || propConfig === void 0 ? void 0 : propConfig.width) {
226
- fixedWidthColumnsWidth += propConfig.width;
227
- }
228
- else {
229
- dynamicWidthColumnCount += 1;
230
- }
231
- }, 0);
232
- return { dynamicWidthColumnCount, fixedWidthColumnsWidth };
233
- }, [columnNames, config]);
234
- React.useEffect(() => {
235
- if (!columnNames) {
236
- return;
237
- }
238
- const storedColumnWidths = serializedStoredColumnWidths
239
- ? JSON.parse(serializedStoredColumnWidths)
240
- : undefined;
241
- const dynamicColumnWidth = Math.max(Math.floor((width - fixedWidthColumnsWidth) / dynamicWidthColumnCount), MINIMUM_COLUMN_WIDTH);
242
- let roundingDifference = (width - fixedWidthColumnsWidth) % dynamicWidthColumnCount;
243
- const freshColumnWidths = columnNames.map((propName) => {
244
- if (propName === SELECT_ALL_COLUMN_NAME) {
245
- return SELECT_ALL_COLUMN_WIDTH;
246
- }
247
- const propConfig = config ? config[propName] : undefined;
248
- if (propConfig === null || propConfig === void 0 ? void 0 : propConfig.width) {
249
- return propConfig === null || propConfig === void 0 ? void 0 : propConfig.width;
250
- }
251
- if (roundingDifference) {
252
- roundingDifference -= 1;
253
- return dynamicColumnWidth + 1;
254
- }
255
- return dynamicColumnWidth;
256
- });
257
- setColumnWidths((storedColumnWidths === null || storedColumnWidths === void 0 ? void 0 : storedColumnWidths.length) === freshColumnWidths.length
258
- ? storedColumnWidths
259
- : freshColumnWidths);
260
- }, [
261
- columnNames,
262
- config,
263
- dynamicWidthColumnCount,
264
- fixedWidthColumnsWidth,
265
- serializedStoredColumnWidths,
266
- settingsStorageKey,
267
- width,
268
- ]);
269
- const getColumnWidth = React.useCallback((columnIndex) => (columnWidths ? columnWidths[columnIndex] : 1), [columnWidths]);
270
- const filteredRenderData = React.useMemo(() => {
271
- if (!renderData ||
272
- (!isColumnFilterable && !isSearchable) ||
273
- isDataFunction) {
274
- return renderData;
275
- }
276
- return renderData.filter((item) => {
277
- const lcSearchQuery = searchQuery.toLowerCase();
278
- if (searchQuery &&
279
- columnNames &&
280
- !columnNames.find((columnName) => `${item[columnName]}`.toLowerCase().includes(lcSearchQuery))) {
281
- return false;
282
- }
283
- let result = true;
284
- Object.entries(columnFilterMap).forEach(([propName, columnFilterValue]) => {
285
- if (!result || columnFilterValue === undefined) {
286
- return;
287
- }
288
- const propConfig = config ? config[propName] : undefined;
289
- if (sourceData && (propConfig === null || propConfig === void 0 ? void 0 : propConfig.filter)) {
290
- result = propConfig.filter(sourceData[item._index], columnFilterValue);
291
- return;
292
- }
293
- const propSchema = properties[propName];
294
- // @ts-ignore
295
- const rawValue = sourceData[item._index][propName];
296
- switch (propSchema === null || propSchema === void 0 ? void 0 : propSchema.type) {
297
- case "boolean":
298
- case "number":
299
- case "integer":
300
- if (typeof columnFilterValue === "object") {
301
- if (columnFilterValue.filterEmpty && rawValue === undefined) {
302
- result = false;
303
- }
304
- for (const operation of Object.keys(ENumberColumnFilterOperation)) {
305
- const operationFilterValue = columnFilterValue[operation];
306
- if (result && isFinite(operationFilterValue)) {
307
- switch (operation) {
308
- case ENumberColumnFilterOperation.EQ:
309
- if (rawValue !== operationFilterValue) {
310
- result = false;
311
- }
312
- break;
313
- case ENumberColumnFilterOperation.GT:
314
- if (rawValue <= operationFilterValue) {
315
- result = false;
316
- }
317
- break;
318
- case ENumberColumnFilterOperation.LT:
319
- if (rawValue >= operationFilterValue) {
320
- result = false;
321
- }
322
- break;
323
- }
324
- }
325
- }
326
- }
327
- else {
328
- result = rawValue === columnFilterValue;
329
- }
330
- break;
331
- // @ts-ignore
332
- case "string":
333
- if (typeof columnFilterValue === "object" &&
334
- (propSchema.format === "date" ||
335
- propSchema.format === "date-time")) {
336
- const { from, to, filterEmpty } = columnFilterValue;
337
- if (!rawValue) {
338
- result = !filterEmpty;
339
- }
340
- else {
341
- const rawDate = rawValue ? new Date(rawValue) : undefined;
342
- if ((from && (!rawDate || rawDate < from)) ||
343
- (to && (!rawDate || rawDate > to))) {
344
- result = false;
345
- }
346
- }
347
- return;
348
- }
349
- // fall through
350
- default:
351
- // fallback by looking at the render value
352
- if (propSchema === null || propSchema === void 0 ? void 0 : propSchema.enum) {
353
- result = rawValue === columnFilterValue;
354
- return;
355
- }
356
- result = `${item[propName]}`
357
- .toLowerCase()
358
- .includes(`${columnFilterValue}`.toLowerCase());
359
- }
360
- });
361
- return result;
362
- });
363
- }, [
364
- renderData,
365
- isColumnFilterable,
366
- isSearchable,
367
- isDataFunction,
368
- searchQuery,
369
- columnNames,
370
- columnFilterMap,
371
- config,
372
- sourceData,
373
- properties,
374
- ]);
375
- // Sort the filtered data
376
- const sortedRenderData = React.useMemo(() => {
377
- var _a;
378
- if (!sortColumn || !filteredRenderData || !sourceData || isDataFunction) {
379
- return filteredRenderData;
380
- }
381
- const sortSchema = properties[sortColumn];
382
- const propConfig = config ? config[sortColumn] : undefined;
383
- const columnSort = propConfig === null || propConfig === void 0 ? void 0 : propConfig.sort;
384
- if (columnSort) {
385
- return filteredRenderData.sort((a, b) => {
386
- const aData = sourceData[a._index];
387
- const bData = sourceData[b._index];
388
- if (!aData) {
389
- return 1;
390
- }
391
- if (!bData) {
392
- return -1;
393
- }
394
- return columnSort(aData, bData, sortAsc);
395
- });
396
- }
397
- const isDate = sortSchema && ((_a = sortSchema.format) === null || _a === void 0 ? void 0 : _a.startsWith("date"));
398
- const sortByValue = getSortByValue(sortSchema, propConfig);
399
- return filteredRenderData.sort((a, b) => {
400
- let x = sortByValue && sourceData[a._index]
401
- ? // @ts-ignore
402
- sourceData[a._index][sortColumn]
403
- : a[sortColumn].toLowerCase();
404
- let y = sortByValue && sourceData[b._index]
405
- ? // @ts-ignore
406
- sourceData[b._index][sortColumn]
407
- : b[sortColumn].toLowerCase();
408
- if (sortByValue && isDate) {
409
- x = new Date(x);
410
- if (isNaN(x)) {
411
- x = startOfTheWorldDate;
412
- }
413
- y = new Date(y);
414
- if (isNaN(y)) {
415
- y = startOfTheWorldDate;
416
- }
417
- }
418
- if (x === y) {
419
- return 0;
420
- }
421
- if (!x) {
422
- return sortAsc ? -1 : 1;
423
- }
424
- if (!y) {
425
- return sortAsc ? 1 : -1;
426
- }
427
- return (x < y ? 1 : -1) * (sortAsc ? -1 : 1);
428
- });
429
- }, [
430
- sortColumn,
431
- filteredRenderData,
432
- sourceData,
433
- isDataFunction,
434
- properties,
435
- config,
436
- sortAsc,
437
- ]);
438
- const onSelectAllIndexesHandler = React.useCallback(() => {
439
- if (!onCheckedIndexesChange || !filteredRenderData) {
440
- return;
441
- }
442
- onCheckedIndexesChange(filteredRenderData
443
- .map((el) => el._index)
444
- .filter((index) => !(disabledCheckedIndexes === null || disabledCheckedIndexes === void 0 ? void 0 : disabledCheckedIndexes.includes(index))));
445
- }, [onCheckedIndexesChange, filteredRenderData, disabledCheckedIndexes]);
446
- const isAllRowsChecked = React.useMemo(() => {
447
- const tableData = [...(filteredRenderData || [])].filter((el) => (checkedIndexes ? checkedIndexes.includes(el._index) : true) ||
448
- (disabledCheckedIndexes
449
- ? !disabledCheckedIndexes.includes(el._index)
450
- : true));
451
- return ((checkedIndexes === null || checkedIndexes === void 0 ? void 0 : checkedIndexes.length) !== 0 &&
452
- tableData.length === (checkedIndexes === null || checkedIndexes === void 0 ? void 0 : checkedIndexes.length));
453
- }, [checkedIndexes, disabledCheckedIndexes, filteredRenderData]);
454
- const disableColumnFilter = React.useCallback((propName) => {
455
- const newColumnFilterMap = Object.assign({}, columnFilterMap);
456
- delete newColumnFilterMap[propName];
457
- if (isDataFunction) {
458
- setIsDirty(true);
459
- }
460
- setColumnFilterMap(newColumnFilterMap);
461
- }, [columnFilterMap, isDataFunction]);
462
- const onSetSortColumn = React.useCallback((x) => {
463
- if (isDataFunction) {
464
- setIsDirty(true);
465
- }
466
- setSortColumn(x);
467
- }, [isDataFunction]);
468
- const onSetSortAsc = React.useCallback((x) => {
469
- if (isDataFunction) {
470
- setIsDirty(true);
471
- }
472
- setSortAsc(x);
473
- }, [isDataFunction]);
474
- const onColumnWidthsChange = React.useCallback((newColumnWidths) => {
475
- if (settingsStorageKey) {
476
- localStorage.setItem(`${settingsStorageKey}.columnWidths`, JSON.stringify(newColumnWidths));
477
- }
478
- setColumnWidths(newColumnWidths);
479
- }, [settingsStorageKey]);
480
- const onColumnPositionChange = React.useCallback((dragColumnName, dropColumnName) => {
481
- if (!columnNames || !columnWidths) {
482
- return;
483
- }
484
- // First move the actual name...
485
- const dragColumnIndex = columnNames.indexOf(dragColumnName);
486
- let newColumnNames = [...columnNames];
487
- newColumnNames.splice(dragColumnIndex, 1);
488
- const dropColumnIndex = newColumnNames.indexOf(dropColumnName);
489
- newColumnNames.splice(dropColumnIndex + 1, 0, dragColumnName);
490
- localStorage.setItem(`${settingsStorageKey}.columnNames`, JSON.stringify(newColumnNames));
491
- setColumnNames(newColumnNames);
492
- // ...then make sure the width of column is moved as well
493
- let newColumnWidths = [...columnWidths];
494
- const draggedColumnWidth = newColumnWidths[dragColumnIndex];
495
- newColumnWidths.splice(dragColumnIndex, 1);
496
- newColumnWidths.splice(dropColumnIndex + 1, 0, draggedColumnWidth);
497
- onColumnWidthsChange(newColumnWidths);
498
- }, [columnNames, columnWidths, onColumnWidthsChange, settingsStorageKey]);
499
- const ConfiguredTh = React.useCallback(({ style, index }) => {
500
- if (!columnNames || !isFinite(style.left)) {
501
- return null;
502
- }
503
- const propName = columnNames[index];
504
- const propSchema = (propName === SELECT_ALL_COLUMN_NAME
505
- ? { type: "boolean" }
506
- : properties[propName]);
507
- const propConfig = config ? config[propName] : undefined;
508
- let columnFilterStatus = isColumnFilterable &&
509
- (propSchema || (propConfig === null || propConfig === void 0 ? void 0 : propConfig.FilterMenu)) &&
510
- (propConfig === null || propConfig === void 0 ? void 0 : propConfig.isFilterable) !== false
511
- ? EColumnFilterStatus.AVAILABLE
512
- : EColumnFilterStatus.UNAVAILABLE;
513
- if (columnFilterMap[propName] !== undefined) {
514
- columnFilterStatus = EColumnFilterStatus.ACTIVE;
515
- }
516
- return (_jsx(Th, { columnFilterStatus: columnFilterStatus,
517
- // disableColumnFilter={disableColumnFilter}
518
- isAllChecked: isAllRowsChecked, isSortable: getIsColumnSortable(!!isSortable, propSchema, propConfig), numberOfSelectedRows: checkedIndexes === null || checkedIndexes === void 0 ? void 0 : checkedIndexes.length, onSelectAllIndexesHandler: onSelectAllIndexesHandler, onColumnPositionChange: resizeColumnIndex === -1 && settingsStorageKey
519
- ? onColumnPositionChange
520
- : undefined, propConfig: propConfig, propIsRequired: required.includes(propName), propName: propName, schema: propSchema, setMenuConfig: setThMenuConfig, setSortAsc: onSetSortAsc, setSortColumn: onSetSortColumn, sortAsc: sortColumn === propName ? sortAsc : undefined, style: style, translate: translate }));
521
- }, [
522
- checkedIndexes === null || checkedIndexes === void 0 ? void 0 : checkedIndexes.length,
523
- columnFilterMap,
524
- columnNames,
525
- config,
526
- isAllRowsChecked,
527
- isColumnFilterable,
528
- isSortable,
529
- onColumnPositionChange,
530
- onSelectAllIndexesHandler,
531
- onSetSortAsc,
532
- onSetSortColumn,
533
- properties,
534
- required,
535
- resizeColumnIndex,
536
- settingsStorageKey,
537
- sortAsc,
538
- sortColumn,
539
- translate,
540
- ]);
541
- const SchemaTableTd = React.useCallback(({ columnIndex, rowIndex, style }) => {
542
- const propName = columnNames[columnIndex];
543
- const propSchema = (propName === SELECT_ALL_COLUMN_NAME
544
- ? { type: "boolean" }
545
- : properties[propName]);
546
- return sourceData ? (_jsx(Td, { checkedIndexes: checkedIndexes, disabledCheckedIndexes: disabledCheckedIndexes, columnIndex: columnIndex, data: sourceData, getRowClassName: getRowClassName, getRowSelected: getRowSelected, onCheckedIndexesChange: onCheckedIndexesChange, onRowClick: onRowClick, onRowDoubleClick: onRowDoubleClick, propConfig: config ? config[propName] : undefined, propName: propName, propSchema: propSchema, rowIndex: rowIndex, sortedRenderData: sortedRenderData, style: style, translate: translate })) : null;
547
- }, [
548
- columnNames,
549
- properties,
550
- sourceData,
551
- checkedIndexes,
552
- disabledCheckedIndexes,
553
- getRowClassName,
554
- getRowSelected,
555
- onCheckedIndexesChange,
556
- onRowClick,
557
- onRowDoubleClick,
558
- config,
559
- sortedRenderData,
560
- translate,
561
- ]);
562
- const onSearchChange = React.useCallback((e) => {
563
- if (isDataFunction) {
564
- setIsDirty(true);
565
- }
566
- setSearchQuery(e.currentTarget.value);
567
- }, [isDataFunction]);
568
- const refreshData = React.useCallback(() => {
569
- setIsDirty(false);
570
- setSourceData(undefined);
571
- }, []);
572
- const onInputKeyDown = React.useCallback((e) => {
573
- if (e.key === "Enter") {
574
- setThMenuConfig(undefined);
575
- if (isDirty) {
576
- refreshData();
577
- }
578
- if (onSearchEnter &&
579
- e.currentTarget.className === "mig-schema-table__search") {
580
- onSearchEnter(searchQuery);
581
- }
582
- }
583
- }, [isDirty, searchQuery, onSearchEnter, refreshData]);
584
- const getRowHeight = React.useCallback(() => rowHeight, [rowHeight]);
585
- const rowWidth = React.useMemo(() => sum(columnWidths), [columnWidths]);
586
- const rowCount = React.useMemo(() => (sortedRenderData ? sortedRenderData.length : 0), [sortedRenderData]);
587
- const tableBodyHeight = React.useMemo(() => {
588
- const rowsHeight = rowHeight * rowCount;
589
- const rowsMaxHeight = maxHeight ? maxHeight - (isSearchable ? 50 : 0) : 0;
590
- return rowsMaxHeight && rowsMaxHeight < rowsHeight
591
- ? rowsMaxHeight
592
- : rowsHeight;
593
- }, [maxHeight, isSearchable, rowCount, rowHeight]);
594
- const onPopoverClose = React.useCallback((e) => {
595
- setThMenuConfig(undefined);
596
- e.preventDefault();
597
- e.stopPropagation();
598
- }, []);
599
- React.useEffect(() => {
600
- if (!useFilterStateHash) {
601
- return;
602
- }
603
- const onHashChange = () => {
604
- setLocationHash(parseLocationHash(window.location.hash));
605
- };
606
- window.addEventListener("hashchange", onHashChange);
607
- return () => {
608
- window.removeEventListener("hashchange", onHashChange);
609
- };
610
- }, [useFilterStateHash]);
611
- React.useEffect(() => {
612
- if (!useFilterStateHash) {
613
- return;
614
- }
615
- setColumnFilterMap((locationHash === null || locationHash === void 0 ? void 0 : locationHash.columnFilterMap) || defaultColumnFilters || {});
616
- setSearchQuery((locationHash === null || locationHash === void 0 ? void 0 : locationHash.searchQuery) || "");
617
- }, [locationHash, useFilterStateHash, defaultColumnFilters]);
618
- const onSchemaColumnFilterChange = React.useCallback((newColumnFilterValue, persistState) => {
619
- if (!thMenuConfig) {
620
- return;
621
- }
622
- if (isDataFunction) {
623
- setIsDirty(true);
624
- }
625
- if (useFilterStateHash && persistState !== false) {
626
- window.location.hash = serializeLocationHash(Object.assign(Object.assign({}, locationHash), { columnFilterMap: Object.assign(Object.assign({}, columnFilterMap), { [thMenuConfig.propName]: newColumnFilterValue }) }));
627
- return;
628
- }
629
- if (newColumnFilterValue === undefined) {
630
- disableColumnFilter(thMenuConfig.propName);
631
- return;
632
- }
633
- setColumnFilterMap((columnFilterMap) => (Object.assign(Object.assign({}, columnFilterMap), { [thMenuConfig.propName]: newColumnFilterValue })));
634
- }, [
635
- columnFilterMap,
636
- disableColumnFilter,
637
- isDataFunction,
638
- locationHash,
639
- thMenuConfig,
640
- useFilterStateHash,
641
- ]);
642
- const onClearFiltersButtonClick = React.useCallback(() => {
643
- if (useFilterStateHash) {
644
- window.location.hash = serializeLocationHash({
645
- columnFilterMap: {},
646
- searchQuery: "",
647
- });
648
- return;
649
- }
650
- setColumnFilterMap({});
651
- setSearchQuery("");
652
- }, [useFilterStateHash]);
653
- const onSearchBlur = React.useCallback(() => {
654
- const oldSearchQuery = (locationHash === null || locationHash === void 0 ? void 0 : locationHash.searchQuery) || "";
655
- if (useFilterStateHash &&
656
- // prevent hash change for undefined vs empty string compare
657
- (searchQuery || oldSearchQuery) &&
658
- searchQuery !== oldSearchQuery) {
659
- window.location.hash = serializeLocationHash(Object.assign(Object.assign({}, locationHash), { searchQuery }));
660
- }
661
- }, [locationHash, searchQuery, useFilterStateHash]);
662
- const onExportDataClick = React.useCallback((e) => {
663
- e.preventDefault();
664
- e.stopPropagation();
665
- if (!sortedRenderData) {
666
- return;
667
- }
668
- const workbook = new Workbook();
669
- const worksheet = workbook.addWorksheet("Data");
670
- if (!sortedRenderData.length) {
671
- return;
672
- }
673
- worksheet.addRow(difference(Object.keys(sortedRenderData[0]), [
674
- "_index",
675
- "SELECT_ALL_COLUMN_NAME",
676
- ]));
677
- worksheet.getRow(1).font = { bold: true };
678
- worksheet.addRows(sortedRenderData.map((row) => {
679
- const { _index, SELECT_ALL_COLUMN_NAME } = row, data = __rest(row, ["_index", "SELECT_ALL_COLUMN_NAME"]);
680
- return Object.values(data);
681
- }));
682
- // Save the workbook to a Blob
683
- workbook.xlsx
684
- .writeBuffer()
685
- .then((buffer) => {
686
- const blob = new Blob([buffer], {
687
- type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
688
- });
689
- saveAs(blob, "export.xlsx");
690
- })
691
- .catch((error) => {
692
- console.error("Error generating Excel file:", error);
693
- });
694
- }, [sortedRenderData]);
695
- const onClearSettingsButtonClick = React.useCallback(() => {
696
- if (!settingsStorageKey) {
697
- return;
698
- }
699
- localStorage.removeItem(`${settingsStorageKey}.columnNames`);
700
- localStorage.removeItem(`${settingsStorageKey}.columnWidths`);
701
- setColumnWidths(undefined);
702
- }, [settingsStorageKey]);
703
- return (_jsxs("div", Object.assign({ className: `mig-schema-table${onRowClick ? " mig-schema-table--clickable-rows" : ""}`, style: Object.assign(Object.assign({}, style), { width: Math.min(rowWidth, width) }), role: "table" }, { children: [_jsxs("div", Object.assign({ className: "mig-schema-table__action-container" }, { children: [_jsx("div", { children: isSearchable ? (_jsx("input", { className: "mig-schema-table__search", type: "text", name: "search", autoComplete: "off", placeholder: searchPlaceholder || "Search...", value: searchQuery, onChange: onSearchChange, onKeyDown: onInputKeyDown, autoFocus: enableAutoFocus, onBlur: onSearchBlur })) : null }), customElement || (_jsx("div", { className: "mig-schema-table__custom_element_placeholder" })), enableRowCounter ? (_jsx("span", Object.assign({ className: "mig-schema-table__row_counter" }, { children: translate("showingFilteredCountOfTotalCount", (sortedRenderData === null || sortedRenderData === void 0 ? void 0 : sortedRenderData.length) || 0, data.length) }))) : null, isExportable ? (_jsx("button", Object.assign({ onClick: onExportDataClick, style: { marginLeft: 8 }, disabled: !(sortedRenderData === null || sortedRenderData === void 0 ? void 0 : sortedRenderData.length) }, { children: translate("exportData") }))) : null, isSearchable || isColumnFilterable ? (_jsx("button", Object.assign({ onClick: onClearFiltersButtonClick, style: { marginLeft: 8 }, disabled: Object.keys(columnFilterMap).length + searchQuery.length === 0 }, { children: translate("clearFilters") }))) : null, settingsStorageKey ? (_jsx("button", Object.assign({ onClick: onClearSettingsButtonClick, style: { marginLeft: 8 }, disabled: !serializedStoredColumnNames && !serializedStoredColumnWidths }, { children: translate("clearSettings") }))) : null] })), columnNames && columnWidths ? (_jsxs("div", Object.assign({ className: "mig-schema-table__column_resize_container" }, { children: [_jsx(Heading, Object.assign({ height: 50, itemCount: columnCount, itemSize: getColumnWidth, layout: "horizontal", width: rowWidth, sortAsc: sortAsc, setSortAsc: onSetSortAsc, setSortColumn: onSetSortColumn, sortColumn: sortColumn, sortedRenderData: sortedRenderData, className: "mig-schema-table__th-row" }, { children: ConfiguredTh }), `thead_${rowWidth}_${sortColumn}_${sortAsc}_${searchQuery}_${columnWidths.join(" ")}`), sourceData && !isDirty ? (_jsx(VariableSizeGrid, Object.assign({ className: "mig-schema-table__tbody", height: tableBodyHeight, width: rowWidth, columnWidth: getColumnWidth, rowHeight: getRowHeight, columnCount: columnCount, rowCount: rowCount, ref: tableRef }, { children: SchemaTableTd }), `tbody_${tableBodyHeight}_${rowWidth}_${sortColumn}_${sortAsc}_${searchQuery}_${columnCount}_${columnWidths.join(" ")}`)) : (_jsx("div", Object.assign({ style: {
704
- width: rowWidth,
705
- height: Math.max(50, tableBodyHeight),
706
- border: "1px solid #BBB",
707
- textAlign: "center",
708
- display: "flex",
709
- backgroundColor: "#CCC",
710
- alignItems: "center",
711
- justifyContent: "center",
712
- } }, { children: isDirty ? (_jsx("button", Object.assign({ onClick: refreshData, className: "btn border" }, { children: "Refresh data" }))) : (_jsx("div", { children: "\u231B Loading..." })) }))), isResizable ? (_jsx(ColumnResizers, { columnWidths: columnWidths, onColumnWidthsChange: onColumnWidthsChange, resizeColumnIndex: resizeColumnIndex, setResizeColumnIndex: setResizeColumnIndex, tableBodyHeight: tableBodyHeight })) : null] }))) : null, createPortal(thMenuConfig ? (_jsx(ThMenu, { isFilterable: isColumnFilterable &&
713
- ((_a = thMenuConfig.propConfig) === null || _a === void 0 ? void 0 : _a.isFilterable) !== false, isSortable: getIsColumnSortable(!!isSortable, schema.properties[thMenuConfig.propName], thMenuConfig.propConfig), onChange: onSchemaColumnFilterChange, onClose: onPopoverClose, onInputKeyDown: onInputKeyDown, propConfig: thMenuConfig.propConfig, propIsRequired: thMenuConfig.propIsRequired, propName: thMenuConfig.propName, propSchema: schema.properties[thMenuConfig.propName], referenceElement: thMenuConfig.referenceElement, setSortAsc: setSortAsc, setSortColumn: setSortColumn, translate: translate, value: columnFilterMap[thMenuConfig.propName] })) : null, document.body)] })));
714
- }
715
- export default React.memo(SchemaTable);