@okta/odyssey-react-mui 1.14.4 → 1.14.6
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/CHANGELOG.md +8 -0
- package/dist/Badge.js +1 -1
- package/dist/Badge.js.map +1 -1
- package/dist/DataTable/DataTable.js +178 -58
- package/dist/DataTable/DataTable.js.map +1 -1
- package/dist/DataTable/DataTableEmptyState.js +55 -0
- package/dist/DataTable/DataTableEmptyState.js.map +1 -0
- package/dist/DataTable/DataTablePagination.js +221 -0
- package/dist/DataTable/DataTablePagination.js.map +1 -0
- package/dist/DataTable/DataTableRowActions.js +34 -24
- package/dist/DataTable/DataTableRowActions.js.map +1 -1
- package/dist/DataTable/DataTableSettings.js +22 -10
- package/dist/DataTable/DataTableSettings.js.map +1 -1
- package/dist/DataTable/constants.js +1 -0
- package/dist/DataTable/constants.js.map +1 -1
- package/dist/DataTable/index.js +1 -0
- package/dist/DataTable/index.js.map +1 -1
- package/dist/DataTable/useRowReordering.js +3 -3
- package/dist/DataTable/useRowReordering.js.map +1 -1
- package/dist/DataTable/useScrollIndication.js +70 -0
- package/dist/DataTable/useScrollIndication.js.map +1 -0
- package/dist/Field.js.map +1 -1
- package/dist/Fieldset.js +17 -14
- package/dist/Fieldset.js.map +1 -1
- package/dist/Form.js +33 -23
- package/dist/Form.js.map +1 -1
- package/dist/MenuButton.js +1 -1
- package/dist/MenuButton.js.map +1 -1
- package/dist/SearchField.js +2 -2
- package/dist/SearchField.js.map +1 -1
- package/dist/labs/DataFilters.js +6 -2
- package/dist/labs/DataFilters.js.map +1 -1
- package/dist/labs/DataTable.js +3 -3
- package/dist/labs/DataTable.js.map +1 -1
- package/dist/labs/FileUpload.js +195 -0
- package/dist/labs/FileUpload.js.map +1 -0
- package/dist/labs/FileUploadIllustration.js +54 -0
- package/dist/labs/FileUploadIllustration.js.map +1 -0
- package/dist/labs/FileUploadPreview.js +109 -0
- package/dist/labs/FileUploadPreview.js.map +1 -0
- package/dist/labs/index.js +1 -0
- package/dist/labs/index.js.map +1 -1
- package/dist/properties/ts/odyssey-react-mui.js +12 -0
- package/dist/properties/ts/odyssey-react-mui.js.map +1 -1
- package/dist/src/DataTable/DataTable.d.ts +36 -18
- package/dist/src/DataTable/DataTable.d.ts.map +1 -1
- package/dist/src/DataTable/DataTableEmptyState.d.ts +21 -0
- package/dist/src/DataTable/DataTableEmptyState.d.ts.map +1 -0
- package/dist/src/DataTable/DataTablePagination.d.ts +33 -0
- package/dist/src/DataTable/DataTablePagination.d.ts.map +1 -0
- package/dist/src/DataTable/DataTableRowActions.d.ts.map +1 -1
- package/dist/src/DataTable/DataTableSettings.d.ts.map +1 -1
- package/dist/src/DataTable/constants.d.ts +1 -0
- package/dist/src/DataTable/constants.d.ts.map +1 -1
- package/dist/src/DataTable/index.d.ts +2 -1
- package/dist/src/DataTable/index.d.ts.map +1 -1
- package/dist/src/DataTable/useRowReordering.d.ts.map +1 -1
- package/dist/src/DataTable/useScrollIndication.d.ts +22 -0
- package/dist/src/DataTable/useScrollIndication.d.ts.map +1 -0
- package/dist/src/Field.d.ts +8 -7
- package/dist/src/Field.d.ts.map +1 -1
- package/dist/src/Fieldset.d.ts.map +1 -1
- package/dist/src/Form.d.ts.map +1 -1
- package/dist/src/OdysseyTranslationProvider.d.ts +1 -1
- package/dist/src/OdysseyTranslationProvider.d.ts.map +1 -1
- package/dist/src/SearchField.d.ts.map +1 -1
- package/dist/src/labs/DataFilters.d.ts +5 -1
- package/dist/src/labs/DataFilters.d.ts.map +1 -1
- package/dist/src/labs/DataTable.d.ts.map +1 -1
- package/dist/src/labs/FileUpload.d.ts +40 -0
- package/dist/src/labs/FileUpload.d.ts.map +1 -0
- package/dist/src/labs/FileUploadIllustration.d.ts +15 -0
- package/dist/src/labs/FileUploadIllustration.d.ts.map +1 -0
- package/dist/src/labs/FileUploadPreview.d.ts +21 -0
- package/dist/src/labs/FileUploadPreview.d.ts.map +1 -0
- package/dist/src/labs/index.d.ts +4 -0
- package/dist/src/labs/index.d.ts.map +1 -1
- package/dist/src/properties/ts/odyssey-react-mui.d.ts +12 -0
- package/dist/src/properties/ts/odyssey-react-mui.d.ts.map +1 -1
- package/dist/src/theme/components.d.ts.map +1 -1
- package/dist/theme/components.js +10 -1
- package/dist/theme/components.js.map +1 -1
- package/dist/tsconfig.production.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/Badge.tsx +1 -1
- package/src/DataTable/DataTable.tsx +293 -85
- package/src/DataTable/DataTableEmptyState.tsx +62 -0
- package/src/DataTable/DataTablePagination.tsx +289 -0
- package/src/DataTable/DataTableRowActions.tsx +35 -37
- package/src/DataTable/DataTableSettings.tsx +43 -17
- package/src/DataTable/constants.ts +1 -0
- package/src/DataTable/index.tsx +7 -1
- package/src/DataTable/useRowReordering.tsx +5 -3
- package/src/DataTable/useScrollIndication.tsx +118 -0
- package/src/Field.tsx +9 -7
- package/src/Fieldset.tsx +24 -18
- package/src/Form.tsx +43 -27
- package/src/MenuButton.tsx +1 -1
- package/src/SearchField.tsx +1 -2
- package/src/labs/DataFilters.tsx +9 -0
- package/src/labs/DataTable.tsx +5 -9
- package/src/labs/FileUpload.tsx +301 -0
- package/src/labs/FileUploadIllustration.tsx +66 -0
- package/src/labs/FileUploadPreview.tsx +150 -0
- package/src/labs/index.ts +4 -2
- package/src/properties/odyssey-react-mui.properties +18 -0
- package/src/properties/ts/odyssey-react-mui.ts +1 -1
- package/src/theme/components.tsx +9 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@okta/odyssey-react-mui",
|
|
3
|
-
"version": "1.14.
|
|
3
|
+
"version": "1.14.6",
|
|
4
4
|
"description": "React MUI components for Odyssey, Okta's design system",
|
|
5
5
|
"author": "Okta, Inc.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"@mui/system": "^5.15.9",
|
|
52
52
|
"@mui/utils": "^5.15.9",
|
|
53
53
|
"@mui/x-date-pickers": "^5.0.15",
|
|
54
|
-
"@okta/odyssey-design-tokens": "^1.14.
|
|
54
|
+
"@okta/odyssey-design-tokens": "^1.14.6",
|
|
55
55
|
"date-fns": "^2.30.0",
|
|
56
56
|
"i18next": "^23.8.2",
|
|
57
57
|
"material-react-table": "^2.11.3",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"react": ">=17 <19",
|
|
64
64
|
"react-dom": ">=17 <19"
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "e9b92857eb24eff1f87ff3ad415e67fb6508e0fc"
|
|
67
67
|
}
|
package/src/Badge.tsx
CHANGED
|
@@ -89,7 +89,7 @@ const Badge = ({
|
|
|
89
89
|
const hasNotificationCount = badgeContent && badgeContent > 0;
|
|
90
90
|
|
|
91
91
|
return hasNotificationCount ? (
|
|
92
|
-
<Box sx={badgeStyles}
|
|
92
|
+
<Box sx={badgeStyles} testId={testId} translate={translate}>
|
|
93
93
|
{formattedContent}
|
|
94
94
|
</Box>
|
|
95
95
|
) : null;
|
|
@@ -10,7 +10,15 @@
|
|
|
10
10
|
* See the License for the specific language governing permissions and limitations under the License.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
ReactNode,
|
|
15
|
+
memo,
|
|
16
|
+
useCallback,
|
|
17
|
+
useEffect,
|
|
18
|
+
useMemo,
|
|
19
|
+
useRef,
|
|
20
|
+
useState,
|
|
21
|
+
} from "react";
|
|
14
22
|
import {
|
|
15
23
|
MRT_Cell,
|
|
16
24
|
MRT_DensityState,
|
|
@@ -18,21 +26,20 @@ import {
|
|
|
18
26
|
MRT_RowData,
|
|
19
27
|
MRT_SortingState,
|
|
20
28
|
MRT_TableOptions,
|
|
21
|
-
|
|
29
|
+
MRT_RowSelectionState,
|
|
30
|
+
MRT_RowVirtualizer,
|
|
22
31
|
MRT_VisibilityState,
|
|
23
|
-
MaterialReactTable,
|
|
24
32
|
useMaterialReactTable,
|
|
33
|
+
MRT_TableContainer,
|
|
25
34
|
} from "material-react-table";
|
|
26
35
|
import {
|
|
27
36
|
ArrowDownIcon,
|
|
28
37
|
ArrowUnsortedIcon,
|
|
29
38
|
DragIndicatorIcon,
|
|
39
|
+
MoreIcon,
|
|
30
40
|
} from "../icons.generated";
|
|
31
|
-
import { densityValues } from "./constants";
|
|
32
|
-
import {
|
|
33
|
-
DataTablePagination,
|
|
34
|
-
paginationTypeValues,
|
|
35
|
-
} from "../labs/DataTablePagination";
|
|
41
|
+
import { densityValues, paginationTypeValues } from "./constants";
|
|
42
|
+
import { DataTablePagination } from "./DataTablePagination";
|
|
36
43
|
import { DataFilter, DataFilters } from "../labs/DataFilters";
|
|
37
44
|
import {
|
|
38
45
|
DataTableRowActions,
|
|
@@ -40,8 +47,31 @@ import {
|
|
|
40
47
|
} from "./DataTableRowActions";
|
|
41
48
|
import { useRowReordering } from "./useRowReordering";
|
|
42
49
|
import { DataTableSettings } from "./DataTableSettings";
|
|
50
|
+
import { MenuButton, MenuButtonProps } from "../MenuButton";
|
|
43
51
|
import { Box } from "../Box";
|
|
44
52
|
import { DataTableRowSelectionState } from ".";
|
|
53
|
+
import {
|
|
54
|
+
DesignTokens,
|
|
55
|
+
useOdysseyDesignTokens,
|
|
56
|
+
} from "../OdysseyDesignTokensContext";
|
|
57
|
+
import { useScrollIndication } from "./useScrollIndication";
|
|
58
|
+
import styled from "@emotion/styled";
|
|
59
|
+
import { DataTableEmptyState } from "./DataTableEmptyState";
|
|
60
|
+
import { Callout } from "../Callout";
|
|
61
|
+
import { t } from "i18next";
|
|
62
|
+
|
|
63
|
+
export type DataTableGetDataType = {
|
|
64
|
+
page?: number;
|
|
65
|
+
resultsPerPage?: number;
|
|
66
|
+
search?: string;
|
|
67
|
+
filters?: DataFilter[];
|
|
68
|
+
sort?: MRT_SortingState;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export type DataTableOnReorderRowsType = {
|
|
72
|
+
rowId: string;
|
|
73
|
+
newRowIndex: number;
|
|
74
|
+
};
|
|
45
75
|
|
|
46
76
|
export type DataTableProps = {
|
|
47
77
|
/**
|
|
@@ -58,8 +88,8 @@ export type DataTableProps = {
|
|
|
58
88
|
*/
|
|
59
89
|
getRowId?: MRT_TableOptions<MRT_RowData>["getRowId"];
|
|
60
90
|
/**
|
|
61
|
-
* The initial density of the table. This is available even if the
|
|
62
|
-
* isn't changeable.
|
|
91
|
+
* The initial density (height & padding) of the table rows. This is available even if the
|
|
92
|
+
* table density isn't changeable by the end user via hasChangeableDensity.
|
|
63
93
|
*/
|
|
64
94
|
initialDensity?: (typeof densityValues)[number];
|
|
65
95
|
/**
|
|
@@ -124,26 +154,14 @@ export type DataTableProps = {
|
|
|
124
154
|
search,
|
|
125
155
|
filters,
|
|
126
156
|
sort,
|
|
127
|
-
}:
|
|
128
|
-
page?: number;
|
|
129
|
-
resultsPerPage?: number;
|
|
130
|
-
search?: string;
|
|
131
|
-
filters?: DataFilter[];
|
|
132
|
-
sort?: MRT_SortingState;
|
|
133
|
-
}) =>
|
|
157
|
+
}: DataTableGetDataType) =>
|
|
134
158
|
| MRT_TableOptions<MRT_RowData>["data"]
|
|
135
159
|
| Promise<MRT_TableOptions<MRT_RowData>["data"]>;
|
|
136
160
|
/**
|
|
137
161
|
* Callback that fires when the user reorders rows within the table. Can be used
|
|
138
162
|
* to propogate order change to the backend.
|
|
139
163
|
*/
|
|
140
|
-
onReorderRows?: ({
|
|
141
|
-
rowId,
|
|
142
|
-
newRowIndex,
|
|
143
|
-
}: {
|
|
144
|
-
rowId: string;
|
|
145
|
-
newRowIndex: number;
|
|
146
|
-
}) => void;
|
|
164
|
+
onReorderRows?: ({ rowId, newRowIndex }: DataTableOnReorderRowsType) => void;
|
|
147
165
|
/**
|
|
148
166
|
* The current page number.
|
|
149
167
|
*/
|
|
@@ -165,6 +183,24 @@ export type DataTableProps = {
|
|
|
165
183
|
* Menu items to include in the optional actions menu on each row.
|
|
166
184
|
*/
|
|
167
185
|
rowActionMenuItems?: DataTableRowActionsProps["rowActionMenuItems"];
|
|
186
|
+
/**
|
|
187
|
+
* Menu items to include in the bulk actions menu, which appears above the table if a row or rows are selected
|
|
188
|
+
*/
|
|
189
|
+
bulkActionMenuItems?: (
|
|
190
|
+
selectedRows: MRT_RowSelectionState,
|
|
191
|
+
) => MenuButtonProps["children"];
|
|
192
|
+
/**
|
|
193
|
+
* If `error` is not undefined, the DataTable will indicate an error.
|
|
194
|
+
*/
|
|
195
|
+
errorMessage?: string;
|
|
196
|
+
/**
|
|
197
|
+
* The component to display when the table is displaying the initial empty state
|
|
198
|
+
*/
|
|
199
|
+
emptyPlaceholder?: ReactNode;
|
|
200
|
+
/**
|
|
201
|
+
* The component to display when the query returns no results
|
|
202
|
+
*/
|
|
203
|
+
noResultsPlaceholder?: ReactNode;
|
|
168
204
|
};
|
|
169
205
|
|
|
170
206
|
const displayColumnDefOptions = {
|
|
@@ -220,6 +256,66 @@ const displayColumnDefOptions = {
|
|
|
220
256
|
},
|
|
221
257
|
};
|
|
222
258
|
|
|
259
|
+
const ScrollableTableContainer = styled("div", {
|
|
260
|
+
shouldForwardProp: (prop) =>
|
|
261
|
+
prop !== "odysseyDesignTokens" &&
|
|
262
|
+
prop !== "isScrollableStart" &&
|
|
263
|
+
prop !== "isScrollableEnd",
|
|
264
|
+
})(
|
|
265
|
+
({
|
|
266
|
+
odysseyDesignTokens,
|
|
267
|
+
isScrollableStart,
|
|
268
|
+
isScrollableEnd,
|
|
269
|
+
}: {
|
|
270
|
+
odysseyDesignTokens: DesignTokens;
|
|
271
|
+
isScrollableStart: boolean;
|
|
272
|
+
isScrollableEnd: boolean;
|
|
273
|
+
}) => ({
|
|
274
|
+
borderBlockEndColor: odysseyDesignTokens.HueNeutral100,
|
|
275
|
+
borderBlockEndStyle: "solid",
|
|
276
|
+
borderBlockEndWidth: odysseyDesignTokens.BorderWidthMain,
|
|
277
|
+
marginBlockEnd: odysseyDesignTokens.Spacing4,
|
|
278
|
+
position: "relative",
|
|
279
|
+
borderInlineStartColor: isScrollableStart
|
|
280
|
+
? odysseyDesignTokens.HueNeutral200
|
|
281
|
+
: "transparent",
|
|
282
|
+
borderInlineStartStyle: "solid",
|
|
283
|
+
borderInlineStartWidth: odysseyDesignTokens.BorderWidthMain,
|
|
284
|
+
"::before": {
|
|
285
|
+
background:
|
|
286
|
+
"linear-gradient(-90deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.33) 50%, rgba(0, 0, 0, 1) 100%)",
|
|
287
|
+
content: '""',
|
|
288
|
+
opacity: isScrollableStart ? "0.075" : "0",
|
|
289
|
+
pointerEvents: "none",
|
|
290
|
+
position: "absolute",
|
|
291
|
+
top: 0,
|
|
292
|
+
left: 0,
|
|
293
|
+
bottom: 0,
|
|
294
|
+
width: odysseyDesignTokens.Spacing6,
|
|
295
|
+
zIndex: 100,
|
|
296
|
+
transition: `opacity ${odysseyDesignTokens.TransitionDurationMain} ${odysseyDesignTokens.TransitionTimingMain}`,
|
|
297
|
+
},
|
|
298
|
+
borderInlineEndColor: isScrollableEnd
|
|
299
|
+
? odysseyDesignTokens.HueNeutral200
|
|
300
|
+
: "transparent",
|
|
301
|
+
borderInlineEndStyle: "solid",
|
|
302
|
+
borderInlineEndWidth: odysseyDesignTokens.BorderWidthMain,
|
|
303
|
+
"::after": {
|
|
304
|
+
background:
|
|
305
|
+
"linear-gradient(90deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.33) 50%, rgba(0, 0, 0, 1) 100%)",
|
|
306
|
+
content: '""',
|
|
307
|
+
opacity: isScrollableEnd ? "0.075" : "0",
|
|
308
|
+
pointerEvents: "none",
|
|
309
|
+
position: "absolute",
|
|
310
|
+
top: 0,
|
|
311
|
+
right: 0,
|
|
312
|
+
bottom: 0,
|
|
313
|
+
width: odysseyDesignTokens.Spacing6,
|
|
314
|
+
transition: `opacity ${odysseyDesignTokens.TransitionDurationMain} ${odysseyDesignTokens.TransitionTimingMain}`,
|
|
315
|
+
},
|
|
316
|
+
}),
|
|
317
|
+
);
|
|
318
|
+
|
|
223
319
|
const DataTable = ({
|
|
224
320
|
columns,
|
|
225
321
|
getRowId: getRowIdProp,
|
|
@@ -244,6 +340,10 @@ const DataTable = ({
|
|
|
244
340
|
hasRowSelection,
|
|
245
341
|
hasSearch,
|
|
246
342
|
hasSorting,
|
|
343
|
+
bulkActionMenuItems,
|
|
344
|
+
errorMessage: errorMessageProp,
|
|
345
|
+
emptyPlaceholder,
|
|
346
|
+
noResultsPlaceholder,
|
|
247
347
|
}: DataTableProps) => {
|
|
248
348
|
const [data, setData] = useState<MRT_RowData[]>([]);
|
|
249
349
|
const [pagination, setPagination] = useState({
|
|
@@ -251,6 +351,15 @@ const DataTable = ({
|
|
|
251
351
|
pageSize: resultsPerPage,
|
|
252
352
|
});
|
|
253
353
|
const [draggingRow, setDraggingRow] = useState<MRT_Row<MRT_RowData> | null>();
|
|
354
|
+
const [isTableContainerScrolledToStart, setIsTableContainerScrolledToStart] =
|
|
355
|
+
useState(true);
|
|
356
|
+
const [isTableContainerScrolledToEnd, setIsTableContainerScrolledToEnd] =
|
|
357
|
+
useState(true);
|
|
358
|
+
const [tableInnerContainerWidth, setTableInnerContainerWidth] =
|
|
359
|
+
useState<string>("100%");
|
|
360
|
+
const tableOuterContainerRef = useRef<HTMLDivElement>(null);
|
|
361
|
+
const tableInnerContainerRef = useRef<HTMLDivElement>(null);
|
|
362
|
+
const tableContentRef = useRef<HTMLTableElement>(null);
|
|
254
363
|
|
|
255
364
|
// Table states
|
|
256
365
|
const [columnSorting, setColumnSorting] = useState<MRT_SortingState>([]);
|
|
@@ -258,8 +367,25 @@ const DataTable = ({
|
|
|
258
367
|
useState<MRT_VisibilityState>();
|
|
259
368
|
const [rowDensity, setRowDensity] =
|
|
260
369
|
useState<MRT_DensityState>(initialDensity);
|
|
370
|
+
const [rowSelection, setRowSelection] = useState<MRT_RowSelectionState>({});
|
|
261
371
|
const [search, setSearch] = useState<string>("");
|
|
262
372
|
const [filters, setFilters] = useState<DataFilter[]>();
|
|
373
|
+
const [initialFilters, setInitialFilters] = useState<DataFilter[]>();
|
|
374
|
+
const [isLoading, setIsLoading] = useState<boolean | undefined>(true);
|
|
375
|
+
const [isEmpty, setIsEmpty] = useState<boolean | undefined>();
|
|
376
|
+
const [errorMessage, setErrorMessage] = useState<string | undefined>(
|
|
377
|
+
errorMessageProp,
|
|
378
|
+
);
|
|
379
|
+
|
|
380
|
+
useScrollIndication({
|
|
381
|
+
tableOuterContainer: tableOuterContainerRef.current,
|
|
382
|
+
tableInnerContainer: tableInnerContainerRef.current,
|
|
383
|
+
setIsTableContainerScrolledToStart: setIsTableContainerScrolledToStart,
|
|
384
|
+
setIsTableContainerScrolledToEnd: setIsTableContainerScrolledToEnd,
|
|
385
|
+
setTableInnerContainerWidth: setTableInnerContainerWidth,
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
const odysseyDesignTokens = useOdysseyDesignTokens();
|
|
263
389
|
|
|
264
390
|
const {
|
|
265
391
|
dragHandleStyles,
|
|
@@ -352,6 +478,29 @@ const DataTable = ({
|
|
|
352
478
|
[],
|
|
353
479
|
);
|
|
354
480
|
|
|
481
|
+
const emptyState = useCallback(() => {
|
|
482
|
+
const noResultsInnerContent = noResultsPlaceholder || (
|
|
483
|
+
<DataTableEmptyState
|
|
484
|
+
heading={t("table.noresults.heading")}
|
|
485
|
+
text={t("table.noresults.text")}
|
|
486
|
+
/>
|
|
487
|
+
);
|
|
488
|
+
|
|
489
|
+
const emptyStateInnerContent =
|
|
490
|
+
emptyPlaceholder && isEmpty ? emptyPlaceholder : noResultsInnerContent;
|
|
491
|
+
|
|
492
|
+
return (
|
|
493
|
+
<Box sx={{ width: tableInnerContainerWidth }}>
|
|
494
|
+
{emptyStateInnerContent}
|
|
495
|
+
</Box>
|
|
496
|
+
);
|
|
497
|
+
}, [
|
|
498
|
+
tableInnerContainerWidth,
|
|
499
|
+
emptyPlaceholder,
|
|
500
|
+
noResultsPlaceholder,
|
|
501
|
+
isEmpty,
|
|
502
|
+
]);
|
|
503
|
+
|
|
355
504
|
const dataTable = useMaterialReactTable({
|
|
356
505
|
columns: columns,
|
|
357
506
|
data: data,
|
|
@@ -361,6 +510,8 @@ const DataTable = ({
|
|
|
361
510
|
sorting: columnSorting,
|
|
362
511
|
globalFilter: search,
|
|
363
512
|
columnVisibility,
|
|
513
|
+
isLoading,
|
|
514
|
+
rowSelection,
|
|
364
515
|
},
|
|
365
516
|
icons: {
|
|
366
517
|
ArrowDownwardIcon: ArrowDownIcon,
|
|
@@ -428,6 +579,7 @@ const DataTable = ({
|
|
|
428
579
|
|
|
429
580
|
// Row selection
|
|
430
581
|
enableRowSelection: hasRowSelection,
|
|
582
|
+
onRowSelectionChange: setRowSelection,
|
|
431
583
|
|
|
432
584
|
// Sorting
|
|
433
585
|
enableSorting: hasSorting,
|
|
@@ -442,77 +594,47 @@ const DataTable = ({
|
|
|
442
594
|
|
|
443
595
|
// Virtualization
|
|
444
596
|
enableRowVirtualization:
|
|
445
|
-
paginationType
|
|
597
|
+
paginationType !== "loadMore" && pagination.pageSize > 50,
|
|
446
598
|
rowVirtualizerInstanceRef:
|
|
447
|
-
useRef<
|
|
599
|
+
useRef<MRT_RowVirtualizer<HTMLDivElement, HTMLTableRowElement>>(null),
|
|
448
600
|
rowVirtualizerOptions: {
|
|
449
601
|
overscan: 4,
|
|
450
602
|
},
|
|
451
603
|
|
|
452
|
-
//
|
|
453
|
-
|
|
454
|
-
<Box sx={{ marginBottom: 5 }}>
|
|
455
|
-
<DataFilters
|
|
456
|
-
onChangeSearch={hasSearch ? setSearch : undefined}
|
|
457
|
-
onChangeFilters={hasFilters ? setFilters : undefined}
|
|
458
|
-
hasSearchSubmitButton={hasSearchSubmitButton}
|
|
459
|
-
searchDelayTime={searchDelayTime}
|
|
460
|
-
filters={hasFilters ? dataTableFilters : undefined}
|
|
461
|
-
additionalActions={
|
|
462
|
-
<DataTableSettings
|
|
463
|
-
hasChangeableDensity={hasChangeableDensity}
|
|
464
|
-
rowDensity={rowDensity}
|
|
465
|
-
setRowDensity={setRowDensity}
|
|
466
|
-
hasColumnVisibility={hasColumnVisibility}
|
|
467
|
-
columns={columns}
|
|
468
|
-
columnVisibility={columnVisibility}
|
|
469
|
-
setColumnVisibility={setColumnVisibility}
|
|
470
|
-
/>
|
|
471
|
-
}
|
|
472
|
-
/>
|
|
473
|
-
</Box>
|
|
474
|
-
),
|
|
604
|
+
// States
|
|
605
|
+
renderEmptyRowsFallback: emptyState,
|
|
475
606
|
|
|
476
|
-
//
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
isNextButtonDisabled={false} // TODO: Add logic for disabling next/load more button
|
|
485
|
-
onClickPrevious={() =>
|
|
486
|
-
setPagination({
|
|
487
|
-
pageIndex: pagination.pageIndex - 1,
|
|
488
|
-
pageSize: pagination.pageSize,
|
|
489
|
-
})
|
|
490
|
-
}
|
|
491
|
-
onClickNext={() => {
|
|
492
|
-
if (paginationType === "loadMore") {
|
|
493
|
-
setPagination({
|
|
494
|
-
pageSize: pagination.pageSize,
|
|
495
|
-
pageIndex: pagination.pageSize + resultsPerPage,
|
|
496
|
-
});
|
|
497
|
-
} else {
|
|
498
|
-
setPagination({
|
|
499
|
-
pageSize: pagination.pageSize,
|
|
500
|
-
pageIndex: pagination.pageIndex + 1,
|
|
501
|
-
});
|
|
502
|
-
}
|
|
503
|
-
}}
|
|
504
|
-
/>
|
|
505
|
-
)
|
|
506
|
-
: undefined,
|
|
607
|
+
// Refs
|
|
608
|
+
muiTableProps: {
|
|
609
|
+
ref: tableContentRef,
|
|
610
|
+
},
|
|
611
|
+
|
|
612
|
+
muiTableContainerProps: {
|
|
613
|
+
ref: tableInnerContainerRef,
|
|
614
|
+
},
|
|
507
615
|
});
|
|
508
616
|
|
|
509
617
|
// Effects
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
618
|
+
const bulkActionMenuButton = useMemo(
|
|
619
|
+
() => (
|
|
620
|
+
<>
|
|
621
|
+
<MenuButton
|
|
622
|
+
buttonVariant="secondary"
|
|
623
|
+
endIcon={<MoreIcon />}
|
|
624
|
+
isDisabled={Object.keys(rowSelection).length === 0}
|
|
625
|
+
ariaLabel="More actions"
|
|
626
|
+
>
|
|
627
|
+
{bulkActionMenuItems?.(rowSelection)}
|
|
628
|
+
</MenuButton>
|
|
629
|
+
</>
|
|
630
|
+
),
|
|
631
|
+
[bulkActionMenuItems, rowSelection],
|
|
632
|
+
);
|
|
513
633
|
|
|
514
634
|
useEffect(() => {
|
|
515
635
|
(async () => {
|
|
636
|
+
setIsLoading(true);
|
|
637
|
+
setErrorMessage(errorMessageProp);
|
|
516
638
|
try {
|
|
517
639
|
const incomingData = await getData?.({
|
|
518
640
|
page: pagination.pageIndex,
|
|
@@ -523,13 +645,99 @@ const DataTable = ({
|
|
|
523
645
|
});
|
|
524
646
|
setData(incomingData);
|
|
525
647
|
} catch (error) {
|
|
648
|
+
setErrorMessage(typeof error === "string" ? error : t("table.error"));
|
|
526
649
|
} finally {
|
|
650
|
+
setIsLoading(false);
|
|
527
651
|
}
|
|
528
652
|
})();
|
|
529
|
-
}, [pagination, columnSorting, search, filters, getData]);
|
|
653
|
+
}, [pagination, columnSorting, search, filters, getData, errorMessageProp]);
|
|
654
|
+
|
|
655
|
+
useEffect(() => {
|
|
656
|
+
if (!initialFilters && filters) {
|
|
657
|
+
setInitialFilters(filters);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
setIsEmpty(
|
|
661
|
+
pagination.pageIndex === currentPage &&
|
|
662
|
+
pagination.pageSize === resultsPerPage &&
|
|
663
|
+
search === "" &&
|
|
664
|
+
filters === initialFilters &&
|
|
665
|
+
data.length === 0,
|
|
666
|
+
);
|
|
667
|
+
}, [
|
|
668
|
+
filters,
|
|
669
|
+
pagination,
|
|
670
|
+
search,
|
|
671
|
+
data,
|
|
672
|
+
currentPage,
|
|
673
|
+
initialFilters,
|
|
674
|
+
resultsPerPage,
|
|
675
|
+
]);
|
|
676
|
+
|
|
677
|
+
useEffect(() => {
|
|
678
|
+
onChangeRowSelection?.(rowSelection);
|
|
679
|
+
}, [rowSelection, onChangeRowSelection]);
|
|
530
680
|
|
|
531
681
|
// Render the table
|
|
532
|
-
return
|
|
682
|
+
return (
|
|
683
|
+
<>
|
|
684
|
+
{(hasSearch ||
|
|
685
|
+
hasFilters ||
|
|
686
|
+
hasChangeableDensity ||
|
|
687
|
+
hasColumnVisibility ||
|
|
688
|
+
bulkActionMenuItems) && (
|
|
689
|
+
<Box sx={{ marginBottom: 5 }}>
|
|
690
|
+
<DataFilters
|
|
691
|
+
onChangeSearch={hasSearch ? setSearch : undefined}
|
|
692
|
+
onChangeFilters={hasFilters ? setFilters : undefined}
|
|
693
|
+
hasSearchSubmitButton={hasSearchSubmitButton}
|
|
694
|
+
searchDelayTime={searchDelayTime}
|
|
695
|
+
filters={hasFilters ? dataTableFilters : undefined}
|
|
696
|
+
isDisabled={isEmpty}
|
|
697
|
+
additionalActions={
|
|
698
|
+
<>
|
|
699
|
+
<DataTableSettings
|
|
700
|
+
hasChangeableDensity={hasChangeableDensity}
|
|
701
|
+
rowDensity={rowDensity}
|
|
702
|
+
setRowDensity={setRowDensity}
|
|
703
|
+
hasColumnVisibility={hasColumnVisibility}
|
|
704
|
+
columns={columns}
|
|
705
|
+
columnVisibility={columnVisibility}
|
|
706
|
+
setColumnVisibility={setColumnVisibility}
|
|
707
|
+
/>
|
|
708
|
+
{bulkActionMenuItems && bulkActionMenuButton}
|
|
709
|
+
</>
|
|
710
|
+
}
|
|
711
|
+
/>
|
|
712
|
+
</Box>
|
|
713
|
+
)}
|
|
714
|
+
|
|
715
|
+
{errorMessage && (
|
|
716
|
+
<Box sx={{ marginBlockEnd: 2 }}>
|
|
717
|
+
<Callout severity="error" text={errorMessage} />
|
|
718
|
+
</Box>
|
|
719
|
+
)}
|
|
720
|
+
|
|
721
|
+
<ScrollableTableContainer
|
|
722
|
+
odysseyDesignTokens={odysseyDesignTokens}
|
|
723
|
+
isScrollableStart={!isTableContainerScrolledToStart}
|
|
724
|
+
isScrollableEnd={!isTableContainerScrolledToEnd}
|
|
725
|
+
ref={tableOuterContainerRef}
|
|
726
|
+
>
|
|
727
|
+
<MRT_TableContainer table={dataTable} />
|
|
728
|
+
</ScrollableTableContainer>
|
|
729
|
+
|
|
730
|
+
{hasPagination && (
|
|
731
|
+
<DataTablePagination
|
|
732
|
+
pagination={pagination}
|
|
733
|
+
setPagination={setPagination}
|
|
734
|
+
totalRows={totalRows}
|
|
735
|
+
isDisabled={isEmpty}
|
|
736
|
+
variant={paginationType}
|
|
737
|
+
/>
|
|
738
|
+
)}
|
|
739
|
+
</>
|
|
740
|
+
);
|
|
533
741
|
};
|
|
534
742
|
|
|
535
743
|
const MemoizedDataTable = memo(DataTable);
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2024-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 { ReactNode, memo } from "react";
|
|
14
|
+
import { Heading4, Paragraph } from "../Typography";
|
|
15
|
+
import { Box } from "../Box";
|
|
16
|
+
import styled from "@emotion/styled";
|
|
17
|
+
import {
|
|
18
|
+
useOdysseyDesignTokens,
|
|
19
|
+
DesignTokens,
|
|
20
|
+
} from "../OdysseyDesignTokensContext";
|
|
21
|
+
|
|
22
|
+
const EmptyContainer = styled("div", {
|
|
23
|
+
shouldForwardProp: (prop) => prop !== "odysseyDesignTokens",
|
|
24
|
+
})(({ odysseyDesignTokens }: { odysseyDesignTokens: DesignTokens }) => ({
|
|
25
|
+
display: "flex",
|
|
26
|
+
flexDirection: "column",
|
|
27
|
+
marginBlock: odysseyDesignTokens.Spacing9,
|
|
28
|
+
padding: odysseyDesignTokens.Spacing5,
|
|
29
|
+
textAlign: "center",
|
|
30
|
+
width: "100%",
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
export type DataTableEmptyStateProps = {
|
|
34
|
+
heading: string;
|
|
35
|
+
text: string;
|
|
36
|
+
primaryButton?: ReactNode;
|
|
37
|
+
secondaryButton?: ReactNode;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const DataTableEmptyState = ({
|
|
41
|
+
heading,
|
|
42
|
+
text,
|
|
43
|
+
primaryButton,
|
|
44
|
+
secondaryButton,
|
|
45
|
+
}: DataTableEmptyStateProps) => {
|
|
46
|
+
const odysseyDesignTokens = useOdysseyDesignTokens();
|
|
47
|
+
return (
|
|
48
|
+
<EmptyContainer odysseyDesignTokens={odysseyDesignTokens}>
|
|
49
|
+
<Heading4>{heading}</Heading4>
|
|
50
|
+
<Paragraph>{text}</Paragraph>
|
|
51
|
+
{(primaryButton || secondaryButton) && (
|
|
52
|
+
<Box sx={{ marginBlockStart: 5 }}>
|
|
53
|
+
{secondaryButton}
|
|
54
|
+
{primaryButton}
|
|
55
|
+
</Box>
|
|
56
|
+
)}
|
|
57
|
+
</EmptyContainer>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const MemoizedDataTableEmptyState = memo(DataTableEmptyState);
|
|
62
|
+
export { MemoizedDataTableEmptyState as DataTableEmptyState };
|