-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
39ee64d
commit 673cf0e
Showing
10 changed files
with
1,068 additions
and
175 deletions.
There are no files selected for viewing
Binary file renamed
BIN
+504 KB
...able-npm-1.12.1-7753958fe4-861b8ce34e.zip → ...able-npm-1.14.0-31498d2f27-648cbe5c63.zip
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,300 @@ | ||
/*! | ||
* Copyright (c) 2022-present, Okta, Inc. and/or its affiliates. All rights reserved. | ||
* The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the "License.") | ||
* | ||
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* | ||
* See the License for the specific language governing permissions and limitations under the License. | ||
*/ | ||
|
||
import { | ||
AlertProps, | ||
TableContainerProps, | ||
TablePaginationProps, | ||
Typography, | ||
} from "@mui/material"; | ||
import MaterialReactTable, { | ||
type MRT_ColumnFiltersState, | ||
type MRT_RowSelectionState, | ||
type MRT_TableInstance, | ||
type MRT_Virtualizer, | ||
} from "material-react-table"; | ||
import { | ||
FunctionComponent, | ||
memo, | ||
UIEvent, | ||
useCallback, | ||
useEffect, | ||
useMemo, | ||
useRef, | ||
useState, | ||
} from "react"; | ||
import { Trans, useTranslation } from "react-i18next"; | ||
|
||
import type { | ||
DefaultMaterialReactTableData, | ||
MaterialReactTableProps, | ||
} from "./materialReactTableTypes"; | ||
|
||
export type PaginatedDataGridProps< | ||
TData extends DefaultMaterialReactTableData | ||
> = { | ||
columns: MaterialReactTableProps<TData>["columns"]; | ||
data: MaterialReactTableProps<TData>["data"]; | ||
fetchMoreData?: () => void; | ||
getRowId?: MaterialReactTableProps<TData>["getRowId"]; | ||
hasError?: boolean; | ||
hasRowSelection?: boolean; | ||
initialState?: MaterialReactTableProps<TData>["initialState"]; | ||
isFetching?: boolean; | ||
onGlobalFilterChange?: MaterialReactTableProps<TData>["onGlobalFilterChange"]; | ||
onPaginationChange?: MaterialReactTableProps<TData>["onPaginationChange"]; | ||
onRowSelectionChange?: MaterialReactTableProps<TData>["onRowSelectionChange"]; | ||
// rowsPerPageOptions?: MaterialReactTableProps<TData>["muiTablePaginationProps"]['rowsPerPageOptions']; | ||
state?: MaterialReactTableProps<TData>["state"]; | ||
ToolbarButtons?: FunctionComponent< | ||
{ table: MRT_TableInstance<TData> } & unknown | ||
>; | ||
}; | ||
|
||
// Once the user has scrolled within this many pixels of the bottom of the table, fetch more data if we can. | ||
const scrollAmountBeforeFetchingData = 400; | ||
|
||
const initialPagination = { | ||
pageIndex: 0, | ||
pageSize: 10, | ||
}; | ||
|
||
const PaginatedDataGrid = <TData extends DefaultMaterialReactTableData>({ | ||
columns, | ||
data, | ||
fetchMoreData, | ||
getRowId, | ||
hasError, | ||
hasRowSelection, | ||
initialState, | ||
isFetching, | ||
onGlobalFilterChange, | ||
onPaginationChange, | ||
onRowSelectionChange: onRowSelectionChangeProp, | ||
state, | ||
ToolbarButtons, | ||
}: PaginatedDataGridProps<TData>) => { | ||
const { t } = useTranslation(); | ||
|
||
const tableContainerRef = useRef<HTMLDivElement>(null); | ||
|
||
const rowVirtualizerInstanceRef = | ||
useRef<MRT_Virtualizer<HTMLDivElement, HTMLTableRowElement>>(null); | ||
|
||
const [columnFilters, setColumnFilters] = useState<MRT_ColumnFiltersState>( | ||
[] | ||
); | ||
|
||
const [globalFilter, setGlobalFilter] = useState<string>(); | ||
|
||
useEffect(() => { | ||
if (globalFilter) { | ||
onGlobalFilterChange?.(globalFilter); | ||
} | ||
}, [globalFilter, onGlobalFilterChange]); | ||
|
||
const totalFetchedRows = data.length ?? 0; | ||
|
||
// const fetchMoreOnBottomReached = useCallback( | ||
// (containerRefElement?: HTMLDivElement | null) => { | ||
// if (containerRefElement) { | ||
// const { scrollHeight, scrollTop, clientHeight } = containerRefElement; | ||
|
||
// if ( | ||
// scrollHeight - scrollTop - clientHeight < | ||
// scrollAmountBeforeFetchingData && | ||
// !isFetching | ||
// ) { | ||
// fetchMoreData?.(); | ||
// } | ||
// } | ||
// }, | ||
// [fetchMoreData, isFetching] | ||
// ); | ||
|
||
useEffect(() => { | ||
try { | ||
// Scroll to top of table when sorting or filters change. | ||
rowVirtualizerInstanceRef.current?.scrollToIndex?.(0); | ||
} catch (error) { | ||
console.error(error); | ||
} | ||
}, [columnFilters, globalFilter]); | ||
|
||
// Check on mount to see if the table is already scrolled to the bottom and immediately needs to fetch more data. | ||
// useEffect(() => { | ||
// fetchMoreOnBottomReached(tableContainerRef.current); | ||
// }, [fetchMoreOnBottomReached]); | ||
|
||
const renderBottomToolbarCustomActions = useCallback( | ||
() => | ||
fetchMoreData ? ( | ||
<Typography> | ||
<Trans | ||
count={totalFetchedRows} | ||
i18nKey="datagrid.fetchedrows.text" | ||
values={{ | ||
totalRows: totalFetchedRows, | ||
}} | ||
/> | ||
</Typography> | ||
) : ( | ||
<Typography> | ||
<Trans | ||
count={totalFetchedRows} | ||
i18nKey="datagrid.rows.text" | ||
values={{ | ||
totalRows: totalFetchedRows, | ||
}} | ||
/> | ||
</Typography> | ||
), | ||
[fetchMoreData, totalFetchedRows] | ||
); | ||
|
||
const renderTopToolbarCustomActions = useCallback< | ||
Exclude< | ||
MaterialReactTableProps<TData>["renderTopToolbarCustomActions"], | ||
undefined | ||
> | ||
>( | ||
({ table }) => <>{ToolbarButtons && <ToolbarButtons table={table} />}</>, | ||
[ToolbarButtons] | ||
); | ||
|
||
const [rowSelection, setRowSelection] = useState<MRT_RowSelectionState>({}); | ||
|
||
useEffect(() => { | ||
onRowSelectionChangeProp?.(rowSelection); | ||
}, [onRowSelectionChangeProp, rowSelection]); | ||
|
||
const [pagination, setPagination] = useState( | ||
initialState?.pagination || initialPagination | ||
); | ||
|
||
const stuffPage = useCallback((p) => { | ||
setPagination((op) => { | ||
const newP = p(op); | ||
console.log("p", newP); | ||
return newP; | ||
}); | ||
}, []); | ||
|
||
useEffect(() => { | ||
console.log("pagination updated"); | ||
const numberOfPages = Math.floor(data.length / pagination.pageSize); | ||
|
||
if (!isFetching && pagination.pageIndex > numberOfPages - 1) { | ||
console.log("fetching more data"); | ||
fetchMoreData?.(); | ||
} | ||
}, [ | ||
data.length, | ||
fetchMoreData, | ||
isFetching, | ||
pagination.pageIndex, | ||
pagination.pageSize, | ||
]); | ||
|
||
useEffect(() => { | ||
onPaginationChange?.({ | ||
pageIndex: pagination.pageIndex, | ||
pageSize: pagination.pageSize, | ||
}); | ||
}, [onPaginationChange, pagination.pageIndex, pagination.pageSize]); | ||
|
||
// const modifiedInitialState = useMemo( | ||
// () => ({ | ||
// pagination, | ||
// ...initialState, | ||
// }), | ||
// [initialState, pagination] | ||
// ); | ||
|
||
const modifiedState = useMemo( | ||
() => ({ | ||
...state, | ||
pagination: { | ||
pageIndex: pagination.pageIndex, | ||
pageSize: pagination.pageSize, | ||
}, | ||
rowSelection, | ||
}), | ||
[pagination.pageIndex, pagination.pageSize, rowSelection, state] | ||
); | ||
|
||
// const muiTableContainerProps: TableContainerProps = useMemo( | ||
// () => ({ | ||
// onScroll: (event: UIEvent<HTMLDivElement>) => | ||
// fetchMoreOnBottomReached(event.target as HTMLDivElement), | ||
// ref: tableContainerRef, | ||
// }), | ||
// [fetchMoreOnBottomReached] | ||
// ); | ||
|
||
const muiToolbarAlertBannerProps: AlertProps = useMemo( | ||
() => | ||
hasError | ||
? { | ||
children: t("datagrid.error"), | ||
severity: "error", | ||
} | ||
: {}, | ||
[hasError, t] | ||
); | ||
|
||
const muiTablePaginationProps: Partial< | ||
Omit<TablePaginationProps, "rowsPerPage"> | ||
> = useMemo( | ||
() => ({ | ||
rowsPerPageOptions: [], | ||
showFirstButton: false, | ||
showLastButton: false, | ||
}), | ||
[] | ||
); | ||
|
||
return ( | ||
<MaterialReactTable | ||
columns={columns} | ||
data={data} | ||
enableMultiRowSelection={hasRowSelection} | ||
enablePagination | ||
enableRowSelection={hasRowSelection} | ||
enableSorting={false} | ||
getRowId={getRowId} | ||
initialState={initialState} | ||
// manualPagination | ||
// muiTableContainerProps={muiTableContainerProps} | ||
muiTablePaginationProps={muiTablePaginationProps} | ||
muiToolbarAlertBannerProps={muiToolbarAlertBannerProps} | ||
onColumnFiltersChange={setColumnFilters} | ||
onGlobalFilterChange={setGlobalFilter} | ||
onPaginationChange={stuffPage} | ||
onRowSelectionChange={setRowSelection} | ||
renderBottomToolbarCustomActions={renderBottomToolbarCustomActions} | ||
renderTopToolbarCustomActions={renderTopToolbarCustomActions} | ||
rowVirtualizerInstanceRef={rowVirtualizerInstanceRef} | ||
rowVirtualizerProps={{ overscan: 4 }} | ||
state={modifiedState} | ||
/> | ||
); | ||
}; | ||
|
||
const MemoizedPaginatedDataGrid = memo( | ||
PaginatedDataGrid | ||
) as typeof PaginatedDataGrid; | ||
|
||
// @ts-expect-error | This is going to error because the component isn't and can't be defined as a `FunctionComponent`, and therefore, doesn't have a `displayName` prop. | ||
MemoizedPaginatedDataGrid.displayName = "PaginatedDataGrid"; | ||
|
||
export { MemoizedPaginatedDataGrid as PaginatedDataGrid }; |
Oops, something went wrong.