diff --git a/src/components/explorer/Excluded.tsx b/src/components/explorer/Excluded.tsx new file mode 100644 index 000000000..0b142a584 --- /dev/null +++ b/src/components/explorer/Excluded.tsx @@ -0,0 +1,35 @@ +import { LinkOutlined } from "@ant-design/icons"; +import type { ColumnFilterItem } from "antd/es/table/interface"; + +type ExcludedProps = { + model: "phenotype" | "disease"; +}; + +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 }) => (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..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( @@ -136,21 +135,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}`;