Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions src/components/calibration/CalibrationClassificationRow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
<MvFloatField
:error="validationErrors[`functionalClassifications.${index}.label`]"
label="Functional range label"
required
>
<template #default="{id, invalid}">
<InputText
Expand Down Expand Up @@ -79,7 +80,9 @@
<!-- Classification (normal/abnormal/not_specified) -->
<div class="wizard-row">
<div class="wizard-help">
<label :id="scopedId(`input-rangeClassification-${index}`)">{{ desc.rangeClassification.help }}</label>
<label :id="scopedId(`input-rangeClassification-${index}`)">
{{ desc.rangeClassification.help }} <MvRequiredMarker />
</label>
<!-- eslint-disable vue/no-v-html -->
<div
v-if="desc.rangeClassification.detail"
Expand All @@ -105,7 +108,9 @@
<template v-if="!classBased">
<div class="wizard-row">
<div class="wizard-help">
<label :id="scopedId(`input-rangeBoundaries-${index}`)">{{ desc.rangeBoundaries.help }}</label>
<label :id="scopedId(`input-rangeBoundaries-${index}`)">
{{ desc.rangeBoundaries.help }} <MvRequiredMarker />
</label>
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-if="desc.rangeBoundaries.detail" class="wizard-help-detail" v-html="desc.rangeBoundaries.detail" />
</div>
Expand Down Expand Up @@ -201,7 +206,11 @@
<div v-if="desc.className.detail" class="wizard-help-detail" v-html="desc.className.detail" />
</div>
<div class="wizard-field">
<MvFloatField :error="validationErrors[`functionalClassifications.${index}.class`]" label="Class name">
<MvFloatField
:error="validationErrors[`functionalClassifications.${index}.class`]"
label="Class name"
required
>
<template #default="{id, invalid}">
<InputText
:id="id"
Expand Down Expand Up @@ -354,6 +363,7 @@ import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome'

import MvFieldError from '@/components/forms/MvFieldError.vue'
import MvFloatField from '@/components/forms/MvFloatField.vue'
import MvRequiredMarker from '@/components/forms/MvRequiredMarker.vue'
import useScopedId from '@/composables/scoped-id'
import {calibrationDescriptions} from '@/data/field-descriptions'
import type {DraftFunctionalClassification, FunctionalClassificationHelper} from '@/lib/calibration-types'
Expand All @@ -368,6 +378,7 @@ export default defineComponent({
InputText,
MvFieldError,
MvFloatField,
MvRequiredMarker,
PMessage: Message,
PButton: Button,
PTextarea: Textarea,
Expand Down
7 changes: 6 additions & 1 deletion src/components/calibration/CalibrationEditor.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<template>
<p v-if="showRequiredLegend !== false" class="pb-3 text-sm text-text-muted">
Fields marked <span class="font-bold text-danger">*</span> are required.
</p>
<CalibrationFields
:allow-class-based="allowClassBased"
:baseline-score="draft.baselineScore"
Expand Down Expand Up @@ -81,7 +84,9 @@ export default defineComponent({
calibrationUrn: {type: String, default: null},
scoreSetUrn: {type: String, default: null},
allowClassBased: {type: Boolean, default: true},
showScoreSetSelector: {type: [Boolean, null] as unknown as PropType<boolean | null>, default: null}
showScoreSetSelector: {type: [Boolean, null] as unknown as PropType<boolean | null>, default: null},
/** Set false when the host page already explains the required-field marker. */
showRequiredLegend: {type: Boolean, default: true}
},

emits: ['canceled', 'saved', 'update:draft'],
Expand Down
24 changes: 21 additions & 3 deletions src/components/calibration/CalibrationFields.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<p>{{ desc.scoreSet.help }}</p>
</div>
<div class="wizard-field">
<MvFloatField :error="validationErrors['scoreSetUrn']" label="Score Set">
<MvFloatField :error="validationErrors['scoreSetUrn']" label="Score Set" required>
<template #default="{id, invalid}">
<PSelect
:id="id"
Expand Down Expand Up @@ -40,7 +40,7 @@
<div v-if="desc.title.detail" class="wizard-help-detail" v-html="desc.title.detail" />
</div>
<div class="wizard-field">
<MvFloatField :error="validationErrors['title']" label="Calibration Title">
<MvFloatField :error="validationErrors['title']" label="Calibration Title" required>
<template #default="{id, invalid}">
<InputText
:id="id"
Expand Down Expand Up @@ -162,6 +162,7 @@
:loading="publicationSearchLoading"
:model-value="methodSources"
:option-label="pubOptionLabel"
:required="sourcesRequired"
:suggestions="publicationSuggestions"
:typeahead="true"
@complete="$emit('search-publications', $event)"
Expand Down Expand Up @@ -196,6 +197,7 @@
:loading="publicationSearchLoading"
:model-value="thresholdSources"
:option-label="pubOptionLabel"
:required="sourcesRequired"
:suggestions="publicationSuggestions"
:typeahead="true"
@complete="$emit('search-publications', $event)"
Expand Down Expand Up @@ -230,6 +232,7 @@
:loading="publicationSearchLoading"
:model-value="evidenceSources"
:option-label="pubOptionLabel"
:required="evidenceSourcesRequired"
:suggestions="publicationSuggestions"
:typeahead="true"
@complete="$emit('search-publications', $event)"
Expand Down Expand Up @@ -276,7 +279,7 @@
<!-- Classes file (class-based mode) -->
<div v-if="classBased" class="wizard-row">
<div class="wizard-help">
<label>{{ desc.classesFile.help }}</label>
<label>{{ desc.classesFile.help }} <MvRequiredMarker /></label>
<!-- eslint-disable-next-line vue/no-v-html -->
<div v-if="desc.classesFile.detail" class="wizard-help-detail" v-html="desc.classesFile.detail" />
</div>
Expand All @@ -293,6 +296,7 @@
empty-text="Drop a CSV file here"
:error="validationErrors['classesFile']"
label="Classes file"
required
:show-label="false"
@select="$emit('classes-file-selected', $event)"
/>
Expand Down Expand Up @@ -376,6 +380,7 @@ import CalibrationClassificationRow from '@/components/calibration/CalibrationCl
import MvFieldError from '@/components/forms/MvFieldError.vue'
import MvFileStatus from '@/components/forms/MvFileStatus.vue'
import MvFloatField from '@/components/forms/MvFloatField.vue'
import MvRequiredMarker from '@/components/forms/MvRequiredMarker.vue'
import MvTagField from '@/components/forms/MvTagField.vue'
import MvUploadField from '@/components/forms/MvUploadField.vue'
import {calibrationDescriptions} from '@/data/field-descriptions'
Expand All @@ -400,6 +405,7 @@ export default defineComponent({
MvFieldError,
MvFileStatus,
MvFloatField,
MvRequiredMarker,
MvTagField,
MvUploadField,
PButton: Button,
Expand Down Expand Up @@ -461,6 +467,18 @@ export default defineComponent({

setup() {
return {desc: calibrationDescriptions(), pubOptionLabel, onClearInput: clearAutoCompleteInput}
},

computed: {
/** Method and threshold sources are required once the calibration defines functional classifications. */
sourcesRequired(): boolean {
return this.functionalClassifications.length > 0
},

/** Evidence sources are required only when a classification carries ACMG evidence. */
evidenceSourcesRequired(): boolean {
return this.functionalClassifications.some((fc) => fc.acmgClassification != null)
}
}
})
</script>
10 changes: 9 additions & 1 deletion src/components/forms/ExperimentFields.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,12 @@
<p v-if="desc.title.detail" class="wizard-help-detail" v-html="desc.title.detail" />
</div>
<div :class="wizardMode && 'wizard-field'">
<MvFloatField :error="validationErrors.title" :hint="wizardMode ? undefined : desc.title.hint" label="Title">
<MvFloatField
:error="validationErrors.title"
:hint="wizardMode ? undefined : desc.title.hint"
label="Title"
required
>
<template #default="{id, invalid}">
<PInputText
:id="id"
Expand All @@ -35,6 +40,7 @@
:error="validationErrors.shortDescription"
:hint="wizardMode ? undefined : desc.shortDescription.hint"
label="Short description"
required
>
<template #default="{id, invalid}">
<PTextarea
Expand Down Expand Up @@ -64,6 +70,7 @@
:hint="wizardMode ? undefined : desc.abstractText.hint"
label="Abstract"
:model-value="abstractText"
required
:rows="wizardMode ? 10 : 4"
@update:model-value="$emit('update:abstractText', $event)"
/>
Expand All @@ -83,6 +90,7 @@
:hint="wizardMode ? undefined : desc.methodText.hint"
label="Methods"
:model-value="methodText"
required
:rows="wizardMode ? 10 : 4"
@update:model-value="$emit('update:methodText', $event)"
/>
Expand Down
3 changes: 2 additions & 1 deletion src/components/forms/KeywordFields.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@
<div v-if="descriptionVisible(kw.key)" class="mt-2">
<MvFloatField
:error="validationErrors[`keywordDescriptions.${kw.key}`]"
:label="`${kw.descriptionLabel} ${keywordKeys[kw.key] === 'Other' ? '(Required)' : '(Optional)'}`"
:label="kw.descriptionLabel"
:required="keywordKeys[kw.key] === 'Other'"
>
<template #default="{id, invalid}">
<PTextarea
Expand Down
11 changes: 8 additions & 3 deletions src/components/forms/MvFloatField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
<div :class="error ? 'mv-field-error' : ''">
<FloatLabel variant="on">
<slot :id="fieldId" :error-id="error ? errorId : undefined" :invalid="!!error" />
<label :for="fieldId">{{ label }}</label>
<label :for="fieldId">
{{ label }}
<MvRequiredMarker v-if="required" />
</label>
</FloatLabel>
<p v-if="hint && !error" class="mt-1 text-xs text-text-muted">{{ hint }}</p>
<MvFieldError :id="errorId" :error="error" />
Expand All @@ -13,18 +16,20 @@
import {defineComponent, type PropType} from 'vue'
import FloatLabel from 'primevue/floatlabel'
import MvFieldError from '@/components/forms/MvFieldError.vue'
import MvRequiredMarker from '@/components/forms/MvRequiredMarker.vue'
import {useFieldId} from '@/composables/scoped-id'

export default defineComponent({
name: 'MvFloatField',

components: {FloatLabel, MvFieldError},
components: {FloatLabel, MvFieldError, MvRequiredMarker},

props: {
label: {type: String, required: true},
error: {type: String as PropType<string | null>, default: null},
id: {type: String as PropType<string | null>, default: null},
hint: {type: String as PropType<string | null>, default: null}
hint: {type: String as PropType<string | null>, default: null},
required: {type: Boolean, default: false}
},

setup(props) {
Expand Down
6 changes: 4 additions & 2 deletions src/components/forms/MvMarkdownField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
</button>
</div>

<MvFloatField :label="label">
<MvFloatField :label="label" :required="required">
<template #default>
<div v-if="previewing" class="markdown-preview p-inputwrapper-filled">
<!-- eslint-disable vue/no-v-html -->
Expand All @@ -31,6 +31,7 @@
v-else
:id="fieldId"
:aria-describedby="error ? errorId : undefined"
:aria-required="required || undefined"
class="w-full"
fluid
:invalid="!!error"
Expand Down Expand Up @@ -64,7 +65,8 @@ export default defineComponent({
rows: {type: Number, default: 10},
error: {type: String as PropType<string | null>, default: null},
id: {type: String as PropType<string | null>, default: null},
hint: {type: String as PropType<string | null>, default: null}
hint: {type: String as PropType<string | null>, default: null},
required: {type: Boolean, default: false}
},

emits: ['update:modelValue'],
Expand Down
14 changes: 14 additions & 0 deletions src/components/forms/MvRequiredMarker.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<template>
<span class="text-xl text-danger">
<span aria-hidden="true">*</span>
<span class="sr-only">(required)</span>
</span>
</template>

<script lang="ts">
import {defineComponent} from 'vue'

export default defineComponent({
name: 'MvRequiredMarker'
})
</script>
12 changes: 9 additions & 3 deletions src/components/forms/MvTagField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
ref="autoCompleteRef"
:aria-describedby="error ? errorId : undefined"
:aria-label="label"
:aria-required="required || undefined"
class="w-full"
:invalid="!!error"
:model-value="modelValue"
Expand Down Expand Up @@ -36,7 +37,10 @@
</slot>
</template>
</AutoComplete>
<label :for="fieldId">{{ label }}</label>
<label :for="fieldId">
{{ label }}
<MvRequiredMarker v-if="required" />
</label>
</FloatLabel>
<p v-if="hint && !error" class="mt-1 text-xs text-text-muted">{{ hint }}</p>
<MvFieldError :id="errorId" :error="error" />
Expand All @@ -48,13 +52,14 @@ import {defineComponent, type PropType} from 'vue'
import AutoComplete from 'primevue/autocomplete'
import FloatLabel from 'primevue/floatlabel'
import MvFieldError from '@/components/forms/MvFieldError.vue'
import MvRequiredMarker from '@/components/forms/MvRequiredMarker.vue'
import {useFieldId} from '@/composables/scoped-id'
import {isEmptySentinel} from '@/lib/form-helpers'

export default defineComponent({
name: 'MvTagField',

components: {AutoComplete, FloatLabel, MvFieldError},
components: {AutoComplete, FloatLabel, MvFieldError, MvRequiredMarker},

inheritAttrs: false,

Expand All @@ -70,7 +75,8 @@ export default defineComponent({
},
suggestions: {type: Array as PropType<unknown[]>, default: () => []},
typeahead: {type: Boolean, default: false},
hint: {type: String, default: null}
hint: {type: String, default: null},
required: {type: Boolean, default: false}
},

emits: ['update:modelValue', 'blur', 'complete', 'escape', 'option-select'],
Expand Down
14 changes: 9 additions & 5 deletions src/components/forms/MvUploadField.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
<template>
<div :class="error ? 'mv-field-error' : 'field'">
<label v-if="showLabel" class="mb-1 block font-semibold text-xs text-text-secondary" :for="fieldId">{{
label
}}</label>
<label v-if="showLabel" class="mb-1 block font-semibold text-xs text-text-secondary" :for="fieldId">
{{ label }}
<MvRequiredMarker v-if="required" />
</label>
<FileUpload
:id="fieldId"
ref="fileUploadRef"
:accept="accept"
:aria-describedby="error ? errorId : undefined"
:aria-label="label"
:aria-required="required || undefined"
:auto="false"
:custom-upload="true"
:file-limit="1"
Expand Down Expand Up @@ -37,12 +39,13 @@
import {defineComponent, type PropType} from 'vue'
import FileUpload from 'primevue/fileupload'
import MvFieldError from '@/components/forms/MvFieldError.vue'
import MvRequiredMarker from '@/components/forms/MvRequiredMarker.vue'
import {useFieldId} from '@/composables/scoped-id'

export default defineComponent({
name: 'MvUploadField',

components: {FileUpload, MvFieldError},
components: {FileUpload, MvFieldError, MvRequiredMarker},

inheritAttrs: false,

Expand All @@ -52,7 +55,8 @@ export default defineComponent({
error: {type: String as PropType<string | null>, default: null},
id: {type: String as PropType<string | null>, default: null},
emptyText: {type: String, default: 'Drop a file here'},
showLabel: {type: Boolean, default: true}
showLabel: {type: Boolean, default: true},
required: {type: Boolean, default: false}
},

emits: ['select', 'remove'],
Expand Down
Loading
Loading