From c89f772988ca19b5ce0c2fae5a32bd8d73d0d182 Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Thu, 29 Aug 2024 16:04:38 -0400 Subject: [PATCH 1/3] feat(explorer): "excluded: found to be absent" for diseases + phenotypes --- src/components/explorer/Excluded.tsx | 36 +++++++++++++++++++ src/components/explorer/IndividualDiseases.js | 17 ++++----- .../explorer/IndividualPhenotypicFeatures.js | 29 ++++----------- src/components/explorer/utils.js | 17 --------- 4 files changed, 52 insertions(+), 47 deletions(-) create mode 100644 src/components/explorer/Excluded.tsx diff --git a/src/components/explorer/Excluded.tsx b/src/components/explorer/Excluded.tsx new file mode 100644 index 000000000..66e8c88e9 --- /dev/null +++ b/src/components/explorer/Excluded.tsx @@ -0,0 +1,36 @@ +import { LinkOutlined } from "@ant-design/icons"; + +type ExcludedProps = { + model: "phenotype" | "disease"; +}; + +export const excludedTableColumnFilterConfig = { + filters: [ + { text: "Excluded", value: "excluded" }, + { text: "Not Excluded", value: "not_excluded" }, + ], + onFilter: ( + value: "excluded" | "not_excluded", + { + excluded, + }: { + excluded: boolean; + }, + ) => (value === "excluded" ? excluded : !excluded), +}; + +const Excluded = ({ model }: ExcludedProps) => ( + + (Excluded: Found to be absent{" "} + + + + ) + +); + +export default Excluded; diff --git a/src/components/explorer/IndividualDiseases.js b/src/components/explorer/IndividualDiseases.js index 12bd1cd9d..bf203246b 100644 --- a/src/components/explorer/IndividualDiseases.js +++ b/src/components/explorer/IndividualDiseases.js @@ -2,12 +2,13 @@ import { Descriptions } from "antd"; import PropTypes from "prop-types"; import { diseasePropTypesShape, individualPropTypesShape } from "@/propTypes"; -import { booleanFieldSorter, ontologyTermSorter, renderBoolean, useIndividualPhenopacketDataIndex } from "./utils"; +import { ontologyTermSorter, useIndividualPhenopacketDataIndex } from "./utils"; import OntologyTerm, { OntologyTermList } from "./OntologyTerm"; import TimeElement from "./TimeElement"; import { RoutedIndividualContent, RoutedIndividualContentTable } from "./RoutedIndividualContent"; import ExtraProperties from "./ExtraProperties"; +import Excluded, { excludedTableColumnFilterConfig } from "@/components/explorer/Excluded"; // TODO: Only show diseases from the relevant dataset, if specified; // highlight those found in search results, if specified @@ -18,15 +19,15 @@ const DISEASES_COLUMNS = [ dataIndex: "term", // Tag the ontology term with a data attribute holding the disease ID. This has no effect, but might // help us debug diseases in production if we need it. - render: (term, disease) => , + // Render excluded beside ontology term with a link to the documentation, if this disease is excluded. + render: (term, { id, excluded }) => ( + <> + {excluded ? : null} + + ), + ...excludedTableColumnFilterConfig, sorter: ontologyTermSorter("term"), }, - { - title: "Excluded", - dataIndex: "excluded", - render: renderBoolean("excluded"), - sorter: booleanFieldSorter("excluded"), - }, { title: "Onset Age", dataIndex: "onset", diff --git a/src/components/explorer/IndividualPhenotypicFeatures.js b/src/components/explorer/IndividualPhenotypicFeatures.js index f28baed30..bd92165da 100644 --- a/src/components/explorer/IndividualPhenotypicFeatures.js +++ b/src/components/explorer/IndividualPhenotypicFeatures.js @@ -7,12 +7,14 @@ import { EM_DASH } from "@/constants"; import { evidencePropTypesShape, individualPropTypesShape, phenotypicFeaturePropTypesShape } from "@/propTypes"; import { isValidUrl } from "@/utils/url"; +import Excluded, { excludedTableColumnFilterConfig } from "./Excluded"; +import ExtraProperties from "./ExtraProperties"; import OntologyTerm, { conditionalOntologyRender } from "./OntologyTerm"; -import { booleanFieldSorter, renderBoolean } from "./utils"; import TimeElement from "./TimeElement"; import { RoutedIndividualContent, RoutedIndividualContentTable } from "./RoutedIndividualContent"; -import ExtraProperties from "./ExtraProperties"; +import { ontologyTermSorter } from "@/components/explorer/utils"; +// noinspection JSUnusedGlobalSymbols const PHENOTYPIC_FEATURES_COLUMNS = [ { title: "Feature", @@ -25,31 +27,14 @@ const PHENOTYPIC_FEATURES_COLUMNS = [ ) : ( <> - {" "} - {excluded ? ( - - (Excluded: Found to be absent{" "} - - - - ) - - ) : null} + {excluded ? : null} ), + ...excludedTableColumnFilterConfig, onCell: ({ header }) => ({ colSpan: header ? 2 : 1, }), - }, - { - title: "Excluded", - key: "excluded", - render: renderBoolean("excluded"), - sorter: booleanFieldSorter("excluded"), + sorter: ontologyTermSorter("type"), }, { title: "Severity", diff --git a/src/components/explorer/utils.js b/src/components/explorer/utils.js index 4076e001e..5da520c5e 100644 --- a/src/components/explorer/utils.js +++ b/src/components/explorer/utils.js @@ -136,21 +136,4 @@ export const ontologyTermSorter = (k) => (a, b) => { return 0; }; -export const booleanFieldSorter = (k) => (a, b) => { - const aVal = a[k]; - const bVal = b[k]; - if (typeof aVal === "boolean" && typeof bVal === "boolean") { - return aVal - bVal; - } - return 0; -}; - -export const renderBoolean = (k) => (_, record) => { - const value = record[k]; - if (typeof value === "boolean") { - return String(value); - } - return EM_DASH; -}; - export const explorerIndividualUrl = (individualID) => `/data/explorer/individuals/${individualID}`; From d22ddbabc0f956806427269b69b57eb48fa9dda3 Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Thu, 29 Aug 2024 16:08:09 -0400 Subject: [PATCH 2/3] chore(explorer): better Excluded table column filter config type --- src/components/explorer/Excluded.tsx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/components/explorer/Excluded.tsx b/src/components/explorer/Excluded.tsx index 66e8c88e9..0b142a584 100644 --- a/src/components/explorer/Excluded.tsx +++ b/src/components/explorer/Excluded.tsx @@ -1,22 +1,21 @@ import { LinkOutlined } from "@ant-design/icons"; +import type { ColumnFilterItem } from "antd/es/table/interface"; type ExcludedProps = { model: "phenotype" | "disease"; }; -export const excludedTableColumnFilterConfig = { +type ExcludedTableColumnFilterConfig = { + filters: ColumnFilterItem[]; + onFilter: (value: "excluded" | "not_excluded", record: { excluded: boolean }) => boolean; +}; + +export const excludedTableColumnFilterConfig: ExcludedTableColumnFilterConfig = { filters: [ { text: "Excluded", value: "excluded" }, { text: "Not Excluded", value: "not_excluded" }, ], - onFilter: ( - value: "excluded" | "not_excluded", - { - excluded, - }: { - excluded: boolean; - }, - ) => (value === "excluded" ? excluded : !excluded), + onFilter: (value, { excluded }) => (value === "excluded" ? excluded : !excluded), }; const Excluded = ({ model }: ExcludedProps) => ( From 8a0a05742fa982f78f4c878da5003ba6d7f075cb Mon Sep 17 00:00:00 2001 From: David Lougheed Date: Thu, 29 Aug 2024 16:16:10 -0400 Subject: [PATCH 3/3] lint --- src/components/explorer/utils.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/explorer/utils.js b/src/components/explorer/utils.js index 5da520c5e..a5e90143f 100644 --- a/src/components/explorer/utils.js +++ b/src/components/explorer/utils.js @@ -1,7 +1,6 @@ import { useEffect, useMemo } from "react"; import { useDispatch, useSelector } from "react-redux"; import { fetchDatasetResourcesIfNecessary } from "@/modules/datasets/actions"; -import { EM_DASH } from "@/constants"; export const useDeduplicatedIndividualBiosamples = (individual) => useMemo(