11import React , { ChangeEvent , useState } from "react" ;
22import { ModelConfig } from "@/dto/FormConfig" ;
3- import { Autocomplete , Button , NativeSelect , TextField , Typography } from "@equinor/eds-core-react" ;
3+ import { Accordion , Autocomplete , Button , NativeSelect , TextField , Typography } from "@equinor/eds-core-react" ;
44import { MetaTooltip } from "@/functions/Tooltip" ;
55import ConvertibleTextField from "@/components/ConvertibleTextField" ;
66import { Columns } from "@/components/styles" ;
@@ -114,28 +114,33 @@ function GridRangeInput({ candidateSubstances }: { candidateSubstances: string[]
114114 ) ;
115115
116116 const axis = axes [ 0 ] ;
117+ const isActive = axis !== undefined ;
118+
119+ const headerText = isActive
120+ ? `Concentration range: ${ optionName ( axis . substance ) } `
121+ : "Concentration range" ;
117122
118123 return (
119- < div style = { { display : "flex" , flexDirection : "column" , gap : "16px" , flexGrow : 1 } } >
120- < Typography variant = "h3" > Concentration range</ Typography >
121- < Typography variant = "body_short" >
122- Optionally vary a single concentration across a range to see how the outputs respond.
123- </ Typography >
124- { axis ? (
125- < >
126- < div style = { { display : "flex" , alignItems : "center" , gap : "8px" } } >
124+ < Accordion >
125+ < Accordion . Item isExpanded = { isActive } >
126+ < Accordion . Header >
127+ { headerText }
128+ </ Accordion . Header >
129+ < Accordion . Panel >
130+ < div style = { { display : "flex" , flexDirection : "column" , gap : "12px" , padding : "4px 0" } } >
127131 < NativeSelect
128132 id = "gridAxis0"
129133 label = "Substance"
130- value = { axis . substance }
134+ value = { axis ? .substance ?? "" }
131135 onChange = { ( e ) => {
132136 if ( e . target . value === "" ) {
133- removeAxis ( 0 ) ;
134- } else {
137+ if ( isActive ) removeAxis ( 0 ) ;
138+ } else if ( isActive ) {
135139 updateAxis ( 0 , { substance : e . target . value } ) ;
140+ } else {
141+ addAxis ( e . target . value ) ;
136142 }
137143 } }
138- style = { { flex : 1 } }
139144 >
140145 < option value = "" > None (single run)</ option >
141146 { candidateSubstances . map ( ( substance ) => (
@@ -144,63 +149,49 @@ function GridRangeInput({ candidateSubstances }: { candidateSubstances: string[]
144149 </ option >
145150 ) ) }
146151 </ NativeSelect >
152+ { isActive && (
153+ < >
154+ < TextField
155+ id = "gridMin0"
156+ type = "number"
157+ label = "From"
158+ unit = "ppm"
159+ step = "any"
160+ min = { 0 }
161+ max = { PPM_MAX }
162+ value = { axis . range . min }
163+ onChange = { ( e : ChangeEvent < HTMLInputElement > ) => updateAxis ( 0 , { range : { ...axis . range , min : e . target . valueAsNumber } } ) }
164+ variant = { axis . range . max > axis . range . min ? undefined : "error" }
165+ />
166+ < TextField
167+ id = "gridMax0"
168+ type = "number"
169+ label = "To"
170+ unit = "ppm"
171+ step = "any"
172+ min = { 0 }
173+ max = { PPM_MAX }
174+ value = { axis . range . max }
175+ onChange = { ( e : ChangeEvent < HTMLInputElement > ) => updateAxis ( 0 , { range : { ...axis . range , max : e . target . valueAsNumber } } ) }
176+ variant = { axis . range . max > axis . range . min ? undefined : "error" }
177+ helperText = { axis . range . max > axis . range . min ? undefined : "'To' must be greater than 'From'" }
178+ />
179+ < TextField
180+ id = "gridSteps0"
181+ type = "number"
182+ label = "Number of values"
183+ step = { 1 }
184+ min = { 2 }
185+ max = { 25 }
186+ value = { axis . range . steps }
187+ onChange = { ( e : ChangeEvent < HTMLInputElement > ) => updateAxis ( 0 , { range : { ...axis . range , steps : e . target . valueAsNumber } } ) }
188+ />
189+ </ >
190+ ) }
147191 </ div >
148- < TextField
149- id = "gridMin0"
150- type = "number"
151- label = "From"
152- unit = "ppm"
153- step = "any"
154- min = { 0 }
155- max = { PPM_MAX }
156- value = { axis . range . min }
157- onChange = { ( e : ChangeEvent < HTMLInputElement > ) => updateAxis ( 0 , { range : { ...axis . range , min : e . target . valueAsNumber } } ) }
158- variant = { axis . range . max > axis . range . min ? undefined : "error" }
159- />
160- < TextField
161- id = "gridMax0"
162- type = "number"
163- label = "To"
164- unit = "ppm"
165- step = "any"
166- min = { 0 }
167- max = { PPM_MAX }
168- value = { axis . range . max }
169- onChange = { ( e : ChangeEvent < HTMLInputElement > ) => updateAxis ( 0 , { range : { ...axis . range , max : e . target . valueAsNumber } } ) }
170- variant = { axis . range . max > axis . range . min ? undefined : "error" }
171- helperText = { axis . range . max > axis . range . min ? undefined : "'To' must be greater than 'From'" }
172- />
173- < TextField
174- id = "gridSteps0"
175- type = "number"
176- label = "Number of values"
177- step = { 1 }
178- min = { 2 }
179- max = { 25 }
180- value = { axis . range . steps }
181- onChange = { ( e : ChangeEvent < HTMLInputElement > ) => updateAxis ( 0 , { range : { ...axis . range , steps : e . target . valueAsNumber } } ) }
182- />
183- </ >
184- ) : (
185- < NativeSelect
186- id = "gridAxis0"
187- label = "Substance"
188- value = ""
189- onChange = { ( e ) => {
190- if ( e . target . value !== "" ) {
191- addAxis ( e . target . value ) ;
192- }
193- } }
194- >
195- < option value = "" > None (single run)</ option >
196- { candidateSubstances . map ( ( substance ) => (
197- < option key = { substance } value = { substance } >
198- { optionName ( substance ) }
199- </ option >
200- ) ) }
201- </ NativeSelect >
202- ) }
203- </ div >
192+ </ Accordion . Panel >
193+ </ Accordion . Item >
194+ </ Accordion >
204195 ) ;
205196}
206197
@@ -316,6 +307,9 @@ const ModelInputs: React.FC<{
316307 ) ;
317308 } ) }
318309 < SubstanceAdder invisible = { invisible } onAdd = { ( item : string ) => setConcentration ( item , 0 ) } />
310+ < div style = { { marginTop : "1rem" } } >
311+ < GridRangeInput candidateSubstances = { gridableSubstances } />
312+ </ div >
319313 </ div >
320314 < div style = { { display : "flex" , flexDirection : "column" , gap : "16px" } } >
321315 < Typography variant = "h3" > Conditions</ Typography >
@@ -341,7 +335,6 @@ const ModelInputs: React.FC<{
341335 { selectedModels . map ( ( model ) => (
342336 < ModelParametersWrapper key = { model . modelId } model = { model } />
343337 ) ) }
344- < GridRangeInput candidateSubstances = { gridableSubstances } />
345338 </ Columns >
346339 { hasInvalidSubstances && (
347340 < Typography
0 commit comments