feat(front): [WIP] new upload process channel form #2081
This commit is contained in:
parent
a8d5011796
commit
50dd404dab
|
@ -15,14 +15,11 @@ interface Events {
|
||||||
(e: 'created'): void
|
(e: 'created'): void
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
const channel = defineModel<Channel>({required: true})
|
||||||
channel: Channel
|
|
||||||
}
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const emit = defineEmits<Events>()
|
const emit = defineEmits<Events>()
|
||||||
const props = defineProps<Props>()
|
|
||||||
|
|
||||||
const title = ref('')
|
const title = ref('')
|
||||||
|
|
||||||
|
@ -35,7 +32,7 @@ const submit = async () => {
|
||||||
try {
|
try {
|
||||||
await axios.post('albums/', {
|
await axios.post('albums/', {
|
||||||
title: title.value,
|
title: title.value,
|
||||||
artist: props.channel.artist?.id
|
artist: channel.value.artist?.id
|
||||||
})
|
})
|
||||||
|
|
||||||
emit('created')
|
emit('created')
|
||||||
|
@ -77,12 +74,10 @@ defineExpose({
|
||||||
</ul>
|
</ul>
|
||||||
</Alert>
|
</Alert>
|
||||||
<div class="ui required field">
|
<div class="ui required field">
|
||||||
<label for="album-title">
|
|
||||||
{{ t('components.channels.AlbumForm.label.albumTitle') }}
|
|
||||||
</label>
|
|
||||||
<Input
|
<Input
|
||||||
v-model="title"
|
v-model="title"
|
||||||
type="text"
|
type="text"
|
||||||
|
:label="t('components.channels.AlbumForm.label.albumTitle')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
|
@ -1,63 +1,105 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Channel } from '~/types'
|
import type { Channel, BackendError } from '~/types'
|
||||||
import Modal from '~/components/ui/Modal.vue'
|
|
||||||
import ChannelAlbumForm from '~/components/channels/AlbumForm.vue'
|
|
||||||
|
|
||||||
import { watch, ref } from 'vue'
|
import axios from 'axios'
|
||||||
|
|
||||||
|
import { watch, ref, emit } from 'vue'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useModal } from '~/ui/composables/useModal.ts'
|
||||||
|
|
||||||
|
import Layout from '~/components/ui/Layout.vue'
|
||||||
|
import Modal from '~/components/ui/Modal.vue'
|
||||||
import Button from '~/components/ui/Button.vue'
|
import Button from '~/components/ui/Button.vue'
|
||||||
import Spacer from '~/components/ui/Spacer.vue'
|
import Input from '~/components/ui/Input.vue'
|
||||||
|
|
||||||
interface Events {
|
|
||||||
(e: 'created'): void
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
channel: Channel
|
|
||||||
}
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const emit = defineEmits<Events>()
|
const channel = defineModel<Channel>({required: true})
|
||||||
defineProps<Props>()
|
defineEmits(['created'])
|
||||||
|
const newAlbumTitle = ref<string>('')
|
||||||
|
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
const submittable = ref(false)
|
const submittable = ref(false)
|
||||||
const show = ref(false)
|
const errors = ref<string[]>([])
|
||||||
|
|
||||||
|
const {isOpen:show} = useModal('album')
|
||||||
|
|
||||||
|
defineEmits(['created'])
|
||||||
|
|
||||||
watch(show, () => {
|
watch(show, () => {
|
||||||
isLoading.value = false
|
isLoading.value = false
|
||||||
submittable.value = false
|
submittable.value = false
|
||||||
})
|
})
|
||||||
|
|
||||||
const albumForm = ref()
|
// Create a new Album and tell the parent to re-fetch all albums
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
show
|
show
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const submit = async () => {
|
||||||
|
isLoading.value = true
|
||||||
|
errors.value = []
|
||||||
|
|
||||||
|
try {
|
||||||
|
await axios.post('albums/', {
|
||||||
|
title: newAlbumTitle.value,
|
||||||
|
artist_credit: [channel.value.artist?.id]
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
errors.value = (error as BackendError).backendErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
emit('created')
|
||||||
|
|
||||||
|
isLoading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal :title="t(channel.artist.content_category === 'podcast' ? 'components.channels.AlbumModal.header.newSeries' : 'components.channels.AlbumModal.header.newAlbum')"
|
<Modal :title="t(channel?.artist?.content_category === 'podcast' ? 'components.channels.AlbumModal.header.newSeries' : 'components.channels.AlbumModal.header.newAlbum')"
|
||||||
v-model="show"
|
v-model="show"
|
||||||
class="small"
|
class="small"
|
||||||
:cancel="t('components.channels.AlbumModal.button.cancel')"
|
:cancel="t('components.channels.AlbumModal.button.cancel')"
|
||||||
>
|
>
|
||||||
<div class="scrolling content">
|
<template #alert>
|
||||||
<channel-album-form
|
<Alert
|
||||||
ref="albumForm"
|
v-if="errors.length > 0"
|
||||||
:channel="channel"
|
red
|
||||||
@loading="isLoading = $event"
|
>
|
||||||
@submittable="submittable = $event"
|
<h4 class="header">
|
||||||
@created="emit('created')"
|
{{ t('components.channels.AlbumForm.header.error') }}
|
||||||
|
</h4>
|
||||||
|
<ul class="list">
|
||||||
|
<li
|
||||||
|
v-for="(error, key) in errors"
|
||||||
|
:key="key"
|
||||||
|
>
|
||||||
|
{{ error }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</Alert>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<Layout form
|
||||||
|
:class="['ui', {loading: isLoading}, 'form']"
|
||||||
|
@submit.stop.prevent
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
v-model="newAlbumTitle"
|
||||||
|
required
|
||||||
|
type="text"
|
||||||
|
:label="t('components.channels.AlbumForm.label.albumTitle')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</Layout>
|
||||||
|
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<Button
|
<Button
|
||||||
:is-loading="isLoading"
|
:is-loading="isLoading"
|
||||||
:disabled="!submittable"
|
:disabled="!submittable"
|
||||||
primary
|
primary
|
||||||
@click.stop.prevent="albumForm.submit()"
|
@click.stop.prevent="submit()"
|
||||||
>
|
>
|
||||||
{{ t('components.channels.AlbumModal.button.create') }}
|
{{ t('components.channels.AlbumModal.button.create') }}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
@ -2,56 +2,46 @@
|
||||||
import type { Album, Channel } from '~/types'
|
import type { Album, Channel } from '~/types'
|
||||||
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { useVModel } from '@vueuse/core'
|
import { ref, watch } from 'vue'
|
||||||
import { reactive, ref, watch } from 'vue'
|
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useModal } from '~/ui/composables/useModal.ts'
|
||||||
|
|
||||||
interface Events {
|
import Layout from '~/components/ui/Layout.vue'
|
||||||
(e: 'update:modelValue', value: string): void
|
import Link from '~/components/ui/Link.vue'
|
||||||
}
|
import Spacer from '~/components/ui/Spacer.vue'
|
||||||
|
|
||||||
interface Props {
|
|
||||||
modelValue: string | null
|
|
||||||
channel: Channel | null
|
|
||||||
}
|
|
||||||
|
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const emit = defineEmits<Events>()
|
const model = defineModel<{channel: Channel, albumId: Album['id'] | '', albums: Album[]}>({ required: true })
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
|
||||||
modelValue: null,
|
|
||||||
channel: null
|
|
||||||
})
|
|
||||||
|
|
||||||
const value = useVModel(props, 'modelValue', emit)
|
const albums = ref<Album[]>([])
|
||||||
|
|
||||||
const albums = reactive<Album[]>([])
|
|
||||||
|
|
||||||
const isLoading = ref(false)
|
const isLoading = ref(false)
|
||||||
const fetchData = async () => {
|
|
||||||
albums.length = 0
|
|
||||||
if (!props.channel?.artist) return
|
|
||||||
|
|
||||||
|
const fetchAlbums = async () => {
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
const response = await axios.get('albums/', {
|
const response = await axios.get('albums/', {
|
||||||
params: {
|
params: {
|
||||||
artist: props.channel?.artist.id,
|
artist: model.value.channel.artist.id,
|
||||||
include_channels: 'true'
|
include_channels: 'true'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log("I found another album with artist", props.channel?.artist.name, ":", response.data.results)
|
console.log("I found another album with artist", model.value.channel.artist.name, ":", response.data.results)
|
||||||
albums.push(...response.data.results)
|
albums.value = response.data.results
|
||||||
isLoading.value = false
|
isLoading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(() => props.channel, fetchData, { immediate: true })
|
watch(() => model.value.channel, fetchAlbums, { immediate: true })
|
||||||
|
watch(albums, (value) => {
|
||||||
|
if (value.length === 1)
|
||||||
|
selectedAlbumId.value = albums.value[0].id
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
|
||||||
<label for="album-dropdown">
|
<label for="album-dropdown">
|
||||||
<span v-if="channel && channel.artist && channel.artist.content_category === 'podcast'">
|
<span v-if="model.channel.artist.content_category === 'podcast'">
|
||||||
{{ t('components.channels.AlbumSelect.label.series') }}
|
{{ t('components.channels.AlbumSelect.label.series') }}
|
||||||
</span>
|
</span>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
|
@ -60,7 +50,7 @@ watch(() => props.channel, fetchData, { immediate: true })
|
||||||
</label>
|
</label>
|
||||||
<select
|
<select
|
||||||
id="album-dropdown"
|
id="album-dropdown"
|
||||||
v-model="value"
|
v-model="model.albumId"
|
||||||
class="ui search normal dropdown"
|
class="ui search normal dropdown"
|
||||||
>
|
>
|
||||||
<option value="">
|
<option value="">
|
||||||
|
@ -75,5 +65,19 @@ watch(() => props.channel, fetchData, { immediate: true })
|
||||||
{{ t('components.channels.AlbumSelect.meta.tracks', album.tracks_count) }}
|
{{ t('components.channels.AlbumSelect.meta.tracks', album.tracks_count) }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
<Layout stack>
|
||||||
|
<Spacer :size="4" />
|
||||||
|
<Link
|
||||||
|
solid
|
||||||
|
primary
|
||||||
|
icon="bi-plus"
|
||||||
|
:to="useModal('album').to"
|
||||||
|
>
|
||||||
|
Add Album
|
||||||
|
<AlbumModal
|
||||||
|
v-model="model.channel"
|
||||||
|
@created="fetchAlbums"
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
</Layout>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,26 +1,31 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { BackendError, Channel, Upload, Track } from '~/types'
|
import type { BackendError, Channel, Upload, Track, Album } from '~/types'
|
||||||
import type { VueUploadItem } from 'vue-upload-component'
|
import type { VueUploadItem } from 'vue-upload-component'
|
||||||
|
|
||||||
import { computed, ref, reactive, watchEffect, watch } from 'vue'
|
import { computed, ref, reactive, watchEffect, watch, onMounted } from 'vue'
|
||||||
import { whenever } from '@vueuse/core'
|
import { whenever } from '@vueuse/core'
|
||||||
import { humanSize } from '~/utils/filters'
|
import { humanSize } from '~/utils/filters'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useStore } from '~/store'
|
import { useStore } from '~/store'
|
||||||
|
import { useModal } from '~/ui/composables/useModal.ts'
|
||||||
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { type paths, type schemas, type operations, type components } from '~/generated/types.ts'
|
import { type paths, type operations, type components } from '~/generated/types.ts'
|
||||||
|
|
||||||
import UploadMetadataForm from '~/components/channels/UploadMetadataForm.vue'
|
import UploadMetadataForm from '~/components/channels/UploadMetadataForm.vue'
|
||||||
import FileUploadWidget from '~/components/library/FileUploadWidget.vue'
|
import FileUploadWidget from '~/components/library/FileUploadWidget.vue'
|
||||||
import LicenseSelect from '~/components/channels/LicenseSelect.vue'
|
import LicenseSelect from '~/components/channels/LicenseSelect.vue'
|
||||||
import AlbumSelect from '~/components/channels/AlbumSelect.vue'
|
import AlbumSelect from '~/components/channels/AlbumSelect.vue'
|
||||||
|
import AlbumModal from '~/components/channels/AlbumModal.vue'
|
||||||
|
|
||||||
import useErrorHandler from '~/composables/useErrorHandler'
|
import useErrorHandler from '~/composables/useErrorHandler'
|
||||||
|
|
||||||
|
import Layout from '~/components/ui/Layout.vue'
|
||||||
import Alert from '~/components/ui/Alert.vue'
|
import Alert from '~/components/ui/Alert.vue'
|
||||||
import Button from '~/components/ui/Button.vue'
|
import Button from '~/components/ui/Button.vue'
|
||||||
|
import Link from '~/components/ui/Link.vue'
|
||||||
import Loader from '~/components/ui/Loader.vue'
|
import Loader from '~/components/ui/Loader.vue'
|
||||||
|
import Spacer from '~/components/ui/Spacer.vue'
|
||||||
|
|
||||||
|
|
||||||
interface Events {
|
interface Events {
|
||||||
|
@ -28,7 +33,7 @@ interface Events {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
channel?: Channel | null
|
channel: Channel | null
|
||||||
}
|
}
|
||||||
|
|
||||||
interface QuotaStatus {
|
interface QuotaStatus {
|
||||||
|
@ -72,29 +77,90 @@ const files = ref([] as VueUploadItem[])
|
||||||
//
|
//
|
||||||
// Channels
|
// Channels
|
||||||
//
|
//
|
||||||
const availableChannels = reactive({
|
const availableChannels = ref<Channel[]>([])
|
||||||
channels: [] as Channel[],
|
|
||||||
count: 0,
|
/*
|
||||||
loading: false
|
availableChannels>1? :=1 :=0
|
||||||
})
|
| | |
|
||||||
|
v v v
|
||||||
|
props select a channel | create empty channel
|
||||||
|
| | null
|
||||||
|
v v |
|
||||||
|
channelDropdownId v
|
||||||
|
|
|
||||||
|
v
|
||||||
|
selectedChannel
|
||||||
|
|
|
||||||
|
v
|
||||||
|
as a model to Album
|
||||||
|
|
|
||||||
|
v
|
||||||
|
albums
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// In the channel dropdown, we can select a value
|
||||||
|
//
|
||||||
|
|
||||||
|
const channelDropdownId = ref<Channel['artist']['id'] | null>(null)
|
||||||
|
const isLoading = ref(false)
|
||||||
|
|
||||||
|
const selectedChannel = computed(()=>
|
||||||
|
props.channel ? props.channel
|
||||||
|
: availableChannels.value.length===0 ? (createEmptyChannel(), null)
|
||||||
|
: availableChannels.value.length===1 ? availableChannels.value[0]
|
||||||
|
: availableChannels.value.find(({artist}) => artist.id === channelDropdownId.value)
|
||||||
|
)
|
||||||
|
|
||||||
|
const emptyChannelCreateRequest:components['schemas']['ChannelCreateRequest'] = {
|
||||||
|
name: store.state.auth.fullUsername,
|
||||||
|
username: store.state.auth.username,
|
||||||
|
description: null,
|
||||||
|
tags: [],
|
||||||
|
content_category: 'music',
|
||||||
|
}
|
||||||
|
|
||||||
|
const createEmptyChannel = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(
|
||||||
|
'channels/',
|
||||||
|
(emptyChannelCreateRequest satisfies operations['create_channel_2']['requestBody']['content']['application/json'])
|
||||||
|
)
|
||||||
|
console.log("Created Channel: ", response.data)
|
||||||
|
} catch (error) {
|
||||||
|
errors.value = (error as BackendError).backendErrors
|
||||||
|
console.log("Error:", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const fetchChannels = async () => {
|
const fetchChannels = async () => {
|
||||||
availableChannels.loading = true
|
isLoading.value = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.get('channels/', { params: { scope: 'me' } })
|
const response = await axios.get('channels/', { params: { scope: 'me' } })
|
||||||
availableChannels.channels = response.data.results
|
availableChannels.value = response.data.results
|
||||||
availableChannels.count = response.data.count
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
errors.value = (error as BackendError).backendErrors
|
errors.value = (error as BackendError).backendErrors
|
||||||
}
|
}
|
||||||
|
|
||||||
availableChannels.loading = false
|
isLoading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const selectedChannel = computed(() => availableChannels.channels[0])
|
// Albums
|
||||||
|
const albumSelection = ref<{channel: Channel, albumId: Album['id'] | '', albums: Album[]}>
|
||||||
|
|
||||||
|
watch(selectedChannel, (channel) =>
|
||||||
|
albumSelection.value =
|
||||||
|
{ channel: channel,
|
||||||
|
albumId: '',
|
||||||
|
albums: []
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const channelChange = async (channelId) => {
|
||||||
|
selectedChannel.value = channelId
|
||||||
|
await fetchAlbums(channelId)
|
||||||
|
}
|
||||||
|
|
||||||
//
|
|
||||||
// Quota and space
|
// Quota and space
|
||||||
//
|
//
|
||||||
const quotaStatus = ref()
|
const quotaStatus = ref()
|
||||||
|
@ -341,34 +407,29 @@ const labels = computed(() => ({
|
||||||
editTitle: t('components.channels.UploadForm.button.edit')
|
editTitle: t('components.channels.UploadForm.button.edit')
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const isLoading = ref(false)
|
|
||||||
const publish = async () => {
|
const publish = async () => {
|
||||||
console.log("starting publish...")
|
console.log("starting publish...")
|
||||||
isLoading.value = true
|
isLoading.value = true
|
||||||
|
|
||||||
errors.value = []
|
errors.value = []
|
||||||
|
|
||||||
|
|
||||||
console.log("first, let's try to create an empty channel...")
|
|
||||||
createEmptyChannel();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Post list of uuids of uploadedFiles to axios action:publish
|
// Post list of uuids of uploadedFiles to axios action:publish
|
||||||
|
|
||||||
/* { import_status: components["schemas"]["ImportStatusEnum"];
|
/* { import_status: components["schemas"]["ImportStatusEnum"];
|
||||||
audio_file: string;} */
|
audio_file: string;} */
|
||||||
|
|
||||||
const theUpdate : components['schemas']['PatchedUploadForOwnerRequest'] = {
|
// const theUpdate : components['schemas']['PatchedUploadForOwnerRequest'] = {
|
||||||
import_status: 'pending',
|
// import_status: 'pending',
|
||||||
}
|
// }
|
||||||
|
|
||||||
await axios.post('uploads/action/', {
|
// await axios.post('uploads/action/', {
|
||||||
action: 'publish',
|
// action: 'publish',
|
||||||
objects: uploadedFiles.value.map((file) => file.response?.uuid)
|
// objects: uploadedFiles.value.map((file) => file.response?.uuid)
|
||||||
} satisfies paths['/api/v2/uploads/action/']['post']['requestBody']['content']['application/json'],
|
// } satisfies paths['/api/v2/uploads/action/']['post']['requestBody']['content']['application/json'],
|
||||||
{
|
// {
|
||||||
headers: { 'Authorization': `Bearer ${store.state.auth.oauth}` }
|
// headers: { 'Authorization': `Bearer ${store.state.auth.oauth}` }
|
||||||
})
|
// })
|
||||||
|
|
||||||
|
|
||||||
console.log("Channels Store Before: ", store.state.channels)
|
console.log("Channels Store Before: ", store.state.channels)
|
||||||
|
@ -396,10 +457,6 @@ defineExpose({
|
||||||
publish
|
publish
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Api Calls
|
// Api Calls
|
||||||
|
|
||||||
// Create a new channel
|
// Create a new channel
|
||||||
|
@ -460,35 +517,12 @@ ChannelCreateRequest: {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const emptyChannelCreateRequest:schemas['ChannelCreateRequest'] = {
|
|
||||||
name: 'empty channel',
|
|
||||||
username: store.state.auth.username,
|
|
||||||
description: null,
|
|
||||||
tags: [],
|
|
||||||
content_category: 'music',
|
|
||||||
}
|
|
||||||
|
|
||||||
//json
|
|
||||||
const emptyCreate_channel_2RequestBodyContentJson:operations['create_channel_2']['requestBody']['content']['application/json'] =
|
|
||||||
emptyChannelCreateRequest
|
|
||||||
|
|
||||||
//post
|
|
||||||
const createEmptyChannel = async () => {
|
|
||||||
try {
|
|
||||||
const response = await axios.post('channels/', emptyCreate_channel_2RequestBodyContentJson)
|
|
||||||
console.log("Created Channel: ", response.data)
|
|
||||||
} catch (error) {
|
|
||||||
errors.value = (error as BackendError).backendErrors
|
|
||||||
console.log("Error:", error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<form
|
<form
|
||||||
:class="['ui', { loading: availableChannels.loading }, 'form component-file-upload']"
|
:class="['ui', { loading: isLoading }, 'form component-file-upload']"
|
||||||
@submit.stop.prevent
|
@submit.stop.prevent
|
||||||
>
|
>
|
||||||
<!-- Error message -->
|
<!-- Error message -->
|
||||||
|
@ -510,23 +544,30 @@ const createEmptyChannel = async () => {
|
||||||
<!-- Select Album and License -->
|
<!-- Select Album and License -->
|
||||||
|
|
||||||
<div :class="['ui', 'required', 'field']">
|
<div :class="['ui', 'required', 'field']">
|
||||||
<label for="channel-dropdown">
|
<label v-if="availableChannels.length === 1" for="channel-dropdown">
|
||||||
{{ t('components.channels.UploadForm.label.channel') }}: {{ selectedChannel?.artist.name }}
|
{{ t('components.channels.UploadForm.label.channel') }}: {{ selectedChannel?.artist.name }}
|
||||||
</label>
|
</label>
|
||||||
|
<label v-else for="channel-dropdown">
|
||||||
|
{{ t('components.channels.UploadForm.label.channel') }}
|
||||||
|
</label>
|
||||||
<select
|
<select
|
||||||
v-if="availableChannels.count > 1"
|
v-if="availableChannels.length > 1"
|
||||||
|
v-model="channelDropdownId"
|
||||||
id="channel-dropdown"
|
id="channel-dropdown"
|
||||||
|
class="dropdown"
|
||||||
>
|
>
|
||||||
<option v-for="channel in availableChannels.channels" :value="channel.uuid">
|
<option v-for="channel in availableChannels" :value="channel.artist.id">
|
||||||
{{ channel.artist.name }}
|
{{ channel.artist.name }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<Layout flex>
|
||||||
<album-select
|
<album-select
|
||||||
v-model.number="values.album"
|
v-if="selectedChannel"
|
||||||
:channel="selectedChannel"
|
v-model="albumSelection"
|
||||||
:class="['ui', 'field']"
|
:class="['ui', 'field']"
|
||||||
/>
|
/>
|
||||||
|
</Layout>
|
||||||
<license-select
|
<license-select
|
||||||
v-model="values.license"
|
v-model="values.license"
|
||||||
:class="['ui', 'field']"
|
:class="['ui', 'field']"
|
||||||
|
|
|
@ -64,7 +64,7 @@ const channelUpload = ref();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal overPopover
|
<Modal
|
||||||
:title="modalTitle"
|
:title="modalTitle"
|
||||||
v-model="isOpen"
|
v-model="isOpen"
|
||||||
>
|
>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { computed, ref, reactive, watch } from 'vue'
|
||||||
import { whenever } from '@vueuse/core'
|
import { whenever } from '@vueuse/core'
|
||||||
import { useStore } from '~/store'
|
import { useStore } from '~/store'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useModal } from '~/ui/composables/useModal.ts'
|
||||||
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
|
@ -17,6 +18,7 @@ import Loader from '~/components/ui/Loader.vue'
|
||||||
import Spacer from '~/components/ui/Spacer.vue'
|
import Spacer from '~/components/ui/Spacer.vue'
|
||||||
import Alert from '~/components/ui/Alert.vue'
|
import Alert from '~/components/ui/Alert.vue'
|
||||||
import Button from '~/components/ui/Button.vue'
|
import Button from '~/components/ui/Button.vue'
|
||||||
|
import Link from '~/components/ui/Link.vue'
|
||||||
|
|
||||||
import useWebSocketHandler from '~/composables/useWebSocketHandler'
|
import useWebSocketHandler from '~/composables/useWebSocketHandler'
|
||||||
|
|
||||||
|
@ -153,7 +155,7 @@ const albumModal = ref()
|
||||||
<channel-entries
|
<channel-entries
|
||||||
:key="String(episodesKey) + 'entries'"
|
:key="String(episodesKey) + 'entries'"
|
||||||
:is-podcast="isPodcast"
|
:is-podcast="isPodcast"
|
||||||
:default-cover="object.artist?.cover"
|
:default-cover="object.artist?.cover || null"
|
||||||
:limit="25"
|
:limit="25"
|
||||||
:filters="{channel: object.uuid, ordering: '-creation_date', page_size: '25'}"
|
:filters="{channel: object.uuid, ordering: '-creation_date', page_size: '25'}"
|
||||||
>
|
>
|
||||||
|
@ -191,17 +193,18 @@ const albumModal = ref()
|
||||||
v-if="isOwner"
|
v-if="isOwner"
|
||||||
class="actions"
|
class="actions"
|
||||||
>
|
>
|
||||||
<a @click.stop.prevent="albumModal.show = true">
|
<Link
|
||||||
|
:to="useModal('album').to"
|
||||||
|
>
|
||||||
<i class="bi bi-plus" />
|
<i class="bi bi-plus" />
|
||||||
{{ t('views.channels.DetailOverview.link.addAlbum') }}
|
{{ t('views.channels.DetailOverview.link.addAlbum') }}
|
||||||
</a>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</h2>
|
</h2>
|
||||||
</channel-series>
|
</channel-series>
|
||||||
<album-modal
|
<album-modal
|
||||||
v-if="isOwner"
|
v-if="isOwner"
|
||||||
ref="albumModal"
|
:model-value="object"
|
||||||
:channel="object"
|
|
||||||
@created="albumModal.show = false; seriesKey = new Date()"
|
@created="albumModal.show = false; seriesKey = new Date()"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
|
|
Loading…
Reference in New Issue