Skip to content
Snippets Groups Projects
Commit a4c2d6f2 authored by Erwan Rouchet's avatar Erwan Rouchet Committed by Bastien Abadie
Browse files

Transcription creation in the details panel

parent 5bbc1b6a
No related branches found
No related tags found
1 merge request!1176Transcription creation in the details panel
import assert from 'assert'
import Vuex from 'vuex'
import AsyncComputed from 'vue-async-computed'
import { createLocalVue, mount } from '@vue/test-utils'
import store from '~/test/store'
import { makeTranscriptionResult, workerVersionsSample } from '~/test/samples'
import TranscriptionsForm from '~/vue/Element/Transcription/Form'
const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(AsyncComputed)
describe('Element', () => {
describe('TranscriptionsForm.vue', () => {
afterEach(() => {
store.reset()
})
it('displays existing manual transcriptions', () => {
const transcription1 = makeTranscriptionResult('Tympole')
const transcription2 = makeTranscriptionResult('Magnemite')
transcription2.worker_version_id = 'versionid'
store.state.corpora.corpora.corpusid = {
id: 'corpusid',
types: {
element: {
display_name: 'Element',
folder: false
}
}
}
store.state.elements.transcriptions.elementid = {
transcription1,
transcription2
}
store.state.process.workerVersions.versionid = workerVersionsSample.results[0]
const wrapper = mount(TranscriptionsForm, {
store,
localVue,
propsData: {
modal: true,
element: {
id: 'elementid',
corpus: { id: 'corpusid' },
type: 'element',
name: 'Element'
}
}
})
assert.deepStrictEqual(
wrapper.findAll('div.has-plain-text').wrappers.map(w => w.text()),
['Tympole', 'Magnemite']
)
})
})
})
import assert from 'assert'
import Vuex from 'vuex'
import AsyncComputed from 'vue-async-computed'
import { createLocalVue, mount } from '@vue/test-utils'
import store from '~/test/store'
import { makeTranscriptionResult, workerVersionsSample } from '~/test/samples'
import TranscriptionsModal from '~/vue/Element/Transcription/Modal'
const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(AsyncComputed)
describe('Element/Transcription/Modal.vue', () => {
afterEach(() => {
store.reset()
})
it('displays existing manual transcriptions', () => {
const transcription1 = makeTranscriptionResult('Tympole')
const transcription2 = makeTranscriptionResult('Magnemite')
transcription2.worker_version_id = 'versionid'
store.state.corpora.corpora.corpusid = {
id: 'corpusid',
types: {
element: {
display_name: 'Element',
folder: false
}
}
}
store.state.elements.transcriptions.elementid = {
transcription1,
transcription2
}
store.state.process.workerVersions.versionid = workerVersionsSample.results[0]
const wrapper = mount(TranscriptionsModal, {
store,
localVue,
propsData: {
modal: true,
element: {
id: 'elementid',
corpus: { id: 'corpusid' },
type: 'element',
name: 'Element'
}
}
})
assert.deepStrictEqual(
wrapper.findAll('div.has-plain-text').wrappers.map(w => w.text()),
['Tympole', 'Magnemite']
)
})
})
......@@ -58,7 +58,7 @@
</button>
</a>
</div>
<TranscriptionsForm
<TranscriptionsModal
v-if="transcriptionModal"
:modal.sync="transcriptionModal"
:element="element"
......@@ -66,6 +66,10 @@
</template>
</DropdownContent>
<hr />
<DropdownContent title="New transcription" v-if="canWriteElement(elementId)">
<TranscriptionCreationForm :element="element" />
</DropdownContent>
<hr />
</template>
<template v-if="metadata.length || canWriteElement(elementId)">
......@@ -95,7 +99,8 @@ import Classifications from './Classifications'
import MLClassSelect from '~/vue/MLClassSelect'
import ElementMetadata from './Metadata'
import DropdownContent from '~/vue/DropdownContent'
import TranscriptionsForm from './Transcription/Form'
import TranscriptionsModal from './Transcription/Modal'
import TranscriptionCreationForm from './Transcription/CreationForm'
import OrientationPanel from './OrientationPanel'
export default {
......@@ -109,7 +114,8 @@ export default {
MLClassSelect,
ElementMetadata,
DropdownContent,
TranscriptionsForm,
TranscriptionsModal,
TranscriptionCreationForm,
OrientationPanel
},
props: {
......
<template>
<form v-on:submit.prevent="create">
<div class="field">
<div class="control">
<textarea
ref="textInput"
v-model="text"
v-on:keyup.enter.ctrl="create"
class="textarea"
:style="orientationStyle(orientation)"
placeholder="Text…"
></textarea>
<template v-if="fieldErrors.text">
<p class="help is-danger" v-for="err in fieldErrors.text" :key="err">{{ err }}</p>
</template>
</div>
</div>
<div class="field is-grouped is-justify-content-space-between">
<div class="control">
<div class="select is-small">
<select
v-model="orientation"
:disabled="loading"
required
>
<option
v-for="(textOrientation, key) in TEXT_ORIENTATIONS"
:key="key"
:value="key"
:title="textOrientation.display"
>
{{ textOrientation.display }}
</option>
</select>
<template v-if="fieldErrors.orientation">
<p
class="help is-danger"
v-for="err in fieldErrors.orientation"
:key="err"
>
{{ err }}
</p>
</template>
</div>
</div>
<div class="control">
<button
type="submit"
class="button is-primary"
:class="{ 'is-loading': loading }"
:disabled="loading || !isValid"
:title="isValid ? 'Create a new transcription' : createDisabledTitle"
>
<span class="icon-plus"></span>
</button>
</div>
</div>
</form>
</template>
<script>
import { mapMutations, mapActions } from 'vuex'
import { TEXT_ORIENTATIONS } from '~/js/config'
import { errorParser, orientationStyle } from '~/js/helpers'
export default {
props: {
element: {
type: Object,
required: true
}
},
data: () => ({
text: '',
orientation: 'horizontal-lr',
fieldErrors: {},
loading: false,
TEXT_ORIENTATIONS
}),
mounted () {
this.$nextTick(() => {
this.$refs.textInput.focus()
})
},
computed: {
isValid () {
return this.text.trim().length > 0 && this.orientation in TEXT_ORIENTATIONS
},
createDisabledTitle () {
const text = this.text.trim()
if (!text && !this.orientation) return 'Please fill out the creation form'
else if (!text) return 'A valid text is required to create the transcription'
else if (!this.orientation || !(this.orientation in TEXT_ORIENTATIONS)) return 'A valid text orientation is required'
return null
}
},
methods: {
...mapActions('elements', ['listTranscriptions']),
...mapMutations('notifications', ['notify']),
orientationStyle,
setErrors (error) {
// Set field errors from API return value
if (!error) this.fieldErrors = {}
else if (!error.response || typeof error.response.data !== 'object') this.fieldErrors = { error: errorParser(error) }
else this.fieldErrors = error.response.data
},
async create () {
if (!this.isValid) return
try {
this.loading = true
await this.$store.dispatch('elements/createTranscription', {
id: this.element.id,
text: this.text,
orientation: this.orientation
})
this.notify({ type: 'success', text: 'Transcription created.' })
// Reset form to default to allow typing a new transcription
this.text = ''
this.orientation = 'horizontal-lr'
} catch (e) {
this.setErrors(e)
this.notify({ type: 'error', text: `An error occurred during transcription creation: ${errorParser(e)}` })
} finally {
this.loading = false
}
}
}
}
</script>
......@@ -58,7 +58,7 @@
:modal.sync="editionModal"
:element="selectedElement"
/>
<TranscriptionsForm
<TranscriptionsModal
v-if="transcriptionModal && selectedElement"
:modal.sync="transcriptionModal"
:element="selectedElement"
......@@ -68,7 +68,7 @@
<script>
import EditionForm from 'vue/Element/EditionForm'
import TranscriptionsForm from 'vue/Element/Transcription/Form'
import TranscriptionsModal from 'vue/Element/Transcription/Modal'
import { mapState, mapMutations, mapGetters, mapActions } from 'vuex'
import { orderBy } from 'lodash'
import { corporaMixin, truncateMixin } from '~/js/mixins'
......@@ -78,7 +78,7 @@ export default {
components: {
TreeItem,
EditionForm,
TranscriptionsForm
TranscriptionsModal
},
mixins: [
corporaMixin,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment