fix: datatable state persistence issues (#746)
This commit is contained in:
@@ -62,6 +62,14 @@ const FileTable = ({
|
||||
const [isAddOpen, setAddOpen, setAddClose] = useToggle(false);
|
||||
const [selectedRows, setSelectedRows] = useState([]);
|
||||
const [isDeleteConfirmationOpen, openDeleteConfirmation, closeDeleteConfirmation] = useToggle(false);
|
||||
const [initialState, setInitialState] = useState({
|
||||
filters: [],
|
||||
hiddenColumns: [],
|
||||
pageIndex: 0,
|
||||
pageSize: 50,
|
||||
selectedRowIds: {},
|
||||
sortBy: [],
|
||||
});
|
||||
|
||||
const {
|
||||
loadingStatus,
|
||||
@@ -143,6 +151,7 @@ const FileTable = ({
|
||||
handleOpenDeleteConfirmation,
|
||||
supportedFileFormats,
|
||||
fileType,
|
||||
setInitialState,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -193,9 +202,7 @@ const FileTable = ({
|
||||
defaultActiveStateValue: defaultVal,
|
||||
togglePlacement: 'left',
|
||||
}}
|
||||
initialState={{
|
||||
pageSize: 50,
|
||||
}}
|
||||
initialState={initialState}
|
||||
tableActions={headerActions}
|
||||
bulkActions={headerActions}
|
||||
columns={tableColumns}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import React from 'react';
|
||||
import React, { useContext, useEffect } from 'react';
|
||||
import _ from 'lodash';
|
||||
import { PropTypes } from 'prop-types';
|
||||
import { injectIntl, intlShape, FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import {
|
||||
Button,
|
||||
DataTableContext,
|
||||
Dropdown,
|
||||
useToggle,
|
||||
} from '@edx/paragon';
|
||||
@@ -20,10 +21,18 @@ const TableActions = ({
|
||||
handleOpenDeleteConfirmation,
|
||||
encodingsDownloadUrl,
|
||||
fileType,
|
||||
setInitialState,
|
||||
// injected
|
||||
intl,
|
||||
}) => {
|
||||
const [isSortOpen, openSort, closeSort] = useToggle(false);
|
||||
const { state } = useContext(DataTableContext);
|
||||
|
||||
// This useEffect saves DataTable state so it can persist after table re-renders due to data reload.
|
||||
useEffect(() => {
|
||||
setInitialState(state);
|
||||
}, [state]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button variant="outline-primary" onClick={openSort} iconBefore={Tune}>
|
||||
@@ -95,6 +104,7 @@ TableActions.propTypes = {
|
||||
encodingsDownloadUrl: PropTypes.string,
|
||||
handleSort: PropTypes.func.isRequired,
|
||||
fileType: PropTypes.string.isRequired,
|
||||
setInitialState: PropTypes.func.isRequired,
|
||||
intl: intlShape.isRequired,
|
||||
};
|
||||
|
||||
|
||||
@@ -20,7 +20,9 @@ const SortAndFilterModal = ({
|
||||
// injected
|
||||
intl,
|
||||
}) => {
|
||||
const { state, setAllFilters, columns } = useContext(DataTableContext);
|
||||
const {
|
||||
state, setAllFilters, columns, gotoPage,
|
||||
} = useContext(DataTableContext);
|
||||
const filterOptions = getFilterOptions(columns);
|
||||
const currentFilters = getCheckedFilters(state);
|
||||
const [sortBy, setSortBy] = useState('dateAdded,desc');
|
||||
@@ -47,6 +49,7 @@ const SortAndFilterModal = ({
|
||||
const handleApply = async () => {
|
||||
await handleSort(sortBy);
|
||||
processFilters(filterBy, columns, setAllFilters);
|
||||
gotoPage(0);
|
||||
closeSort();
|
||||
};
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@ export const getFilters = (state, columns) => {
|
||||
if (filterColumn) {
|
||||
currentFilters = getFilterDisplayName(filterColumn, value);
|
||||
} else {
|
||||
const [serachValue] = value;
|
||||
currentFilters = [{ name: serachValue, value: serachValue }];
|
||||
const searchValue = Array.isArray(value) ? value[0] : value;
|
||||
currentFilters = [{ name: searchValue, value: searchValue }];
|
||||
}
|
||||
allFilters.push(...currentFilters);
|
||||
});
|
||||
|
||||
@@ -35,8 +35,8 @@ describe('getCurrentViewRange', () => {
|
||||
});
|
||||
|
||||
describe('getFilters', () => {
|
||||
it('should return filter when columns is empty', () => {
|
||||
const state = { filters: [{ id: 'test', value: ['unknown'] }] };
|
||||
it('should return filter object for text search with no filters', () => {
|
||||
const state = { filters: [{ id: 'test', value: 'unknown' }] };
|
||||
const columns = [];
|
||||
const expected = [{ name: 'unknown', value: 'unknown' }];
|
||||
const actual = getFilters(state, columns);
|
||||
@@ -44,7 +44,22 @@ describe('getFilters', () => {
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should return filtern for specific column', () => {
|
||||
it('should return filter object for text search with filters', () => {
|
||||
const state = { filters: [{ id: 'test', value: ['unknown'] }, { id: 'validColumn', value: ['filter1'] }] };
|
||||
const columns = [{
|
||||
id: 'validColumn',
|
||||
filterChoices: [
|
||||
{ name: 'Filter 1', value: 'filter1' },
|
||||
{ name: 'Filter 2', value: 'filter2' },
|
||||
],
|
||||
}];
|
||||
const expected = [{ name: 'unknown', value: 'unknown' }, { name: 'Filter 1', value: 'filter1' }];
|
||||
const actual = getFilters(state, columns);
|
||||
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it('should return filter object for no text search with filters', () => {
|
||||
const state = { filters: [{ id: 'validColumn', value: ['filter1'] }] };
|
||||
const columns = [{
|
||||
id: 'validColumn',
|
||||
|
||||
Reference in New Issue
Block a user