Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[13] fix: retain search table settings and order #281

Merged
merged 28 commits into from
Aug 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
af90d14
Update URL parameters to reflect active tab
noctillion Aug 15, 2023
a3920ed
Include datasetId as
noctillion Aug 15, 2023
06b1de4
Import history hooks
noctillion Aug 15, 2023
0c7d6a2
Reset colum order for
noctillion Aug 15, 2023
2035b14
Implement actions for set and
noctillion Aug 15, 2023
79cedbd
Implement reducer for set ans reset
noctillion Aug 15, 2023
95acfed
remove log
noctillion Aug 15, 2023
86a477b
Implement hooks for explorer reults tables
noctillion Aug 15, 2023
0ad6f84
Implements column sort tracking
noctillion Aug 15, 2023
f2999a2
Implements column sort tracking
noctillion Aug 15, 2023
ba14aba
Implements column sort tracking
noctillion Aug 15, 2023
3eb1a21
Handle back navigation by updating state and URL
noctillion Aug 15, 2023
86187df
Initialize sorted info with useMemo
noctillion Aug 15, 2023
9ada540
Implement action for set active tab
noctillion Aug 16, 2023
ac2ae1a
Implement reducer for set active tab
noctillion Aug 16, 2023
7838aab
Update explorer hooks
noctillion Aug 16, 2023
4484f94
Implement set active tab to redux state
noctillion Aug 16, 2023
a6f8ffe
Update tab persistace mechanish
noctillion Aug 16, 2023
fb48694
Revert "Update URL parameters to reflect active tab"
noctillion Aug 16, 2023
8d9122f
Revert "Import history hooks"
noctillion Aug 16, 2023
50b2804
Merge branch 'bug/retain_search_table_setting_order_tab' into bug/ret…
noctillion Aug 16, 2023
ffe0943
Remove typo
noctillion Aug 16, 2023
65c0670
Reset tab selection with a new search
noctillion Aug 16, 2023
545b6ec
Refactor destructuring props
noctillion Aug 23, 2023
3786db7
Refactor sortData ordering
noctillion Aug 23, 2023
1064c0a
Use useLocation hook to access current location
noctillion Aug 23, 2023
d789a44
Remove unnecessary code
noctillion Aug 23, 2023
098d873
remove logs
noctillion Aug 26, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions src/components/explorer/BiosamplesTable.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import React from "react";
import PropTypes from "prop-types";
import { Link } from "react-router-dom";
import { useSortedColumns } from "./hooks/explorerHooks";
import { Link, useLocation } from "react-router-dom";
import { useSelector } from "react-redux";
import { countNonNullElements } from "../../utils/misc";
import ExplorerSearchResultsTable from "./ExplorerSearchResultsTable";

const NO_EXPERIMENTS_VALUE = -Infinity;

const BiosampleRender = ({ biosample, alternateIds, individualId }) => {
const location = useLocation();
const alternateIdsList = alternateIds ?? [];
const listRender = alternateIdsList.length ? ` (${alternateIdsList.join(", ")})` : "";
return (
Expand Down Expand Up @@ -166,12 +169,26 @@ const SEARCH_RESULT_COLUMNS_BIOSAMPLE = [
},
];

const BiosamplesTable = ({ data }) => {
const BiosamplesTable = ({ data, datasetID }) => {
const tableSortOrder = useSelector(
(state) => state.explorer.tableSortOrderByDatasetID[datasetID]?.["biosamples"],
);

const { sortedData, columnsWithSortOrder } = useSortedColumns(
data,
tableSortOrder,
SEARCH_RESULT_COLUMNS_BIOSAMPLE,
);

return (
<ExplorerSearchResultsTable
dataStructure={SEARCH_RESULT_COLUMNS_BIOSAMPLE}
data={data}
data={sortedData}
sortColumnKey={tableSortOrder?.sortColumnKey}
sortOrder={tableSortOrder?.sortOrder}
activeTab="biosamples"
columns={columnsWithSortOrder}
currentPage={tableSortOrder?.currentPage}
/>
);
};
Expand All @@ -193,6 +210,7 @@ BiosamplesTable.propTypes = {
experimentTypes: PropTypes.arrayOf(PropTypes.string).isRequired,
}),
).isRequired,
datasetID: PropTypes.string.isRequired,
};


Expand Down
27 changes: 24 additions & 3 deletions src/components/explorer/ExperimentsTable.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import React from "react";
import { Link } from "react-router-dom";
import { Link, useLocation } from "react-router-dom";
import { useSelector } from "react-redux";
import PropTypes from "prop-types";
import { useSortedColumns } from "./hooks/explorerHooks";
import ExplorerSearchResultsTable from "./ExplorerSearchResultsTable";

const ExperimentRender = ({ experimentId, individual }) => {
const location = useLocation();
const alternateIds = individual.alternate_ids ?? [];
const listRender = alternateIds.length ? `(${alternateIds.join(", ")})` : "";

Expand Down Expand Up @@ -69,9 +72,26 @@ const SEARCH_RESULT_COLUMNS_EXP = [
},
];

const ExperimentsTable = ({ data }) => {
const ExperimentsTable = ({ data, datasetID }) => {
const tableSortOrder = useSelector(
(state) => state.explorer.tableSortOrderByDatasetID[datasetID]?.["experiments"],
);

const { sortedData, columnsWithSortOrder } = useSortedColumns(
data,
tableSortOrder,
SEARCH_RESULT_COLUMNS_EXP,
);
return (
<ExplorerSearchResultsTable dataStructure={SEARCH_RESULT_COLUMNS_EXP} data={data} activeTab="experiments" />
<ExplorerSearchResultsTable
dataStructure={SEARCH_RESULT_COLUMNS_EXP}
data={sortedData}
sortColumnKey={tableSortOrder?.sortColumnKey}
sortOrder={tableSortOrder?.sortOrder}
activeTab="experiments"
columns={columnsWithSortOrder}
currentPage={tableSortOrder?.currentPage}
/>
);
};

Expand All @@ -88,6 +108,7 @@ ExperimentsTable.propTypes = {
experimentType: PropTypes.string.isRequired,
}),
).isRequired,
datasetID: PropTypes.string.isRequired,
};

export default ExperimentsTable;
26 changes: 19 additions & 7 deletions src/components/explorer/ExplorerDatasetSearch.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useEffect } from "react";
import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { useParams } from "react-router-dom";

Expand All @@ -15,6 +15,8 @@ import {
removeDataTypeQueryForm,
updateDataTypeQueryForm,
setSelectedRows,
resetTableSortOrder,
setActiveTab,
} from "../../modules/explorer/actions";

import IndividualsTable from "./IndividualsTable";
Expand All @@ -34,19 +36,21 @@ const hasNonEmptyArrayProperty = (targetObject, propertyKey) => {
};

const ExplorerDatasetSearch = () => {
const [activeKey, setActiveKey] = useState(TAB_KEYS.INDIVIDUAL);
const dispatch = useDispatch();
const { dataset } = useParams();
const dispatch = useDispatch();

const datasetsByID = useSelector((state) =>
Object.fromEntries(
state.projects.items.flatMap((p) => p.datasets.map((d) => [d.identifier, { ...d, project: p.identifier }])),
),
);

const activeKey = useSelector((state) => state.explorer.activeTabByDatasetID[dataset]) || TAB_KEYS.INDIVIDUAL;
noctillion marked this conversation as resolved.
Show resolved Hide resolved
const dataTypeForms = useSelector((state) => state.explorer.dataTypeFormsByDatasetID[dataset] || []);
const fetchingSearch = useSelector((state) => state.explorer.fetchingSearchByDatasetID[dataset] || false);
const fetchingTextSearch = useSelector((state) => state.explorer.fetchingTextSearch || false);
const searchResults = useSelector((state) => state.explorer.searchResultsByDatasetID[dataset] || null);

console.debug("search results: ", searchResults);

const handleSetSelectedRows = (...args) => dispatch(setSelectedRows(dataset, ...args));
Expand All @@ -57,11 +61,13 @@ const ExplorerDatasetSearch = () => {
}, []);

const onTabChange = (newActiveKey) => {
setActiveKey(newActiveKey);
dispatch(setActiveTab(dataset, newActiveKey));
handleSetSelectedRows([]);
};

const performSearch = () => {
dispatch(setActiveTab(dataset, TAB_KEYS.INDIVIDUAL));
dispatch(resetTableSortOrder(dataset));
dispatch(performSearchIfPossible(dataset));
};

Expand Down Expand Up @@ -96,16 +102,22 @@ const ExplorerDatasetSearch = () => {
(showTabs ? (
<Tabs defaultActiveKey={TAB_KEYS.INDIVIDUAL} onChange={onTabChange} activeKey={activeKey}>
<TabPane tab="Individual" key={TAB_KEYS.INDIVIDUAL}>
<IndividualsTable data={searchResults.searchFormattedResults} />
<IndividualsTable
data={searchResults.searchFormattedResults}
datasetID={dataset}/>
</TabPane>
{hasBiosamples && (
<TabPane tab="Biosamples" key={TAB_KEYS.BIOSAMPLES}>
<BiosamplesTable data={searchResults.searchFormattedResultsBiosamples} />
<BiosamplesTable
data={searchResults.searchFormattedResultsBiosamples}
datasetID={dataset}/>
</TabPane>
)}
{hasExperiments && (
<TabPane tab="Experiments" key={TAB_KEYS.EXPERIMENTS}>
<ExperimentsTable data={searchResults.searchFormattedResultsExperiment} />
<ExperimentsTable
data={searchResults.searchFormattedResultsExperiment}
datasetID={dataset}/>
</TabPane>
)}
</Tabs>
Expand Down
6 changes: 3 additions & 3 deletions src/components/explorer/ExplorerIndividualContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ class ExplorerIndividualContent extends Component {

this.state = {
backUrl: null,
selectedTab: "overview",
};
}

Expand All @@ -61,8 +60,9 @@ class ExplorerIndividualContent extends Component {
}

componentDidMount() {
const backUrl = (this.props.location.state || {}).backUrl;
if (backUrl) this.setState({backUrl});
const { location } = this.props;
const { backUrl } = location.state || {};
if (backUrl) this.setState({ backUrl });
this.fetchIndividualData();
}

Expand Down
31 changes: 26 additions & 5 deletions src/components/explorer/ExplorerSearchResultsTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,21 @@ import {
performIndividualsDownloadCSVIfPossible,
performBiosamplesDownloadCSVIfPossible,
performExperimentsDownloadCSVIfPossible,
setTableSortOrder,
} from "../../modules/explorer/actions";

const PAGE_SIZE = 25;

const ExplorerSearchResultsTable = ({ data, activeTab, ...props }) => {
const ExplorerSearchResultsTable = ({
data,
activeTab,
columns,
currentPage: initialCurrentPage,
sortOrder,
sortColumnKey,
}) => {
const { dataset } = useParams();
const [currentPage, setCurrentPage] = useState(1);
const [currentPage, setCurrentPage] = useState(initialCurrentPage || 1);
const [numResults] = useState(data.length);

const [summaryModalVisible, setSummaryModalVisible] = useState(false);
Expand Down Expand Up @@ -50,16 +58,16 @@ const ExplorerSearchResultsTable = ({ data, activeTab, ...props }) => {
}
};

const onPageChange = (pageObj) => {
const onPageChange = (pageObj, filters, sorter) => {
setCurrentPage(pageObj.current);
dispatch(setTableSortOrder(dataset, sorter.field, sorter.order, activeTab, pageObj.current));
};

const tableStyle = {
opacity: fetchingSearch ? 0.5 : 1,
pointerEvents: fetchingSearch ? "none" : "auto",
};


const rowSelection = {
type: "checkbox",
selectedRowKeys: selectedRows,
Expand All @@ -83,6 +91,14 @@ const ExplorerSearchResultsTable = ({ data, activeTab, ...props }) => {
],
};

const sortedInfo = useMemo(
() => ({
order: sortOrder,
columnKey: sortColumnKey,
}),
[sortOrder, sortColumnKey],
);

return (
<div>
<Typography.Title level={4}>
Expand Down Expand Up @@ -132,8 +148,9 @@ const ExplorerSearchResultsTable = ({ data, activeTab, ...props }) => {
bordered
disabled={fetchingSearch}
size="middle"
columns={props.dataStructure}
columns={columns}
dataSource={data || []}
sortedInfo={sortedInfo}
onChange={onPageChange}
pagination={{
pageSize: PAGE_SIZE,
Expand Down Expand Up @@ -173,6 +190,10 @@ ExplorerSearchResultsTable.propTypes = {
type: PropTypes.string,
data: PropTypes.arrayOf(PropTypes.object),
activeTab: PropTypes.string.isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
sortOrder: PropTypes.string,
sortColumnKey: PropTypes.string,
currentPage: PropTypes.number,
};

export default ExplorerSearchResultsTable;
28 changes: 23 additions & 5 deletions src/components/explorer/IndividualsTable.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import React from "react";
import PropTypes from "prop-types";
import { Link } from "react-router-dom";
import { useSortedColumns } from "./hooks/explorerHooks";
import { Link, useLocation } from "react-router-dom";
import { useSelector } from "react-redux";
import ExplorerSearchResultsTable from "./ExplorerSearchResultsTable";

const IndividualRender = ({individual}) => {
const location = useLocation();
const alternateIds = individual.alternate_ids ?? [];
const listRender = alternateIds.length ? " (" + alternateIds.join(", ") + ")" : "";
return (
<>
<Link
to={(location) => ({
to={{
pathname: `/data/explorer/individuals/${individual.id}/overview`,
state: { backUrl: location.pathname },
noctillion marked this conversation as resolved.
Show resolved Hide resolved
})}
}}
>
{individual.id}
</Link>{" "}
Expand Down Expand Up @@ -59,18 +62,33 @@ const SEARCH_RESULT_COLUMNS = [
},
];

const IndividualsTable = ({ data }) => {
const IndividualsTable = ({ data, datasetID }) => {
const tableSortOrder = useSelector(
(state) => state.explorer.tableSortOrderByDatasetID[datasetID]?.["individuals"],
);

const { sortedData, columnsWithSortOrder } = useSortedColumns(
data,
tableSortOrder,
SEARCH_RESULT_COLUMNS,
);

return (
<ExplorerSearchResultsTable
dataStructure={SEARCH_RESULT_COLUMNS}
data={data}
data={sortedData}
sortColumnKey={tableSortOrder?.sortColumnKey}
sortOrder={tableSortOrder?.sortOrder}
activeTab="individuals"
columns={columnsWithSortOrder}
currentPage={tableSortOrder?.currentPage}
/>
);
};

IndividualsTable.propTypes = {
data: PropTypes.array.isRequired,
datasetID: PropTypes.string.isRequired,
};

export default IndividualsTable;
31 changes: 31 additions & 0 deletions src/components/explorer/hooks/explorerHooks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useMemo } from "react";

export const useSortedColumns = (data, tableSortOrder, columnsDefinition) => {
const sortColumnKey = tableSortOrder?.sortColumnKey;
const sortOrder = tableSortOrder?.sortOrder;

const sortData = (dataToSort, sortKey, order) => {
const column = columnsDefinition.find((col) => col.dataIndex === sortKey);
if (column && column.sorter) {
return [...dataToSort].sort((a, b) => {
return order === "ascend" ? column.sorter(a, b) : column.sorter(b, a);
});
}
return dataToSort;
};

const sortedData = useMemo(() => {
return sortData(data, sortColumnKey, sortOrder);
}, [data, sortColumnKey, sortOrder, columnsDefinition]);

const columnsWithSortOrder = useMemo(() => {
return columnsDefinition.map((column) => {
if (column.dataIndex === sortColumnKey) {
return { ...column, sortOrder };
}
return column;
});
}, [sortColumnKey, sortOrder, columnsDefinition]);

return { sortedData, columnsWithSortOrder };
};
Loading