Skip to content
Snippets Groups Projects
Commit bdf83bd8 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Resolve "Hide an artist in the UI"

parent d4d4e60e
No related branches found
No related tags found
No related merge requests found
......@@ -23,7 +23,7 @@
</h2>
<div class="ui hidden divider"></div>
<radio-button type="artist" :object-id="artist.id"></radio-button>
<play-button :is-playable="isPlayable" class="orange" :artist="artist.id">
<play-button :is-playable="isPlayable" class="orange" :artist="artist">
<translate :translate-context="'Content/Artist/Button.Label/Verb'">Play all albums</translate>
</play-button>
......@@ -37,6 +37,20 @@
</a>
</div>
</section>
<div class="ui small text container" v-if="contentFilter">
<div class="ui hidden divider"></div>
<div class="ui message">
<p>
<translate>You are currently hiding content related to this artist.</translate>
</p>
<router-link class="right floated" :to="{name: 'settings'}">
<translate :translate-context="'Content/Moderation/Link'">Review my filters</translate>
</router-link>
<button @click="$store.dispatch('moderation/deleteContentFilter', contentFilter.uuid)" class="ui basic tiny button">
<translate :translate-context="'Content/Moderation/Button.Label'">Remove filter</translate>
</button>
</div>
</div>
<section v-if="isLoadingAlbums" class="ui vertical stripe segment">
<div :class="['ui', 'centered', 'active', 'inline', 'loader']"></div>
</section>
......@@ -105,7 +119,7 @@ export default {
var self = this
this.isLoading = true
logger.default.debug('Fetching artist "' + this.id + '"')
axios.get("tracks/", { params: { artist: this.id } }).then(response => {
axios.get("tracks/", { params: { artist: this.id, hidden: '' } }).then(response => {
self.tracks = response.data.results
self.totalTracks = response.data.count
})
......@@ -115,7 +129,7 @@ export default {
self.isLoadingAlbums = true
axios
.get("albums/", {
params: { artist: self.id, ordering: "-release_date" }
params: { artist: self.id, ordering: "-release_date", hidden: '' }
})
.then(response => {
self.totalAlbums = response.data.count
......@@ -180,6 +194,12 @@ export default {
this.$store.getters["instance/absoluteUrl"](this.cover.original) +
")"
)
},
contentFilter () {
let self = this
return this.$store.getters['moderation/artistFilters']().filter((e) => {
return e.target.id === this.artist.id
})[0]
}
},
watch: {
......
......@@ -173,6 +173,9 @@ export default {
query() {
this.updateQueryString()
this.fetchData()
},
"$store.state.moderation.lastUpdate": function () {
this.fetchData()
}
}
}
......
<template>
<modal @update:show="update" :show="$store.state.moderation.showFilterModal">
<div class="header">
<translate
v-if="type === 'artist'"
key="1"
:translate-context="'Popup/Moderation/Title/Verb'"
:translate-params="{name: target.name}">Do you want to hide content from artist "%{ name }"?</translate>
</div>
<div class="scrolling content">
<div class="description">
<div v-if="errors.length > 0" class="ui negative message">
<div class="header"><translate :translate-context="'Popup/Moderation/Error message'">Error while creating filter</translate></div>
<ul class="list">
<li v-for="error in errors">{{ error }}</li>
</ul>
</div>
<template v-if="type === 'artist'">
<p>
<translate :translate-context="'Popup/Moderation/Paragraph'">
You will not see tracks, albums and user activity linked to this artist anymore:
</translate>
</p>
<ul>
<li><translate :translate-context="'Popup/Moderation/List item'">In other users favorites and listening history</translate></li>
<li><translate :translate-context="'Popup/Moderation/List item'">In "Recently added" widget</translate></li>
<li><translate :translate-context="'Popup/Moderation/List item'">In artists and album listings</translate></li>
<li><translate :translate-context="'Popup/Moderation/List item'">In radio suggestions</translate></li>
</ul>
<p>
<translate :translate-context="'Popup/Moderation/Paragraph'">
You can manage and update your filters anytime from your account settings.
</translate>
</p>
</template>
</div>
</div>
<div class="actions">
<div class="ui cancel button"><translate :translate-context="'Popup/*/Button.Label'">Cancel</translate></div>
<div :class="['ui', 'green', {loading: isLoading}, 'button']" @click="hide"><translate :translate-context="'Popup/*/Button.Label'">Hide content</translate></div>
</div>
</modal>
</template>
<script>
import _ from '@/lodash'
import axios from 'axios'
import {mapState} from 'vuex'
import logger from '@/logging'
import Modal from '@/components/semantic/Modal'
export default {
components: {
Modal,
},
data () {
return {
formKey: String(new Date()),
errors: [],
isLoading: false
}
},
computed: {
...mapState({
type: state => state.moderation.filterModalTarget.type,
target: state => state.moderation.filterModalTarget.target,
})
},
methods: {
update (v) {
this.$store.commit('moderation/showFilterModal', v)
this.errors = []
},
hide () {
let self = this
self.isLoading = true
let payload = {
target: {
type: this.type,
id: this.target.id,
}
}
return axios.post('moderation/content-filters/', payload).then(response => {
logger.default.info('Successfully added track to playlist')
self.update(false)
self.$store.commit('moderation/lastUpdate', new Date())
self.isLoading = false
let msg = this.$pgettext('*/Moderation/Message', 'Content filter successfully added')
self.$store.commit('moderation/contentFilter', response.data)
self.$store.commit('ui/addMessage', {
content: msg,
date: new Date()
})
}, error => {
console.log('error', error)
logger.default.error(`Error while hiding ${self.type} ${self.target.id}`)
self.errors = error.backendErrors
self.isLoading = false
})
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
......@@ -6,7 +6,6 @@
<button :disabled="!previousPage" @click="fetchData(previousPage)" :class="['ui', {disabled: !previousPage}, 'circular', 'icon', 'basic', 'button']"><i :class="['ui', 'angle up', 'icon']"></i></button>
<button :disabled="!nextPage" @click="fetchData(nextPage)" :class="['ui', {disabled: !nextPage}, 'circular', 'icon', 'basic', 'button']"><i :class="['ui', 'angle down', 'icon']"></i></button>
<button @click="fetchData(url)" :class="['ui', 'circular', 'icon', 'basic', 'button']"><i :class="['ui', 'refresh', 'icon']"></i></button>
<div v-if="isLoading" class="ui inverted active dimmer">
<div class="ui loader"></div>
</div>
......@@ -71,6 +70,9 @@ export default {
watch: {
offset () {
this.fetchData()
},
"$store.state.moderation.lastUpdate": function () {
this.fetchData(this.url)
}
}
}
......
......@@ -10,4 +10,5 @@ export default {
sortBy: require('lodash/sortBy'),
throttle: require('lodash/throttle'),
uniq: require('lodash/uniq'),
remove: require('lodash/remove'),
}
......@@ -125,6 +125,7 @@ export default {
})
dispatch('ui/fetchUnreadNotifications', null, { root: true })
dispatch('favorites/fetch', null, { root: true })
dispatch('moderation/fetchContentFilters', null, { root: true })
dispatch('playlists/fetchOwn', null, { root: true })
}, (response) => {
logger.default.info('Error while fetching user profile')
......
......@@ -5,6 +5,7 @@ import createPersistedState from 'vuex-persistedstate'
import favorites from './favorites'
import auth from './auth'
import instance from './instance'
import moderation from './moderation'
import queue from './queue'
import radios from './radios'
import player from './player'
......@@ -19,6 +20,7 @@ export default new Vuex.Store({
auth,
favorites,
instance,
moderation,
queue,
radios,
playlists,
......
......@@ -104,6 +104,7 @@ export default {
let modules = [
'auth',
'favorites',
'moderation',
'player',
'playlists',
'queue',
......
import axios from 'axios'
import logger from '@/logging'
import _ from '@/lodash'
export default {
namespaced: true,
state: {
filters: [],
showFilterModal: false,
lastUpdate: new Date(),
filterModalTarget: {
type: null,
target: null,
}
},
mutations: {
filterModalTarget (state, value) {
state.filterModalTarget = value
},
empty (state) {
state.filters = []
},
lastUpdate (state, value) {
state.lastUpdate = value
},
contentFilter (state, value) {
state.filters.push(value)
},
showFilterModal (state, value) {
state.showFilterModal = value
if (!value) {
state.filterModalTarget = {
type: null,
target: null,
}
}
},
reset (state) {
state.filters = []
state.filterModalTarget = null
state.showFilterModal = false
},
deleteContentFilter (state, uuid) {
state.filters = state.filters.filter((e) => {
return e.uuid != uuid
})
}
},
getters: {
artistFilters: (state) => () => {
let f = state.filters.filter((f) => {
return f.target.type === 'artist'
})
let p = _.sortBy(f, [(e) => { return e.creation_date }])
p.reverse()
return p
},
},
actions: {
hide ({commit}, payload) {
commit('filterModalTarget', payload)
commit('showFilterModal', true)
},
fetchContentFilters ({dispatch, state, commit, rootState}, url) {
let params = {}
let promise
if (url) {
promise = axios.get(url)
} else {
commit('empty')
params = {
page_size: 100,
ordering: '-creation_date'
}
promise = axios.get('moderation/content-filters/', {params: params})
}
return promise.then((response) => {
logger.default.info('Fetched a batch of ' + response.data.results.length + ' filters')
if (response.data.next) {
dispatch('fetchContentFilters', response.data.next)
}
response.data.results.forEach(result => {
commit('contentFilter', result)
})
})
},
deleteContentFilter ({commit}, uuid) {
return axios.delete(`moderation/content-filters/${ uuid }/`).then((response) => {
commit('deleteContentFilter', uuid)
})
}
}
}
......@@ -271,3 +271,8 @@ canvas.color-thief {
.ui.list .list.icon {
padding-left: 0;
}
.ui.dropdown .item[disabled] {
display: none;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment