Skip to content

Commit 086195a

Browse files
authored
Merge pull request #116 from brainlife/enh/metadata_alert
Enh/metadata_alert
2 parents d46adf2 + 7a6142d commit 086195a

File tree

9 files changed

+677
-99
lines changed

9 files changed

+677
-99
lines changed

handler/preprocess.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ else
230230

231231
if [ ! -s $root/list ]; then
232232
echo "Could not find any MRI (or PET) DICOM files in upload. Uploaded files likely do not conform to DICOM format, aborting"
233-
echo "Please contact the ezBIDS team ([email protected]) or https://github.com/brainlife/ezbids/issues for assistance"
233+
echo "Please contact the ezBIDS team ([email protected] or https://github.com/brainlife/ezbids/issues) for assistance"
234234
exit 1
235235
fi
236236

ui/src/Objects.vue

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,8 @@
290290
so._type.startsWith('pet') ||
291291
so._type.startsWith('func') ||
292292
so._type.startsWith('fmap') ||
293-
so._type.startsWith('dwi')
293+
so._type.startsWith('dwi') ||
294+
so._type.startsWith('anat')
294295
"
295296
label="Relevant Metadata"
296297
>
@@ -388,9 +389,14 @@ import { defineComponent } from 'vue';
388389
import datatype from './components/datatype.vue';
389390
import ModalityForm from './components/modalityForm.vue';
390391
392+
import anatYaml from '../src/assets/schema/rules/sidecars/anat.yaml';
393+
import funcYaml from '../src/assets/schema/rules/sidecars/func.yaml';
394+
import fmapYaml from '../src/assets/schema/rules/sidecars/fmap.yaml';
395+
import dwiYaml from '../src/assets/schema/rules/sidecars/dwi.yaml';
391396
import aslYaml from '../src/assets/schema/rules/sidecars/asl.yaml';
392397
import petYaml from '../src/assets/schema/rules/sidecars/pet.yaml';
393-
import metadata_types from '../src/assets/schema/rules/sidecars/metadata_types.yaml';
398+
import megYaml from '../src/assets/schema/rules/sidecars/meg.yaml';
399+
import metadataInfo from '../src/assets/schema/rules/sidecars/metadata.yaml';
394400
395401
import { IObject, Session, OrganizedSession, OrganizedSubject } from './store';
396402
import { prettyBytes } from './filters';

ui/src/SeriesPage.vue

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555
</div>
5656
<div v-if="ss">
5757
<h5>BIDS Datatype, Suffix, Entities</h5>
58-
<!-- <pre>{{ getFieldsMetaData(ss.type) }}</pre> -->
5958
<el-form label-width="150px">
6059
<el-alert v-if="ss.message" :title="ss.message" type="info" show-icon style="margin-bottom: 4px" />
6160
<div style="margin-bottom: 10px">
@@ -122,20 +121,6 @@
122121
</template>
123122
</el-popover>
124123
</el-form-item>
125-
<!-- <p style="border-top: 1px solid #eee; padding: 10px 20px;">
126-
<small>The following metadata fields are required, recommoneded, or optional for this datatype/suffix. Please enter missing required information.</small>
127-
<el-form-item v-for="(v, md) in getSomeMetadata(ss.type)" :key="md"
128-
:label="md.toString()+'-'+(v=='required'?' *':'')" label-width="350" style="width: 350px">
129-
<el-popover v-if="bidsSchema.metadata[md]" :width="350"
130-
:title="bidsSchema.metadata[md].name"
131-
:content="bidsSchema.metadata[md].description">
132-
<template #reference>
133-
<el-input v-model="ss.md" size="small" :required="v == 'required'" @change="validateAll()"/>
134-
</template>
135-
</el-popover>
136-
</el-form-item>
137-
<p style="border-top: 1px solid #eee; padding: 10px 20px;"></p>
138-
</p> -->
139124
</div>
140125

141126
<div v-if="ss.type && (ss.type.startsWith('fmap/') || ss.type === 'perf/m0scan')">
@@ -241,7 +226,9 @@
241226
ss.type.startsWith('pet') ||
242227
ss.type.startsWith('func') ||
243228
ss.type.startsWith('fmap') ||
244-
ss.type.startsWith('dwi')
229+
ss.type.startsWith('dwi') ||
230+
ss.type.startsWith('anat') ||
231+
ss.type.startsWith('meg')
245232
"
246233
label="Relevant Metadata"
247234
>
@@ -316,17 +303,22 @@ import { prettyBytes } from './filters';
316303
317304
import { Series, IObject } from './store';
318305
319-
import { validateEntities, validate_B0FieldIdentifier_B0FieldSource } from './libUnsafe';
306+
import { validateEntities, validate_B0FieldIdentifier_B0FieldSource, metadataAlerts } from './libUnsafe';
307+
import anatYaml from '../src/assets/schema/rules/sidecars/anat.yaml';
308+
import funcYaml from '../src/assets/schema/rules/sidecars/func.yaml';
309+
import fmapYaml from '../src/assets/schema/rules/sidecars/fmap.yaml';
310+
import dwiYaml from '../src/assets/schema/rules/sidecars/dwi.yaml';
320311
import aslYaml from '../src/assets/schema/rules/sidecars/asl.yaml';
321312
import petYaml from '../src/assets/schema/rules/sidecars/pet.yaml';
322-
import metadata_types from '../src/assets/schema/rules/sidecars/metadata_types.yaml';
313+
import megYaml from '../src/assets/schema/rules/sidecars/meg.yaml';
314+
import metadataInfo from '../src/assets/schema/rules/sidecars/metadata.yaml';
315+
323316
import AsyncImageLink from './components/AsyncImageLink.vue';
324317
325318
// @ts-ignore
326319
import { Splitpanes, Pane } from 'splitpanes';
327320
328321
import 'splitpanes/dist/splitpanes.css';
329-
import axios from './axios.instance';
330322
331323
export default defineComponent({
332324
components: {
@@ -342,8 +334,7 @@ export default defineComponent({
342334
return {
343335
showInfo: {} as any,
344336
ss: null as Series | null, //selected series
345-
petYaml: petYaml,
346-
aslYaml: aslYaml,
337+
metadataAlertsFields: [] as any,
347338
fields: {},
348339
showDialog: false,
349340
rules: {},
@@ -390,6 +381,42 @@ export default defineComponent({
390381
validate_B0FieldIdentifier_B0FieldSource(s);
391382
}
392383
384+
/* Alert users to metadata issues, such as missing required fields or
385+
improperly-formmated metadata field values.
386+
*/
387+
let bidsDatatypeMetadata = {};
388+
if (['perf/asl', 'perf/m0scan'].includes(s.type)) {
389+
bidsDatatypeMetadata = aslYaml;
390+
} else if (s.type.startsWith('pet')) {
391+
bidsDatatypeMetadata = petYaml;
392+
} else if (s.type.startsWith('func')) {
393+
bidsDatatypeMetadata = funcYaml;
394+
} else if (s.type.startsWith('fmap')) {
395+
bidsDatatypeMetadata = fmapYaml;
396+
} else if (s.type.startsWith('dwi')) {
397+
bidsDatatypeMetadata = dwiYaml;
398+
} else if (s.type.startsWith('anat')) {
399+
bidsDatatypeMetadata = anatYaml;
400+
} else if (s.type.startsWith('meg')) {
401+
bidsDatatypeMetadata = megYaml;
402+
}
403+
404+
const metadataAlertsFields = metadataAlerts(
405+
bidsDatatypeMetadata,
406+
metadataInfo,
407+
this.ezbids,
408+
s.series_idx,
409+
s.type
410+
);
411+
// console.log(s.type);
412+
// console.log('metadataAlertsFields', metadataAlertsFields);
413+
if (metadataAlertsFields.length) {
414+
let warn: string = `'Required metadata is missing and/or provided metadata field values have improper
415+
format. Please click on the "Edit Metadata" button below to resolve. You may skip fields for which you
416+
do not know the proper value, but you will not have a fully BIDS-compliant dataset.'`;
417+
s.validationWarnings.push(warn);
418+
}
419+
393420
// DON'T REALLY NEED THIS if setRun() functionality is in place
394421
395422
// //let user know if multiple series have same datatype and entity labels
@@ -465,13 +492,6 @@ export default defineComponent({
465492
});
466493
}
467494
}
468-
469-
// Alert users to check relevant metadata ("Edit Metadata" button for any perf sequences)
470-
if (s.type.startsWith('perf/') || s.type.startsWith('pet/')) {
471-
s.validationWarnings.push(
472-
"Please check to ensure that all necessary metadata is provided, by clicking on the 'Edit Metadata' button below"
473-
);
474-
}
475495
},
476496
477497
isValid(cb: (v?: string) => void) {
@@ -490,6 +510,7 @@ export default defineComponent({
490510
submitForm(data: any) {
491511
//TODO: should we make an interface for data in store/index.ts?
492512
this.ezbids = data;
513+
this.ezbids.series.forEach(this.validate);
493514
},
494515
},
495516
});
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#
2+
# Groups of related metadata fields
3+
#
4+
# Assumptions: never need disjunction of selectors
5+
# Assumptions: top-to-bottom overrides is sufficient logic
6+
7+
---
8+
# Anatomy imaging data
9+
10+
MRIAnatomyCommonMetadataFields:
11+
selectors:
12+
- datatype == "anat"
13+
- match(extension, "^\.nii(\.gz)?$")
14+
fields:
15+
ContrastBolusIngredient: optional
16+
RepetitionTimeExcitation: optional
17+
RepetitionTimePreparation: optional
18+
19+
TaskMetadata:
20+
selectors:
21+
- datatype == "anat"
22+
- entity.task != null
23+
- match(extension, "^\.nii(\.gz)?$")
24+
fields:
25+
TaskName:
26+
level: recommended
27+
level_addendum: if `task` entity is present
28+
TaskDescription:
29+
level: recommended
30+
level_addendum: if `task` entity is present
31+
Instructions:
32+
level: recommended
33+
level_addendum: if `task` entity is present

0 commit comments

Comments
 (0)