@@ -8,6 +8,9 @@ import ExpandableFileForm from './ExpandableFileForm'
88
99import { TextFormField } from './form-components'
1010import { findBundleChildren , validateFile } from './upload-utils'
11+ import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons'
12+ import { OverlayTrigger , Popover } from 'react-bootstrap'
13+ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
1114
1215const REQUIRED_FIELDS = [ { label : 'species' , propertyName : 'taxon_id' } ,
1316 { label : 'Biosample input type' , propertyName : 'expression_file_info.biosample_input_type' } ,
@@ -19,6 +22,9 @@ const RAW_COUNTS_REQUIRED_FIELDS = REQUIRED_FIELDS.concat([{
1922const PROCESSED_ASSOCIATION_FIELD = [
2023 { label : 'Associated raw counts files' , propertyName : 'expression_file_info.raw_counts_associations' }
2124]
25+ const RAW_LOCATION_FIELD = [
26+ { label : 'Raw count data location' , propertyName : 'raw_location' } ,
27+ ]
2228
2329/** renders a form for editing/uploading an expression file (raw or processed) and any bundle children */
2430export default function ExpressionFileForm ( {
@@ -49,6 +55,10 @@ export default function ExpressionFileForm({
4955 if ( rawCountsRequired && ! isRawCountsFile ) {
5056 requiredFields = requiredFields . concat ( PROCESSED_ASSOCIATION_FIELD )
5157 }
58+ const requireLocation = ( rawCountsRequired || isRawCountsFile ) && isAnnDataExperience
59+ if ( requireLocation ) {
60+ requiredFields = requiredFields . concat ( RAW_LOCATION_FIELD )
61+ }
5262 const validationMessages = validateFile ( { file, allFiles, allowedFileExts, requiredFields, isAnnDataExperience } )
5363
5464 const associatedRawCounts = ! isAnnDataExperience && file . expression_file_info . raw_counts_associations . map ( id => ( {
@@ -61,9 +71,45 @@ export default function ExpressionFileForm({
6171 setShowRawCountsUnits ( rawCountsVal )
6272 }
6373
74+ /** create the tooltip and message for the .obsm key name section */
75+ function rawSlotMessage ( ) {
76+ const rawSlotToolTip = < span >
77+ < OverlayTrigger
78+ trigger = { [ 'hover' , 'focus' ] }
79+ rootClose placement = "top"
80+ delayHide = { 1500 }
81+ overlay = { rawSlotHelpContent ( ) } >
82+ < span > Raw count data location * < FontAwesomeIcon icon = { faQuestionCircle } /> </ span >
83+ </ OverlayTrigger >
84+ </ span >
85+
86+ return < span >
87+ { rawSlotToolTip }
88+ </ span >
89+ }
90+
91+ /** gets the popup message to describe .obsm keys */
92+ function rawSlotHelpContent ( ) {
93+ const layersLink = < a href = "https://anndata.readthedocs.io/en/latest/generated/anndata.AnnData.layers.html"
94+ target = "_blank" > layers</ a >
95+ const rawLink = < a href = "https://anndata.readthedocs.io/en/latest/generated/anndata.AnnData.raw.html"
96+ target = "_blank" > .raw</ a >
97+ return < Popover id = "cluster-obsm-key-name-popover" className = "tooltip-wide" >
98+ < div >
99+ Location of raw count data in your AnnData file. This can be the raw slot ({ rawLink } ) or the name of a layer in
100+ the { layersLink } section.
101+ </ div >
102+ </ Popover >
103+ }
104+
64105 return < ExpandableFileForm { ...{
65- file, allFiles, updateFile, saveFile,
66- allowedFileExts, deleteFile, validationMessages, bucketName, isInitiallyExpanded, isAnnDataExperience
106+ file,
107+ allFiles,
108+ updateFile,
109+ saveFile,
110+ allowedFileExts,
111+ deleteFile,
112+ validationMessages, bucketName, isInitiallyExpanded, isAnnDataExperience
67113 } } >
68114 { ! isAnnDataExperience &&
69115 < div className = "form-group" >
@@ -123,25 +169,32 @@ export default function ExpressionFileForm({
123169 { isAnnDataExperience &&
124170 < div className = "row" >
125171 < div className = "form-radio col-sm-4" >
126- < label className = "labeled-select" > I have raw count data in the < strong > adata.raw </ strong > slot </ label >
172+ < label className = "labeled-select" > I have raw count data</ label >
127173 < label className = "sublabel" >
128174 < input type = "radio"
129175 name = { `anndata-raw-counts-${ file . _id } ` }
130176 value = "true"
131177 checked = { isRawCountsFile }
132- onChange = { e => toggleIsRawCounts ( true ) } />
178+ onChange = { e => toggleIsRawCounts ( true ) } />
133179 Yes
134180 </ label >
135181 < label className = "sublabel" >
136182 < input type = "radio"
137183 name = { `anndata-raw-counts-${ file . _id } ` }
138184 value = "false"
139185 checked = { ! isRawCountsFile }
140- onChange = { e => toggleIsRawCounts ( false ) } />
186+ onChange = { e => toggleIsRawCounts ( false ) } />
141187 No
142188 </ label >
143189 </ div >
144- { showRawCountsUnits && < div className = "col-sm-8" >
190+ { requireLocation && < div className = "col-sm-4" >
191+ < TextFormField label = { rawSlotMessage ( ) }
192+ fieldName = "raw_location"
193+ file = { file }
194+ updateFile = { updateFile }
195+ placeholderText = 'Specify .raw or name of layer' /> </ div >
196+ }
197+ { showRawCountsUnits && < div className = "col-sm-4" >
145198 < ExpressionFileInfoSelect label = "Units *"
146199 propertyName = "units"
147200 rawOptions = { fileMenuOptions . units }
0 commit comments