funkwhale/front/src/views/channels/DetailOverview.vue

260 lines
7.4 KiB
Vue

<template>
<section>
<div
v-if="pendingUploads.length > 0"
class="ui info message"
>
<template v-if="isSuccessfull">
<i
role="button"
class="close icon"
@click="pendingUploads = []"
/>
<h3 class="ui header">
<translate translate-context="Content/Channel/Header">
Uploads published successfully
</translate>
</h3>
<p>
<translate translate-context="Content/Channel/Paragraph">
Processed uploads:
</translate> {{ processedUploads.length }}/{{ pendingUploads.length }}
</p>
</template>
<template v-else-if="isOver">
<h3 class="ui header">
<translate translate-context="Content/Channel/Header">
Some uploads couldn't be published
</translate>
</h3>
<div class="ui hidden divider" />
<router-link
v-if="skippedUploads.length > 0"
class="ui basic button"
:to="{name: 'content.libraries.files', query: {q: 'status:skipped'}}"
>
<translate translate-context="Content/Channel/Button">
View skipped uploads
</translate>
</router-link>
<router-link
v-if="erroredUploads.length > 0"
class="ui basic button"
:to="{name: 'content.libraries.files', query: {q: 'status:errored'}}"
>
<translate translate-context="Content/Channel/Button">
View errored uploads
</translate>
</router-link>
</template>
<template v-else>
<div class="ui inline right floated active loader" />
<h3 class="ui header">
<translate translate-context="Content/Channel/Header">
Uploads are being processed
</translate>
</h3>
<p>
<translate translate-context="Content/Channel/Paragraph">
Your uploads are being processed by Funkwhale and will be live very soon.
</translate>
</p>
<p>
<translate translate-context="Content/Channel/Paragraph">
Processed uploads:
</translate> {{ processedUploads.length }}/{{ pendingUploads.length }}
</p>
</template>
</div>
<div v-if="$store.getters['ui/layoutVersion'] === 'small'">
<rendered-description
:content="object.artist.description"
:update-url="`channels/${object.uuid}/`"
:can-update="false"
/>
<div class="ui hidden divider" />
</div>
<channel-entries
:key="String(episodesKey) + 'entries'"
:is-podcast="isPodcast"
:default-cover="object.artist.cover"
:limit="25"
:filters="{channel: object.uuid, ordering: '-creation_date', page_size: '25'}"
>
<h2 class="ui header">
<translate
v-if="isPodcast"
key="1"
translate-context="Content/Channel/Paragraph"
>
Latest episodes
</translate>
<translate
v-else
key="2"
translate-context="Content/Channel/Paragraph"
>
Latest tracks
</translate>
</h2>
</channel-entries>
<div class="ui hidden divider" />
<channel-series
:key="String(seriesKey) + 'series'"
:filters="seriesFilters"
:is-podcast="isPodcast"
>
<h2 class="ui with-actions header">
<translate
v-if="isPodcast"
key="1"
translate-context="Content/Channel/Paragraph"
>
Series
</translate>
<translate
v-else
key="2"
translate-context="*/*/*"
>
Albums
</translate>
<div
v-if="isOwner"
class="actions"
>
<a @click.stop.prevent="$refs.albumModal.show = true">
<i class="plus icon" />
<translate translate-context="Content/Profile/Button">Add new</translate>
</a>
</div>
</h2>
</channel-series>
<album-modal
v-if="isOwner"
ref="albumModal"
:channel="object"
@created="$refs.albumModal.show = false; seriesKey = new Date()"
/>
</section>
</template>
<script>
import axios from 'axios'
import qs from 'qs'
import ChannelEntries from '~/components/audio/ChannelEntries.vue'
import ChannelSeries from '~/components/audio/ChannelSeries.vue'
import AlbumModal from '~/components/channels/AlbumModal.vue'
export default {
components: {
ChannelEntries,
ChannelSeries,
AlbumModal
},
props: { object: { type: Object, required: true } },
data () {
return {
seriesKey: new Date(),
episodesKey: new Date(),
pendingUploads: []
}
},
computed: {
isPodcast () {
return this.object.artist.content_category === 'podcast'
},
isOwner () {
return this.$store.state.auth.authenticated && this.object.attributed_to.full_username === this.$store.state.auth.fullUsername
},
seriesFilters () {
const filters = { artist: this.object.artist.id, ordering: '-creation_date' }
if (!this.isOwner) {
filters.playable = 'true'
}
return filters
},
processedUploads () {
return this.pendingUploads.filter((u) => {
return u.import_status !== 'pending'
})
},
erroredUploads () {
return this.pendingUploads.filter((u) => {
return u.import_status === 'errored'
})
},
skippedUploads () {
return this.pendingUploads.filter((u) => {
return u.import_status === 'skipped'
})
},
finishedUploads () {
return this.pendingUploads.filter((u) => {
return u.import_status === 'finished'
})
},
pendingUploadsById () {
const d = {}
this.pendingUploads.forEach((u) => {
d[u.uuid] = u
})
return d
},
isOver () {
return this.pendingUploads && this.processedUploads.length === this.pendingUploads.length
},
isSuccessfull () {
return this.pendingUploads && this.finishedUploads.length === this.pendingUploads.length
}
},
watch: {
'$store.state.channels.latestPublication' (v) {
if (v && v.uploads && v.channel.uuid === this.object.uuid) {
this.pendingUploads = [...this.pendingUploads, ...v.uploads]
}
},
'isOver' (v) {
if (v) {
this.seriesKey = new Date()
this.episodesKey = new Date()
}
}
},
async created () {
if (this.isOwner) {
await this.fetchPendingUploads()
this.$store.commit('ui/addWebsocketEventHandler', {
eventName: 'import.status_updated',
id: 'fileUploadChannel',
handler: this.handleImportEvent
})
}
},
unmounted () {
this.$store.commit('ui/removeWebsocketEventHandler', {
eventName: 'import.status_updated',
id: 'fileUploadChannel'
})
},
methods: {
handleImportEvent (event) {
if (!this.pendingUploadsById[event.upload.uuid]) {
return
}
Object.assign(this.pendingUploadsById[event.upload.uuid], event.upload)
},
async fetchPendingUploads () {
const response = await axios.get('uploads/', {
params: { channel: this.object.uuid, import_status: ['pending', 'skipped', 'errored'], include_channels: 'true' },
paramsSerializer: function (params) {
return qs.stringify(params, { indices: false })
}
})
this.pendingUploads = response.data.results
}
}
}
</script>