diff --git a/ui/src/components/hintDataSelect.tsx b/ui/src/components/hintDataSelect.tsx index 2d18198fb..2f8cbaf89 100644 --- a/ui/src/components/hintDataSelect.tsx +++ b/ui/src/components/hintDataSelect.tsx @@ -58,15 +58,7 @@ export function HintDataSelect(props: HintDataSelectProps) { }; return ( - { - e.preventDefault(); - e.stopPropagation(); - }} - onMouseUp={(e) => { - e.stopPropagation(); - }} - > + theme.palette.primary.main, + "& .MuiOutlinedInput-input": { + px: 0, + py: "2px", + }, + "& .MuiSelect-select": (theme: Theme) => ({ + ...theme.typography.body2, + }), + "& .MuiOutlinedInput-notchedOutline": { + borderStyle: "none", + }, + }; +} diff --git a/ui/src/criteria/textSearch.tsx b/ui/src/criteria/textSearch.tsx index 9a266844c..9ea01c5d4 100644 --- a/ui/src/criteria/textSearch.tsx +++ b/ui/src/criteria/textSearch.tsx @@ -193,16 +193,7 @@ function TextSearchInline(props: TextSearchInlineProps) { return ( {!!hintDataState.data?.hintData?.enumHintOptions ? ( - { - e.preventDefault(); - e.stopPropagation(); - }} - onMouseUp={(e) => { - e.stopPropagation(); - }} - > + { - e.stopPropagation(); - e.preventDefault(); - }} - onMouseUp={(e) => { - e.stopPropagation(); - }} - onDelete={(e) => { - e.stopPropagation(); + onDelete={() => { onDelete(c); }} /> diff --git a/ui/src/criteria/unhintedValue.tsx b/ui/src/criteria/unhintedValue.tsx index a54bb0417..47fbf1136 100644 --- a/ui/src/criteria/unhintedValue.tsx +++ b/ui/src/criteria/unhintedValue.tsx @@ -168,15 +168,7 @@ function UnhintedValueInline(props: UnhintedValueInlineProps) { return ( - { - e.preventDefault(); - e.stopPropagation(); - }} - onMouseUp={(e) => { - e.stopPropagation(); - }} - > + } diff --git a/ui/src/demographicCharts.tsx b/ui/src/demographicCharts.tsx index 7bad974be..e429e5073 100644 --- a/ui/src/demographicCharts.tsx +++ b/ui/src/demographicCharts.tsx @@ -1,11 +1,19 @@ +import MenuItem from "@mui/material/MenuItem"; +import OutlinedInput from "@mui/material/OutlinedInput"; +import Select, { SelectChangeEvent } from "@mui/material/Select"; +import FormControl from "@mui/material/FormControl"; import Paper from "@mui/material/Paper"; import Typography from "@mui/material/Typography"; +import { uncontainedSelectSx } from "components/select"; import { Cohort } from "data/source"; import { useUnderlay } from "hooks"; import { GridBox } from "layout/gridBox"; import GridLayout from "layout/gridLayout"; import { ReactNode } from "react"; import { VizContainer } from "viz/vizContainer"; +import { useState } from "react"; +import Empty from "components/empty"; +import { Underlay } from "underlaysSlice"; export type DemographicChartsProps = { cohort?: Cohort; @@ -15,6 +23,23 @@ export type DemographicChartsProps = { export function DemographicCharts(props: DemographicChartsProps) { const underlay = useUnderlay(); + const [selectedVisualizations, setSelectedVisualizations] = useState( + getInitialVisualizations(underlay) + ); + + const onSelect = (event: SelectChangeEvent) => { + const { + target: { value: sel }, + } = event; + if (typeof sel === "string") { + // This case is only for selects with text input. + return; + } + + setSelectedVisualizations(sel); + storeSelectedVisualizations(underlay.name, sel); + }; + return ( - + Cohort visualizations - + + + {props.extraControls} theme.spacing(3), }} > - {underlay.visualizations.map((v) => - props.cohort ? ( - - ) : null + {selectedVisualizations.length > 0 ? ( + underlay.visualizations.map((v) => + selectedVisualizations.find((sv) => sv === v.name) && + props.cohort ? ( + + ) : null + ) + ) : ( + )} ); } + +// TODO(tjennison): Store the selected visualizations in local storage per +// underlay for now. Longer term, these should be stored on the backend but +// there a few options about whether they should be stored attached to the +// cohort, study, user, etc. as part of the visualiation changes. +function storageKey(underlay: string) { + return `tanagra-selected-visualizations-${underlay}`; +} + +function loadSelectedVisualizations(underlay: string): string[] | undefined { + const stored = localStorage.getItem(storageKey(underlay)); + if (!stored) { + return undefined; + } + return JSON.parse(stored); +} + +function storeSelectedVisualizations(underlay: string, sel: string[]) { + localStorage.setItem(storageKey(underlay), JSON.stringify(sel)); +} + +function getInitialVisualizations(underlay: Underlay) { + const stored = loadSelectedVisualizations(underlay.name); + if (!stored) { + return ( + underlay.uiConfiguration.defaultVisualizations ?? + underlay.visualizations.map((viz) => viz.name) + ); + } + + return stored.filter((v) => + underlay.visualizations.find((viz) => viz.name === v) + ); +} diff --git a/ui/src/overview.tsx b/ui/src/overview.tsx index a880f7783..694c9cb93 100644 --- a/ui/src/overview.tsx +++ b/ui/src/overview.tsx @@ -1,3 +1,4 @@ +import { uncontainedSelectSx } from "components/select"; import DeleteIcon from "@mui/icons-material/Delete"; import EditIcon from "@mui/icons-material/Edit"; import ErrorOutlineIcon from "@mui/icons-material/ErrorOutline"; @@ -135,10 +136,19 @@ export function Overview() { /> + + + + + - - - - - ); @@ -441,6 +442,7 @@ function ParticipantsGroupSection(props: { ) : ( e.stopPropagation()} inputProps={{ type: "number", min: 1, @@ -697,19 +699,7 @@ function ReducingOperatorSelect(props: { : undefined, }); }} - sx={{ - color: (theme) => theme.palette.primary.main, - "& .MuiOutlinedInput-input": { - px: 0, - py: "2px", - }, - "& .MuiSelect-select": (theme) => ({ - ...theme.typography.body2, - }), - "& .MuiOutlinedInput-notchedOutline": { - borderStyle: "none", - }, - }} + sx={uncontainedSelectSx()} > Any mention of @@ -851,16 +841,6 @@ function ParticipantsGroup(props: { return ( { - navigate( - "../" + - cohortURL( - cohort.id, - props.groupSection.id, - !selected ? props.group.id : undefined - ) - ); - }} sx={{ p: 2, height: "auto", @@ -869,15 +849,7 @@ function ParticipantsGroup(props: { backgroundColor: "#F1F2FA", boxShadow: "inset 0 -1px 0 #BEC2E9, inset 0 1px 0 #BEC2E9", } - : { - "&:hover": { - textDecoration: "underline", - cursor: "pointer", - color: (theme) => - (theme.typography as { link: { color: string } }).link - .color, - }, - }), + : undefined), }} > @@ -894,10 +866,29 @@ function ParticipantsGroup(props: { )} { + navigate( + "../" + + cohortURL( + cohort.id, + props.groupSection.id, + !selected ? props.group.id : undefined + ) + ); + }} sx={{ textOverflow: "ellipsis", whiteSpace: "nowrap", overflow: "hidden", + "&:hover": { + textDecoration: "underline", + cursor: "pointer", + color: (theme) => + !selected + ? (theme.typography as { link: { color: string } }).link + .color + : undefined, + }, }} > - { - e.preventDefault(); - e.stopPropagation(); - }} - onMouseUp={(e) => { - e.stopPropagation(); - }} - > + {selected && !!plugin.renderEdit ? ( ) : null} - + {modifierCriteria[i].config.displayName} - { - e.preventDefault(); - e.stopPropagation(); - }} - onMouseUp={(e) => { - e.stopPropagation(); - }} + + deleteCohortCriteriaModifier( + context, + props.groupSection.id, + props.group.id, + p.id + ) + } > - - deleteCohortCriteriaModifier( - context, - props.groupSection.id, - props.group.id, - p.id - ) - } - > - - - + + diff --git a/ui/src/plugins/vumc/biovu.tsx b/ui/src/plugins/vumc/biovu.tsx index 4f6292b09..06716d78b 100644 --- a/ui/src/plugins/vumc/biovu.tsx +++ b/ui/src/plugins/vumc/biovu.tsx @@ -146,15 +146,7 @@ function BioVUInline(props: BioVUInlineProps) { return !props.config.plasmaFilter ? ( - { - e.preventDefault(); - e.stopPropagation(); - }} - onMouseUp={(e) => { - e.stopPropagation(); - }} - > + - { - e.preventDefault(); - e.stopPropagation(); - }} - onMouseUp={(e) => { - e.stopPropagation(); - }} - > + @@ -194,15 +178,7 @@ function BioVUInline(props: BioVUInlineProps) { - { - e.preventDefault(); - e.stopPropagation(); - }} - onMouseUp={(e) => { - e.stopPropagation(); - }} - > + diff --git a/ui/src/underlaysSlice.ts b/ui/src/underlaysSlice.ts index 580398277..08222408c 100644 --- a/ui/src/underlaysSlice.ts +++ b/ui/src/underlaysSlice.ts @@ -26,6 +26,7 @@ export type UIConfiguration = { demographicChartConfigs: DemographicChartConfig; criteriaSearchConfig: CriteriaSearchConfig; cohortReviewConfig: CohortReviewConfig; + defaultVisualizations: string[]; }; export type FeatureConfig = {