-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WIP (parameter form has component test but cannot yet be submitted)
- Loading branch information
1 parent
9e0e8b8
commit dda7c27
Showing
9 changed files
with
459 additions
and
174 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,240 @@ | ||
<template> | ||
<div> | ||
<CForm | ||
v-if="props.metaData" | ||
class="inputs" | ||
:data-test="JSON.stringify(formData)" | ||
@submit.prevent="submitForm" | ||
> | ||
<div | ||
v-for="(parameter) in parametersOfTypeSelect" | ||
:key="parameter.id" | ||
class="field-container" | ||
> | ||
<CIcon | ||
v-if="parameterIcons[parameter.id] && !optionsAreTerse(parameter)" | ||
:icon="parameterIcons[parameter.id]" | ||
class="parameter-icon" | ||
/> | ||
<CFormSelect | ||
v-if="!optionsAreTerse(parameter)" | ||
:ref="parameter.id" | ||
v-model="formData[parameter.id]" | ||
:label="parameter.label" | ||
:aria-label="parameter.label" | ||
:options="parameter.options.map((option: ParameterOption) => { | ||
return { label: option.label, value: option.id }; | ||
})" | ||
:feedback="true ? '' : 'Please select a parameter'" | ||
:invalid="true ? false : true" | ||
:size="largeScreen ? 'lg' : ''" | ||
/> | ||
<CCol v-else class="button-group-container"> | ||
<CRow> | ||
<CIcon | ||
v-if="parameterIcons[parameter.id]" | ||
:icon="parameterIcons[parameter.id]" | ||
class="parameter-icon" | ||
/> | ||
<CFormLabel :for="parameter.id"> | ||
{{ parameter.label }} | ||
</CFormLabel> | ||
</CRow> | ||
<CRow> | ||
<CButtonGroup | ||
role="group" | ||
:aria-label="parameter.label" | ||
:size="largeScreen ? 'lg' : ''" | ||
@click="disableRunButton = false" | ||
> | ||
<CFormCheck | ||
v-for="(option) in parameter.options" | ||
:id="option.id" | ||
:key="option.id" | ||
v-model="formData[parameter.id]" | ||
type="radio" | ||
:button="{ color: 'primary', variant: 'outline' }" | ||
:name="parameter.id" | ||
autocomplete="off" | ||
:label="option.label" | ||
:value="option.id" | ||
/> | ||
</CButtonGroup> | ||
</CRow> | ||
</CCol> | ||
</div> | ||
<div | ||
v-if="globeParameter" | ||
class="field-container" | ||
> | ||
<CIcon | ||
v-if="parameterIcons[globeParameter.id]" | ||
:icon="parameterIcons[globeParameter.id]" | ||
class="parameter-icon" | ||
/> | ||
<CFormSelect | ||
v-model="formData[globeParameter.id]" | ||
:data-test="`${globeParameter.id}-select`" | ||
:label="globeParameter.label" | ||
:aria-label="globeParameter.label" | ||
:options="selectOptions(globeParameter)" | ||
:size="largeScreen ? 'lg' : ''" | ||
/> | ||
</div> | ||
<CButton | ||
id="run-button" | ||
color="primary" | ||
:size="largeScreen ? 'lg' : ''" | ||
type="submit" | ||
@click="console.log('not implemetned yet')" | ||
> | ||
Run | ||
<CIcon | ||
icon="cilArrowRight" | ||
/> | ||
</CButton> | ||
</CForm> | ||
<CAlert v-else-if="props.metadataFetchStatus === 'error'" color="warning"> | ||
Failed to retrieve metadata from R API. {{ metadataFetchError }} | ||
</CAlert> | ||
<CSpinner v-else-if="props.metadataFetchStatus === 'pending'" /> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import type { FetchError } from "ofetch"; | ||
import { CIcon } from "@coreui/icons-vue"; | ||
import type { MetaData, Parameter, ParameterOption } from "@/types/daedalusApiResponseTypes"; | ||
import type { AsyncDataRequestStatus } from "#app"; | ||
const props = defineProps<{ | ||
globeParameter: Parameter | undefined | ||
metaData: MetaData | undefined | ||
metadataFetchStatus: AsyncDataRequestStatus | ||
metadataFetchError: FetchError | null | ||
}>(); | ||
const formData = ref( | ||
// Create a new object with keys set to the id values of the metaData.parameters array of objects, and all values set to empty refs. | ||
props.metaData?.parameters.reduce((accumulator, parameter) => { | ||
if (parameter.parameterType !== "select" && parameter.parameterType !== "globeSelect") { | ||
accumulator[parameter.id] = ref(""); | ||
return accumulator; | ||
} | ||
// TODO: Make default country UK after November 2024 workshop | ||
if (parameter.id === "country") { | ||
accumulator[parameter.id] = ref("Thailand"); | ||
} else { | ||
// Don't set an empty value or there will be a disjoint between the select component and the formData object, | ||
// since the select component will visually appear to have an option selected (the first), but the formData object will have | ||
// an empty string. | ||
const defaultOption = parameter.defaultOption || parameter.options[0].id; | ||
accumulator[parameter.id] = ref(defaultOption); | ||
} | ||
return accumulator; | ||
}, {} as { [key: string]: any }), | ||
); | ||
const parameterIcons = { | ||
country: "cilGlobeAlt", | ||
response: "cilShieldAlt", | ||
vaccine: "cilIndustry", | ||
pathogen: "cilBug", | ||
}; | ||
const parametersOfTypeSelect = computed(() => { | ||
if (props.metaData) { | ||
return props.metaData.parameters.filter(parameter => parameter.parameterType === "select"); | ||
} else { | ||
return []; | ||
} | ||
}); | ||
const globeParameter = computed(() => { | ||
if (props.metaData) { | ||
return props.metaData.parameters.filter(parameter => parameter.parameterType === "globeSelect")[0]; | ||
} else { | ||
return undefined; | ||
} | ||
}); | ||
const selectOptions = (parameter: Parameter) => { | ||
return parameter.options.map((option: ParameterOption) => { | ||
// Because the select component does not seem to honour the initial v-model value, we had to manually | ||
// set the 'selected' attribute below. | ||
// As a result, this list of options is recalculated each time an option is selected. | ||
return { label: option.label, value: option.id, selected: option.id === formData.value![parameter.id] }; | ||
}); | ||
}; | ||
const optionsAreTerse = (parameter: Parameter) => { | ||
const eachOptionIsASingleWord = parameter.options.filter((option) => { | ||
return option.label.includes(" "); | ||
}).length === 0; | ||
return parameter.options.length <= 5 && eachOptionIsASingleWord; | ||
}; | ||
const submitForm = () => { | ||
// console.log(formData.value); | ||
}; | ||
const largeScreen = ref(true); | ||
const breakpoint = 992; // CoreUI's "lg" breakpoint | ||
const setFieldSizes = () => { | ||
if (window.innerWidth < breakpoint) { | ||
largeScreen.value = false; | ||
} else { | ||
largeScreen.value = true; | ||
} | ||
}; | ||
onMounted(() => { | ||
setFieldSizes(); | ||
window.addEventListener("resize", setFieldSizes); | ||
}); | ||
onBeforeUnmount(() => { | ||
window.removeEventListener("resize", setFieldSizes); | ||
}); | ||
watchEffect(() => { | ||
// if (formData.value) { | ||
// console.log(formData.value) | ||
// } | ||
}); | ||
</script> | ||
|
||
<style lang="scss"> | ||
.inputs { | ||
display: flex; | ||
flex-wrap: wrap; | ||
row-gap: 1rem; | ||
column-gap: 1rem; | ||
// background-color: rgba(100, 100, 100, 0.5); | ||
// background-color: rgba(255, 255, 255, 0.5); /* Adjust opacity as needed */ | ||
// mix-blend-mode: overlay; | ||
// backdrop-filter: blur(5px); | ||
} | ||
.field-container { | ||
min-width: 15rem; | ||
flex-grow: 1; | ||
.parameter-icon { | ||
margin-left: 0.75rem; | ||
margin-right: 0.5rem; | ||
padding: 0; | ||
} | ||
.button-group-container .parameter-icon { | ||
margin-left: 1.5rem; | ||
} | ||
} | ||
#run-button { | ||
align-self: flex-end; | ||
min-width: 7rem; | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.