@@ -21,7 +21,7 @@ import {
2121 useFindEntityAndVariable ,
2222 useSubsettingClient ,
2323} from '../../../hooks/workspace' ;
24- import { ReactNode , useEffect , useMemo , useRef } from 'react' ;
24+ import { ReactNode , useCallback , useEffect , useMemo , useRef } from 'react' ;
2525import { ComputationStepContainer } from '../ComputationStepContainer' ;
2626import { ValuePicker } from '../../visualizations/implementations/ValuePicker' ;
2727import { useToggleStarredVariable } from '../../../hooks/starredVariables' ;
@@ -38,7 +38,7 @@ import {
3838import { IsEnabledInPickerParams } from '../../visualizations/VisualizationTypes' ;
3939import { entityTreeToArray } from '../../../utils/study-metadata' ;
4040import { InputVariables } from '../../visualizations/InputVariables' ;
41- import { enqueueSnackbar } from 'notistack ' ;
41+ import useSnackbar from '@veupathdb/coreui/lib/components/notifications/useSnackbar ' ;
4242import { useCachedPromise } from '../../../hooks/cachedPromise' ;
4343import { DataElementConstraintRecord } from '../../../utils/data-element-constraints' ;
4444import { DifferentialExpressionConfig } from '../../../types/apps' ;
@@ -252,11 +252,13 @@ export function DifferentialExpressionConfiguration(
252252 visualizationId,
253253 changeConfigHandlerOverride,
254254 showStepNumber = true ,
255+ readonlyInputNames,
255256 } = props ;
256257
257258 const configuration = computation . descriptor
258259 . configuration as DifferentialExpressionConfig ;
259260 const studyMetadata = useStudyMetadata ( ) ;
261+ const { enqueueSnackbar } = useSnackbar ( ) ;
260262 const dataClient = useDataClient ( ) ;
261263 const toggleStarredVariable = useToggleStarredVariable ( props . analysisState ) ;
262264 const filters = analysisState . analysis ?. descriptor . subset . descriptor ;
@@ -286,11 +288,6 @@ export function DifferentialExpressionConfiguration(
286288 ) ;
287289
288290 useEffect ( ( ) => {
289- if (
290- ! configuration . comparator ||
291- ( ! configuration . comparator . groupA && ! configuration . comparator . groupB )
292- )
293- return ;
294291 if (
295292 previousSubset . current &&
296293 ! isEqual (
@@ -301,20 +298,25 @@ export function DifferentialExpressionConfiguration(
301298 previousSubset . current =
302299 analysisState . analysis ?. descriptor . subset . descriptor ;
303300
304- // Reset the groupA and groupB values.
305- changeConfigHandler ( 'comparator' , {
306- variable : configuration . comparator . variable ,
307- groupA : undefined ,
308- groupB : undefined ,
309- } ) ;
310-
311- enqueueSnackbar (
312- < span >
313- Reset differential expression group A and B values due to changed
314- subset.
315- </ span > ,
316- { variant : 'info' }
317- ) ;
301+ if (
302+ configuration . comparator &&
303+ ( configuration . comparator . groupA || configuration . comparator . groupB )
304+ ) {
305+ // Reset the groupA and groupB values.
306+ changeConfigHandler ( 'comparator' , {
307+ variable : configuration . comparator . variable ,
308+ groupA : undefined ,
309+ groupB : undefined ,
310+ } ) ;
311+
312+ enqueueSnackbar (
313+ < span >
314+ Reset differential expression reference and comparison group
315+ specification due to changed subset.
316+ </ span > ,
317+ { variant : 'info' }
318+ ) ;
319+ }
318320 }
319321 } , [
320322 analysisState . analysis ?. descriptor . subset . descriptor ,
@@ -330,6 +332,17 @@ export function DifferentialExpressionConfiguration(
330332 [ studyMetadata ]
331333 ) ;
332334
335+ // Helper to get display name for a variable descriptor (used for read-only labels)
336+ const getVariableDisplayName = useCallback (
337+ ( varDescriptor : any ) => {
338+ if ( ! varDescriptor ) return undefined ;
339+ const result = findEntityAndVariable ( varDescriptor ) ;
340+ if ( ! result ) return undefined ;
341+ return `${ result . entity . displayName } > ${ result . variable . displayName } ` ;
342+ } ,
343+ [ findEntityAndVariable ]
344+ ) ;
345+
333346 const selectedComparatorVariable = useMemo ( ( ) => {
334347 if (
335348 configuration &&
@@ -458,17 +471,33 @@ export function DifferentialExpressionConfiguration(
458471 label : 'Gene Identifier' ,
459472 role : 'axis' ,
460473 titleOverride : 'Expression Data' ,
474+ ...( readonlyInputNames ?. includes ( 'identifierVariable' )
475+ ? {
476+ readonlyValue :
477+ getVariableDisplayName (
478+ configuration . identifierVariable
479+ ) ?? 'Not selected' ,
480+ }
481+ : { } ) ,
461482 } ,
462483 {
463484 name : 'valueVariable' ,
464485 label : 'Count type' ,
465486 role : 'axis' ,
487+ ...( readonlyInputNames ?. includes ( 'valueVariable' )
488+ ? {
489+ readonlyValue :
490+ getVariableDisplayName ( configuration . valueVariable ) ??
491+ 'Not selected' ,
492+ }
493+ : { } ) ,
466494 } ,
467495 {
468496 name : 'comparatorVariable' ,
469497 label : 'Metadata Variable' ,
470498 role : 'stratification' ,
471499 titleOverride : 'Group Comparison' ,
500+ styleOverride : { minWidth : '30em' } ,
472501 } ,
473502 ] }
474503 entities = { entities }
@@ -479,14 +508,18 @@ export function DifferentialExpressionConfiguration(
479508 } }
480509 onChange = { ( vars ) => {
481510 if (
511+ ! readonlyInputNames ?. includes ( 'identifierVariable' ) &&
482512 vars . identifierVariable !== configuration . identifierVariable
483513 ) {
484514 changeConfigHandler (
485515 'identifierVariable' ,
486516 vars . identifierVariable
487517 ) ;
488518 }
489- if ( vars . valueVariable !== configuration . valueVariable ) {
519+ if (
520+ ! readonlyInputNames ?. includes ( 'valueVariable' ) &&
521+ vars . valueVariable !== configuration . valueVariable
522+ ) {
490523 changeConfigHandler ( 'valueVariable' , vars . valueVariable ) ;
491524 }
492525 if (
@@ -508,6 +541,7 @@ export function DifferentialExpressionConfiguration(
508541 analysisState . analysis ?. descriptor . starredVariables ?? [ ]
509542 }
510543 toggleStarredVariable = { toggleStarredVariable }
544+ labelWidth = "12em"
511545 />
512546 </ div >
513547 < div className = { cx ( '-DiffExpressionOuterConfigContainer' ) } >
0 commit comments