@okta/odyssey-react-mui 1.6.20 → 1.6.21

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.
Files changed (75) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/Button.js +2 -2
  3. package/dist/Button.js.map +1 -1
  4. package/dist/MenuButton.js +16 -2
  5. package/dist/MenuButton.js.map +1 -1
  6. package/dist/MenuContext.js +2 -1
  7. package/dist/MenuContext.js.map +1 -1
  8. package/dist/MenuItem.js +6 -3
  9. package/dist/MenuItem.js.map +1 -1
  10. package/dist/SearchField.js.map +1 -1
  11. package/dist/icons.generated/ArrowBottom.js +33 -0
  12. package/dist/icons.generated/ArrowBottom.js.map +1 -0
  13. package/dist/icons.generated/ArrowTop.js +33 -0
  14. package/dist/icons.generated/ArrowTop.js.map +1 -0
  15. package/dist/icons.generated/index.js +2 -0
  16. package/dist/icons.generated/index.js.map +1 -1
  17. package/dist/labs/DataFilters.js +366 -0
  18. package/dist/labs/DataFilters.js.map +1 -0
  19. package/dist/labs/DataTable.js +366 -0
  20. package/dist/labs/DataTable.js.map +1 -0
  21. package/dist/labs/DataTablePagination.js +74 -0
  22. package/dist/labs/DataTablePagination.js.map +1 -0
  23. package/dist/labs/PaginatedTable.js +9 -6
  24. package/dist/labs/PaginatedTable.js.map +1 -1
  25. package/dist/labs/StaticTable.js +8 -5
  26. package/dist/labs/StaticTable.js.map +1 -1
  27. package/dist/labs/index.js +4 -1
  28. package/dist/labs/index.js.map +1 -1
  29. package/dist/labs/materialReactTableTypes.js.map +1 -1
  30. package/dist/src/MenuButton.d.ts +12 -2
  31. package/dist/src/MenuButton.d.ts.map +1 -1
  32. package/dist/src/MenuContext.d.ts +1 -0
  33. package/dist/src/MenuContext.d.ts.map +1 -1
  34. package/dist/src/MenuItem.d.ts.map +1 -1
  35. package/dist/src/SearchField.d.ts +16 -0
  36. package/dist/src/SearchField.d.ts.map +1 -1
  37. package/dist/src/icons.generated/ArrowBottom.d.ts +16 -0
  38. package/dist/src/icons.generated/ArrowBottom.d.ts.map +1 -0
  39. package/dist/src/icons.generated/ArrowTop.d.ts +16 -0
  40. package/dist/src/icons.generated/ArrowTop.d.ts.map +1 -0
  41. package/dist/src/icons.generated/index.d.ts +2 -0
  42. package/dist/src/icons.generated/index.d.ts.map +1 -1
  43. package/dist/src/labs/DataFilters.d.ts +85 -0
  44. package/dist/src/labs/DataFilters.d.ts.map +1 -0
  45. package/dist/src/labs/DataTable.d.ts +193 -0
  46. package/dist/src/labs/DataTable.d.ts.map +1 -0
  47. package/dist/src/labs/DataTablePagination.d.ts +25 -0
  48. package/dist/src/labs/DataTablePagination.d.ts.map +1 -0
  49. package/dist/src/labs/PaginatedTable.d.ts.map +1 -1
  50. package/dist/src/labs/StaticTable.d.ts.map +1 -1
  51. package/dist/src/labs/index.d.ts +4 -2
  52. package/dist/src/labs/index.d.ts.map +1 -1
  53. package/dist/src/labs/materialReactTableTypes.d.ts +1 -1
  54. package/dist/src/labs/materialReactTableTypes.d.ts.map +1 -1
  55. package/dist/src/theme/components.d.ts.map +1 -1
  56. package/dist/theme/components.js +137 -64
  57. package/dist/theme/components.js.map +1 -1
  58. package/dist/tsconfig.production.tsbuildinfo +1 -1
  59. package/package.json +4 -4
  60. package/src/Button.tsx +2 -2
  61. package/src/MenuButton.tsx +50 -8
  62. package/src/MenuContext.ts +2 -0
  63. package/src/MenuItem.tsx +5 -3
  64. package/src/SearchField.tsx +8 -0
  65. package/src/icons.generated/ArrowBottom.tsx +43 -0
  66. package/src/icons.generated/ArrowTop.tsx +43 -0
  67. package/src/icons.generated/index.ts +2 -0
  68. package/src/labs/DataFilters.tsx +601 -0
  69. package/src/labs/DataTable.tsx +681 -0
  70. package/src/labs/DataTablePagination.tsx +88 -0
  71. package/src/labs/PaginatedTable.tsx +35 -33
  72. package/src/labs/StaticTable.tsx +26 -29
  73. package/src/labs/index.ts +6 -3
  74. package/src/labs/{materialReactTableTypes.ts → materialReactTableTypes.tsx} +1 -1
  75. package/src/theme/components.tsx +154 -62
@@ -0,0 +1,681 @@
1
+ /*!
2
+ * Copyright (c) 2023-present, Okta, Inc. and/or its affiliates. All rights reserved.
3
+ * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.")
4
+ *
5
+ * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
6
+ * Unless required by applicable law or agreed to in writing, software
7
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
8
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9
+ *
10
+ * See the License for the specific language governing permissions and limitations under the License.
11
+ */
12
+
13
+ import {
14
+ MRT_Updater,
15
+ MRT_Virtualizer,
16
+ MRT_RowData,
17
+ MRT_TableOptions,
18
+ useMaterialReactTable,
19
+ MRT_SortingState,
20
+ MRT_DensityState,
21
+ MRT_VisibilityState,
22
+ MRT_TableContainer,
23
+ MRT_RowSelectionState,
24
+ MRT_Row,
25
+ MRT_ColumnDef,
26
+ } from "material-react-table";
27
+ import {
28
+ Fragment,
29
+ ReactElement,
30
+ memo,
31
+ useCallback,
32
+ useEffect,
33
+ useMemo,
34
+ useRef,
35
+ useState,
36
+ } from "react";
37
+ import {
38
+ ArrowTopIcon,
39
+ ArrowBottomIcon,
40
+ ArrowDownIcon,
41
+ ArrowUpIcon,
42
+ DragIndicatorIcon,
43
+ ListIcon,
44
+ ShowIcon,
45
+ MoreIcon,
46
+ } from "../icons.generated";
47
+ import { Checkbox as MuiCheckbox } from "@mui/material";
48
+ import {
49
+ DataTablePagination,
50
+ paginationTypeValues,
51
+ } from "./DataTablePagination";
52
+ import { DataFilter, DataFilters } from "./DataFilters";
53
+ import { Button } from "../Button";
54
+ import { Box } from "../Box";
55
+ import { MenuButton, MenuItem } from "..";
56
+ import { ArrowUnsortedIcon } from "../icons.generated";
57
+
58
+ export const densityValues = ["comfortable", "spacious", "compact"] as const;
59
+
60
+ export type {
61
+ MRT_ColumnFiltersState,
62
+ MRT_SortingState,
63
+ MRT_ColumnDef as TableColumn,
64
+ } from "material-react-table";
65
+
66
+ // The shape of the table columns,
67
+ // with props named to match their MRT_ColumnDef counterparts
68
+ export type DataColumn = {
69
+ /**
70
+ * The unique ID of the column
71
+ */
72
+ accessorKey: string;
73
+ /**
74
+ * The human-friendly title of the column
75
+ */
76
+ header: string;
77
+ /**
78
+ * Customize the way each cell in the column is
79
+ * displayed via a custom React component.
80
+ */
81
+ Cell?: MRT_ColumnDef<MRT_RowData>["Cell"];
82
+ /**
83
+ * The UI control that will be used to filter the column.
84
+ * Defaults to a standard text input.
85
+ */
86
+ filterVariant?: MRT_ColumnDef<MRT_RowData>["filterVariant"];
87
+ /**
88
+ * If the filter control has preset options (such as a select or multi-select),
89
+ * these are the options provided.
90
+ */
91
+ filterSelectOptions?: Array<{ label: string; value: string }>;
92
+ /**
93
+ * The optional column width, in pixels
94
+ */
95
+ size?: number;
96
+ /**
97
+ * The minimum column width, in pixels
98
+ */
99
+ minSize?: number;
100
+ /**
101
+ * The maximum column width, in pixels
102
+ */
103
+ maxSize?: number;
104
+ /**
105
+ * If set to false, the column won't be filterable
106
+ */
107
+ enableColumnFilter?: boolean;
108
+ /**
109
+ * If set to false, the column won't be searchable
110
+ */
111
+ enableGlobalFilter?: boolean;
112
+ /**
113
+ * If set to false, the column won't be sortable
114
+ */
115
+ enableSorting?: boolean;
116
+ /**
117
+ * If set to false, the column won't be resizable
118
+ */
119
+ enableResizing?: boolean;
120
+ /**
121
+ * If set to false, the column won't be hideable
122
+ */
123
+ enableHiding?: boolean;
124
+ };
125
+
126
+ export type DataTableProps = {
127
+ /**
128
+ * The columns that make up the table
129
+ */
130
+ columns: DataColumn[];
131
+ /**
132
+ * The data that goes into the table, which will be displayed
133
+ * as the table rows
134
+ */
135
+ data: MRT_TableOptions<MRT_RowData>["data"];
136
+ /**
137
+ * The total number of rows in the table. Optional, because it's sometimes impossible
138
+ * to calculate. Used in table pagination to know when to disable the "next"/"more" button.
139
+ */
140
+ totalRows?: number;
141
+ /**
142
+ * The function to get the ID of a row
143
+ */
144
+ getRowId?: MRT_TableOptions<MRT_RowData>["getRowId"];
145
+ /**
146
+ * The initial density of the table. This is available even if the table density
147
+ * isn't changeable.
148
+ */
149
+ initialDensity?: (typeof densityValues)[number];
150
+ /**
151
+ * If true, the end user will be able to change the table density.
152
+ */
153
+ hasChangeableDensity?: boolean;
154
+ /**
155
+ * If true, the end user can resize individual columns.
156
+ */
157
+ hasColumnResizing?: boolean;
158
+ /**
159
+ * If true, the end user will be able to show/hide columns.
160
+ */
161
+ hasColumnVisibility?: boolean;
162
+ /**
163
+ * If true, the end user will be able to filter columns.
164
+ */
165
+ hasFilters?: boolean;
166
+ /**
167
+ * If true, the table will include pagination controls.
168
+ */
169
+ hasPagination?: boolean;
170
+ /**
171
+ * If true, the table will include checkboxes on each row, enabling
172
+ * the user to select some or all rows.
173
+ */
174
+ hasRowSelection?: boolean;
175
+ /**
176
+ * If true, the global table search controls will be shown.
177
+ */
178
+ hasSearch?: boolean;
179
+ /**
180
+ * If true, the end user can sort columns (ascending, descending, or neither)
181
+ */
182
+ hasSorting?: boolean;
183
+ /**
184
+ * If true, the end user can reorder rows via a drag-and-drop interface
185
+ */
186
+ hasRowReordering?: boolean;
187
+ /**
188
+ * If true, the search field will include a Search button, rather than
189
+ * firing on input change.
190
+ */
191
+ hasSearchSubmitButton?: boolean;
192
+ /**
193
+ * Callback that fires when a row (or rows) is selected or unselected.
194
+ */
195
+ onRowSelectionChange?: (rowSelection: MRT_RowSelectionState) => void;
196
+ /**
197
+ * Callback that fires whenever the table needs to fetch new data, due to changes in
198
+ * page, results per page, search input, filters, or sorting
199
+ */
200
+ fetchDataFn: ({
201
+ page,
202
+ resultsPerPage,
203
+ search,
204
+ filters,
205
+ sort,
206
+ }: {
207
+ page?: number;
208
+ resultsPerPage?: number;
209
+ search?: string;
210
+ filters?: DataFilter[];
211
+ sort?: MRT_SortingState;
212
+ }) => MRT_TableOptions<MRT_RowData>["data"];
213
+ /**
214
+ * Callback that fires when the user reorders rows within the table. Can be used
215
+ * to propogate order change to the backend.
216
+ */
217
+ reorderDataFn?: ({
218
+ rowId,
219
+ newIndex,
220
+ }: {
221
+ rowId: string;
222
+ newIndex: number;
223
+ }) => void;
224
+ /**
225
+ * The current page number.
226
+ */
227
+ page?: number;
228
+ /**
229
+ * The number of results per page.
230
+ */
231
+ resultsPerPage?: number;
232
+ /**
233
+ * The type of pagination controls shown. Defaults to next/prev buttons, but can be
234
+ * set to a simple "Load more" button by setting to "loadMore".
235
+ */
236
+ paginationType?: (typeof paginationTypeValues)[number];
237
+ /**
238
+ * Action buttons to display in each row
239
+ */
240
+ rowActionButtons?: (
241
+ row: MRT_RowData
242
+ ) => ReactElement<typeof Button | typeof Fragment>;
243
+ /**
244
+ * Menu items to include in the optional actions menu on each row.
245
+ */
246
+ rowActionMenuItems?: (
247
+ row: MRT_RowData
248
+ ) => ReactElement<typeof MenuItem | typeof Fragment>;
249
+ };
250
+
251
+ const DataTable = ({
252
+ columns,
253
+ data: dataProp,
254
+ getRowId,
255
+ page: pageProp = 1,
256
+ initialDensity = densityValues[0],
257
+ resultsPerPage: resultsPerPageProp = 20,
258
+ fetchDataFn,
259
+ reorderDataFn,
260
+ totalRows,
261
+ hasSearchSubmitButton,
262
+ paginationType = "paged",
263
+ onRowSelectionChange,
264
+ rowActionButtons,
265
+ rowActionMenuItems,
266
+ hasChangeableDensity,
267
+ hasColumnResizing,
268
+ hasColumnVisibility,
269
+ hasFilters,
270
+ hasPagination,
271
+ hasRowReordering,
272
+ hasRowSelection,
273
+ hasSearch,
274
+ hasSorting,
275
+ }: DataTableProps) => {
276
+ const [draggingRow, setDraggingRow] = useState<MRT_Row<MRT_RowData> | null>();
277
+ const [showSkeletons, setShowSkeletons] = useState<boolean>(true);
278
+ const [data, setData] =
279
+ useState<MRT_TableOptions<MRT_RowData>["data"]>(dataProp);
280
+ const [page, setPage] = useState<number>(pageProp);
281
+ const [resultsPerPage, setResultsPerPage] =
282
+ useState<number>(resultsPerPageProp);
283
+ const [rowSelection, setRowSelection] = useState<MRT_RowSelectionState>({});
284
+ const [sorting, setSorting] = useState<MRT_SortingState>([]);
285
+ const [density, setDensity] = useState<MRT_DensityState>(initialDensity);
286
+
287
+ const initialColumnVisibility = useMemo(() => {
288
+ return columns.reduce((acc, column) => {
289
+ acc[column.accessorKey as string] = true;
290
+ return acc;
291
+ }, {} as MRT_VisibilityState);
292
+ }, [columns]);
293
+
294
+ const [columnVisibility, setColumnVisibility] = useState<MRT_VisibilityState>(
295
+ initialColumnVisibility
296
+ );
297
+
298
+ const [globalFilter, setGlobalFilter] = useState<string>("");
299
+ const [filters, setFilters] = useState<Array<DataFilter>>();
300
+
301
+ const refreshData = useCallback(async () => {
302
+ setShowSkeletons(true);
303
+ try {
304
+ const newData = await fetchDataFn({
305
+ page: page,
306
+ resultsPerPage: resultsPerPage,
307
+ sort: sorting,
308
+ search: globalFilter,
309
+ filters: filters,
310
+ });
311
+ setData(newData);
312
+ setShowSkeletons(false);
313
+ } catch (error) {
314
+ console.log(error);
315
+ setShowSkeletons(false);
316
+ }
317
+ }, [page, resultsPerPage, sorting, globalFilter, filters, fetchDataFn]);
318
+
319
+ const handleSortingChange = useCallback(
320
+ (updater: MRT_Updater<MRT_SortingState>) => {
321
+ setSorting((prevSorting) =>
322
+ updater instanceof Function ? updater(prevSorting) : sorting
323
+ );
324
+ },
325
+ [sorting]
326
+ );
327
+
328
+ const handleColumnVisibility = useCallback(
329
+ (columnId: string) => {
330
+ setColumnVisibility((prevVisibility) => ({
331
+ ...prevVisibility,
332
+ [columnId]: !columnVisibility[columnId],
333
+ }));
334
+ },
335
+ [columnVisibility]
336
+ );
337
+
338
+ const handleSearch = useCallback((value: string) => {
339
+ setGlobalFilter(value);
340
+ }, []);
341
+
342
+ const handleFilters = useCallback((updatedFilters: Array<DataFilter>) => {
343
+ setFilters(updatedFilters);
344
+ }, []);
345
+
346
+ const handleRowSelectionChange = useCallback(
347
+ (updater: MRT_Updater<MRT_RowSelectionState>) => {
348
+ setRowSelection((prevRowSelection) =>
349
+ updater instanceof Function ? updater(prevRowSelection) : rowSelection
350
+ );
351
+ },
352
+ [rowSelection]
353
+ );
354
+
355
+ const handleReordering = useCallback(
356
+ ({ rowId, newIndex }: { rowId: string; newIndex: number }) => {
357
+ if (newIndex < 0) {
358
+ return;
359
+ }
360
+
361
+ if (totalRows && newIndex > totalRows) {
362
+ return;
363
+ }
364
+
365
+ reorderDataFn?.({ rowId, newIndex });
366
+ refreshData();
367
+ },
368
+ [totalRows, reorderDataFn, refreshData]
369
+ );
370
+
371
+ useEffect(() => {
372
+ setShowSkeletons(false);
373
+ }, [data]);
374
+
375
+ useEffect(() => {
376
+ refreshData();
377
+ }, [refreshData, page, resultsPerPage, sorting, globalFilter, filters]);
378
+
379
+ useEffect(() => {
380
+ onRowSelectionChange?.(rowSelection);
381
+ }, [rowSelection, onRowSelectionChange]);
382
+
383
+ const rowVirtualizerInstanceRef =
384
+ useRef<MRT_Virtualizer<HTMLDivElement, HTMLTableRowElement>>(null);
385
+
386
+ const table = useMaterialReactTable({
387
+ columns: columns,
388
+ data: data,
389
+ state: {
390
+ density,
391
+ sorting,
392
+ globalFilter,
393
+ columnVisibility,
394
+ rowSelection,
395
+ showSkeletons,
396
+ },
397
+ rowVirtualizerInstanceRef: rowVirtualizerInstanceRef,
398
+ rowVirtualizerOptions: { overscan: 4 },
399
+ enableRowVirtualization:
400
+ paginationType === "loadMore" || resultsPerPage > 50,
401
+ enableColumnResizing: hasColumnResizing,
402
+ enableDensityToggle: false,
403
+ enableFullScreenToggle: false,
404
+ enablePagination: false,
405
+ enableRowSelection: hasRowSelection,
406
+ enableFilters: false,
407
+ enableHiding: false,
408
+ enableRowOrdering: hasRowReordering,
409
+ enableRowDragging: hasRowReordering,
410
+ enableSorting: hasSorting,
411
+ selectAllMode: "all",
412
+ enableColumnActions: false,
413
+ layoutMode: "grid-no-grow",
414
+ displayColumnDefOptions: {
415
+ "mrt-row-actions": {
416
+ muiTableBodyCellProps: {
417
+ align: "right",
418
+ sx: {
419
+ overflow: "visible",
420
+ width: "unset",
421
+ },
422
+ },
423
+ muiTableHeadCellProps: {
424
+ align: "right",
425
+ sx: {
426
+ width: "unset",
427
+ // TODO: Make the right padding here 16px (and possibly adapt it to the density padding)
428
+ },
429
+ },
430
+ },
431
+ "mrt-row-drag": {
432
+ header: "",
433
+ muiTableBodyCellProps: {
434
+ sx: {
435
+ minWidth: 0,
436
+ width: 32,
437
+ },
438
+ },
439
+ muiTableHeadCellProps: {
440
+ sx: {
441
+ minWidth: 0,
442
+ width: 32,
443
+ },
444
+ },
445
+ },
446
+ },
447
+ enableGlobalFilter: false,
448
+ manualFiltering: true,
449
+ manualSorting: true,
450
+ getRowId: getRowId,
451
+ icons: {
452
+ ArrowDownwardIcon: ArrowDownIcon,
453
+ DragHandleIcon: DragIndicatorIcon,
454
+ SyncAltIcon: ArrowUnsortedIcon,
455
+ },
456
+ onSortingChange: handleSortingChange,
457
+ onRowSelectionChange: handleRowSelectionChange,
458
+ enableRowActions:
459
+ hasRowReordering || rowActionButtons || rowActionMenuItems ? true : false,
460
+ positionActionsColumn: "last",
461
+
462
+ muiTableHeadCellProps: ({ column }) => ({
463
+ className: sorting.find((item) => item.id === column.id)
464
+ ? "isSorted"
465
+ : "isUnsorted",
466
+ }),
467
+
468
+ muiTableBodyRowProps: ({ table, row }) => ({
469
+ className:
470
+ draggingRow?.id === row.id && table.getState().hoveredRow?.id !== row.id
471
+ ? "isDragging"
472
+ : table.getState().hoveredRow?.id === row.id &&
473
+ draggingRow?.id !== row.id
474
+ ? "isDragTarget"
475
+ : draggingRow?.id === row.id &&
476
+ table.getState().hoveredRow?.id === row.id
477
+ ? "isDragging isDragTarget"
478
+ : undefined,
479
+ }),
480
+
481
+ muiRowDragHandleProps: {
482
+ tabIndex: -1,
483
+ onDragEnd: () => {
484
+ const cols = table.getAllColumns();
485
+ cols[0].toggleVisibility();
486
+
487
+ const { draggingRow, hoveredRow } = table.getState();
488
+ if (draggingRow) {
489
+ handleReordering({
490
+ rowId: draggingRow.id,
491
+ newIndex: (hoveredRow as MRT_RowData).index,
492
+ });
493
+ }
494
+
495
+ setDraggingRow(null);
496
+ },
497
+
498
+ onDragCapture: () => {
499
+ if (!draggingRow && table.getState().draggingRow?.id) {
500
+ setDraggingRow(table.getState().draggingRow);
501
+ }
502
+ },
503
+ },
504
+
505
+ renderRowActions: ({ row }) => {
506
+ const currentIndex = row.index + (page - 1) * resultsPerPage;
507
+
508
+ return (
509
+ <Box sx={{ display: "flex" }}>
510
+ {rowActionButtons?.(row)}
511
+ {(rowActionMenuItems || hasRowReordering) && (
512
+ <MenuButton
513
+ endIcon={<MoreIcon />}
514
+ size="small"
515
+ buttonVariant="floating"
516
+ ariaLabel="More actions"
517
+ menuAlignment="right"
518
+ >
519
+ {rowActionMenuItems && (
520
+ <>
521
+ {rowActionMenuItems(row)}
522
+ <hr />
523
+ </>
524
+ )}
525
+ <MenuItem
526
+ isDisabled={currentIndex <= 0}
527
+ onClick={() => handleReordering({ rowId: row.id, newIndex: 0 })}
528
+ >
529
+ <ArrowTopIcon /> Bring to front
530
+ </MenuItem>
531
+ <MenuItem
532
+ isDisabled={currentIndex <= 0}
533
+ onClick={() =>
534
+ handleReordering({
535
+ rowId: row.id,
536
+ newIndex: currentIndex <= 0 ? 0 : currentIndex - 1,
537
+ })
538
+ }
539
+ >
540
+ <ArrowUpIcon /> Bring forward
541
+ </MenuItem>
542
+ <MenuItem
543
+ isDisabled={totalRows ? currentIndex >= totalRows - 1 : false}
544
+ onClick={() =>
545
+ handleReordering({
546
+ rowId: row.id,
547
+ newIndex: currentIndex + 1,
548
+ })
549
+ }
550
+ >
551
+ <ArrowDownIcon /> Send backward
552
+ </MenuItem>
553
+ <>
554
+ {totalRows && (
555
+ <MenuItem
556
+ isDisabled={currentIndex >= totalRows - 1}
557
+ onClick={() =>
558
+ handleReordering({
559
+ rowId: row.id,
560
+ newIndex: totalRows,
561
+ })
562
+ }
563
+ >
564
+ <ArrowBottomIcon /> Send to back
565
+ </MenuItem>
566
+ )}
567
+ </>
568
+ </MenuButton>
569
+ )}
570
+ </Box>
571
+ );
572
+ },
573
+ });
574
+
575
+ const tableSettings = useMemo(
576
+ () => (
577
+ <>
578
+ {hasChangeableDensity && (
579
+ <MenuButton
580
+ endIcon={<ListIcon />}
581
+ ariaLabel="Table density"
582
+ menuAlignment="right"
583
+ shouldCloseOnSelect={false}
584
+ >
585
+ <>
586
+ {densityValues.map((value: MRT_DensityState) => (
587
+ <MenuItem
588
+ key={value}
589
+ isSelected={density === value}
590
+ onClick={() => setDensity(value)}
591
+ >
592
+ {`${value.charAt(0).toUpperCase()}${value.slice(1)}`}
593
+ </MenuItem>
594
+ ))}
595
+ </>
596
+ </MenuButton>
597
+ )}
598
+
599
+ {hasColumnVisibility && (
600
+ <MenuButton
601
+ endIcon={<ShowIcon />}
602
+ ariaLabel="Show/hide columns"
603
+ menuAlignment="right"
604
+ shouldCloseOnSelect={false}
605
+ >
606
+ <>
607
+ {columns
608
+ .filter((column) => column.enableHiding !== false)
609
+ .map((column) => (
610
+ <MenuItem
611
+ key={column.accessorKey}
612
+ onClick={() =>
613
+ handleColumnVisibility(column.accessorKey as string)
614
+ }
615
+ >
616
+ <MuiCheckbox
617
+ checked={
618
+ columnVisibility[column.accessorKey as string] !== false
619
+ }
620
+ />
621
+ {column.header}
622
+ </MenuItem>
623
+ ))}
624
+ </>
625
+ </MenuButton>
626
+ )}
627
+ </>
628
+ ),
629
+ [density, columnVisibility, columns, hasChangeableDensity]
630
+ );
631
+
632
+ return (
633
+ <Box sx={{ display: "flex", flexDirection: "column", gap: 4 }}>
634
+ <DataFilters
635
+ onChangeSearch={hasSearch ? handleSearch : undefined}
636
+ onChangeFilters={handleFilters}
637
+ hasSearchSubmitButton={hasSearchSubmitButton}
638
+ additionalActions={tableSettings}
639
+ filters={
640
+ hasFilters
641
+ ? columns
642
+ .filter((column) => column.enableColumnFilter !== false)
643
+ .map((column) => {
644
+ return {
645
+ id: column.accessorKey as string,
646
+ label: column.header,
647
+ variant: column.filterVariant ?? "text",
648
+ options: column.filterSelectOptions,
649
+ };
650
+ })
651
+ : undefined
652
+ }
653
+ />
654
+
655
+ <MRT_TableContainer table={table} />
656
+
657
+ {hasPagination && (
658
+ <DataTablePagination
659
+ paginationType={paginationType}
660
+ currentNumberOfResults={data.length}
661
+ currentPage={page}
662
+ isPreviousButtonDisabled={page <= 1}
663
+ isNextButtonDisabled={false} // TODO: Add logic for disabling next/load more button
664
+ onClickPrevious={() => setPage(page - 1)}
665
+ onClickNext={() => {
666
+ if (paginationType === "loadMore") {
667
+ setResultsPerPage(resultsPerPage + resultsPerPageProp);
668
+ } else {
669
+ setPage(page + 1);
670
+ }
671
+ }}
672
+ />
673
+ )}
674
+ </Box>
675
+ );
676
+ };
677
+
678
+ const MemoizedDataTable = memo(DataTable);
679
+ MemoizedDataTable.displayName = "DataTable";
680
+
681
+ export { MemoizedDataTable as DataTable };