diff --git a/packages/frontend/src/components/LayoutObject.tsx b/packages/frontend/src/components/LayoutObject.tsx deleted file mode 100644 index fe21508..0000000 --- a/packages/frontend/src/components/LayoutObject.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { Box, TextField, Checkbox, FormGroup, FormControlLabel, Divider, IconButton, Tooltip } from '@mui/material'; -import { FC, useState, ChangeEvent } from 'react'; -import { Layout } from '../types/ExperimentTypes'; -import InfoIcon from '@mui/icons-material/Info'; -interface LayoutComponentProps { - layoutOptions: Layout[]; - value: Layout; - onChange: (arg0: Layout) => void; -} - -export const LayoutComponent: FC = (props) => { - const [selectedOption, setSelectedOption] = useState(); - const [mediaVol, setMediaVol] = useState(''); - const [textfieldError, setTextfieldError] = useState(false); - const handleCheckboxChange = (option: Layout) => { - if (selectedOption === option) { - setSelectedOption(null); - } else { - setSelectedOption(option); - props.onChange(option); - } - }; - const handleTextChange = (event: ChangeEvent, _min: number, _max: number) => { - if (event.target) { - if (/^\d*\.?\d*$/.test(event.target.value)) { - // const vol = parseInt(event.target.value); - // if(vol >= min && vol <= max){ - setMediaVol(event.target.value); - setTextfieldError(false); - props.value.params.mediaVolume = parseFloat(event.target.value); - - // }else{ - // setTextfieldError(true); - // } - } else { - setTextfieldError(true); - } - } - }; - return ( - - - {props.layoutOptions.map((option, index) => { - return ( - - - - { - navigator.clipboard.writeText(option.desc); - }} - > - - - - handleCheckboxChange(option)} - checked={selectedOption === option} - /> - - } - /> - {selectedOption === option && ( - handleTextChange(e, option.min, option.max)} - error={textfieldError} - helperText={textfieldError ? 'Please input numbers only' : ''} - /> - )} - - - ); - })} - - - ); -}; diff --git a/packages/frontend/src/components/MediaObject.tsx b/packages/frontend/src/components/MediaObject.tsx deleted file mode 100644 index 99d52fe..0000000 --- a/packages/frontend/src/components/MediaObject.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { Box, TextField, FormGroup, FormControlLabel, Checkbox, Divider, Tooltip, IconButton } from '@mui/material'; -import { FC, useState, ChangeEvent } from 'react'; -import { Media } from '../types/ExperimentTypes'; -import InfoIcon from '@mui/icons-material/Info'; - -interface MediaComponentProps { - mediaOptions: Media[]; - value: Media; - onChange: (arg0: Media) => void; -} - -export const MediaComponent: FC = (props) => { - const [selectedOption, setSelectedOption] = useState(props.mediaOptions[0]); - const [mediaVol, setMediaVol] = useState(''); - const [textfieldError, setTextfieldError] = useState(false); - const handleCheckboxChange = (option: Media) => { - if (selectedOption === option) { - setSelectedOption(null); - } else { - setSelectedOption(option); - props.onChange(option); - // props.value = option; - } - }; - const handleTextChange = (event: ChangeEvent) => { - if (event.target) { - if (/^\d*\.?\d*$/.test(event.target.value)) { - setMediaVol(event.target.value); - setTextfieldError(false); - props.value.params.mediaConcentration = parseFloat(event.target.value); - } else { - setTextfieldError(true); - } - } - }; - return ( - - - {props.mediaOptions.map((option, index) => { - return ( - - - - { - navigator.clipboard.writeText(option.desc); - }} - > - - - - handleCheckboxChange(option)} - checked={selectedOption === option} - /> - - } - /> - {selectedOption === option && ( - - )} - - - ); - })} - - - ); -}; diff --git a/packages/frontend/src/components/ModelObject.tsx b/packages/frontend/src/components/ModelObject.tsx deleted file mode 100644 index 2406a9b..0000000 --- a/packages/frontend/src/components/ModelObject.tsx +++ /dev/null @@ -1,202 +0,0 @@ -import { - Box, - TextField, - Checkbox, - FormGroup, - FormControlLabel, - RadioGroup, - Radio, - FormLabel, - Grid, - Divider, - Tooltip, - IconButton, - Typography -} from '@mui/material'; -import { FC, useState } from 'react'; -import { MetabolicModel } from '../types/ExperimentTypes'; -import InfoIcon from '@mui/icons-material/Info'; - -interface ModelComponentProps { - modelOptions: MetabolicModel[]; - value: MetabolicModel; - modelLimit: number; - onChange: (arg0: MetabolicModel) => void; -} - -const defaultParams: MetabolicModel['params'] = { - demographicNoise: false, - demographicNoiseAmplitude: 0.001, - uptakeVMax: 10, - uptakeKm: 10e-5, - deathRate: 0.001, - biomassLinearDiffusivity: 0.001, - biomassNonlinearDiffusivity: 0.6 -}; - -export const ModelComponent: FC = (props) => { - console.log(props.modelOptions); - const [selectedOption, setSelectedOption] = useState(); - const [modelParams, setModelParams] = useState(defaultParams); - const [textfieldError, setTextfieldError] = useState(false); - const handleCheckboxChange = (option: MetabolicModel) => { - if (selectedOption === option) { - setSelectedOption(null); - } else { - setSelectedOption(option); - props.onChange(option); - } - }; - const handleTextChange = (field: string, value: string) => { - if (/^\d*\.?\d*$/.test(value)) { - setModelParams({ ...modelParams, [field]: parseFloat(value) }); - props.value.params = { ...modelParams, [field]: parseFloat(value) }; - setTextfieldError(false); - } else { - setTextfieldError(true); - } - }; - - const handleRadioChange = (value: boolean) => { - setModelParams({ ...modelParams, demographicNoise: value }); - }; - - return ( - - - {props.modelOptions.map((option, index) => { - return ( - - {option.name}} - control={ - <> - - { - navigator.clipboard.writeText(option.desc); - }} - > - - - - handleCheckboxChange(option)} - checked={selectedOption === option} - /> - - } - /> - {selectedOption === option && ( - <> - - - Demographic Noise - - - - - handleRadioChange(true)} - value={true} - name="demoNoise-radio-button-yes" - inputProps={{ 'aria-label': 'Yes' }} - /> - } - /> - handleRadioChange(false)} - value={false} - name="demoNoise-radio-button-no" - inputProps={{ 'aria-label': 'No' }} - /> - } - /> - - - - - handleTextChange('demographicNoiseAmplitude', event.target.value)} - error={textfieldError} - helperText={textfieldError ? 'Please input numbers only' : ''} - sx={{ marginTop: 2 }} - inputProps={{ - step: '0.000000001' - }} - /> - handleTextChange('deathRate', event.target.value)} - error={textfieldError} - helperText={textfieldError ? 'Please input numbers only' : ''} - sx={{ marginTop: 2 }} - inputProps={{ - step: '0.000000001' - }} - /> - handleTextChange('biomassLinearDiffusivity', event.target.value)} - error={textfieldError} - helperText={textfieldError ? 'Please input numbers only' : ''} - sx={{ marginTop: 2 }} - inputProps={{ - step: '0.000000001' - }} - /> - handleTextChange('biomassNonlinearDiffusivity', event.target.value)} - error={textfieldError} - helperText={textfieldError ? 'Please input numbers only' : ''} - sx={{ marginTop: 2 }} - inputProps={{ - step: '0.000000001' - }} - /> - {/* */} - - )} - - - ); - })} - - - ); -}; diff --git a/packages/frontend/src/components/SidebarObject.tsx b/packages/frontend/src/components/SidebarObject.tsx deleted file mode 100644 index b82ad69..0000000 --- a/packages/frontend/src/components/SidebarObject.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { Box, Accordion, AccordionSummary, AccordionDetails, List, ListItemText, Typography } from '@mui/material'; -import { FC } from 'react'; -import { SummaryCard } from '../types/ExperimentTypes'; -import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; -export interface SidebarcardProps { - item: SummaryCard; -} - -const textPairing: { [key: string]: string } = { - mediaVolume: 'Media Volume(ml)', - mediaConcentration: 'Media Concentration(mmol/cm3)', - demographicNoise: 'Demographic Noise', - demographicNoiseAmplitude: 'Demographic Noise Amplitude', - uptakeVMax: 'Uptake Vmax', - uptakeKm: 'Uptake Km', - deathRate: 'Death Rate', - biomassLinearDiffusivity: 'Biomass Linear Diffusivity', - biomassNonlinearDiffusivity: 'Biomass Non-Linear Diffusivity', - simulatedTime: 'Simulated Time', - timeSteps: 'No. of steps', - nutrientDiffusivity: 'Nutrient Diffusivity', - logFrequency: 'Save Frequency', - vMax: 'Vmax', - km: 'Km' -}; - -export const SidebarCard: FC = (props) => { - return ( - - - } aria-controls="panel1-content" id="panel1-header"> - {props.item.label} - - - - - {Object.keys(props.item.info.params).map((key, index) => { - let ret; - if (typeof props.item.info.params[key] === 'boolean') { - ret = ( - - {textPairing[key]}: {String(props.item.info.params[key])} - - ); - } else { - ret = ( - - {textPairing[key]}: {props.item.info.params[key]} - - ); - } - return ret; - })} - - - - - - ); -}; diff --git a/packages/frontend/src/components/parameters/GlobalParamsView.tsx b/packages/frontend/src/components/parameters/GlobalParamsView.tsx index aec66c9..88fcd7c 100644 --- a/packages/frontend/src/components/parameters/GlobalParamsView.tsx +++ b/packages/frontend/src/components/parameters/GlobalParamsView.tsx @@ -13,7 +13,7 @@ export const GlobalParamsView: React.FC = ({ params }) => Time Step: {params.timeStep} Log Frequency: {params.logFreq} - Default Diff Const: {params.defaultDiffConst} + Nutrient Diffusivity: {params.defaultDiffConst} cm2/s Default VMax: {params.defaultVMax} Default KM: {params.defaultKm} Max Cycles: {params.maxCycles} diff --git a/packages/frontend/src/components/parameters/LayoutParamsView.tsx b/packages/frontend/src/components/parameters/LayoutParamsView.tsx new file mode 100644 index 0000000..2219858 --- /dev/null +++ b/packages/frontend/src/components/parameters/LayoutParamsView.tsx @@ -0,0 +1,21 @@ +import { LayoutParametersInput } from '../../graphql/graphql'; +import { Card, CardHeader, CardContent, List, ListItem } from '@mui/material'; +import { getLayoutName } from '../../helpers/names'; + +export interface LayoutParamsViewProps { + params: LayoutParametersInput; +} + +export const LayoutParamsView: React.FC = ({ params }) => { + return ( + + + + + Type: {getLayoutName(params.type)} + Volume: {params.volume} ml + + + + ); +}; diff --git a/packages/frontend/src/components/parameters/MetaboliteParamsView.tsx b/packages/frontend/src/components/parameters/MetaboliteParamsView.tsx index d2051ff..4330c37 100644 --- a/packages/frontend/src/components/parameters/MetaboliteParamsView.tsx +++ b/packages/frontend/src/components/parameters/MetaboliteParamsView.tsx @@ -1,5 +1,6 @@ import { Card, CardContent, CardHeader, List, ListItem } from '@mui/material'; import { MetaboliteParametersInput } from '../../graphql/graphql'; +import { getMetaboliteName } from '../../helpers/names'; export interface MetaboliteParamsViewProps { params: MetaboliteParametersInput; @@ -11,8 +12,8 @@ export const MetaboliteParamsView: React.FC = ({ para - Type: {params.type} - Amount: {params.concentration} + Type: {getMetaboliteName(params.type)} + Amount: {params.concentration} mmol/cm3 diff --git a/packages/frontend/src/components/parameters/ModelParamsView.tsx b/packages/frontend/src/components/parameters/ModelParamsView.tsx index 4e75055..649b763 100644 --- a/packages/frontend/src/components/parameters/ModelParamsView.tsx +++ b/packages/frontend/src/components/parameters/ModelParamsView.tsx @@ -1,5 +1,6 @@ import { Card, CardContent, CardHeader, List, ListItem, Paper } from '@mui/material'; import { ModelParametersInput } from '../../graphql/graphql'; +import { getModelName } from '../../helpers/names'; export interface ModelParamsViewProps { params: ModelParametersInput[]; @@ -22,8 +23,10 @@ const SingleModelParamsView: React.FC<{ params: ModelParametersInput }> = ({ par return ( - Name: {params.name} - Neutral Drift: {params.neutralDrift} + + Name: {getModelName(params.name)} + + Neutral Drift: {params.neutralDrift ? 'True' : 'False'} Neutral Drift Amp: {params.neutralDriftAmp} Death Rate: {params.deathRate} Linear Diffusivity: {params.linearDiffusivity} diff --git a/packages/frontend/src/components/parameters/ViewParameters.tsx b/packages/frontend/src/components/parameters/ViewParameters.tsx index d332939..e97287a 100644 --- a/packages/frontend/src/components/parameters/ViewParameters.tsx +++ b/packages/frontend/src/components/parameters/ViewParameters.tsx @@ -3,6 +3,7 @@ import { SimulationRequestInput } from '../../graphql/graphql'; import { MetaboliteParamsView } from './MetaboliteParamsView'; import { ModelParamsView } from './ModelParamsView'; import { GlobalParamsView } from './GlobalParamsView'; +import { LayoutParamsView } from './LayoutParamsView'; type Parameters = Omit; @@ -14,6 +15,7 @@ export const ViewParameters: React.FC = ({ params }) => { return ( Parameters + diff --git a/packages/frontend/src/helpers/names.ts b/packages/frontend/src/helpers/names.ts new file mode 100644 index 0000000..02c464e --- /dev/null +++ b/packages/frontend/src/helpers/names.ts @@ -0,0 +1,41 @@ +import { LayoutType, MetaboliteType, ModelName } from "../graphql/graphql"; + + +export const getLayoutName = (type: LayoutType) => { + switch (type) { + case LayoutType.PetriCenter: + return '3 cm Petri Dish (Center Colony)'; + case LayoutType.PetriRandom: + return '3 cm Petri Dish (Random Lawn)'; + case LayoutType.TestTube: + return 'Test Tube'; + default: + throw Error(`Unknown layout type ${type}`); + } +}; + +export const getMetaboliteName = (type: MetaboliteType) => { + switch (type) { + case MetaboliteType.Rich: + return 'Rich'; + case MetaboliteType.Glucose: + return 'Glucose'; + case MetaboliteType.Acetate: + return 'Acetate'; + default: + throw Error(`Unknown metabolite type: ${type}`); + } +}; + +export const getModelName = (name: ModelName) => { + switch (name) { + case ModelName.EColi: + return 'Escherichia coli Core'; + case ModelName.Nitrobacter: + return 'Nitrobacter winogradskyi'; + case ModelName.Nitrosomonas: + return 'Nitrosomonas europaea'; + default: + throw new Error(`Unknown model name: ${name}`); + } +}; diff --git a/packages/frontend/src/pages/ExperimentForm.tsx b/packages/frontend/src/pages/ExperimentForm.tsx index 8de7106..ccdd49d 100644 --- a/packages/frontend/src/pages/ExperimentForm.tsx +++ b/packages/frontend/src/pages/ExperimentForm.tsx @@ -5,25 +5,26 @@ import { Box, Stack, Button } from '@mui/material'; import { ErrorObject } from 'ajv'; import { useState } from 'react'; import { useNavigate } from 'react-router'; -import { MetaboliteType } from '../graphql/graphql'; +import { LayoutType, MetaboliteType, ModelName } from '../graphql/graphql'; +import { getLayoutName, getMetaboliteName, getModelName } from '../helpers/names'; const getSchema = (metaboliteType: MetaboliteType | null) => { // The models supported are based on the metabolite type let models = [ { - const: 'E_COLI', - title: 'Escherichia coli Core' + const: ModelName.EColi, + title: getModelName(ModelName.EColi) } ]; if (metaboliteType == MetaboliteType.Rich) { models = [ { - const: 'NITROSOMONAS', - title: 'Nitrosomonas europaea' + const: ModelName.Nitrosomonas, + title: getModelName(ModelName.Nitrosomonas) }, { - const: 'NITROBACTER', - title: 'Nitrobacter winogradskyi' + const: ModelName.Nitrobacter, + title: getModelName(ModelName.Nitrobacter) } ]; } @@ -39,21 +40,22 @@ const getSchema = (metaboliteType: MetaboliteType | null) => { type: 'string', oneOf: [ { - const: 'PETRI_CENTER', - title: '3 cm Petri Dish (Center Colony)' + const: LayoutType.PetriCenter, + title: getLayoutName(LayoutType.PetriCenter) }, { - const: 'PETRI_RANDOM', - title: '3 cm Petri Dish (Random Lawn)' + const: LayoutType.PetriRandom, + title: getLayoutName(LayoutType.PetriRandom) }, { - const: 'TEST_TUBE', - title: 'Test Tube' + const: LayoutType.TestTube, + title: getLayoutName(LayoutType.TestTube) } ] }, volume: { - type: 'number' + type: 'number', + title: 'Volume (ml)' } }, required: ['type', 'volume'] @@ -66,21 +68,22 @@ const getSchema = (metaboliteType: MetaboliteType | null) => { type: 'string', oneOf: [ { - const: 'GLUCOSE', - title: 'Glucose' + const: MetaboliteType.Glucose, + title: getMetaboliteName(MetaboliteType.Glucose) }, { - const: 'ACETATE', - title: 'Acetate' + const: MetaboliteType.Acetate, + title: getMetaboliteName(MetaboliteType.Acetate) }, { - const: 'RICH', - title: 'Rich' + const: MetaboliteType.Rich, + title: getMetaboliteName(MetaboliteType.Rich) } ] }, concentration: { - type: 'number' + type: 'number', + title: 'Concentration (mmol/cm3)' } }, required: ['type', 'concentration'] @@ -132,7 +135,8 @@ const getSchema = (metaboliteType: MetaboliteType | null) => { }, defaultDiffConst: { type: 'number', - default: 0.000006 + default: 0.000006, + title: 'Nutrient Diffusivity (cm2/s)' }, defaultVMax: { type: 'number', diff --git a/packages/frontend/src/pages/ExperimentSubmitted.tsx b/packages/frontend/src/pages/ExperimentSubmitted.tsx index fbbe548..78d63a2 100644 --- a/packages/frontend/src/pages/ExperimentSubmitted.tsx +++ b/packages/frontend/src/pages/ExperimentSubmitted.tsx @@ -1,73 +1,23 @@ import { useState } from 'react'; -import { Box, Button, Drawer, Grid, Typography } from '@mui/material'; +import { Box, Drawer, Stack, Typography } from '@mui/material'; import FooterStepper from '../components/FooterStepper'; -import { Link } from 'react-router-dom'; export function ExperimentSubmittedPage() { const [activeStep, _setActiveStep] = useState(2); return ( <> - - - - - - EXPERIMENT SUBMITTED! - + + + EXPERIMENT SUBMITTED! - - Thank you for using the COMETS Layout Builder! - + Thank you for using the COMETS Layout Builder! - - Your layout is now running. You will be sent an email with a link to the results of your layout once - it’s done running. - - - - - - + + Your layout is now running. You will be sent an email with a link to the results of your layout once it’s + done running. + + { - push(item: SummaryCard): number; - push(...item: SummaryCard[]): number; -} - -export function cometsType(obj: any): string { - if (metabolicModels.includes(obj.name)) { - return 'MetabolicModel'; - } else if (media.includes(obj.name)) { - return 'Media'; - } else if (layout.includes(obj.name)) { - return 'Layout'; - } else { - return 'Global Parameters'; - } -} - -// Private Helper Functions and consts - -const metabolicModels = [ - 'Escherichia coli Core', - 'Escherichia coli', - 'Nitrosomonas europaea', - 'Nitrobacter winogradskyi', - 'E. Coli Core', - 'E. Coli', - 'S. Enterica' -]; -const layout = ['9 cm Petri Dish (Center Colony)', '9 cm Petri Dish (Random Lawn)', 'Test Tube', 'EcoFab']; -const media = [ - 'Minimal Core Glucose', - 'Minimal Core Acetate', - 'M9 Minimal Glucose', - 'M9 Minimal Acetate', - 'Rich Media' -]; diff --git a/packages/frontend/src/types/Layout.tsx b/packages/frontend/src/types/Layout.tsx deleted file mode 100644 index 4ed2afa..0000000 --- a/packages/frontend/src/types/Layout.tsx +++ /dev/null @@ -1,10 +0,0 @@ -export type Layout = { - name: string; - desc: string; - min: number; - max: number; - params: { - [key: string]: number; - mediaVolume: number; - }; -}; diff --git a/packages/frontend/src/types/Media.tsx b/packages/frontend/src/types/Media.tsx deleted file mode 100644 index d290834..0000000 --- a/packages/frontend/src/types/Media.tsx +++ /dev/null @@ -1,11 +0,0 @@ -export type Media = { - name: string; - desc: string; - min: number; - max: number; - mainMetabolites: string; //this is to check if its acetate or glucose or something else - params: { - [key: string]: number; - mediaConcentration: number; - }; -}; diff --git a/packages/frontend/src/types/Model.tsx b/packages/frontend/src/types/Model.tsx deleted file mode 100644 index 9320694..0000000 --- a/packages/frontend/src/types/Model.tsx +++ /dev/null @@ -1,14 +0,0 @@ -export type MetabolicModel = { - name: string; - desc: string; - params: { - [key: string]: boolean | number; - demographicNoise: boolean; - demographicNoiseAmplitude: number; - uptakeVMax: number; - uptakeKm: number; - deathRate: number; - biomassLinearDiffusivity: number; - biomassNonlinearDiffusivity: number; - }; -}; diff --git a/packages/frontend/src/types/SummaryCard.tsx b/packages/frontend/src/types/SummaryCard.tsx deleted file mode 100644 index d25ae9c..0000000 --- a/packages/frontend/src/types/SummaryCard.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { MetabolicModel } from './Model'; -import { Layout } from './Layout'; -import { Media } from './Media'; - -export type SummaryCard = { - label: string; - desc: string; - info: MetabolicModel | Layout | Media; -}; - -export interface SummaryCardArray extends Array { - push(item: SummaryCard): number; - push(...item: SummaryCard[]): number; -}