fix: datatable state persistence issues (#746)

This commit is contained in:
Raymond Zhou
2023-12-15 11:52:59 -08:00
committed by GitHub
parent da5d64ad9e
commit 75eb0c307e
5 changed files with 45 additions and 10 deletions

View File

@@ -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}

View File

@@ -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,
};

View File

@@ -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();
};

View File

@@ -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);
});

View File

@@ -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',