From 85aef4422ac8305b2428081b13892c5642476f60 Mon Sep 17 00:00:00 2001
From: Bat <baptiste@gelez.xyz>
Date: Sat, 31 Mar 2018 12:59:45 +0100
Subject: [PATCH] Add a detail page for radios

---
 api/funkwhale_api/radios/serializers.py       |  3 +
 api/funkwhale_api/radios/views.py             | 12 +++
 .../src/components/library/radios/Builder.vue |  2 +-
 front/src/components/radios/Card.vue          |  6 +-
 front/src/router/index.js                     |  2 +
 front/src/views/radios/Detail.vue             | 87 +++++++++++++++++++
 6 files changed, 110 insertions(+), 2 deletions(-)
 create mode 100644 front/src/views/radios/Detail.vue

diff --git a/api/funkwhale_api/radios/serializers.py b/api/funkwhale_api/radios/serializers.py
index 520e98652f..2e7e6a409f 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 4265264422..371ba973e7 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 9b8786cc6e..5fbf0c9926 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 d2c14c37c7..17de3c85fe 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 8028444613..d41764227b 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 0000000000..a35f0db008
--- /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>
-- 
GitLab