<template> <div class="ui vertical stripe segment" v-title="'Radio Builder'"> <div> <div> <h2 class="ui header"><i18next path="Builder"/></h2> <i18next tag="p" path="You can use this interface to build your own custom radio, which will play tracks according to your criteria"/> <div class="ui form"> <div class="inline fields"> <div class="field"> <i18next tag="label" for="name" path="Radio name"/> <input id="name" type="text" v-model="radioName" placeholder="My awesome radio" /> </div> <div class="field"> <input id="public" type="checkbox" v-model="isPublic" /> <i18next tag="label" for="public" path="Display publicly"/> </div> <button :disabled="!canSave" @click="save" class="ui green button"><i18next path="Save"/></button> <radio-button v-if="id" type="custom" :custom-radio-id="id"></radio-button> </div> </div> <div class="ui form"> <p><i18next path="Add filters to customize your radio"/></p> <div class="inline field"> <select class="ui dropdown" v-model="currentFilterType"> <option value=""><i18next path="Select a filter"/></option> <option v-for="f in availableFilters" :value="f.type">{{ f.label }}</option> </select> <button :disabled="!currentFilterType" @click="add" class="ui button"><i18next path="Add filter"/></button> </div> <p v-if="currentFilter"> {{ currentFilter.help_text }} </p> </div> <table class="ui table"> <thead> <tr> <i18next tag="th" class="two wide" path="Filter name"/> <i18next tag="th" class="one wide" path="Exclude"/> <i18next tag="th" class="six wide" path="Config"/> <i18next tag="th" class="five wide" path="Candidates"/> <i18next tag="th" class="two wide" path="Actions"/> </tr> </thead> <tbody> <builder-filter v-for="(f, index) in filters" :key="(f, index, f.hash)" :index="index" @update-config="updateConfig" @delete="deleteFilter" :config="f.config" :filter="f.filter"> </builder-filter> </tbody> </table> <template v-if="checkResult"> <i18next tag="h3" class="ui header" path="{%0%} tracks matching combined filters"> {{ checkResult.candidates.count }} </i18next> <track-table v-if="checkResult.candidates.sample" :tracks="checkResult.candidates.sample"></track-table> </template> </div> </div> </div> </template> <script> import axios from 'axios' import $ from 'jquery' import _ from 'lodash' import BuilderFilter from './Filter' import TrackTable from '@/components/audio/track/Table' import RadioButton from '@/components/radios/Button' export default { props: { id: {required: false} }, components: { BuilderFilter, TrackTable, RadioButton }, data: function () { return { availableFilters: [], currentFilterType: null, filters: [], checkResult: null, radioName: '', isPublic: true } }, created: function () { let self = this this.fetchFilters().then(() => { if (self.id) { self.fetch() } }) }, mounted () { $('.ui.dropdown').dropdown() }, methods: { fetchFilters: function () { let self = this let url = 'radios/radios/filters/' return axios.get(url).then((response) => { self.availableFilters = response.data }) }, add () { this.filters.push({ config: {}, filter: this.currentFilter, hash: +new Date() }) this.fetchCandidates() }, updateConfig (index, field, value) { this.filters[index].config[field] = value this.fetchCandidates() }, deleteFilter (index) { this.filters.splice(index, 1) this.fetchCandidates() }, fetch: function () { let self = this let url = 'radios/radios/' + this.id + '/' axios.get(url).then((response) => { self.filters = response.data.config.map(f => { return { config: f, filter: this.availableFilters.filter(e => { return e.type === f.type })[0], hash: +new Date() } }) self.radioName = response.data.name self.isPublic = response.data.is_public }) }, fetchCandidates: function () { let self = this let url = 'radios/radios/validate/' let final = this.filters.map(f => { let c = _.clone(f.config) c.type = f.filter.type return c }) final = { 'filters': [ {'type': 'group', filters: final} ] } axios.post(url, final).then((response) => { self.checkResult = response.data.filters[0] }) }, save: function () { let self = this let final = this.filters.map(f => { let c = _.clone(f.config) c.type = f.filter.type return c }) final = { 'name': this.radioName, 'is_public': this.isPublic, 'config': final } if (this.id) { let url = 'radios/radios/' + this.id + '/' axios.put(url, final).then((response) => { }) } else { let url = 'radios/radios/' axios.post(url, final).then((response) => { self.$router.push({ name: 'library.radios.detail', params: { id: response.data.id } }) }) } } }, computed: { canSave: function () { return ( this.radioName.length > 0 && this.checkErrors.length === 0 ) }, checkErrors: function () { if (!this.checkResult) { return [] } let errors = this.checkResult.errors return errors }, currentFilter: function () { let self = this return this.availableFilters.filter(e => { return e.type === self.currentFilterType })[0] } }, watch: { filters: { handler: function () { this.fetchCandidates() }, deep: true } } } </script>