funkwhale/front/src/components/playlists/PlaylistModal.vue

291 wiersze
9.1 KiB
Vue
Czysty Zwykły widok Historia

<template>
2021-12-06 10:35:20 +00:00
<modal
:show="$store.state.playlists.showModal"
@update:show="update"
>
<h4 class="header">
<template v-if="track">
<h2 class="ui header">
2021-12-06 10:35:20 +00:00
<translate translate-context="Popup/Playlist/Title/Verb">
Add to playlist
</translate>
<div
2021-12-06 10:35:20 +00:00
v-translate="{artist: track.artist.name, title: track.title}"
class="ui sub header"
2019-03-20 10:36:16 +00:00
translate-context="Popup/Playlist/Paragraph"
2021-12-06 10:35:20 +00:00
:translate-params="{artist: track.artist.name, title: track.title}"
>
2018-06-30 13:28:47 +00:00
"%{ title }", by %{ artist }
</div>
</h2>
</template>
2021-12-06 10:35:20 +00:00
<translate
v-else
translate-context="Popup/Playlist/Title/Verb"
>
Manage playlists
</translate>
</h4>
<div class="scrolling content">
2021-12-06 10:35:20 +00:00
<playlist-form :key="formKey" />
<div class="ui divider" />
<div v-if="playlists.length > 0">
2021-12-06 10:35:20 +00:00
<div
v-if="showDuplicateTrackAddConfirmation"
role="alert"
class="ui warning message"
>
<p
v-translate="{track: track.title, playlist: duplicateTrackAddInfo.playlist_name}"
2021-12-06 10:35:20 +00:00
translate-context="Popup/Playlist/Paragraph"
:translate-params="{track: track.title, playlist: duplicateTrackAddInfo.playlist_name}"
>
<strong>%{ track }</strong> is already in <strong>%{ playlist }</strong>.
</p>
<button
2021-12-06 10:35:20 +00:00
class="ui small basic cancel button"
@click="duplicateTrackAddConfirm(false)"
2021-12-06 10:35:20 +00:00
>
<translate translate-context="*/*/Button.Label/Verb">
Cancel
</translate>
</button>
<button
2020-05-15 12:12:36 +00:00
class="ui small success button"
2021-12-06 10:35:20 +00:00
@click="addToPlaylist(lastSelectedPlaylist, true)"
>
<translate translate-context="*/Playlist/Button.Label/Verb">
Add anyways
</translate>
</button>
</div>
2021-12-06 10:35:20 +00:00
<div
v-if="errors.length > 0"
role="alert"
class="ui negative message"
>
<h4 class="header">
<translate translate-context="Popup/Playlist/Error message.Title">
The track can't be added to a playlist
</translate>
</h4>
2018-03-20 22:41:15 +00:00
<ul class="list">
2021-12-06 10:35:20 +00:00
<li
v-for="(error, key) in errors"
:key="key"
>
{{ error }}
</li>
2018-03-20 22:41:15 +00:00
</ul>
</div>
2021-12-06 10:35:20 +00:00
<h4 class="ui header">
<translate translate-context="Popup/Playlist/Title">
Available playlists
</translate>
</h4>
<div class="ui form">
<div class="fields">
<div class="field">
<label for="playlist-name-filter"><translate translate-context="Popup/Playlist/Label">Filter</translate></label>
2021-12-06 10:35:20 +00:00
<input
id="playlist-name-filter"
v-model="playlistNameFilter"
type="text"
class="inline"
:placeholder="labels.filterPlaylistField"
>
</div>
</div>
</div>
2021-12-06 10:35:20 +00:00
<table
v-if="sortedPlaylists.length > 0"
class="ui unstackable very basic table"
>
2018-03-20 22:41:15 +00:00
<thead>
<tr>
2020-08-01 09:11:51 +00:00
<th><span class="visually-hidden"><translate translate-context="*/*/*/Verb">Edit</translate></span></th>
2021-12-06 10:35:20 +00:00
<th>
<translate translate-context="*/*/*/Noun">
Name
</translate>
</th>
<th class="sorted descending">
<translate translate-context="Popup/Playlist/Table.Label/Short">
Last modification
</translate>
</th>
<th>
<translate translate-context="*/*/*">
Tracks
</translate>
</th>
2018-03-20 22:41:15 +00:00
</tr>
</thead>
<tbody>
2021-12-06 10:35:20 +00:00
<tr
v-for="(playlist, key) in sortedPlaylists"
:key="key"
>
2018-03-20 22:41:15 +00:00
<td>
<router-link
class="ui icon basic small button"
2021-12-06 10:35:20 +00:00
:to="{name: 'library.playlists.detail', params: {id: playlist.id }, query: {mode: 'edit'}}"
>
<i class="ui pencil icon" />
<span class="visually-hidden"><translate translate-context="*/*/*/Verb">Edit</translate></span>
</router-link>
2018-03-20 22:41:15 +00:00
</td>
2020-08-01 09:11:51 +00:00
<td>
2021-12-06 10:35:20 +00:00
<router-link
:to="{name: 'library.playlists.detail', params: {id: playlist.id }}"
@click.native="update(false)"
>
{{ playlist.name }}
</router-link>
</td>
<td><human-date :date="playlist.modification_date" /></td>
2018-03-20 22:41:15 +00:00
<td>{{ playlist.tracks_count }}</td>
<td>
2020-08-11 12:07:06 +00:00
<button
2018-03-20 22:41:15 +00:00
v-if="track"
2020-05-15 12:12:36 +00:00
class="ui success icon basic small right floated button"
2018-07-01 19:50:50 +00:00
:title="labels.addToPlaylist"
2021-12-06 10:35:20 +00:00
@click.prevent="addToPlaylist(playlist.id, false)"
>
<i class="plus icon" /> <translate translate-context="Popup/Playlist/Table.Button.Label/Verb">
Add track
</translate>
2020-08-11 12:07:06 +00:00
</button>
2018-03-20 22:41:15 +00:00
</td>
</tr>
</tbody>
</table>
<template v-else>
2020-05-15 12:12:36 +00:00
<div class="ui small placeholder segment component-placeholder">
<h4 class="ui header">
2021-12-06 10:35:20 +00:00
<translate translate-context="Popup/Playlist/EmptyState">
No results matching your filter
</translate>
2021-12-06 10:35:20 +00:00
</h4>
</div>
</template>
</div>
2021-12-06 10:35:20 +00:00
<template v-else>
<div class="ui placeholder segment">
<div class="ui icon header">
<i class="list icon" />
<translate translate-context="Content/Home/Placeholder">
No playlists have been created yet
</translate>
</div>
</div>
</template>
2018-03-20 22:41:15 +00:00
</div>
<div class="actions">
2021-12-06 10:35:20 +00:00
<button class="ui basic cancel button">
<translate translate-context="*/*/Button.Label/Verb">
Cancel
</translate>
</button>
2018-03-20 22:41:15 +00:00
</div>
</modal>
</template>
<script>
import { filter, sortBy, flow } from 'lodash-es'
import axios from 'axios'
2021-12-06 10:35:20 +00:00
import { mapState } from 'vuex'
2022-04-23 07:37:43 +00:00
import Modal from '~/components/semantic/Modal.vue'
import PlaylistForm from '~/components/playlists/Form.vue'
2022-04-18 16:17:51 +00:00
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
import useLogger from '~/composables/useLogger'
const logger = useLogger()
export default {
components: {
Modal,
PlaylistForm
},
2022-04-18 16:17:51 +00:00
setup () {
const guard = () => {
this.$store.commit('playlists/showModal', false)
this.showDuplicateTrackAddConfirmation = false
}
onBeforeRouteUpdate(guard)
onBeforeRouteLeave(guard)
},
data () {
return {
formKey: String(new Date()),
errors: [],
playlistNameFilter: '',
duplicateTrackAddInfo: {},
showDuplicateTrackAddConfirmation: false,
2021-12-06 10:35:20 +00:00
lastSelectedPlaylist: -1
}
},
computed: {
...mapState({
2018-03-20 18:57:34 +00:00
playlists: state => state.playlists.playlists,
track: state => state.playlists.modalTrack
}),
2018-07-01 19:50:50 +00:00
labels () {
return {
addToPlaylist: this.$pgettext('Popup/Playlist/Table.Button.Tooltip/Verb', 'Add to this playlist'),
filterPlaylistField: this.$pgettext('Popup/Playlist/Form/Placeholder', 'Enter playlist name')
2018-07-01 19:50:50 +00:00
}
},
sortedPlaylists () {
2021-12-06 10:35:20 +00:00
const regexp = new RegExp(this.playlistNameFilter, 'i')
const p = flow(
filter((e) => e.name.match(regexp) !== null),
2021-12-06 10:35:20 +00:00
sortBy((e) => { return e.modification_date })
)(this.playlists)
p.reverse()
return p
}
2018-03-20 22:41:15 +00:00
},
watch: {
'$store.state.playlists.showModal' () {
this.formKey = String(new Date())
this.showDuplicateTrackAddConfirmation = false
2018-03-20 22:41:15 +00:00
}
2021-12-06 10:35:20 +00:00
},
methods: {
update (v) {
this.$store.commit('playlists/showModal', v)
},
addToPlaylist (playlistId, allowDuplicate) {
const self = this
const payload = {
tracks: [this.track.id],
allow_duplicates: allowDuplicate
}
self.lastSelectedPlaylist = playlistId
return axios.post(`playlists/${playlistId}/add`, payload).then(response => {
logger.info('Successfully added track to playlist')
2021-12-06 10:35:20 +00:00
self.update(false)
self.$store.dispatch('playlists/fetchOwn')
}, error => {
if (error.backendErrors.length === 1 && error.backendErrors[0].code === 'tracks_already_exist_in_playlist') {
self.duplicateTrackAddInfo = error.backendErrors[0]
self.showDuplicateTrackAddConfirmation = true
} else {
self.errors = error.backendErrors
self.showDuplicateTrackAddConfirmation = false
}
})
},
duplicateTrackAddConfirm (v) {
this.showDuplicateTrackAddConfirmation = v
}
}
}
</script>