refactor(front): [WIP] modernize upload form (for Channels)
This commit is contained in:
parent
60463d405e
commit
b78d1f8992
|
@ -3,15 +3,13 @@ import type { BackendError, Channel, Upload, Track } from '~/types'
|
|||
import type { VueUploadItem } from 'vue-upload-component'
|
||||
|
||||
import { computed, ref, reactive, watchEffect, watch } from 'vue'
|
||||
import { whenever, useCurrentElement } from '@vueuse/core'
|
||||
import { whenever } from '@vueuse/core'
|
||||
import { humanSize } from '~/utils/filters'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useStore } from '~/store'
|
||||
|
||||
import axios from 'axios'
|
||||
|
||||
import $ from 'jquery'
|
||||
|
||||
import UploadMetadataForm from '~/components/channels/UploadMetadataForm.vue'
|
||||
import FileUploadWidget from '~/components/library/FileUploadWidget.vue'
|
||||
import LicenseSelect from '~/components/channels/LicenseSelect.vue'
|
||||
|
@ -21,7 +19,6 @@ import useErrorHandler from '~/composables/useErrorHandler'
|
|||
|
||||
interface Events {
|
||||
(e: 'status', status: UploadStatus): void
|
||||
(e: 'step', step: 1 | 2 | 3): void
|
||||
}
|
||||
|
||||
interface Props {
|
||||
|
@ -238,7 +235,7 @@ const fetchAudioMetadata = async (uuid: string) => {
|
|||
|
||||
for (const key of ['title', 'position', 'tags'] as const) {
|
||||
if (uploadImportData[uuid][key] === undefined) {
|
||||
uploadImportData[uuid][key] = response.data[key] as never
|
||||
// uploadImportData[uuid][key] = response.data[key] as never
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,27 +299,7 @@ const retry = async (file: VueUploadItem) => {
|
|||
fetchChannels()
|
||||
fetchQuota()
|
||||
|
||||
//
|
||||
// Step
|
||||
//
|
||||
const step = ref<1 | 2 | 3>(1)
|
||||
watchEffect(() => {
|
||||
emit('step', step.value)
|
||||
|
||||
if (step.value === 2) {
|
||||
selectedUploadId.value = null
|
||||
}
|
||||
})
|
||||
|
||||
watch(selectedUploadId, async (to, from) => {
|
||||
if (to) {
|
||||
step.value = 3
|
||||
}
|
||||
|
||||
if (!to && step.value !== 2) {
|
||||
step.value = 2
|
||||
}
|
||||
|
||||
watch(selectedUploadId, async (_, from) => {
|
||||
if (from) {
|
||||
await patchUpload(from, { import_metadata: uploadImportData[from] })
|
||||
}
|
||||
|
@ -360,29 +337,42 @@ const labels = computed(() => ({
|
|||
|
||||
const isLoading = ref(false)
|
||||
const publish = async () => {
|
||||
console.log("starting publish...")
|
||||
isLoading.value = true
|
||||
|
||||
errors.value = []
|
||||
|
||||
try {
|
||||
await axios.post('uploads/action/', {
|
||||
// Post list of uuids of uploadedFiles to axios action:publish
|
||||
await axios.put('uploads/action/', {
|
||||
action: 'publish',
|
||||
objects: uploadedFiles.value.map((file) => file.response?.uuid)
|
||||
})
|
||||
|
||||
console.log("starting posting to axios action:publish...")
|
||||
|
||||
console.log("Channels Store Before: ", store.state.channels)
|
||||
|
||||
// Tell the store that the uploaded files are pending import
|
||||
store.commit('channels/publish', {
|
||||
uploads: uploadedFiles.value.map((file) => ({ ...file.response, import_status: 'pending' })),
|
||||
channel: selectedChannel.value
|
||||
})
|
||||
|
||||
console.log("Channels Store After: ", store.state.channels)
|
||||
|
||||
} catch (error) {
|
||||
// TODO: Use inferred error type instead of typecasting
|
||||
errors.value = (error as BackendError).backendErrors
|
||||
console.log("Error:", error)
|
||||
}
|
||||
|
||||
isLoading.value = false
|
||||
|
||||
console.log("...finished publish")
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
step,
|
||||
publish
|
||||
})
|
||||
</script>
|
||||
|
@ -392,6 +382,8 @@ defineExpose({
|
|||
:class="['ui', { loading: availableChannels.loading }, 'form component-file-upload']"
|
||||
@submit.stop.prevent
|
||||
>
|
||||
<!-- Error message -->
|
||||
|
||||
<div
|
||||
v-if="errors.length > 0"
|
||||
role="alert"
|
||||
|
@ -409,7 +401,10 @@ defineExpose({
|
|||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div :class="['ui', 'required', {hidden: step > 1}, 'field']">
|
||||
|
||||
<!-- Select Album and License -->
|
||||
|
||||
<div :class="['ui', 'required', 'field']">
|
||||
<label for="channel-dropdown">
|
||||
{{ t('components.channels.UploadForm.label.channel') }}: {{ selectedChannel?.artist.name }}
|
||||
</label>
|
||||
|
@ -417,13 +412,13 @@ defineExpose({
|
|||
<album-select
|
||||
v-model.number="values.album"
|
||||
:channel="selectedChannel"
|
||||
:class="['ui', {hidden: step > 1}, 'field']"
|
||||
:class="['ui', 'field']"
|
||||
/>
|
||||
<license-select
|
||||
v-model="values.license"
|
||||
:class="['ui', {hidden: step > 1}, 'field']"
|
||||
:class="['ui', 'field']"
|
||||
/>
|
||||
<div :class="['ui', {hidden: step > 1}, 'message']">
|
||||
<div :class="['ui', 'message']">
|
||||
<div class="content">
|
||||
<p>
|
||||
<i class="copyright icon" />
|
||||
|
@ -431,152 +426,151 @@ defineExpose({
|
|||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="step === 2 || step === 3">
|
||||
|
||||
<!-- Files to upload -->
|
||||
|
||||
<div
|
||||
v-if="remainingSpace === 0"
|
||||
role="alert"
|
||||
class="ui warning message"
|
||||
>
|
||||
<div class="content">
|
||||
<p>
|
||||
<i class="warning icon" />
|
||||
{{ t('components.channels.UploadForm.warning.quota') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div
|
||||
v-if="remainingSpace === 0"
|
||||
role="alert"
|
||||
class="ui warning message"
|
||||
v-if="draftUploads?.length > 0 && includeDraftUploads === undefined"
|
||||
class="ui visible info message"
|
||||
>
|
||||
<p>
|
||||
<i class="redo icon" />
|
||||
{{ t('components.channels.UploadForm.message.pending') }}
|
||||
</p>
|
||||
<button
|
||||
class="ui basic button"
|
||||
@click.stop.prevent="includeDraftUploads = false"
|
||||
>
|
||||
{{ t('components.channels.UploadForm.button.ignore') }}
|
||||
</button>
|
||||
<button
|
||||
class="ui basic button"
|
||||
@click.stop.prevent="includeDraftUploads = true"
|
||||
>
|
||||
{{ t('components.channels.UploadForm.button.resume') }}
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
v-if="uploadedFiles.length > 0"
|
||||
>
|
||||
<div
|
||||
v-for="file in uploadedFiles"
|
||||
:key="file.id"
|
||||
class="channel-file"
|
||||
>
|
||||
<div class="content">
|
||||
<div
|
||||
v-if="file.response?.uuid"
|
||||
role="button"
|
||||
class="ui basic icon button"
|
||||
:title="labels.editTitle"
|
||||
@click.stop.prevent="selectedUploadId = file.response?.uuid"
|
||||
>
|
||||
<i class="pencil icon" />
|
||||
</div>
|
||||
<div
|
||||
v-if="file.error"
|
||||
class="ui basic danger icon label"
|
||||
:title="file.error.toString()"
|
||||
@click.stop.prevent="selectedUploadId = file.response?.uuid"
|
||||
>
|
||||
<i class="warning sign icon" />
|
||||
</div>
|
||||
<div
|
||||
v-else-if="file.active && !file.response"
|
||||
class="ui active slow inline loader"
|
||||
/>
|
||||
</div>
|
||||
<h4 class="ui header">
|
||||
<template v-if="file.metadata.title">
|
||||
{{ file.metadata.title }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ file.name }}
|
||||
</template>
|
||||
<div class="sub header">
|
||||
<template v-if="file.response?.uuid">
|
||||
{{ humanSize(file.size ?? 0) }}
|
||||
<template v-if="file.response.duration">
|
||||
<span class="middle middledot symbol" />
|
||||
<human-duration :duration="file.response.duration" />
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span v-if="file.active">
|
||||
{{ t('components.channels.UploadForm.status.uploading') }}
|
||||
</span>
|
||||
<span v-else-if="file.error">
|
||||
{{ t('components.channels.UploadForm.status.errored') }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ t('components.channels.UploadForm.status.pending') }}
|
||||
</span>
|
||||
<span class="middle middledot symbol" />
|
||||
{{ humanSize(file.size ?? 0) }}
|
||||
<span class="middle middledot symbol" />
|
||||
{{ parseFloat(file.progress ?? '0') }}
|
||||
<span class="percent symbol" />
|
||||
</template>
|
||||
<span class="middle middledot symbol" />
|
||||
<a @click.stop.prevent="remove(file)">
|
||||
{{ t('components.channels.UploadForm.button.remove') }}
|
||||
</a>
|
||||
<template v-if="file.error">
|
||||
<span class="middle middledot symbol" />
|
||||
<a @click.stop.prevent="retry(file)">
|
||||
{{ t('components.channels.UploadForm.button.retry') }}
|
||||
</a>
|
||||
</template>
|
||||
</div>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
<upload-metadata-form
|
||||
v-if="selectedUpload"
|
||||
v-model:values="uploadImportData[selectedUploadId]"
|
||||
:upload="selectedUpload"
|
||||
/>
|
||||
<div
|
||||
class="ui message"
|
||||
>
|
||||
<div class="content">
|
||||
<p>
|
||||
<i class="warning icon" />
|
||||
{{ t('components.channels.UploadForm.warning.quota') }}
|
||||
<i class="info icon" />
|
||||
{{ t('components.channels.UploadForm.description.extensions', {extensions: store.state.ui.supportedExtensions.join(', ')}) }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div
|
||||
v-if="step === 2 && draftUploads?.length > 0 && includeDraftUploads === undefined"
|
||||
class="ui visible info message"
|
||||
>
|
||||
<p>
|
||||
<i class="redo icon" />
|
||||
{{ t('components.channels.UploadForm.message.pending') }}
|
||||
</p>
|
||||
<button
|
||||
class="ui basic button"
|
||||
@click.stop.prevent="includeDraftUploads = false"
|
||||
>
|
||||
{{ t('components.channels.UploadForm.button.ignore') }}
|
||||
</button>
|
||||
<button
|
||||
class="ui basic button"
|
||||
@click.stop.prevent="includeDraftUploads = true"
|
||||
>
|
||||
{{ t('components.channels.UploadForm.button.resume') }}
|
||||
</button>
|
||||
<file-upload-widget
|
||||
ref="upload"
|
||||
v-model="files"
|
||||
:class="['ui', 'icon', 'basic', 'button', 'channels']"
|
||||
:data="baseImportMetadata"
|
||||
@input-file="beforeFileUpload"
|
||||
>
|
||||
<div>
|
||||
<i class="upload icon" />
|
||||
{{ t('components.channels.UploadForm.message.dragAndDrop') }}
|
||||
</div>
|
||||
<div
|
||||
v-if="uploadedFiles.length > 0"
|
||||
:class="[{hidden: step === 3}]"
|
||||
>
|
||||
<div
|
||||
v-for="file in uploadedFiles"
|
||||
:key="file.id"
|
||||
class="channel-file"
|
||||
>
|
||||
<div class="content">
|
||||
<div
|
||||
v-if="file.response?.uuid"
|
||||
role="button"
|
||||
class="ui basic icon button"
|
||||
:title="labels.editTitle"
|
||||
@click.stop.prevent="selectedUploadId = file.response?.uuid"
|
||||
>
|
||||
<i class="pencil icon" />
|
||||
</div>
|
||||
<div
|
||||
v-if="file.error"
|
||||
class="ui basic danger icon label"
|
||||
:title="file.error.toString()"
|
||||
@click.stop.prevent="selectedUploadId = file.response?.uuid"
|
||||
>
|
||||
<i class="warning sign icon" />
|
||||
</div>
|
||||
<div
|
||||
v-else-if="file.active && !file.response"
|
||||
class="ui active slow inline loader"
|
||||
/>
|
||||
</div>
|
||||
<h4 class="ui header">
|
||||
<template v-if="file.metadata.title">
|
||||
{{ file.metadata.title }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ file.name }}
|
||||
</template>
|
||||
<div class="sub header">
|
||||
<template v-if="file.response?.uuid">
|
||||
{{ humanSize(file.size ?? 0) }}
|
||||
<template v-if="file.response.duration">
|
||||
<span class="middle middledot symbol" />
|
||||
<human-duration :duration="file.response.duration" />
|
||||
</template>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span v-if="file.active">
|
||||
{{ t('components.channels.UploadForm.status.uploading') }}
|
||||
</span>
|
||||
<span v-else-if="file.error">
|
||||
{{ t('components.channels.UploadForm.status.errored') }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ t('components.channels.UploadForm.status.pending') }}
|
||||
</span>
|
||||
<span class="middle middledot symbol" />
|
||||
{{ humanSize(file.size ?? 0) }}
|
||||
<span class="middle middledot symbol" />
|
||||
{{ parseFloat(file.progress ?? '0') }}
|
||||
<span class="percent symbol" />
|
||||
</template>
|
||||
<span class="middle middledot symbol" />
|
||||
<a @click.stop.prevent="remove(file)">
|
||||
{{ t('components.channels.UploadForm.button.remove') }}
|
||||
</a>
|
||||
<template v-if="file.error">
|
||||
<span class="middle middledot symbol" />
|
||||
<a @click.stop.prevent="retry(file)">
|
||||
{{ t('components.channels.UploadForm.button.retry') }}
|
||||
</a>
|
||||
</template>
|
||||
</div>
|
||||
</h4>
|
||||
</div>
|
||||
<div class="ui very small divider" />
|
||||
<div>
|
||||
{{ t('components.channels.UploadForm.label.openBrowser') }}
|
||||
</div>
|
||||
<upload-metadata-form
|
||||
v-if="selectedUpload"
|
||||
v-model:values="uploadImportData[selectedUploadId]"
|
||||
:upload="selectedUpload"
|
||||
/>
|
||||
<div
|
||||
v-if="step === 2"
|
||||
class="ui message"
|
||||
>
|
||||
<div class="content">
|
||||
<p>
|
||||
<i class="info icon" />
|
||||
{{ t('components.channels.UploadForm.description.extensions', {extensions: store.state.ui.supportedExtensions.join(', ')}) }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<file-upload-widget
|
||||
ref="upload"
|
||||
v-model="files"
|
||||
:class="['ui', 'icon', 'basic', 'button', 'channels', {hidden: step === 3}]"
|
||||
:data="baseImportMetadata"
|
||||
@input-file="beforeFileUpload"
|
||||
>
|
||||
<div>
|
||||
<i class="upload icon" />
|
||||
{{ t('components.channels.UploadForm.message.dragAndDrop') }}
|
||||
</div>
|
||||
<div class="ui very small divider" />
|
||||
<div>
|
||||
{{ t('components.channels.UploadForm.label.openBrowser') }}
|
||||
</div>
|
||||
</file-upload-widget>
|
||||
<div class="ui hidden divider" />
|
||||
</template>
|
||||
</file-upload-widget>
|
||||
<div class="ui hidden divider" />
|
||||
</template>
|
||||
</form>
|
||||
</template>
|
||||
|
|
Loading…
Reference in New Issue