@mini_7/material-react-table-mcp 4.0.0 → 4.0.1
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 +1 -1
- package/data/examples/advanced.js +215 -0
- package/data/examples/aggregation-and-grouping.js +116 -0
- package/data/examples/aggregation-multi.js +89 -0
- package/data/examples/alternate-column-filtering.js +38 -0
- package/data/examples/alternate-detail-panel.js +65 -0
- package/data/examples/alternate-pagination.js +17 -0
- package/data/examples/basic.js +86 -0
- package/data/examples/chart-detail-panel.js +69 -0
- package/data/examples/column-actions-space.js +34 -0
- package/data/examples/column-alignment.js +58 -0
- package/data/examples/custom-column-actions.js +74 -0
- package/data/examples/custom-column-filtering-ui.js +59 -0
- package/data/examples/custom-headless.js +85 -0
- package/data/examples/custom-top-toolbar.js +60 -0
- package/data/examples/customize-display-columns.js +72 -0
- package/data/examples/customize-filter-components.js +78 -0
- package/data/examples/customize-filter-modes.js +59 -0
- package/data/examples/customize-filter-variants.js +98 -0
- package/data/examples/customize-global-filter-component.js +37 -0
- package/data/examples/customize-remove-column-grouping.js +75 -0
- package/data/examples/customize-row-selection.js +43 -0
- package/data/examples/customize-table-styles.js +81 -0
- package/data/examples/disable-column-actions.js +26 -0
- package/data/examples/disable-column-hiding.js +74 -0
- package/data/examples/disable-density-toggle.js +37 -0
- package/data/examples/dynamic-columns.js +124 -0
- package/data/examples/editing-crud-cell.js +288 -0
- package/data/examples/editing-crud-modal.js +275 -0
- package/data/examples/editing-crud-row.js +255 -0
- package/data/examples/editing-crud-table.js +280 -0
- package/data/examples/editing-crud-tree.js +328 -0
- package/data/examples/enable-cell-actions.js +52 -0
- package/data/examples/enable-click-to-copy.js +33 -0
- package/data/examples/enable-column-grouping.js +69 -0
- package/data/examples/enable-column-ordering.js +37 -0
- package/data/examples/enable-column-pinning.js +58 -0
- package/data/examples/enable-column-resizing.js +45 -0
- package/data/examples/enable-column-virtualization.js +19 -0
- package/data/examples/enable-detail-panel-conditionally.js +61 -0
- package/data/examples/enable-detail-panel-virtualized.js +64 -0
- package/data/examples/enable-expanding-tree.js +87 -0
- package/data/examples/enable-filter-facet-values.js +52 -0
- package/data/examples/enable-row-dragging.js +102 -0
- package/data/examples/enable-row-numbers-original.js +37 -0
- package/data/examples/enable-row-numbers-static.js +37 -0
- package/data/examples/enable-row-ordering.js +40 -0
- package/data/examples/enable-row-pinning-select.js +64 -0
- package/data/examples/enable-row-pinning-static.js +39 -0
- package/data/examples/enable-row-pinning-sticky.js +57 -0
- package/data/examples/enable-row-selection.js +71 -0
- package/data/examples/enable-row-virtualization.js +85 -0
- package/data/examples/enable-sticky-header.js +47 -0
- package/data/examples/expanding-tree-expanded.js +98 -0
- package/data/examples/expanding-tree-flat-parse.js +102 -0
- package/data/examples/expanding-tree-root-expanded.js +120 -0
- package/data/examples/export-to-csv.js +84 -0
- package/data/examples/export-to-pdf.js +76 -0
- package/data/examples/external-toolbar.js +82 -0
- package/data/examples/font-awesome-icons.js +62 -0
- package/data/examples/infinite-scrolling.js +137 -0
- package/data/examples/lazy-detail-panel.js +164 -0
- package/data/examples/lazy-sub-rows.js +118 -0
- package/data/examples/linear-progress.js +48 -0
- package/data/examples/loading.js +34 -0
- package/data/examples/localization-i18n-ar.js +40 -0
- package/data/examples/localization-i18n-az.js +38 -0
- package/data/examples/localization-i18n-bg.js +38 -0
- package/data/examples/localization-i18n-cs.js +38 -0
- package/data/examples/localization-i18n-da.js +38 -0
- package/data/examples/localization-i18n-de.js +38 -0
- package/data/examples/localization-i18n-el.js +38 -0
- package/data/examples/localization-i18n-en.js +38 -0
- package/data/examples/localization-i18n-es.js +38 -0
- package/data/examples/localization-i18n-et.js +38 -0
- package/data/examples/localization-i18n-fa.js +40 -0
- package/data/examples/localization-i18n-fi.js +38 -0
- package/data/examples/localization-i18n-fr.js +38 -0
- package/data/examples/localization-i18n-he.js +40 -0
- package/data/examples/localization-i18n-hr.js +38 -0
- package/data/examples/localization-i18n-hu.js +38 -0
- package/data/examples/localization-i18n-hy.js +40 -0
- package/data/examples/localization-i18n-id.js +38 -0
- package/data/examples/localization-i18n-it.js +38 -0
- package/data/examples/localization-i18n-ja.js +38 -0
- package/data/examples/localization-i18n-ko.js +38 -0
- package/data/examples/localization-i18n-nl.js +38 -0
- package/data/examples/localization-i18n-no.js +38 -0
- package/data/examples/localization-i18n-np.js +38 -0
- package/data/examples/localization-i18n-pl.js +38 -0
- package/data/examples/localization-i18n-pt-BR.js +38 -0
- package/data/examples/localization-i18n-pt.js +38 -0
- package/data/examples/localization-i18n-ro.js +38 -0
- package/data/examples/localization-i18n-ru.js +38 -0
- package/data/examples/localization-i18n-sk.js +38 -0
- package/data/examples/localization-i18n-sr-Cyrl-RS.js +38 -0
- package/data/examples/localization-i18n-sr-Latn-RS.js +38 -0
- package/data/examples/localization-i18n-sv.js +38 -0
- package/data/examples/localization-i18n-tr.js +38 -0
- package/data/examples/localization-i18n-uk.js +38 -0
- package/data/examples/localization-i18n-vi.js +38 -0
- package/data/examples/localization-i18n-zh-hans.js +38 -0
- package/data/examples/localization-i18n-zh-hant.js +38 -0
- package/data/examples/manual-selection.js +81 -0
- package/data/examples/minimal.js +66 -0
- package/data/examples/mui-theme.js +109 -0
- package/data/examples/multi-sorting.js +48 -0
- package/data/examples/persistent-state.js +126 -0
- package/data/examples/react-query.js +122 -0
- package/data/examples/remote.js +113 -0
- package/data/examples/row-actions-buttons.js +54 -0
- package/data/examples/row-actions-menu-items.js +36 -0
- package/data/examples/single-row-selection.js +74 -0
- package/data/examples/virtualized.js +122 -0
- package/dist/data.js +31 -9
- package/dist/index.js +18 -6
- package/package.json +1 -1
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { lazy, Suspense, useMemo, useState } from 'react';
|
|
2
|
+
import { MaterialReactTable, createRow, useMaterialReactTable, } from 'material-react-table';
|
|
3
|
+
import { Box, Button, IconButton, Tooltip, darken, lighten, } from '@mui/material';
|
|
4
|
+
import { QueryClient, QueryClientProvider, useMutation, useQuery, useQueryClient, } from '@tanstack/react-query';
|
|
5
|
+
import { fakeData, usStates } from './makeData';
|
|
6
|
+
import PersonAddAltIcon from '@mui/icons-material/PersonAddAlt';
|
|
7
|
+
import EditIcon from '@mui/icons-material/Edit';
|
|
8
|
+
import DeleteIcon from '@mui/icons-material/Delete';
|
|
9
|
+
const Example = () => {
|
|
10
|
+
const [creatingRowIndex, setCreatingRowIndex] = useState();
|
|
11
|
+
const [validationErrors, setValidationErrors] = useState({});
|
|
12
|
+
const columns = useMemo(() => [
|
|
13
|
+
{
|
|
14
|
+
accessorKey: 'id',
|
|
15
|
+
header: 'Id',
|
|
16
|
+
enableEditing: false,
|
|
17
|
+
size: 80,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
accessorKey: 'firstName',
|
|
21
|
+
header: 'First Name',
|
|
22
|
+
muiEditTextFieldProps: {
|
|
23
|
+
required: true,
|
|
24
|
+
error: !!validationErrors?.firstName,
|
|
25
|
+
helperText: validationErrors?.firstName,
|
|
26
|
+
//remove any previous validation errors when user focuses on the input
|
|
27
|
+
onFocus: () => setValidationErrors({
|
|
28
|
+
...validationErrors,
|
|
29
|
+
firstName: undefined,
|
|
30
|
+
}),
|
|
31
|
+
//optionally add validation checking for onBlur or onChange
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
accessorKey: 'lastName',
|
|
36
|
+
header: 'Last Name',
|
|
37
|
+
muiEditTextFieldProps: {
|
|
38
|
+
required: true,
|
|
39
|
+
error: !!validationErrors?.lastName,
|
|
40
|
+
helperText: validationErrors?.lastName,
|
|
41
|
+
//remove any previous validation errors when user focuses on the input
|
|
42
|
+
onFocus: () => setValidationErrors({
|
|
43
|
+
...validationErrors,
|
|
44
|
+
lastName: undefined,
|
|
45
|
+
}),
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
accessorKey: 'city',
|
|
50
|
+
header: 'City',
|
|
51
|
+
muiEditTextFieldProps: {
|
|
52
|
+
required: true,
|
|
53
|
+
error: !!validationErrors?.city,
|
|
54
|
+
helperText: validationErrors?.city,
|
|
55
|
+
//remove any previous validation errors when user focuses on the input
|
|
56
|
+
onFocus: () => setValidationErrors({
|
|
57
|
+
...validationErrors,
|
|
58
|
+
city: undefined,
|
|
59
|
+
}),
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
accessorKey: 'state',
|
|
64
|
+
header: 'State',
|
|
65
|
+
editVariant: 'select',
|
|
66
|
+
editSelectOptions: usStates,
|
|
67
|
+
muiEditTextFieldProps: {
|
|
68
|
+
select: true,
|
|
69
|
+
error: !!validationErrors?.state,
|
|
70
|
+
helperText: validationErrors?.state,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
], [validationErrors]);
|
|
74
|
+
//call CREATE hook
|
|
75
|
+
const { mutateAsync: createUser, isPending: isCreatingUser } = useCreateUser();
|
|
76
|
+
//call READ hook
|
|
77
|
+
const { data: fetchedUsers = [], isError: isLoadingUsersError, isFetching: isFetchingUsers, isLoading: isLoadingUsers, } = useGetUsers();
|
|
78
|
+
//call UPDATE hook
|
|
79
|
+
const { mutateAsync: updateUser, isPending: isUpdatingUser } = useUpdateUser();
|
|
80
|
+
//call DELETE hook
|
|
81
|
+
const { mutateAsync: deleteUser, isPending: isDeletingUser } = useDeleteUser();
|
|
82
|
+
//CREATE action
|
|
83
|
+
const handleCreateUser = async ({ values, row, table, }) => {
|
|
84
|
+
const newValidationErrors = validateUser(values);
|
|
85
|
+
if (Object.values(newValidationErrors).some((error) => error)) {
|
|
86
|
+
setValidationErrors(newValidationErrors);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
setValidationErrors({});
|
|
90
|
+
await createUser({ ...values, managerId: row.original.managerId });
|
|
91
|
+
table.setCreatingRow(null); //exit creating mode
|
|
92
|
+
};
|
|
93
|
+
//UPDATE action
|
|
94
|
+
const handleSaveUser = async ({ values, table, }) => {
|
|
95
|
+
const newValidationErrors = validateUser(values);
|
|
96
|
+
if (Object.values(newValidationErrors).some((error) => error)) {
|
|
97
|
+
setValidationErrors(newValidationErrors);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
setValidationErrors({});
|
|
101
|
+
await updateUser(values);
|
|
102
|
+
table.setEditingRow(null); //exit editing mode
|
|
103
|
+
};
|
|
104
|
+
//DELETE action
|
|
105
|
+
const openDeleteConfirmModal = (row) => {
|
|
106
|
+
if (window.confirm('Are you sure you want to delete this user?')) {
|
|
107
|
+
deleteUser(row.original.id);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const table = useMaterialReactTable({
|
|
111
|
+
columns,
|
|
112
|
+
data: fetchedUsers,
|
|
113
|
+
createDisplayMode: 'row', // ('modal', and 'custom' are also available)
|
|
114
|
+
editDisplayMode: 'row', // ('modal', 'cell', 'table', and 'custom' are also available)
|
|
115
|
+
enableColumnPinning: true,
|
|
116
|
+
enableEditing: true,
|
|
117
|
+
enableExpanding: true,
|
|
118
|
+
positionCreatingRow: creatingRowIndex, //index where new row is inserted before
|
|
119
|
+
getRowId: (row) => row.id,
|
|
120
|
+
muiToolbarAlertBannerProps: isLoadingUsersError
|
|
121
|
+
? {
|
|
122
|
+
color: 'error',
|
|
123
|
+
children: 'Error loading data',
|
|
124
|
+
}
|
|
125
|
+
: undefined,
|
|
126
|
+
muiTableContainerProps: {
|
|
127
|
+
sx: {
|
|
128
|
+
minHeight: '500px',
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
muiTableBodyRowProps: ({ row }) => ({
|
|
132
|
+
//conditional styling based on row depth
|
|
133
|
+
sx: (theme) => ({
|
|
134
|
+
td: {
|
|
135
|
+
backgroundColor: darken(lighten(theme.palette.background.paper, 0.1), row.depth * (theme.palette.mode === 'dark' ? 0.2 : 0.1)),
|
|
136
|
+
},
|
|
137
|
+
}),
|
|
138
|
+
}),
|
|
139
|
+
onCreatingRowCancel: () => setValidationErrors({}),
|
|
140
|
+
onCreatingRowSave: handleCreateUser,
|
|
141
|
+
onEditingRowCancel: () => setValidationErrors({}),
|
|
142
|
+
onEditingRowSave: handleSaveUser,
|
|
143
|
+
renderRowActions: ({ row, staticRowIndex, table }) => (<Box sx={{ display: 'flex', gap: '1rem' }}>
|
|
144
|
+
<Tooltip title="Edit">
|
|
145
|
+
<IconButton onClick={() => table.setEditingRow(row)}>
|
|
146
|
+
<EditIcon />
|
|
147
|
+
</IconButton>
|
|
148
|
+
</Tooltip>
|
|
149
|
+
<Tooltip title="Delete">
|
|
150
|
+
<IconButton color="error" onClick={() => openDeleteConfirmModal(row)}>
|
|
151
|
+
<DeleteIcon />
|
|
152
|
+
</IconButton>
|
|
153
|
+
</Tooltip>
|
|
154
|
+
<Tooltip title="Add Subordinate">
|
|
155
|
+
<IconButton onClick={() => {
|
|
156
|
+
setCreatingRowIndex((staticRowIndex || 0) + 1);
|
|
157
|
+
table.setCreatingRow(createRow(table, {
|
|
158
|
+
id: null,
|
|
159
|
+
firstName: '',
|
|
160
|
+
lastName: '',
|
|
161
|
+
city: '',
|
|
162
|
+
state: '',
|
|
163
|
+
managerId: row.id,
|
|
164
|
+
subRows: [],
|
|
165
|
+
}, -1, row.depth + 1));
|
|
166
|
+
}}>
|
|
167
|
+
<PersonAddAltIcon />
|
|
168
|
+
</IconButton>
|
|
169
|
+
</Tooltip>
|
|
170
|
+
</Box>),
|
|
171
|
+
renderTopToolbarCustomActions: ({ table }) => (<Button startIcon={<PersonAddAltIcon />} variant="contained" onClick={() => {
|
|
172
|
+
setCreatingRowIndex(table.getRowModel().rows.length); //create new row at bottom of table
|
|
173
|
+
table.setCreatingRow(true);
|
|
174
|
+
}}>
|
|
175
|
+
Create New User
|
|
176
|
+
</Button>),
|
|
177
|
+
initialState: {
|
|
178
|
+
columnPinning: { end: [], start: ['mrt-row-actions'] },
|
|
179
|
+
expanded: true,
|
|
180
|
+
pagination: { pageSize: 20, pageIndex: 0 },
|
|
181
|
+
},
|
|
182
|
+
state: {
|
|
183
|
+
isLoading: isLoadingUsers,
|
|
184
|
+
isSaving: isCreatingUser || isUpdatingUser || isDeletingUser,
|
|
185
|
+
showAlertBanner: isLoadingUsersError,
|
|
186
|
+
showProgressBars: isFetchingUsers,
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
return <MaterialReactTable table={table}/>;
|
|
190
|
+
};
|
|
191
|
+
//CREATE hook (post new user to api)
|
|
192
|
+
function useCreateUser() {
|
|
193
|
+
const queryClient = useQueryClient();
|
|
194
|
+
return useMutation({
|
|
195
|
+
mutationFn: async (user) => {
|
|
196
|
+
console.info('create user', user);
|
|
197
|
+
//send api update request here
|
|
198
|
+
await new Promise((resolve) => setTimeout(resolve, 1000)); //fake api call
|
|
199
|
+
return Promise.resolve();
|
|
200
|
+
},
|
|
201
|
+
//client side optimistic update
|
|
202
|
+
onMutate: (newUserInfo) => {
|
|
203
|
+
queryClient.setQueryData(['users'], (_prevUsers) => {
|
|
204
|
+
const prevUsers = JSON.parse(JSON.stringify(_prevUsers));
|
|
205
|
+
newUserInfo.subRows = [];
|
|
206
|
+
if (newUserInfo.managerId) {
|
|
207
|
+
const manager = findUserInTree(newUserInfo.managerId, prevUsers);
|
|
208
|
+
if (manager) {
|
|
209
|
+
manager.subRows = [
|
|
210
|
+
...(manager.subRows || []),
|
|
211
|
+
{
|
|
212
|
+
...newUserInfo,
|
|
213
|
+
id: `${manager.id}.${(manager.subRows?.length || 0) + 1}`,
|
|
214
|
+
},
|
|
215
|
+
];
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
prevUsers.push({
|
|
220
|
+
...newUserInfo,
|
|
221
|
+
id: `${prevUsers.length + 1}`,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
return [...prevUsers];
|
|
225
|
+
});
|
|
226
|
+
},
|
|
227
|
+
// onSettled: () => queryClient.invalidateQueries({ queryKey: ['users'] }), //refetch users after mutation, disabled for demo
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
//READ hook (get users from api)
|
|
231
|
+
function useGetUsers() {
|
|
232
|
+
return useQuery({
|
|
233
|
+
queryKey: ['users'],
|
|
234
|
+
queryFn: async () => {
|
|
235
|
+
//send api request here
|
|
236
|
+
await new Promise((resolve) => setTimeout(resolve, 1000)); //fake api call
|
|
237
|
+
return Promise.resolve(fakeData);
|
|
238
|
+
},
|
|
239
|
+
refetchOnWindowFocus: false,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
//UPDATE hook (put user in api)
|
|
243
|
+
function useUpdateUser() {
|
|
244
|
+
const queryClient = useQueryClient();
|
|
245
|
+
return useMutation({
|
|
246
|
+
mutationFn: async (user) => {
|
|
247
|
+
console.info('update user', user);
|
|
248
|
+
//send api update request here
|
|
249
|
+
await new Promise((resolve) => setTimeout(resolve, 1000)); //fake api call
|
|
250
|
+
return Promise.resolve();
|
|
251
|
+
},
|
|
252
|
+
//client side optimistic update
|
|
253
|
+
onMutate: (newUserInfo) => {
|
|
254
|
+
queryClient.setQueryData(['users'], (prevUsers) => {
|
|
255
|
+
let user = findUserInTree(newUserInfo.id, prevUsers);
|
|
256
|
+
user = { ...user, ...newUserInfo };
|
|
257
|
+
return [...prevUsers];
|
|
258
|
+
});
|
|
259
|
+
},
|
|
260
|
+
// onSettled: () => queryClient.invalidateQueries({ queryKey: ['users'] }), //refetch users after mutation, disabled for demo
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
//DELETE hook (delete user in api)
|
|
264
|
+
function useDeleteUser() {
|
|
265
|
+
const queryClient = useQueryClient();
|
|
266
|
+
return useMutation({
|
|
267
|
+
mutationFn: async (userId) => {
|
|
268
|
+
console.info('delete user', userId);
|
|
269
|
+
//send api update request here
|
|
270
|
+
await new Promise((resolve) => setTimeout(resolve, 1000)); //fake api call
|
|
271
|
+
return Promise.resolve();
|
|
272
|
+
},
|
|
273
|
+
//client side optimistic update
|
|
274
|
+
onMutate: (userId) => {
|
|
275
|
+
queryClient.setQueryData(['users'], (prevUsers) => {
|
|
276
|
+
const newUsers = JSON.parse(JSON.stringify(prevUsers));
|
|
277
|
+
//remove user
|
|
278
|
+
const user = findUserInTree(userId, newUsers);
|
|
279
|
+
if (user) {
|
|
280
|
+
const manager = findUserInTree(user.managerId, newUsers);
|
|
281
|
+
if (manager) {
|
|
282
|
+
manager.subRows = manager.subRows?.filter((subUser) => subUser.id !== user.id);
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
return newUsers.filter((user) => user.id !== userId);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return [...newUsers];
|
|
289
|
+
});
|
|
290
|
+
},
|
|
291
|
+
// onSettled: () => queryClient.invalidateQueries({ queryKey: ['users'] }), //refetch users after mutation, disabled for demo
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
//react query setup in App.tsx
|
|
295
|
+
const ReactQueryDevtoolsProduction = lazy(() => import('@tanstack/react-query-devtools/build/modern/production.js').then((d) => ({
|
|
296
|
+
default: d.ReactQueryDevtools,
|
|
297
|
+
})));
|
|
298
|
+
const queryClient = new QueryClient();
|
|
299
|
+
export default function App() {
|
|
300
|
+
return (<QueryClientProvider client={queryClient}>
|
|
301
|
+
<Example />
|
|
302
|
+
<Suspense fallback={null}>
|
|
303
|
+
<ReactQueryDevtoolsProduction />
|
|
304
|
+
</Suspense>
|
|
305
|
+
</QueryClientProvider>);
|
|
306
|
+
}
|
|
307
|
+
const validateRequired = (value) => !!value.length;
|
|
308
|
+
function validateUser(user) {
|
|
309
|
+
return {
|
|
310
|
+
firstName: !validateRequired(user.firstName)
|
|
311
|
+
? 'First Name is Required'
|
|
312
|
+
: '',
|
|
313
|
+
lastName: !validateRequired(user.lastName) ? 'Last Name is Required' : '',
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function findUserInTree(managerId, users) {
|
|
317
|
+
for (let i = 0; i < users.length; i++) {
|
|
318
|
+
if (users[i].id === managerId) {
|
|
319
|
+
return users[i];
|
|
320
|
+
}
|
|
321
|
+
if (users[i].subRows) {
|
|
322
|
+
const found = findUserInTree(managerId, users[i].subRows);
|
|
323
|
+
if (found)
|
|
324
|
+
return found;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { MaterialReactTable, MRT_ActionMenuItem, useMaterialReactTable, } from 'material-react-table';
|
|
3
|
+
import { data } from './makeData';
|
|
4
|
+
import { Divider } from '@mui/material';
|
|
5
|
+
import EmailIcon from '@mui/icons-material/Email';
|
|
6
|
+
import PersonOffOutlinedIcon from '@mui/icons-material/PersonOffOutlined';
|
|
7
|
+
export const Example = () => {
|
|
8
|
+
const columns = useMemo(
|
|
9
|
+
//column definitions...
|
|
10
|
+
() => [
|
|
11
|
+
{
|
|
12
|
+
accessorKey: 'firstName',
|
|
13
|
+
header: 'First Name',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
accessorKey: 'lastName',
|
|
17
|
+
header: 'Last Name',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
accessorKey: 'address',
|
|
21
|
+
header: 'Address',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
accessorKey: 'city',
|
|
25
|
+
header: 'City',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
accessorKey: 'state',
|
|
29
|
+
header: 'State',
|
|
30
|
+
},
|
|
31
|
+
], []);
|
|
32
|
+
const table = useMaterialReactTable({
|
|
33
|
+
columns,
|
|
34
|
+
data,
|
|
35
|
+
enableCellActions: true,
|
|
36
|
+
enableClickToCopy: 'context-menu',
|
|
37
|
+
enableEditing: true,
|
|
38
|
+
editDisplayMode: 'cell',
|
|
39
|
+
renderCellActionMenuItems: ({ closeMenu, table, internalMenuItems }) => [
|
|
40
|
+
...internalMenuItems,
|
|
41
|
+
<Divider key="divider"/>,
|
|
42
|
+
<MRT_ActionMenuItem icon={<EmailIcon />} key={1} label="Item 1" onClick={() => {
|
|
43
|
+
closeMenu();
|
|
44
|
+
}} table={table}/>,
|
|
45
|
+
<MRT_ActionMenuItem icon={<PersonOffOutlinedIcon />} key={2} label="Item 2" onClick={() => {
|
|
46
|
+
closeMenu();
|
|
47
|
+
}} table={table}/>,
|
|
48
|
+
],
|
|
49
|
+
});
|
|
50
|
+
return <MaterialReactTable table={table}/>;
|
|
51
|
+
};
|
|
52
|
+
export default Example;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { MaterialReactTable } from 'material-react-table';
|
|
3
|
+
import { ContentCopy } from '@mui/icons-material';
|
|
4
|
+
import { data } from './makeData';
|
|
5
|
+
const Example = () => {
|
|
6
|
+
const columns = useMemo(() => [
|
|
7
|
+
{
|
|
8
|
+
accessorKey: 'firstName',
|
|
9
|
+
header: 'First Name',
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
accessorKey: 'lastName',
|
|
13
|
+
header: 'Last Name',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
accessorKey: 'email',
|
|
17
|
+
header: 'Email',
|
|
18
|
+
enableClickToCopy: true,
|
|
19
|
+
muiCopyButtonProps: {
|
|
20
|
+
fullWidth: true,
|
|
21
|
+
startIcon: <ContentCopy />,
|
|
22
|
+
sx: { justifyContent: 'flex-start' },
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
accessorKey: 'city',
|
|
27
|
+
header: 'City',
|
|
28
|
+
enableClickToCopy: true,
|
|
29
|
+
},
|
|
30
|
+
], []);
|
|
31
|
+
return <MaterialReactTable columns={columns} data={data}/>;
|
|
32
|
+
};
|
|
33
|
+
export default Example;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { useMemo, useState } from 'react';
|
|
2
|
+
import { MaterialReactTable, useMaterialReactTable, } from 'material-react-table';
|
|
3
|
+
import { data } from './makeData';
|
|
4
|
+
import { FormControl, FormControlLabel, FormLabel, Radio, RadioGroup, Stack, } from '@mui/material';
|
|
5
|
+
const Example = () => {
|
|
6
|
+
const columns = useMemo(
|
|
7
|
+
//column definitions...
|
|
8
|
+
() => [
|
|
9
|
+
{
|
|
10
|
+
header: 'First Name',
|
|
11
|
+
accessorKey: 'firstName',
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
header: 'Last Name',
|
|
15
|
+
accessorKey: 'lastName',
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
header: 'Age',
|
|
19
|
+
accessorKey: 'age',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
header: 'Gender',
|
|
23
|
+
accessorKey: 'gender',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
header: 'State',
|
|
27
|
+
accessorKey: 'state',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
header: 'Salary',
|
|
31
|
+
accessorKey: 'salary',
|
|
32
|
+
},
|
|
33
|
+
], []);
|
|
34
|
+
//demo state
|
|
35
|
+
const [groupedColumnMode, setGroupedColumnMode] = useState('reorder'); //default is 'reorder
|
|
36
|
+
const table = useMaterialReactTable({
|
|
37
|
+
columns,
|
|
38
|
+
data,
|
|
39
|
+
enableGrouping: true,
|
|
40
|
+
groupedColumnMode,
|
|
41
|
+
initialState: {
|
|
42
|
+
expanded: true, //expand all groups by default
|
|
43
|
+
grouping: ['state', 'gender'], //an array of columns to group by by default (can be multiple)
|
|
44
|
+
pagination: { pageIndex: 0, pageSize: 20 },
|
|
45
|
+
},
|
|
46
|
+
muiTableContainerProps: { sx: { maxHeight: '800px' } },
|
|
47
|
+
});
|
|
48
|
+
return (<Stack sx={{
|
|
49
|
+
gap: '1rem',
|
|
50
|
+
}}>
|
|
51
|
+
<DemoRadioGroup groupedColumnMode={groupedColumnMode} setGroupedColumnMode={setGroupedColumnMode}/>
|
|
52
|
+
<MaterialReactTable table={table}/>
|
|
53
|
+
</Stack>);
|
|
54
|
+
};
|
|
55
|
+
export default Example;
|
|
56
|
+
//demo...
|
|
57
|
+
const DemoRadioGroup = ({ groupedColumnMode, setGroupedColumnMode, }) => {
|
|
58
|
+
return (<FormControl sx={{ margin: 'auto', textAlign: 'center' }}>
|
|
59
|
+
<FormLabel>Grouped Column Mode</FormLabel>
|
|
60
|
+
<RadioGroup row value={groupedColumnMode} onChange={(event) => setGroupedColumnMode(event.target.value === 'false'
|
|
61
|
+
? false
|
|
62
|
+
: event.target.value)}>
|
|
63
|
+
<FormControlLabel control={<Radio />} label='"reorder" (default)' value="reorder"/>
|
|
64
|
+
<FormControlLabel control={<Radio />} label='"remove"' value="remove"/>
|
|
65
|
+
<FormControlLabel value={false} control={<Radio />} label="false"/>
|
|
66
|
+
</RadioGroup>
|
|
67
|
+
</FormControl>);
|
|
68
|
+
};
|
|
69
|
+
//end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { MaterialReactTable, useMaterialReactTable, } from 'material-react-table';
|
|
3
|
+
import { data } from './makeData';
|
|
4
|
+
const Example = () => {
|
|
5
|
+
const columns = useMemo(() => [
|
|
6
|
+
{
|
|
7
|
+
accessorKey: 'firstName',
|
|
8
|
+
header: 'First Name',
|
|
9
|
+
},
|
|
10
|
+
//column definitions...
|
|
11
|
+
{
|
|
12
|
+
accessorKey: 'lastName',
|
|
13
|
+
header: 'Last Name',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
accessorKey: 'address',
|
|
17
|
+
header: 'Address',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
accessorKey: 'city',
|
|
21
|
+
header: 'City',
|
|
22
|
+
},
|
|
23
|
+
//end
|
|
24
|
+
{
|
|
25
|
+
accessorKey: 'state',
|
|
26
|
+
enableColumnOrdering: false, //disable column ordering for this column,
|
|
27
|
+
header: 'State',
|
|
28
|
+
},
|
|
29
|
+
], []);
|
|
30
|
+
const table = useMaterialReactTable({
|
|
31
|
+
columns,
|
|
32
|
+
data,
|
|
33
|
+
enableColumnOrdering: true,
|
|
34
|
+
});
|
|
35
|
+
return <MaterialReactTable table={table}/>;
|
|
36
|
+
};
|
|
37
|
+
export default Example;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { MaterialReactTable, useMaterialReactTable, } from 'material-react-table';
|
|
3
|
+
import { data } from './makeData';
|
|
4
|
+
import { MenuItem } from '@mui/material';
|
|
5
|
+
const Example = () => {
|
|
6
|
+
const columns = useMemo(() => [
|
|
7
|
+
{
|
|
8
|
+
accessorKey: 'id',
|
|
9
|
+
enableColumnPinning: false, //disable column pinning for this column
|
|
10
|
+
header: 'ID',
|
|
11
|
+
size: 50,
|
|
12
|
+
},
|
|
13
|
+
//column definitions...
|
|
14
|
+
{
|
|
15
|
+
accessorKey: 'firstName',
|
|
16
|
+
header: 'First Name',
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
accessorKey: 'middleName',
|
|
20
|
+
header: 'Middle Name',
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
accessorKey: 'lastName',
|
|
24
|
+
header: 'Last Name',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
accessorKey: 'address',
|
|
28
|
+
header: 'Address',
|
|
29
|
+
size: 300,
|
|
30
|
+
},
|
|
31
|
+
//end
|
|
32
|
+
{
|
|
33
|
+
accessorKey: 'city', //this column gets pinned to the right by default because of the initial state,
|
|
34
|
+
header: 'City',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
accessorKey: 'state', //this column gets pinned left by default because of the the initial state,
|
|
38
|
+
header: 'State',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
accessorKey: 'country',
|
|
42
|
+
header: 'Country',
|
|
43
|
+
},
|
|
44
|
+
], []);
|
|
45
|
+
const table = useMaterialReactTable({
|
|
46
|
+
columns,
|
|
47
|
+
data,
|
|
48
|
+
enableColumnPinning: true,
|
|
49
|
+
enableRowActions: true,
|
|
50
|
+
layoutMode: 'grid-no-grow', //constant column widths
|
|
51
|
+
renderRowActionMenuItems: () => [<MenuItem key="action">Action</MenuItem>],
|
|
52
|
+
initialState: {
|
|
53
|
+
columnPinning: { end: ['city'], start: ['mrt-row-actions', 'state'] },
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
return <MaterialReactTable table={table}/>;
|
|
57
|
+
};
|
|
58
|
+
export default Example;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import { MaterialReactTable, useMaterialReactTable, } from 'material-react-table';
|
|
3
|
+
import { data } from './makeData';
|
|
4
|
+
const Example = () => {
|
|
5
|
+
const columns = useMemo(() => [
|
|
6
|
+
{
|
|
7
|
+
accessorKey: 'firstName',
|
|
8
|
+
header: 'First Name', //uses the default width from defaultColumn prop
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
accessorKey: 'lastName',
|
|
12
|
+
header: 'Last Name',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
accessorKey: 'email',
|
|
16
|
+
header: 'Email Address',
|
|
17
|
+
size: 250, //increase the width of this column
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
accessorKey: 'city',
|
|
21
|
+
header: 'City',
|
|
22
|
+
size: 200, //decrease the width of this column
|
|
23
|
+
enableResizing: false, //disable resizing for this column
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
accessorKey: 'country',
|
|
27
|
+
header: 'Country',
|
|
28
|
+
size: 140, //decrease the width of this column
|
|
29
|
+
},
|
|
30
|
+
], []);
|
|
31
|
+
const table = useMaterialReactTable({
|
|
32
|
+
columns,
|
|
33
|
+
data,
|
|
34
|
+
//optionally override the default column widths
|
|
35
|
+
defaultColumn: {
|
|
36
|
+
maxSize: 400,
|
|
37
|
+
minSize: 80,
|
|
38
|
+
size: 160, //default size is usually 180
|
|
39
|
+
},
|
|
40
|
+
enableColumnResizing: true,
|
|
41
|
+
columnResizeMode: 'onChange', //default
|
|
42
|
+
});
|
|
43
|
+
return <MaterialReactTable table={table}/>;
|
|
44
|
+
};
|
|
45
|
+
export default Example;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { useRef } from 'react';
|
|
2
|
+
import { MaterialReactTable, useMaterialReactTable, } from 'material-react-table';
|
|
3
|
+
import { fakeColumns, fakeData } from './makeData';
|
|
4
|
+
const Example = () => {
|
|
5
|
+
//optionally access the underlying virtualizer instance
|
|
6
|
+
const columnVirtualizerInstanceRef = useRef(null);
|
|
7
|
+
const table = useMaterialReactTable({
|
|
8
|
+
columnVirtualizerInstanceRef, //optional
|
|
9
|
+
columnVirtualizerOptions: { overscan: 4 }, //optionally customize the virtualizer
|
|
10
|
+
columns: fakeColumns, //500 columns
|
|
11
|
+
data: fakeData,
|
|
12
|
+
enableColumnPinning: true,
|
|
13
|
+
enableColumnResizing: true,
|
|
14
|
+
enableColumnVirtualization: true,
|
|
15
|
+
enableRowNumbers: true,
|
|
16
|
+
});
|
|
17
|
+
return <MaterialReactTable table={table}/>;
|
|
18
|
+
};
|
|
19
|
+
export default Example;
|