Something went wrong on our end
DetailsPanel.vue 8.48 KiB
<template>
<div>
<div v-if="!element || !corpusId" class="loading-content loader"></div>
<template v-else>
<template v-if="elementType.folder === false">
<OrientationPanel :element-id="elementId" />
<hr />
</template>
<template v-if="(canWriteElement(elementId) && hasMlClasses[corpusId]) || classifications.length">
<DropdownContent id="classifications" title="Classifications">
<Classifications v-if="element.classifications" :element="element" />
<form v-on:submit.prevent="createClassification">
<div v-if="canWriteElement(elementId) && hasMlClasses" class="field">
<p class="control is-expanded">
<MLClassSelect
ref="newClassificationSelect"
v-model="selectedNewClassification"
v-model:is-valid="validClassification"
placeholder="Add a classification"
exclude-manual
auto-select
:classifications="element.classifications"
:corpus-id="corpusId"
/>
</p>
</div>
<p class="help is-danger" v-if="manualClassificationExists">A manual classification for this ML class already exists.</p>
</form>
</DropdownContent>
<hr />
</template>
<template v-if="elementType.folder === false">
<DropdownContent id="transcriptions" title="Transcriptions">
<Transcriptions :element="element" />
<template v-if="canWriteElement(elementId)">
<div class="has-text-right">
<a v-on:click="transcriptionModal = true">
<button class="button has-text">
manage
</button>
</a>
</div>
<TranscriptionsModal
v-if="transcriptionModal"
v-model:modal="transcriptionModal"
:element="element"
/>
</template>
</DropdownContent>
<hr />
<template v-if="canWriteElement(elementId)">
<DropdownContent id="new-transcription" title="New transcription">
<TranscriptionCreationForm :element="element" />
</DropdownContent>
<hr />
</template>
</template>
<DropdownContent id="metadata" title="Metadata">
<ElementMetadata :corpus-id="corpusId" :element-id="element.id" />
</DropdownContent>
<hr />
<DropdownContent id="datasets" title="Datasets">
<div class="loader m-auto is-size-3" v-if="datasets === null">
</div>
<div class="message-body has-text-grey" v-else-if="datasets.length === 0">
No datasets
</div>
<table v-else class="table is-fullwidth is-hoverable">
<thead>
<th>Name</th>
<th>Set</th>
</thead>
<tbody>
<tr v-for="({ dataset, set }) in datasets" :key="dataset.id + set">
<td>
<router-link
:to="{ name: 'dataset-details', params: { datasetId: dataset.id } }"
title="Dataset details"
>
{{ dataset.name }}
</router-link>
</td>
<td>{{ set }}</td>
</tr>
</tbody>
</table>
</DropdownContent>
<EntityLinks
:element-id="element.id"
v-if="elementType.folder === false"
/>
</template>
</div>
</template>
<script lang="ts">
import {
mapState as mapVuexState,
mapGetters as mapVuexGetters,
mapActions as mapVuexActions
} from 'vuex'
import { corporaMixin } from '@/mixins'
import { defineComponent, PropType } from 'vue'
import { UUID_REGEX } from '@/config'
import { UUID, Element } from '@/types'
import { ElementDataset } from '@/types/dataset'
import { mapState, mapActions } from 'pinia'
import { useElementsStore } from '@/stores'
import DropdownContent from '@/components/DropdownContent.vue'
import MLClassSelect from '@/components/MLClassSelect.vue'
import EntityLinks from '@/components/Entity/Links.vue'
import Classifications from '@/components/Element/Classifications'
import ElementMetadata from '@/components/Element/Metadata'
import OrientationPanel from '@/components/Element/OrientationPanel.vue'
import Transcriptions from '@/components/Element/Transcription'
import TranscriptionsModal from '@/components/Element/Transcription/Modal.vue'
import TranscriptionCreationForm from '@/components/Element/Transcription/CreationForm.vue'
export default defineComponent({
mixins: [
corporaMixin
],
components: {
Classifications,
DropdownContent,
ElementMetadata,
EntityLinks,
MLClassSelect,
OrientationPanel,
TranscriptionCreationForm,
Transcriptions,
TranscriptionsModal
},
props: {
/**
* Id of the element
*/
elementId: {
type: String as PropType<UUID>,
validator: value => typeof value === 'string' && UUID_REGEX.test(value),
required: true
}
},
data: () => ({
selectedNewClassification: '',
validClassification: null,
isSavingNewClassification: false,
transcriptionModal: false
}),
computed: {
...mapVuexState('elements', ['elements', 'transcriptions']),
...mapVuexState('process', ['workerVersions', 'workers']),
...mapVuexState('classification', ['hasMlClasses']),
...mapState(useElementsStore, ['elementDatasets']),
...mapVuexGetters('elements', {
// canWrite and canAdmin are already defined in corporaMixin
canWriteElement: 'canWrite',
canAdminElement: 'canAdmin'
}),
element (): Element | null {
return this.elements?.[this.elementId] ?? null
},
corpusId (): UUID | null {
return this.element?.corpus?.id ?? null
},
elementType () {
return this.element ? this.getType(this.element.type) : {}
},
manualClassificationExists () {
// A manual classification with the selected ML class exists; cannot create
return this.selectedNewClassification &&
this.element &&
this.element.classifications &&
this.element.classifications.find(c => (c.ml_class.id === this.selectedNewClassification && !c.worker_version && !c.worker_run))
},
canCreateClassification () {
return this.element && this.selectedNewClassification && !this.manualClassificationExists && !this.isSavingNewClassification
},
classifications () {
return (this.element && this.element.classifications) || []
},
metadata () {
// @ts-expect-error Some Element attributes like metadata are set on the fly on the former store
return (this.element && this.element?.metadata) || []
},
datasets (): ElementDataset[] | null {
return this.elementDatasets?.[this.elementId] ?? null
}
},
methods: {
...mapVuexActions('classification', { classificationCreate: 'create' }),
...mapVuexActions('elements', { retrieveElement: 'get' }),
...mapActions(useElementsStore, ['listElementDatasets']),
async createClassification () {
if (!this.canCreateClassification) return
this.isSavingNewClassification = true
try {
await this.classificationCreate({
elementId: this.elementId,
mlClass: this.selectedNewClassification
})
} finally {
this.selectedNewClassification = ''
this.isSavingNewClassification = false
}
}
},
watch: {
elementId: {
immediate: true,
handler (id: UUID) {
if (!id) return
/*
* Do not retrieve the element again if it already exists in the store,
* unless it lacks some of the attributes only available from RetrieveElement.
* Some elements in the store can come from list endpoints such as those of the children tree.
* This ensures there are no strange behaviors where some actions are only sometimes disabled when they shouldn't,
* or some element attributes are not displayed at all.
*/
if (!this.element || this.element.id !== id || !this.element.rights || !this.element.classifications) this.retrieveElement({ id })
if (!Array.isArray(this.elementDatasets[id])) this.listElementDatasets(id)
}
},
selectedNewClassification () {
this.createClassification()
}
}
})
</script>
<style scoped>
.loading-content {
font-size: 2.5rem;
margin: 2.5rem auto 0 auto;
}
.button.has-tooltip-multiline {
width: 1rem;
height: 1.5rem;
margin-right: 1ch;
}
.has-margin-left {
margin-left: auto;
}
</style>