diff --git a/api/funkwhale_api/radios/serializers.py b/api/funkwhale_api/radios/serializers.py index 520e98652f4238de071ae49f419525f745e97785..2e7e6a409fb4e4102f1d713faaeb94ca3b7e759a 100644 --- a/api/funkwhale_api/radios/serializers.py +++ b/api/funkwhale_api/radios/serializers.py @@ -1,6 +1,7 @@ from rest_framework import serializers from funkwhale_api.music.serializers import TrackSerializerNested +from funkwhale_api.users.serializers import UserBasicSerializer from . import filters from . import models @@ -15,6 +16,8 @@ class FilterSerializer(serializers.Serializer): class RadioSerializer(serializers.ModelSerializer): + user = UserBasicSerializer(read_only=True) + class Meta: model = models.Radio fields = ( diff --git a/api/funkwhale_api/radios/views.py b/api/funkwhale_api/radios/views.py index 42652644224446ccade4d43b36c995581bb15783..371ba973e7e54e8e499821ed909919aa426591eb 100644 --- a/api/funkwhale_api/radios/views.py +++ b/api/funkwhale_api/radios/views.py @@ -20,6 +20,7 @@ class RadioViewSet( mixins.RetrieveModelMixin, mixins.UpdateModelMixin, mixins.ListModelMixin, + mixins.DestroyModelMixin, viewsets.GenericViewSet): serializer_class = serializers.RadioSerializer @@ -40,6 +41,17 @@ class RadioViewSet( raise Http404 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']) def filters(self, request, *args, **kwargs): serializer = serializers.FilterSerializer( diff --git a/front/src/components/library/radios/Builder.vue b/front/src/components/library/radios/Builder.vue index 9b8786cc6eb91181dcbb3e17a697f6b5a8edc881..5fbf0c992618616e0c0be0f76e458deb997737b8 100644 --- a/front/src/components/library/radios/Builder.vue +++ b/front/src/components/library/radios/Builder.vue @@ -180,7 +180,7 @@ export default { let url = 'radios/radios/' axios.post(url, final).then((response) => { self.$router.push({ - name: 'library.radios.edit', + name: 'library.radios.detail', params: { id: response.data.id } diff --git a/front/src/components/radios/Card.vue b/front/src/components/radios/Card.vue index d2c14c37c78dfbc23b858c93a5eddd28b3519fb9..17de3c85fe3c67d5a124d046aa9e5fa233503396 100644 --- a/front/src/components/radios/Card.vue +++ b/front/src/components/radios/Card.vue @@ -1,7 +1,11 @@ <template> <div class="ui card"> <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"> {{ radio.description }} </div> diff --git a/front/src/router/index.js b/front/src/router/index.js index 802844461325560a48cf8002f21ef8e3f5462594..d41764227bb1a1cbd3536791ae24275b7228d249 100644 --- a/front/src/router/index.js +++ b/front/src/router/index.js @@ -18,6 +18,7 @@ import LibraryTrack from '@/components/library/Track' import LibraryImport from '@/components/library/import/Main' import LibraryRadios from '@/components/library/Radios' import RadioBuilder from '@/components/library/radios/Builder' +import RadioDetail from '@/views/radios/Detail' import BatchList from '@/components/library/import/BatchList' import BatchDetail from '@/components/library/import/BatchDetail' 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/:id', name: 'library.radios.edit', component: RadioBuilder, props: true }, + { path: 'radios/:id', name: 'library.radios.detail', component: RadioDetail, props: true }, { path: 'playlists/', name: 'library.playlists.browse', diff --git a/front/src/views/radios/Detail.vue b/front/src/views/radios/Detail.vue new file mode 100644 index 0000000000000000000000000000000000000000..a35f0db00803bec2e9b3af8e8649760eea5ba319 --- /dev/null +++ b/front/src/views/radios/Detail.vue @@ -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>