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

Sorting variables; Lag Time required; Various fixes #326

Merged
merged 4 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions frontend-v2/src/components/TextField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type Props<T extends FieldValues> = {
rules?: Record<string, unknown>;
mode?: "onChange" | "onBlur";
textFieldProps?: material.TextFieldProps;
autoShrink?: boolean;
sx?: material.SxProps
};

Expand All @@ -26,6 +27,7 @@ function TextField<T extends FieldValues>({
rules,
mode,
textFieldProps,
autoShrink,
sx
}: Props<T>): React.ReactElement {
const [fieldValue, setFieldValue] = useFieldState({ name, control });
Expand Down Expand Up @@ -66,6 +68,7 @@ function TextField<T extends FieldValues>({
}
name={name}
id={name}
InputLabelProps={autoShrink !== undefined ? { shrink: autoShrink } : {}}
variant="outlined"
value={
fieldValue === undefined || fieldValue === null ? "" : fieldValue
Expand Down
2 changes: 2 additions & 0 deletions frontend-v2/src/features/login/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@ const Login: React.FC<LoginProps> = ({ onLogin, isLoading, errorMessage }) => {
control={control}
textFieldProps={{ autoComplete: "username" }}
mode="onChange"
autoShrink={true}
/>
<TextField
label="Password"
name="password"
control={control}
textFieldProps={{ autoComplete: "password", type: "password" }}
mode="onChange"
autoShrink={true}
/>
<Button
type="submit"
Expand Down
46 changes: 38 additions & 8 deletions frontend-v2/src/features/model/MapVariablesTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
CombinedModelRead,
CompoundRead,
ProjectRead,
ProjectSpeciesEnum,
UnitRead,
VariableRead,
} from "../../app/backendApi";
Expand Down Expand Up @@ -39,10 +40,13 @@ const MapVariablesTab: React.FC<Props> = ({
compound,
}: Props) => {
const [dosings, setDosing] = React.useState<
{ key: number; hasDosingSelected: boolean, projectId: number }[]
{ key: number; hasDosingSelected: boolean; projectId: number, species: ProjectSpeciesEnum | undefined }[]
>([]);
const [linkToPds, setLinkToPd] = React.useState<
{ key: number; hasPdSelected: boolean, projectId: number }[]
{ key: number; hasPdSelected: boolean; projectId: number, species: ProjectSpeciesEnum | undefined }[]
>([]);
const [lagTimes, setLagTimes] = React.useState<
{ key: number; hasLagTimeSelected: boolean; projectId: number, species: ProjectSpeciesEnum | undefined }[]
>([]);

const iconRef = React.useRef<HTMLDivElement | null>(null);
Expand All @@ -54,6 +58,10 @@ const MapVariablesTab: React.FC<Props> = ({
.filter(({ projectId }) => projectId === project?.id)
.map(({ hasPdSelected }) => hasPdSelected)
.some(Boolean);
const isAnyLagTimeSelected = lagTimes
.filter(({ projectId }) => projectId === project?.id)
.map(({ hasLagTimeSelected }) => hasLagTimeSelected)
.some(Boolean);
const isPreclinical = project.species !== "H" && model.is_library_model;
const concentrationUnit = units.find((unit) => unit.symbol === "pmol/L");
const amountUnit = isPreclinical
Expand Down Expand Up @@ -154,18 +162,38 @@ const MapVariablesTab: React.FC<Props> = ({

const updateDosings = (key: number, value: boolean) => {
setDosing((prevDosings) => [
...prevDosings.filter(({ key: dosingKey }) => key !== dosingKey),
{ key, hasDosingSelected: value, projectId: project?.id },
...prevDosings.filter(({ key: dosingKey, species, projectId }) => key !== dosingKey && species === project.species && projectId === project.id),
{ key, hasDosingSelected: value, projectId: project?.id, species: project?.species },
]);
};

const updateLinksToPd = (key: number, value: boolean) => {
setLinkToPd((prevLinks) => [
...prevLinks.filter(({ key: linkKey }) => key !== linkKey),
{ key, hasPdSelected: value, projectId: project?.id },
...prevLinks.filter(({ key: linkKey, species, projectId }) => key !== linkKey && species === project.species && projectId === project.id),
{ key, hasPdSelected: value, projectId: project?.id, species: project?.species },
]);
};

const updateLagTimes = (key: number, value: boolean) => {
setLagTimes((prevLags) => [
...prevLags.filter(({ key: lagKey, species, projectId }) => key !== lagKey && species === project.species && projectId === project.id),
{ key, hasLagTimeSelected: value, projectId: project?.id, species: project?.species },
]);
};

const sortVariables = (variable1: VariableRead, variable2: VariableRead) => {
if (variable1.name.startsWith('C') && variable2.name.startsWith('A')) {
return -1;
}

if (variable1.name.startsWith('A') && variable2.name.startsWith('C')) {
return 1;
}

return variable1.name < variable2.name ? -1 : 1;
}


return (
<TableContainer sx={{ width: "90%" }}>
<Table>
Expand Down Expand Up @@ -196,7 +224,7 @@ const MapVariablesTab: React.FC<Props> = ({
<TableCell>
<div style={{ ...defaultHeaderSx }}>
{" "}
Lag Time
Lag Time <span style={{ color: "red" }}>*</span>
<HelpButton title={"Lag Time"}>{lagTimeHelp}</HelpButton>
</div>
</TableCell>
Expand Down Expand Up @@ -265,7 +293,7 @@ const MapVariablesTab: React.FC<Props> = ({
<TableCell colSpan={5}>No variables found</TableCell>
</TableRow>
)}
{timeVaryingVariables.map((variable) => (
{timeVaryingVariables.sort(sortVariables).map((variable) => (
<VariableRow
key={variable.id}
variable={variable}
Expand All @@ -280,6 +308,8 @@ const MapVariablesTab: React.FC<Props> = ({
isAnyDosingSelected={isAnyDosingSelected}
updateLinksToPd={updateLinksToPd}
isAnyLinkToPdSelected={isAnyLinkToPdSelected}
updateLagTimes={updateLagTimes}
isAnyLagTimeSelected={isAnyLagTimeSelected}
/>
))}
</TableBody>
Expand Down
43 changes: 28 additions & 15 deletions frontend-v2/src/features/model/VariableRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ interface Props {
isAnyDosingSelected: boolean;
updateLinksToPd: (key: number, value: boolean) => void;
isAnyLinkToPdSelected: boolean;
updateLagTimes: (key: number, value: boolean) => void;
isAnyLagTimeSelected: boolean;
}

type DerivedVariableType = "RO" | "FUP" | "BPR" | "TLG";
Expand All @@ -57,6 +59,8 @@ const VariableRow: React.FC<Props> = ({
isAnyDosingSelected,
updateLinksToPd,
isAnyLinkToPdSelected,
updateLagTimes,
isAnyLagTimeSelected,
}) => {
const {
fields: mappings,
Expand Down Expand Up @@ -125,6 +129,21 @@ const VariableRow: React.FC<Props> = ({
: mappings.find((mapping) => mapping.pk_variable === variable.id) !==
undefined;

const onClickDerived = (type: DerivedVariableType) => () => {
const index = derivedIndex(type);
return index >= 0 ? removeDerived(index) : addDerived(type);
};

const derivedIndex = (type: DerivedVariableType) => {
return derivedVariables.findIndex(
(ro) => ro.pk_variable === variable.id && ro.type === type,
);
};

const isLinkedTo = (type: DerivedVariableType) => {
return derivedIndex(type) >= 0;
};

useEffect(() => {
updateDosings(variable.id, hasProtocol);
}, [hasProtocol]);
Expand All @@ -133,6 +152,10 @@ const VariableRow: React.FC<Props> = ({
updateLinksToPd(variable.id, linkToPD);
}, [linkToPD]);

useEffect(() => {
updateLagTimes(variable.id, isLinkedTo("TLG"));
}, [isLinkedTo("TLG")]);

if (
variable.constant ||
variable.name === "t" ||
Expand Down Expand Up @@ -247,21 +270,6 @@ const VariableRow: React.FC<Props> = ({
derivedVariablesRemove(index);
};

const onClickDerived = (type: DerivedVariableType) => () => {
const index = derivedIndex(type);
return index >= 0 ? removeDerived(index) : addDerived(type);
};

const derivedIndex = (type: DerivedVariableType) => {
return derivedVariables.findIndex(
(ro) => ro.pk_variable === variable.id && ro.type === type,
);
};

const isLinkedTo = (type: DerivedVariableType) => {
return derivedIndex(type) >= 0;
};

const noMapToPD = isPD || effectVariable === undefined || !isConcentration;
const noDerivedVariables = !isConcentration || isPD;
const isC1 = model.is_library_model && variable.qname.endsWith(".C1");
Expand Down Expand Up @@ -315,6 +323,11 @@ const VariableRow: React.FC<Props> = ({
<FormControlLabel
control={
<MuiCheckbox
sx={{
"& .MuiSvgIcon-root": {
color: isAnyLagTimeSelected ? "inherit" : "red",
},
}}
checked={isLinkedTo("TLG")}
onClick={onClickDerived("TLG")}
data-cy={`checkbox-tlag-${variable.name}`}
Expand Down
66 changes: 35 additions & 31 deletions frontend-v2/src/features/simulation/Simulations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,8 @@ const Simulations: React.FC = () => {
setParametersHeight(height);
}, [parametersRef?.current?.clientHeight])

const updateWindowDimensions = () => window.innerWidth < 1000 && setLayout('horizontal');
window.addEventListener("resize", updateWindowDimensions);

// reset form and sliders if simulation changes
useEffect(() => {
Expand Down Expand Up @@ -495,8 +497,8 @@ const Simulations: React.FC = () => {
};

return (
<Grid container xl={12} sx={{ marginBottom: layout === 'horizontal' ? `${parametersHeight}px` : 0}}>
<Grid item xs={layout === "vertical" ? 7 : 12}>
<Grid container sx={{ marginBottom: layout === 'vertical' ? 0 : `${parametersHeight}px` }}>
<Grid item xl={layout === "vertical" ? 8 : 12} md={layout === "vertical" ? 7 : 12} xs={layout === "vertical" ? 6 : 12}>
<Stack direction={"row"} alignItems={"center"}>
<DropdownButton
useIcon={false}
Expand All @@ -507,33 +509,6 @@ const Simulations: React.FC = () => {
Add new plot
</DropdownButton>
</Stack>
<Grid container spacing={1}>
{plots.map((plot, index) => (
<Grid item xs={12} xl={layout === "vertical" ? 12 : 6} key={index}>
{data && model ? (
<SimulationPlotView
index={index}
plot={plot}
data={data}
variables={variables || []}
control={control}
setValue={setValue}
remove={removePlot}
units={units}
compound={compound}
model={model}
/>
) : (
<div>Loading...</div>
)}
</Grid>
))}
</Grid>
<Snackbar open={Boolean(simulateError)} autoHideDuration={6000}>
<Alert severity="error">
Error simulating model: {simulateError?.error || "unknown error"}
</Alert>
</Snackbar>
{plots.length > 0 && (
<>
<Stack
Expand Down Expand Up @@ -561,15 +536,44 @@ const Simulations: React.FC = () => {
</Stack>
</>
)}
<Grid container spacing={1}>
{plots.map((plot, index) => (
<Grid item xl={layout === "vertical" ? 12 : 6} md={layout === "vertical" ? 12 : 6} xs={layout === "vertical" ? 12 : 12} key={index}>
{data && model ? (
<SimulationPlotView
index={index}
plot={plot}
data={data}
variables={variables || []}
control={control}
setValue={setValue}
remove={removePlot}
units={units}
compound={compound}
model={model}
/>
) : (
<div>Loading...</div>
)}
</Grid>
))}
</Grid>
<Snackbar open={Boolean(simulateError)} autoHideDuration={6000}>
<Alert severity="error">
Error simulating model: {simulateError?.error || "unknown error"}
</Alert>
</Snackbar>
</Grid>
<Grid
ref={parametersRef}
item
xl={layout === "vertical" ? 4 : 12}
xl={layout === "vertical" ? 3 : 12}
md={layout === "vertical" ? 4 : 12}
xs={layout === "vertical" ? 5 : 12}
sx={
layout === "vertical"
? { position: "fixed", right: 0, paddingLeft: "1rem", width: '100%' }
: { position: "fixed", bottom: 0, height: 'auto', backgroundColor: 'white', width: '-webkit-fill-available' }
: { position: "fixed", bottom: 0, paddingBottom: '3rem', height: 'auto', backgroundColor: 'white', width: '-webkit-fill-available' }
}
>
<Stack direction="column">
Expand Down
23 changes: 15 additions & 8 deletions frontend-v2/src/features/trial/Doses.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useEffect } from "react";
import { TableCell, TableRow, IconButton, Button } from "@mui/material";
import { TableCell, TableRow, IconButton, Button, Stack } from "@mui/material";
import {
ProjectRead,
Protocol,
Expand All @@ -14,6 +14,7 @@ import UnitField from "../../components/UnitField";
import FloatField from "../../components/FloatField";
import IntegerField from "../../components/IntegerField";
import useDirty from "../../hooks/useDirty";
import HelpButton from "../../components/HelpButton";

interface Props {
project: ProjectRead;
Expand Down Expand Up @@ -186,13 +187,19 @@ const Doses: React.FC<Props> = ({ project, protocol, units }) => {
</TableCell>
</TableRow>
))}
<Button
onClick={handleAddRow}
variant="outlined"
sx={{ fontSize: ".5rem" }}
>
Add New Row
</Button>
<Stack direction='row' width='max-content'>
<Button
onClick={handleAddRow}
variant="outlined"
sx={{ fontSize: ".5rem" }}
>
Add New Row
</Button>
<HelpButton title="Add Dose Line">
Adding an additional dosing line allows defining complex dosing
regimens (e.g. changing dosing frequency and/or dosing levels)
</HelpButton>
</Stack>
</>
);
};
Expand Down
7 changes: 1 addition & 6 deletions frontend-v2/src/features/trial/Protocols.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,7 @@ const Protocols: React.FC = () => {
<TableCell align="right">
<div style={{ ...defaultHeaderSx }}>
{" "}
Add Dose Line{" "}
<HelpButton title="Add Dose Line">
Adding an additional dosing line allows defining complex
dosing regimens (e.g. changing dosing frequency and/or dosing
levels)
</HelpButton>
Remove{" "}
</div>
</TableCell>
</TableRow>
Expand Down
Loading