Add a detail page for radios
This commit is contained in:
parent
876aee19cf
commit
85aef4422a
|
@ -1,6 +1,7 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from funkwhale_api.music.serializers import TrackSerializerNested
|
from funkwhale_api.music.serializers import TrackSerializerNested
|
||||||
|
from funkwhale_api.users.serializers import UserBasicSerializer
|
||||||
|
|
||||||
from . import filters
|
from . import filters
|
||||||
from . import models
|
from . import models
|
||||||
|
@ -15,6 +16,8 @@ class FilterSerializer(serializers.Serializer):
|
||||||
|
|
||||||
|
|
||||||
class RadioSerializer(serializers.ModelSerializer):
|
class RadioSerializer(serializers.ModelSerializer):
|
||||||
|
user = UserBasicSerializer(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Radio
|
model = models.Radio
|
||||||
fields = (
|
fields = (
|
||||||
|
|
|
@ -20,6 +20,7 @@ class RadioViewSet(
|
||||||
mixins.RetrieveModelMixin,
|
mixins.RetrieveModelMixin,
|
||||||
mixins.UpdateModelMixin,
|
mixins.UpdateModelMixin,
|
||||||
mixins.ListModelMixin,
|
mixins.ListModelMixin,
|
||||||
|
mixins.DestroyModelMixin,
|
||||||
viewsets.GenericViewSet):
|
viewsets.GenericViewSet):
|
||||||
|
|
||||||
serializer_class = serializers.RadioSerializer
|
serializer_class = serializers.RadioSerializer
|
||||||
|
@ -40,6 +41,17 @@ class RadioViewSet(
|
||||||
raise Http404
|
raise Http404
|
||||||
return serializer.save(user=self.request.user)
|
return serializer.save(user=self.request.user)
|
||||||
|
|
||||||
|
@detail_route(methods=['get'])
|
||||||
|
def tracks(self, request, *args, **kwargs):
|
||||||
|
radio = self.get_object()
|
||||||
|
tracks = radio.get_candidates().for_nested_serialization()
|
||||||
|
serializer = TrackSerializerNested(tracks, many=True)
|
||||||
|
data = {
|
||||||
|
'count': len(tracks),
|
||||||
|
'results': serializer.data
|
||||||
|
}
|
||||||
|
return Response(data, status=200)
|
||||||
|
|
||||||
@list_route(methods=['get'])
|
@list_route(methods=['get'])
|
||||||
def filters(self, request, *args, **kwargs):
|
def filters(self, request, *args, **kwargs):
|
||||||
serializer = serializers.FilterSerializer(
|
serializer = serializers.FilterSerializer(
|
||||||
|
|
|
@ -180,7 +180,7 @@ export default {
|
||||||
let url = 'radios/radios/'
|
let url = 'radios/radios/'
|
||||||
axios.post(url, final).then((response) => {
|
axios.post(url, final).then((response) => {
|
||||||
self.$router.push({
|
self.$router.push({
|
||||||
name: 'library.radios.edit',
|
name: 'library.radios.detail',
|
||||||
params: {
|
params: {
|
||||||
id: response.data.id
|
id: response.data.id
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="ui card">
|
<div class="ui card">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="header">{{ radio.name }}</div>
|
<div class="header">
|
||||||
|
<router-link class="discrete link" :to="{name: 'library.radios.detail', params: {id: radio.id}}">
|
||||||
|
{{ radio.name }}
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
{{ radio.description }}
|
{{ radio.description }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -18,6 +18,7 @@ import LibraryTrack from '@/components/library/Track'
|
||||||
import LibraryImport from '@/components/library/import/Main'
|
import LibraryImport from '@/components/library/import/Main'
|
||||||
import LibraryRadios from '@/components/library/Radios'
|
import LibraryRadios from '@/components/library/Radios'
|
||||||
import RadioBuilder from '@/components/library/radios/Builder'
|
import RadioBuilder from '@/components/library/radios/Builder'
|
||||||
|
import RadioDetail from '@/views/radios/Detail'
|
||||||
import BatchList from '@/components/library/import/BatchList'
|
import BatchList from '@/components/library/import/BatchList'
|
||||||
import BatchDetail from '@/components/library/import/BatchDetail'
|
import BatchDetail from '@/components/library/import/BatchDetail'
|
||||||
import RequestsList from '@/components/requests/RequestsList'
|
import RequestsList from '@/components/requests/RequestsList'
|
||||||
|
@ -111,6 +112,7 @@ export default new Router({
|
||||||
},
|
},
|
||||||
{ path: 'radios/build', name: 'library.radios.build', component: RadioBuilder, props: true },
|
{ path: 'radios/build', name: 'library.radios.build', component: RadioBuilder, props: true },
|
||||||
{ path: 'radios/build/:id', name: 'library.radios.edit', component: RadioBuilder, props: true },
|
{ path: 'radios/build/:id', name: 'library.radios.edit', component: RadioBuilder, props: true },
|
||||||
|
{ path: 'radios/:id', name: 'library.radios.detail', component: RadioDetail, props: true },
|
||||||
{
|
{
|
||||||
path: 'playlists/',
|
path: 'playlists/',
|
||||||
name: 'library.playlists.browse',
|
name: 'library.playlists.browse',
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div v-if="isLoading" class="ui vertical segment" v-title="'Radio'">
|
||||||
|
<div :class="['ui', 'centered', 'active', 'inline', 'loader']"></div>
|
||||||
|
</div>
|
||||||
|
<div v-if="!isLoading && radio" class="ui head vertical center aligned stripe segment" v-title="radio.name">
|
||||||
|
<div class="segment-content">
|
||||||
|
<h2 class="ui center aligned icon header">
|
||||||
|
<i class="circular inverted feed blue icon"></i>
|
||||||
|
<div class="content">
|
||||||
|
{{ radio.name }}
|
||||||
|
<div class="sub header">
|
||||||
|
Radio containing {{ tracks.length }} tracks,
|
||||||
|
by <username :username="radio.user.username"></username>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</h2>
|
||||||
|
<div class="ui hidden divider"></div>
|
||||||
|
<radio-button type="custom" :custom-radio-id="radio.id"></radio-button>
|
||||||
|
<router-link class="ui icon button" :to="{name: 'library.radios.edit', params: {id: radio.id}}" exact>
|
||||||
|
<i class="pencil icon"></i>
|
||||||
|
Edit…
|
||||||
|
</router-link>
|
||||||
|
<dangerous-button class="labeled icon" :action="deleteRadio">
|
||||||
|
<i class="trash icon"></i> Delete
|
||||||
|
<p slot="modal-header">Do you want to delete the radio "{{ radio.name }}"?</p>
|
||||||
|
<p slot="modal-content">This will completely delete this radio and cannot be undone.</p>
|
||||||
|
<p slot="modal-confirm">Delete radio</p>
|
||||||
|
</dangerous-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ui vertical stripe segment">
|
||||||
|
<h2>Tracks</h2>
|
||||||
|
<track-table :tracks="tracks"></track-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import axios from 'axios'
|
||||||
|
import TrackTable from '@/components/audio/track/Table'
|
||||||
|
import RadioButton from '@/components/radios/Button'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
id: {required: true}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
TrackTable,
|
||||||
|
RadioButton
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
isLoading: false,
|
||||||
|
radio: null,
|
||||||
|
tracks: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created: function () {
|
||||||
|
this.fetch()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
fetch: function () {
|
||||||
|
let self = this
|
||||||
|
self.isLoading = true
|
||||||
|
let url = 'radios/radios/' + this.id + '/'
|
||||||
|
axios.get(url).then((response) => {
|
||||||
|
self.radio = response.data
|
||||||
|
axios.get(url + 'tracks').then((response) => {
|
||||||
|
this.tracks = response.data.results
|
||||||
|
}).then(() => {
|
||||||
|
self.isLoading = false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
deleteRadio () {
|
||||||
|
let self = this
|
||||||
|
let url = 'radios/radios/' + this.id + '/'
|
||||||
|
axios.delete(url).then((response) => {
|
||||||
|
self.$router.push({
|
||||||
|
path: '/library'
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
Loading…
Reference in New Issue