tp-react-elements 2.0.3 → 2.0.5
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 +6 -2
- package/dist/_virtual/index.esm11.js +2 -2
- package/dist/_virtual/index.esm12.js +2 -2
- package/dist/_virtual/index.esm13.js +2 -2
- package/dist/_virtual/index.esm14.js +2 -2
- package/dist/_virtual/index.esm4.js +2 -2
- package/dist/_virtual/index.esm5.js +2 -2
- package/dist/_virtual/index.esm6.js +2 -2
- package/dist/components/DateRangePicker/DateRangePicker.esm.js +49 -72
- package/dist/components/Form/FormRender.esm.js +1 -1
- package/dist/components/FormComponents/DatePicker/DatepickerWrapperV2.esm.js +10 -15
- package/dist/components/FormComponents/DatePicker/DatetimepickerWrapper.esm.js +53 -61
- package/dist/components/FormComponents/FileUpload/FormRenderFileUpload.esm.js +54 -68
- package/dist/components/FormComponents/FileUpload/FormRenderMultiFileUpload.esm.js +61 -76
- package/dist/components/FormComponents/FileUpload/MultiFileWithPreview.esm.js +103 -132
- package/dist/components/FormComponents/FormNumberField/FormNumberField.d.ts +0 -38
- package/dist/components/FormComponents/FormNumberField/FormNumberField.esm.js +32 -97
- package/dist/components/FormComponents/FormNumberField/FormNumberFieldDecimal.esm.js +44 -38
- package/dist/components/FormComponents/FormTextField/FormTextField.esm.js +3 -3
- package/dist/components/FormComponents/FormTextFieldWithSelect/FormTextFieldWithSelect.esm.js +3 -2
- package/dist/components/FormComponents/PasswordField/PasswordField.esm.js +4 -4
- package/dist/components/FormComponents/RichTextEditor/RichTextEditor.esm.js +23 -22
- package/dist/components/FormComponents/Select/SearchableSelect.esm.js +9 -9
- package/dist/components/FormComponents/TimePicker/TimePicker.esm.js +19 -19
- package/dist/components/FormComponents/index.esm.js +2 -2
- package/dist/components/ModalField/ConfirmationDialog.esm.js +3 -3
- package/dist/components/ModalField/ModalField.esm.js +5 -12
- package/dist/components/PaginatedGrid/DynamicFilterBar.d.ts +17 -2
- package/dist/components/PaginatedGrid/DynamicFilterBar.esm.js +161 -61
- package/dist/components/PaginatedGrid/GenericPaginatedGrid.d.ts +21 -3
- package/dist/components/PaginatedGrid/GenericPaginatedGrid.esm.js +133 -92
- package/dist/components/SelectField/MultiSelectFieldComponent.esm.js +3 -3
- package/dist/components/SessionTimeOut/SessionTimeOut.esm.js +33 -34
- package/dist/node_modules/react-date-range/dist/components/DateInput/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/DateRange/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/DateRangePicker/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/DayCell/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/DefinedRange/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/InputRangeField/index.esm.js +1 -1
- package/dist/node_modules/react-date-range/dist/components/Month/index.esm.js +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
2
2
|
import { useMemo, useState, useRef, useLayoutEffect, useCallback } from 'react';
|
|
3
|
-
import
|
|
3
|
+
import * as XLSX from 'xlsx-js-style';
|
|
4
|
+
import { MRT_ToggleGlobalFilterButton, MRT_ShowHideColumnsButton, MRT_ToggleDensePaddingButton, MRT_ToggleFullScreenButton, useMaterialReactTable, MaterialReactTable } from 'material-react-table';
|
|
4
5
|
import { useQuery, keepPreviousData } from '@tanstack/react-query';
|
|
5
6
|
import { Box, Tooltip, IconButton, GlobalStyles, Typography, Select, MenuItem, CircularProgress } from '@mui/material';
|
|
6
7
|
import RefreshIcon from '@mui/icons-material/Refresh';
|
|
@@ -52,6 +53,8 @@ const buildBodyGlobalStyles = (bodyFont) => ({
|
|
|
52
53
|
'.tp-gpg-root .MuiTableBody-root .MuiTableCell-root': {
|
|
53
54
|
fontSize: `${bodyFont} !important`,
|
|
54
55
|
lineHeight: 1.35,
|
|
56
|
+
borderRight: '1px solid rgba(224,224,224,1)',
|
|
57
|
+
userSelect: 'text',
|
|
55
58
|
},
|
|
56
59
|
});
|
|
57
60
|
const buildHeaderGlobalStyles = (headerMin, headerMax, headerFont, headerBgColor) => {
|
|
@@ -191,7 +194,7 @@ const OverlayLoader = ({ message }) => (jsxs(Box, { sx: {
|
|
|
191
194
|
bgcolor: 'rgba(255,255,255,0.80)', backdropFilter: 'blur(2px)',
|
|
192
195
|
zIndex: 10, gap: 1.5,
|
|
193
196
|
}, children: [jsx(CircularProgress, { size: 50, thickness: 4 }), jsx(Typography, { variant: "body2", color: "text.secondary", fontWeight: 500, children: message })] }));
|
|
194
|
-
const PaginationFooter = ({ pageIndex, pageSize, totalRecords, isFetching, isLoading, canPrev, canNext, onFirst, onPrev, onNext, onLast, onPageSizeChange, pageSizeOptions, density, }) => {
|
|
197
|
+
const PaginationFooter = ({ pageIndex, pageSize, totalRecords, isFetching, isLoading, canPrev, canNext, onFirst, onPrev, onNext, onLast, onPageSizeChange, pageSizeOptions, density, gridId, }) => {
|
|
195
198
|
const fs = density.footerFontSize;
|
|
196
199
|
const selectH = density.footerMinHeight - 8;
|
|
197
200
|
const startRow = totalRecords === 0 ? 0 : pageIndex * pageSize + 1;
|
|
@@ -203,7 +206,7 @@ const PaginationFooter = ({ pageIndex, pageSize, totalRecords, isFetching, isLoa
|
|
|
203
206
|
bgcolor: 'background.paper', flexWrap: 'wrap',
|
|
204
207
|
minHeight: density.footerMinHeight,
|
|
205
208
|
flexShrink: 0,
|
|
206
|
-
}, children: [jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.75 }, children: [jsx(Typography, { sx: { fontSize: fs }, color: "text.secondary", noWrap: true, children: "Rows per page:" }), jsx(Select, { value: pageSize, onChange: (e) => onPageSizeChange(Number(e.target.value)), size: "small", variant: "outlined", sx: {
|
|
209
|
+
}, children: [jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.75 }, children: [jsx(Typography, { sx: { fontSize: fs }, color: "text.secondary", noWrap: true, children: "Rows per page:" }), jsx(Select, { value: pageSize, onChange: (e) => onPageSizeChange(Number(e.target.value)), inputProps: { id: `${gridId}_page_size_select` }, size: "small", variant: "outlined", sx: {
|
|
207
210
|
height: selectH, fontSize: fs - 1, minWidth: 72,
|
|
208
211
|
'.MuiSelect-select': { py: '2px !important' },
|
|
209
212
|
'.MuiOutlinedInput-notchedOutline': { borderColor: 'divider' },
|
|
@@ -211,23 +214,31 @@ const PaginationFooter = ({ pageIndex, pageSize, totalRecords, isFetching, isLoa
|
|
|
211
214
|
? 'Loading…'
|
|
212
215
|
: totalRecords === 0
|
|
213
216
|
? 'No records'
|
|
214
|
-
: `${startRow.toLocaleString()}–${endRow.toLocaleString()} of ${totalRecords.toLocaleString()}` }), jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.25 }, children: [jsx(Tooltip, { title: "First page", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: onFirst, disabled: !canPrev, sx: { p: 0.5 }, children: jsx(FirstPageIcon, { sx: { fontSize: density.footerIconSize } }) }) }) }), jsx(Tooltip, { title: "Previous page", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: onPrev, disabled: !canPrev, sx: { p: 0.5 }, children: jsx(ChevronLeftIcon, { sx: { fontSize: density.footerIconSize } }) }) }) }), jsx(Typography, { fontWeight: 600, sx: {
|
|
217
|
+
: `${startRow.toLocaleString()}–${endRow.toLocaleString()} of ${totalRecords.toLocaleString()}` }), jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.25 }, children: [jsx(Tooltip, { title: "First page", children: jsx("span", { children: jsx(IconButton, { id: `${gridId}_first_page_icon`, size: "small", onClick: onFirst, disabled: !canPrev, sx: { p: 0.5 }, children: jsx(FirstPageIcon, { sx: { fontSize: density.footerIconSize } }) }) }) }), jsx(Tooltip, { title: "Previous page", children: jsx("span", { children: jsx(IconButton, { id: `${gridId}_prev_page_icon`, size: "small", onClick: onPrev, disabled: !canPrev, sx: { p: 0.5 }, children: jsx(ChevronLeftIcon, { sx: { fontSize: density.footerIconSize } }) }) }) }), jsx(Typography, { fontWeight: 600, sx: {
|
|
215
218
|
mx: 0.5,
|
|
216
219
|
minWidth: density.footerMinHeight - 12,
|
|
217
220
|
height: density.footerMinHeight - 12,
|
|
218
221
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
219
222
|
borderRadius: 1, border: '1px solid', borderColor: 'primary.main',
|
|
220
223
|
color: 'primary.main', bgcolor: 'rgba(25,118,210,0.07)', fontSize: fs - 1,
|
|
221
|
-
}, children: pageIndex + 1 }), jsx(Tooltip, { title: "Next page", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: onNext, disabled: !canNext, sx: { p: 0.5 }, children: jsx(ChevronRightIcon, { sx: { fontSize: density.footerIconSize } }) }) }) }), jsx(Tooltip, { title: "Last page", children: jsx("span", { children: jsx(IconButton, { size: "small", onClick: onLast, disabled: !canNext, sx: { p: 0.5 }, children: jsx(LastPageIcon, { sx: { fontSize: density.footerIconSize } }) }) }) })] })] }));
|
|
224
|
+
}, children: pageIndex + 1 }), jsx(Tooltip, { title: "Next page", children: jsx("span", { children: jsx(IconButton, { id: `${gridId}_next_page_icon`, size: "small", onClick: onNext, disabled: !canNext, sx: { p: 0.5 }, children: jsx(ChevronRightIcon, { sx: { fontSize: density.footerIconSize } }) }) }) }), jsx(Tooltip, { title: "Last page", children: jsx("span", { children: jsx(IconButton, { id: `${gridId}_last_page_icon`, size: "small", onClick: onLast, disabled: !canNext, sx: { p: 0.5 }, children: jsx(LastPageIcon, { sx: { fontSize: density.footerIconSize } }) }) }) })] })] }));
|
|
222
225
|
};
|
|
223
226
|
// ─── GenericPaginatedGrid ─────────────────────────────────────────────────────
|
|
224
|
-
function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize = 10000, exportFilename = 'export', tableHeight, tableMinHeight = '300px', tableMaxHeight, autoFillViewport = true, layoutMode = 'grid', uiDensity = 'default', uiDensityOptions, pageSizeOptions = [1000, 5000, 10000], showGlobalSearchByDefault =
|
|
227
|
+
function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs, defaultFilters, defaultVisibleFilterIds, batchSize = 10000, exportFilename = 'export', gridId, tableHeight, tableMinHeight = '300px', tableMaxHeight, autoFillViewport = true, layoutMode = 'grid', uiDensity = 'default', uiDensityOptions, pageSizeOptions = [1000, 5000, 10000], showGlobalSearchByDefault = false, headerBgColor, exportHeaderBgColor, exportHeaderTextColor, headerMinHeight, headerMaxHeight, headerMaxLines, headerFontSize, bodyFontSize, maxVisibleFilters = 4, muiTableBodyCellProps: gridBodyCellProps, muiTableHeadCellProps: gridHeadCellProps, renderDetailPanel, enableExpanding = !!renderDetailPanel, }) {
|
|
225
228
|
const densityTokens = useMemo(() => ({ ...UI_DENSITY_PRESETS[uiDensity], ...uiDensityOptions }), [uiDensity, uiDensityOptions]);
|
|
229
|
+
const resolvedGridId = gridId ?? exportFilename;
|
|
226
230
|
const resolvedHeaderMinHeight = toCssSize(headerMinHeight, uiDensity === 'compact' ? '34px' : '40px');
|
|
227
231
|
const resolvedHeaderMaxHeight = toCssSize(headerMaxHeight, uiDensity === 'compact' ? '56px' : '72px');
|
|
228
232
|
const resolvedHeaderFontSize = toCssSize(headerFontSize ?? densityTokens.headerFontSize, uiDensity === 'compact' ? '11px' : '12px');
|
|
229
233
|
const resolvedBodyFontSize = toCssSize(bodyFontSize ?? densityTokens.bodyFontSize, uiDensity === 'compact' ? '11px' : '12px');
|
|
230
234
|
const tableStyleOverrides = useMemo(() => ({
|
|
235
|
+
// Static rules folded in here so the whole object comes from one useMemo
|
|
236
|
+
// and GlobalStyles receives a stable reference unless these props change.
|
|
237
|
+
'button[aria-label="Pin to right"]': { display: 'none' },
|
|
238
|
+
'.tp-gpg-root .MuiTableSortLabel-icon': { display: 'none !important' },
|
|
239
|
+
'.tp-gpg-root button[aria-label="Move"]': { display: 'none !important' },
|
|
240
|
+
'.tp-gpg-root [data-column-id="mrt-row-spacer"]': { display: 'none !important' },
|
|
241
|
+
'.tp-gpg-root .Mui-TableHeadCell-ColumnSpacer': { display: 'none !important' },
|
|
231
242
|
...buildHeaderGlobalStyles(resolvedHeaderMinHeight, resolvedHeaderMaxHeight, resolvedHeaderFontSize, headerBgColor),
|
|
232
243
|
...buildBodyGlobalStyles(resolvedBodyFontSize),
|
|
233
244
|
}), [
|
|
@@ -408,22 +419,112 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
408
419
|
setPagination((p) => ({ ...p, pageIndex: 0 }));
|
|
409
420
|
}, [defaultFilters, defaultVisible]);
|
|
410
421
|
const handleExport = useCallback(() => {
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
422
|
+
const dataCols = columns.filter((c) => 'accessorKey' in c && c.accessorKey);
|
|
423
|
+
// xlsx-js-style requires 8-char ARGB (AA + RRGGBB). Prepend full-opacity "FF".
|
|
424
|
+
const toArgb = (hex, fallback = 'FF1565C0') => hex?.startsWith('#') ? 'FF' + hex.slice(1).toUpperCase().padEnd(6, '0') : fallback;
|
|
425
|
+
const headerArgb = toArgb(exportHeaderBgColor ?? headerBgColor);
|
|
426
|
+
const textArgb = toArgb(exportHeaderTextColor, 'FFFFFFFF');
|
|
427
|
+
const headerRow = dataCols.map((c) => c.header ?? '');
|
|
428
|
+
const dataRows = rows.map((row) => dataCols.map((c) => String(row[c.accessorKey] ?? '')));
|
|
429
|
+
const ws = XLSX.utils.aoa_to_sheet([headerRow, ...dataRows]);
|
|
430
|
+
// Style header row
|
|
431
|
+
dataCols.forEach((_, colIdx) => {
|
|
432
|
+
const cellRef = XLSX.utils.encode_cell({ r: 0, c: colIdx });
|
|
433
|
+
if (ws[cellRef]) {
|
|
434
|
+
ws[cellRef].s = {
|
|
435
|
+
fill: { patternType: 'solid', fgColor: { rgb: headerArgb } },
|
|
436
|
+
font: { bold: true, color: { rgb: textArgb }, sz: 10 },
|
|
437
|
+
alignment: { horizontal: 'center', vertical: 'center', wrapText: true },
|
|
438
|
+
border: {
|
|
439
|
+
bottom: { style: 'thin', color: { rgb: 'FFCCCCCC' } },
|
|
440
|
+
right: { style: 'thin', color: { rgb: 'FFCCCCCC' } },
|
|
441
|
+
},
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
});
|
|
445
|
+
// Auto-fit column widths — single O(n) pass accumulates max length per column
|
|
446
|
+
// instead of one reduce() per column (was O(n × cols)).
|
|
447
|
+
const colWidths = dataCols.map((c) => (c.header ?? '').length);
|
|
448
|
+
for (const row of rows) {
|
|
449
|
+
const r = row;
|
|
450
|
+
for (let ci = 0; ci < dataCols.length; ci++) {
|
|
451
|
+
const len = String(r[dataCols[ci].accessorKey] ?? '').length;
|
|
452
|
+
if (len > colWidths[ci])
|
|
453
|
+
colWidths[ci] = len;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
ws['!cols'] = colWidths.map((w) => ({ wch: Math.max(w, 8) + 2 }));
|
|
457
|
+
const wb = XLSX.utils.book_new();
|
|
458
|
+
XLSX.utils.book_append_sheet(wb, ws, 'Data');
|
|
459
|
+
XLSX.writeFile(wb, `${exportFilename}-page${pagination.pageIndex + 1}.xlsx`);
|
|
460
|
+
}, [columns, rows, exportFilename, pagination.pageIndex, headerBgColor, exportHeaderBgColor, exportHeaderTextColor]);
|
|
461
|
+
// ── Memoized cell-prop builders ───────────────────────────────────────────
|
|
462
|
+
// These are functions passed to MRT per-cell. Without useCallback they get
|
|
463
|
+
// new references on every render, forcing MRT to rebuild every cell's sx.
|
|
464
|
+
const memoizedHeadCellProps = useCallback((params) => {
|
|
465
|
+
const { column, table } = params;
|
|
466
|
+
const colDef = column.columnDef.muiTableHeadCellProps;
|
|
467
|
+
const colResolved = typeof colDef === 'function' ? (colDef({ column, table }) ?? {}) : colDef ?? {};
|
|
468
|
+
const gridResolved = typeof gridHeadCellProps === 'function'
|
|
469
|
+
? (gridHeadCellProps({ column, table }) ?? {})
|
|
470
|
+
: gridHeadCellProps ?? {};
|
|
471
|
+
const align = (colResolved.align ?? gridResolved.align ?? 'left');
|
|
472
|
+
const { sx: gridSx, align: _ga, ...gridRest } = gridResolved;
|
|
473
|
+
const { sx: colSx, align: _ca, ...colRest } = colResolved;
|
|
474
|
+
return {
|
|
475
|
+
...gridRest,
|
|
476
|
+
...colRest,
|
|
477
|
+
align,
|
|
478
|
+
sx: [
|
|
479
|
+
buildHeaderCellSx(align, resolvedHeaderMinHeight, resolvedHeaderMaxHeight, resolvedHeaderFontSize, headerBgColor, headerMaxLines),
|
|
480
|
+
...(gridSx ? [gridSx] : []),
|
|
481
|
+
...(colSx ? [colSx] : []),
|
|
482
|
+
],
|
|
483
|
+
};
|
|
484
|
+
}, [
|
|
485
|
+
resolvedHeaderMinHeight,
|
|
486
|
+
resolvedHeaderMaxHeight,
|
|
487
|
+
resolvedHeaderFontSize,
|
|
488
|
+
headerBgColor,
|
|
489
|
+
headerMaxLines,
|
|
490
|
+
gridHeadCellProps,
|
|
491
|
+
]);
|
|
492
|
+
const memoizedBodyCellProps = useCallback((params) => {
|
|
493
|
+
const { cell, column, row, table } = params;
|
|
494
|
+
const colDef = column.columnDef.muiTableBodyCellProps;
|
|
495
|
+
const colResolved = typeof colDef === 'function' ? (colDef({ cell, column, row, table }) ?? {}) : colDef ?? {};
|
|
496
|
+
const gridResolved = typeof gridBodyCellProps === 'function'
|
|
497
|
+
? (gridBodyCellProps({ cell, column, row, table }) ?? {})
|
|
498
|
+
: gridBodyCellProps ?? {};
|
|
499
|
+
const { sx: gridSx, ...gridRest } = gridResolved;
|
|
500
|
+
const { sx: colSx, ...colRest } = colResolved;
|
|
501
|
+
return {
|
|
502
|
+
...gridRest,
|
|
503
|
+
...colRest,
|
|
504
|
+
sx: [
|
|
505
|
+
{
|
|
506
|
+
whiteSpace: 'nowrap',
|
|
507
|
+
fontSize: resolvedBodyFontSize,
|
|
508
|
+
lineHeight: 1.35,
|
|
509
|
+
borderRight: '1px solid rgba(224,224,224,1)',
|
|
510
|
+
},
|
|
511
|
+
...(gridSx ? [gridSx] : []),
|
|
512
|
+
...(colSx ? [colSx] : []),
|
|
513
|
+
],
|
|
514
|
+
};
|
|
515
|
+
}, [resolvedBodyFontSize, gridBodyCellProps]);
|
|
516
|
+
// ── Memoized toolbar render functions ─────────────────────────────────────
|
|
517
|
+
// Defined with useCallback so MRT receives stable references and does not
|
|
518
|
+
// re-render the toolbar on every isFetching / data update cycle.
|
|
519
|
+
const renderTopToolbarCustomActions = useCallback(() => (jsxs(Box, { sx: { display: 'flex', alignItems: 'center', flex: 1, minWidth: 0, pr: 1, gap: 0.5 }, children: [jsxs(Box, { sx: { display: 'flex', alignItems: 'center', flexShrink: 0, gap: 0.25 }, children: [jsx(Tooltip, { title: "Clear filters & refresh", children: jsx("span", { children: jsx(IconButton, { id: `${resolvedGridId}_refresh_icon`, size: "small", onClick: () => { handleClearAll(); refetch(); }, disabled: isFetching, sx: { p: uiDensity === 'compact' ? 0.35 : 0.5 }, children: jsx(RefreshIcon, { sx: { fontSize: uiDensity === 'compact' ? 18 : 20 } }) }) }) }), jsx(Tooltip, { title: "Export batch as Excel (.xlsx)", children: jsx("span", { children: jsx(IconButton, { id: `${resolvedGridId}_export_icon`, size: "small", onClick: handleExport, disabled: rows.length === 0 || isFetching, sx: { p: uiDensity === 'compact' ? 0.35 : 0.5 }, children: jsx(FileDownloadIcon, { sx: { fontSize: uiDensity === 'compact' ? 18 : 20 } }) }) }) })] }), jsx(Box, { sx: { flex: 1, minWidth: 0 }, children: jsx(DynamicFilterBar, { serverFilterDefs: serverFilterDefs, visibleFilterIds: visibleFilterIds, onToggleFilter: handleToggleFilter, filterValues: filterValues, onFilterValuesChange: handleFilterValuesChange, columnFilters: columnFilters, onColumnFilterChange: setColumnFilters, availableColumns: availableColumns, maxVisibleFilters: maxVisibleFilters, uiDensity: uiDensity, filterChipFontSize: densityTokens.filterChipFontSize, filterChipMinHeight: densityTokens.filterChipMinHeight, filterLabelFontSize: densityTokens.filterLabelFontSize, gridId: resolvedGridId }) })] })), [
|
|
520
|
+
resolvedGridId, isFetching, rows.length, uiDensity,
|
|
521
|
+
handleClearAll, refetch, handleExport,
|
|
522
|
+
serverFilterDefs, visibleFilterIds, handleToggleFilter,
|
|
523
|
+
filterValues, handleFilterValuesChange, columnFilters, setColumnFilters,
|
|
524
|
+
availableColumns, maxVisibleFilters, densityTokens, handleToggleFilter,
|
|
525
|
+
]);
|
|
526
|
+
const renderToolbarInternalActions = useCallback(({ table: t }) => (jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.5 }, children: [jsx(MRT_ToggleGlobalFilterButton, { table: t, id: `${resolvedGridId}_global_search_icon` }), jsx(MRT_ShowHideColumnsButton, { table: t, id: `${resolvedGridId}_columns_icon` }), jsx(MRT_ToggleDensePaddingButton, { table: t, id: `${resolvedGridId}_density_icon` }), jsx(MRT_ToggleFullScreenButton, { table: t, id: `${resolvedGridId}_fullscreen_icon` })] })), [resolvedGridId]);
|
|
527
|
+
const renderBottomToolbar = useCallback(({ table: t }) => (jsx(PaginationFooter, { pageIndex: t.getState().pagination.pageIndex, pageSize: t.getState().pagination.pageSize, totalRecords: totalRecords, isFetching: isFetching, isLoading: isLoading, canPrev: t.getCanPreviousPage() && !isFetching, canNext: t.getCanNextPage() && !isFetching, onFirst: () => t.firstPage(), onPrev: () => t.previousPage(), onNext: () => t.nextPage(), onLast: () => t.lastPage(), onPageSizeChange: (s) => t.setPageSize(s), pageSizeOptions: pageSizeOptions, density: densityTokens, gridId: resolvedGridId })), [totalRecords, isFetching, isLoading, pageSizeOptions, densityTokens, resolvedGridId]);
|
|
427
528
|
// ── Table instance ─────────────────────────────────────────────────────────
|
|
428
529
|
const table = useMaterialReactTable({
|
|
429
530
|
columns: processedColumns,
|
|
@@ -580,71 +681,18 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
580
681
|
...(headerBgColor ? { backgroundColor: headerBgColor } : {}),
|
|
581
682
|
},
|
|
582
683
|
},
|
|
583
|
-
muiTableHeadCellProps:
|
|
584
|
-
|
|
585
|
-
// ── Resolve column-level props ────────────────────────────────────────
|
|
586
|
-
const colDef = column.columnDef.muiTableHeadCellProps;
|
|
587
|
-
const colResolved = typeof colDef === 'function' ? (colDef({ column, table }) ?? {}) : colDef ?? {};
|
|
588
|
-
// ── Resolve grid-level props ──────────────────────────────────────────
|
|
589
|
-
const gridResolved = typeof gridHeadCellProps === 'function'
|
|
590
|
-
? (gridHeadCellProps({ column, table }) ?? {})
|
|
591
|
-
: gridHeadCellProps ?? {};
|
|
592
|
-
// Column align overrides grid align; default 'left'
|
|
593
|
-
const align = (colResolved.align ?? gridResolved.align ?? 'left');
|
|
594
|
-
const { sx: gridSx, align: _ga, ...gridRest } = gridResolved;
|
|
595
|
-
const { sx: colSx, align: _ca, ...colRest } = colResolved;
|
|
596
|
-
return {
|
|
597
|
-
...gridRest, // grid-level props (className, etc.)
|
|
598
|
-
...colRest, // column-level overrides
|
|
599
|
-
align,
|
|
600
|
-
sx: [
|
|
601
|
-
buildHeaderCellSx(align, resolvedHeaderMinHeight, resolvedHeaderMaxHeight, resolvedHeaderFontSize, headerBgColor, headerMaxLines),
|
|
602
|
-
...(gridSx ? [gridSx] : []),
|
|
603
|
-
...(colSx ? [colSx] : []),
|
|
604
|
-
],
|
|
605
|
-
};
|
|
606
|
-
},
|
|
607
|
-
muiTableBodyCellProps: (params) => {
|
|
608
|
-
const { cell, column, row, table } = params;
|
|
609
|
-
// ── Resolve column-level props ────────────────────────────────────────
|
|
610
|
-
const colDef = column.columnDef.muiTableBodyCellProps;
|
|
611
|
-
const colResolved = typeof colDef === 'function' ? (colDef({ cell, column, row, table }) ?? {}) : colDef ?? {};
|
|
612
|
-
// ── Resolve grid-level props ──────────────────────────────────────────
|
|
613
|
-
const gridResolved = typeof gridBodyCellProps === 'function'
|
|
614
|
-
? (gridBodyCellProps({ cell, column, row, table }) ?? {})
|
|
615
|
-
: gridBodyCellProps ?? {};
|
|
616
|
-
const { sx: gridSx, ...gridRest } = gridResolved;
|
|
617
|
-
const { sx: colSx, ...colRest } = colResolved;
|
|
618
|
-
return {
|
|
619
|
-
...gridRest, // grid-level props (title, className, etc.)
|
|
620
|
-
...colRest, // column-level overrides (align, etc.)
|
|
621
|
-
sx: [
|
|
622
|
-
// 1. base styles — always applied
|
|
623
|
-
{
|
|
624
|
-
whiteSpace: 'nowrap',
|
|
625
|
-
fontSize: resolvedBodyFontSize,
|
|
626
|
-
lineHeight: 1.35,
|
|
627
|
-
borderRight: '1px solid rgba(224,224,224,1)',
|
|
628
|
-
},
|
|
629
|
-
// 2. grid-level sx additions
|
|
630
|
-
...(gridSx ? [gridSx] : []),
|
|
631
|
-
// 3. column-level sx overrides (minWidth, maxWidth, textAlign, etc.)
|
|
632
|
-
...(colSx ? [colSx] : []),
|
|
633
|
-
],
|
|
634
|
-
};
|
|
635
|
-
},
|
|
684
|
+
muiTableHeadCellProps: memoizedHeadCellProps,
|
|
685
|
+
muiTableBodyCellProps: memoizedBodyCellProps,
|
|
636
686
|
muiToolbarAlertBannerProps: isError
|
|
637
687
|
? { color: 'error', children: 'Failed to load data. Please try again.' }
|
|
638
688
|
: undefined,
|
|
639
|
-
|
|
640
|
-
//
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
renderToolbarInternalActions: ({ table: t }) => (jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 0.5 }, children: [jsx(MRT_ToggleGlobalFilterButton, { table: t }), jsx(MRT_ShowHideColumnsButton, { table: t }), jsx(MRT_ToggleDensePaddingButton, { table: t }), jsx(MRT_ToggleFullScreenButton, { table: t })] })),
|
|
645
|
-
renderBottomToolbar: ({ table: t }) => (jsx(PaginationFooter, { pageIndex: t.getState().pagination.pageIndex, pageSize: t.getState().pagination.pageSize, totalRecords: totalRecords, isFetching: isFetching, isLoading: isLoading, canPrev: t.getCanPreviousPage() && !isFetching, canNext: t.getCanNextPage() && !isFetching, onFirst: () => t.firstPage(), onPrev: () => t.previousPage(), onNext: () => t.nextPage(), onLast: () => t.lastPage(), onPageSizeChange: (s) => t.setPageSize(s), pageSizeOptions: pageSizeOptions, density: densityTokens })),
|
|
689
|
+
// Memoized via useCallback above — stable references prevent MRT from
|
|
690
|
+
// re-rendering the toolbar on every isFetching / data update cycle.
|
|
691
|
+
renderTopToolbarCustomActions,
|
|
692
|
+
renderToolbarInternalActions,
|
|
693
|
+
renderBottomToolbar,
|
|
646
694
|
});
|
|
647
|
-
return (jsxs(Box, { ref: containerRef, className: "tp-gpg-root", sx: {
|
|
695
|
+
return (jsxs(Box, { ref: containerRef, id: resolvedGridId, className: "tp-gpg-root", sx: {
|
|
648
696
|
position: 'relative',
|
|
649
697
|
height: resolvedHeight,
|
|
650
698
|
minHeight: tableMinHeight,
|
|
@@ -652,14 +700,7 @@ function GenericPaginatedGrid({ columns, fetchPage, queryKey, serverFilterDefs,
|
|
|
652
700
|
display: 'flex',
|
|
653
701
|
flexDirection: 'column',
|
|
654
702
|
overflow: 'hidden',
|
|
655
|
-
}, children: [jsx(GlobalStyles, { styles: {
|
|
656
|
-
'button[aria-label="Pin to right"]': { display: 'none' },
|
|
657
|
-
'.tp-gpg-root .MuiTableSortLabel-icon': { display: 'none !important' },
|
|
658
|
-
'.tp-gpg-root button[aria-label="Move"]': { display: 'none !important' },
|
|
659
|
-
'.tp-gpg-root [data-column-id="mrt-row-spacer"]': { display: 'none !important' },
|
|
660
|
-
'.tp-gpg-root .Mui-TableHeadCell-ColumnSpacer': { display: 'none !important' },
|
|
661
|
-
...tableStyleOverrides,
|
|
662
|
-
} }), isLoading && jsx(OverlayLoader, { message: "Loading data\u2026" }), !isLoading && isFetching && jsx(OverlayLoader, { message: "Updating data\u2026" }), jsx(Box, { sx: { flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', overflow: 'hidden' }, children: jsx(MaterialReactTable, { table: table }) })] }));
|
|
703
|
+
}, children: [jsx(GlobalStyles, { styles: tableStyleOverrides }), isLoading && jsx(OverlayLoader, { message: "Loading data\u2026" }), !isLoading && isFetching && jsx(OverlayLoader, { message: "Updating data\u2026" }), jsx(Box, { sx: { flex: 1, minHeight: 0, display: 'flex', flexDirection: 'column', overflow: 'hidden' }, children: jsx(MaterialReactTable, { table: table }) })] }));
|
|
663
704
|
}
|
|
664
705
|
|
|
665
706
|
export { GenericPaginatedGrid as default };
|
|
@@ -6,7 +6,7 @@ import ListItemText from '@mui/material/ListItemText';
|
|
|
6
6
|
import MenuItem from '@mui/material/MenuItem';
|
|
7
7
|
import Select from '@mui/material/Select';
|
|
8
8
|
import * as React from 'react';
|
|
9
|
-
import { useState } from 'react';
|
|
9
|
+
import { useState, useCallback } from 'react';
|
|
10
10
|
|
|
11
11
|
const ITEM_HEIGHT = 36;
|
|
12
12
|
const ITEM_PADDING_TOP = 2;
|
|
@@ -52,11 +52,11 @@ function MultiSelectFieldComponent({ value, options, onChangeFn, disable = false
|
|
|
52
52
|
setSelectAll(false);
|
|
53
53
|
}
|
|
54
54
|
}, [filterOptions, fieldValue]);
|
|
55
|
-
const handleChange = (event) => {
|
|
55
|
+
const handleChange = useCallback((event) => {
|
|
56
56
|
const { target: { value }, } = event;
|
|
57
57
|
setPersonName(typeof value === 'string' ? value?.split(',') : value);
|
|
58
58
|
onChangeFn((typeof value === 'string' ? value?.split(',') : value).join(','));
|
|
59
|
-
};
|
|
59
|
+
}, [onChangeFn]);
|
|
60
60
|
const selectedOptions = options.filter((item) => fieldValue?.split(',').some((value) => value === item.value));
|
|
61
61
|
const selectedValues = selectedOptions.map((item) => item.label).join(' , ');
|
|
62
62
|
return (jsx(Box, { children: jsx(FormControl, { fullWidth: true, ref: containerRef, sx: {
|
|
@@ -1,62 +1,61 @@
|
|
|
1
|
-
import { jsx
|
|
2
|
-
import { useState, useEffect } from 'react';
|
|
1
|
+
import { jsx } from 'react/jsx-runtime';
|
|
2
|
+
import { useState, useCallback, useRef, useEffect } from 'react';
|
|
3
3
|
import { useIdleTimer } from 'react-idle-timer';
|
|
4
4
|
import ConfirmationDialog from '../ModalField/ConfirmationDialog.esm.js';
|
|
5
5
|
|
|
6
6
|
const secondsToMMSS = (totalSeconds) => {
|
|
7
7
|
const minutes = Math.floor(totalSeconds / 60);
|
|
8
8
|
const seconds = Math.floor(totalSeconds % 60);
|
|
9
|
-
|
|
10
|
-
const formattedSeconds = String(seconds).padStart(2, '0');
|
|
11
|
-
return `${formattedMinutes}:${formattedSeconds}`;
|
|
9
|
+
return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
|
|
12
10
|
};
|
|
13
11
|
const promptBeforeValue = 120000;
|
|
14
12
|
const SessionTimeOut = ({ sessionTime, handleSubmitSession, onSessionExpire, handleSessionCancel, SubmitButtonName = 'Submit', }) => {
|
|
15
13
|
const [openConfirmModal, setOpenConfirmModal] = useState(false);
|
|
16
|
-
const
|
|
17
|
-
const providedTimestamp = new Date(expiryDetails).getTime();
|
|
14
|
+
const providedTimestamp = new Date(sessionTime).getTime();
|
|
18
15
|
const currentTimestamp = new Date().getTime();
|
|
19
|
-
const
|
|
20
|
-
const timeout = remainingTime;
|
|
16
|
+
const timeout = providedTimestamp - currentTimestamp;
|
|
21
17
|
const promptBeforeIdle = Math.min(promptBeforeValue, timeout - 1000);
|
|
22
18
|
const [, setRemainingTimeInSeconds] = useState(Math.ceil(timeout / 1000));
|
|
23
19
|
const [formattedRemainingTime, setFormattedRemainingTime] = useState(secondsToMMSS(Math.ceil(timeout / 1000)));
|
|
24
|
-
const onIdle = () => {
|
|
25
|
-
if (sessionTime)
|
|
20
|
+
const onIdle = useCallback(() => {
|
|
21
|
+
if (sessionTime)
|
|
26
22
|
onSessionExpire();
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const handleSubmit = () => {
|
|
30
|
-
handleSubmitSession();
|
|
31
|
-
setOpenConfirmModal(false);
|
|
32
|
-
};
|
|
33
|
-
const handleCancel = () => {
|
|
34
|
-
handleSessionCancel();
|
|
35
|
-
setOpenConfirmModal(false);
|
|
36
|
-
};
|
|
37
|
-
const onPrompt = () => {
|
|
23
|
+
}, [sessionTime, onSessionExpire]);
|
|
24
|
+
const onPrompt = useCallback(() => {
|
|
38
25
|
setOpenConfirmModal(true);
|
|
39
|
-
};
|
|
26
|
+
}, []);
|
|
40
27
|
const { getRemainingTime } = useIdleTimer({
|
|
41
28
|
onIdle,
|
|
42
29
|
onPrompt,
|
|
43
30
|
promptBeforeIdle,
|
|
44
31
|
timeout,
|
|
45
|
-
throttle: 1000,
|
|
32
|
+
throttle: 1000,
|
|
46
33
|
});
|
|
34
|
+
// Keep a ref to getRemainingTime so the interval effect never needs it
|
|
35
|
+
// as a reactive dependency — react-idle-timer guarantees it is stable,
|
|
36
|
+
// but ESLint cannot verify that, which previously caused a spurious
|
|
37
|
+
// re-subscription on every render.
|
|
38
|
+
const getRemainingTimeRef = useRef(getRemainingTime);
|
|
39
|
+
getRemainingTimeRef.current = getRemainingTime;
|
|
47
40
|
useEffect(() => {
|
|
48
41
|
const interval = setInterval(() => {
|
|
49
|
-
const remainingSeconds = Math.ceil(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
setFormattedRemainingTime(
|
|
53
|
-
}, 1000);
|
|
54
|
-
return () =>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
42
|
+
const remainingSeconds = Math.ceil(getRemainingTimeRef.current() / 1000);
|
|
43
|
+
const show = promptBeforeIdle !== promptBeforeValue;
|
|
44
|
+
setRemainingTimeInSeconds(show ? remainingSeconds : 0);
|
|
45
|
+
setFormattedRemainingTime(show ? secondsToMMSS(remainingSeconds) : '00:00');
|
|
46
|
+
}, 1000);
|
|
47
|
+
return () => clearInterval(interval);
|
|
48
|
+
}, [promptBeforeIdle]); // getRemainingTime intentionally omitted — stable ref used instead
|
|
49
|
+
const handleSubmit = useCallback(() => {
|
|
50
|
+
handleSubmitSession();
|
|
51
|
+
setOpenConfirmModal(false);
|
|
52
|
+
}, [handleSubmitSession]);
|
|
53
|
+
const handleCancel = useCallback(() => {
|
|
54
|
+
handleSessionCancel();
|
|
55
|
+
setOpenConfirmModal(false);
|
|
56
|
+
}, [handleSessionCancel]);
|
|
58
57
|
const sessionMessage = `Your session will expire in ${formattedRemainingTime} seconds. Do you want to extend the session?`;
|
|
59
|
-
return (jsx(
|
|
58
|
+
return (jsx(ConfirmationDialog, { openConfirmDialog: openConfirmModal, handleCancel: handleCancel, onClickSubmit: handleSubmit, text: sessionMessage, Submit: SubmitButtonName }));
|
|
60
59
|
};
|
|
61
60
|
|
|
62
61
|
export { SessionTimeOut as default };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as DateInput } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as DateInput } from '../../../../../_virtual/index.esm13.js';
|
|
2
2
|
import React__default from 'react';
|
|
3
3
|
import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
|
|
4
4
|
import { __require as requireClassnames } from '../../../../classnames/index.esm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as DateRange } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as DateRange } from '../../../../../_virtual/index.esm6.js';
|
|
2
2
|
import React__default from 'react';
|
|
3
3
|
import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
|
|
4
4
|
import { __require as requireCalendar } from '../Calendar/index.esm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as DateRangePicker } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as DateRangePicker } from '../../../../../_virtual/index.esm4.js';
|
|
2
2
|
import React__default from 'react';
|
|
3
3
|
import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
|
|
4
4
|
import { __require as requireDateRange } from '../DateRange/index.esm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as DayCell } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as DayCell } from '../../../../../_virtual/index.esm12.js';
|
|
2
2
|
import React__default from 'react';
|
|
3
3
|
import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
|
|
4
4
|
import { __require as requireClassnames } from '../../../../classnames/index.esm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as DefinedRange } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as DefinedRange } from '../../../../../_virtual/index.esm5.js';
|
|
2
2
|
import React__default from 'react';
|
|
3
3
|
import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
|
|
4
4
|
import { __require as requireStyles } from '../../styles.esm.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as InputRangeField } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as InputRangeField } from '../../../../../_virtual/index.esm11.js';
|
|
2
2
|
import React__default from 'react';
|
|
3
3
|
import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { __exports as Month } from '../../../../../_virtual/index.
|
|
1
|
+
import { __exports as Month } from '../../../../../_virtual/index.esm14.js';
|
|
2
2
|
import React__default from 'react';
|
|
3
3
|
import { __require as requirePropTypes } from '../../../../prop-types/index.esm.js';
|
|
4
4
|
import { __require as requireDayCell } from '../DayCell/index.esm.js';
|