Merge branch '750-do-not-display-empty-tables-headers' into 'develop'
Added placeholders across the application Closes #750 See merge request funkwhale/funkwhale!922
This commit is contained in:
commit
9ce24284d7
|
@ -0,0 +1 @@
|
|||
Placeholders will now be shown if no content is available across the application (#750)
|
|
@ -35,7 +35,14 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!isLoading && albums.length === 0">No results matching your query.</div>
|
||||
<template v-if="!isLoading && albums.length === 0">
|
||||
<div class="ui placeholder segment">
|
||||
<div class="ui icon header">
|
||||
<i class="compact disc icon"></i>
|
||||
No results matching your query
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<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 class="ui divided unstackable items">
|
||||
<div v-if="count > 0" class="ui divided unstackable items">
|
||||
<div :class="['item', itemClasses]" v-for="object in objects" :key="object.id">
|
||||
<div class="ui tiny image">
|
||||
<img v-if="object.track.album.cover.original" v-lazy="$store.getters['instance/absoluteUrl'](object.track.album.cover.medium_square_crop)">
|
||||
|
@ -51,6 +51,17 @@
|
|||
<div class="ui loader"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="ui placeholder segment">
|
||||
<div class="ui icon header">
|
||||
<i class="music icon"></i>
|
||||
<translate translate-context="Content/Home/Placeholder">
|
||||
Nothing found
|
||||
</translate>
|
||||
</div>
|
||||
<div v-if="isLoading" class="ui inverted active dimmer">
|
||||
<div class="ui loader"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
</h2>
|
||||
<radio-button v-if="hasFavorites" type="favorites"></radio-button>
|
||||
</section>
|
||||
<section class="ui vertical stripe segment">
|
||||
<section v-if="hasFavorites" class="ui vertical stripe segment">
|
||||
<div :class="['ui', {'loading': isLoading}, 'form']">
|
||||
<div class="fields">
|
||||
<div class="field">
|
||||
|
@ -46,7 +46,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<track-table v-if="results" :tracks="results.results"></track-table>
|
||||
<div class="ui center aligned basic segment">
|
||||
<pagination
|
||||
|
@ -58,6 +57,18 @@
|
|||
></pagination>
|
||||
</div>
|
||||
</section>
|
||||
<div v-else class="ui placeholder segment">
|
||||
<div class="ui icon header">
|
||||
<i class="broken heart icon"></i>
|
||||
<translate
|
||||
translate-context="Content/Home/Placeholder"
|
||||
>No tracks have been added to your favorites yet</translate>
|
||||
</div>
|
||||
<router-link :to="'/library'" class="ui green labeled icon button">
|
||||
<i class="headphones icon"></i>
|
||||
<translate translate-context="Content/*/Verb">Browse the library</translate>
|
||||
</router-link>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -59,6 +59,23 @@
|
|||
:key="album.id"
|
||||
:album="album"></album-card>
|
||||
</div>
|
||||
<div v-else class="ui placeholder segment sixteen wide column" style="text-align: center; display: flex; align-items: center">
|
||||
<div class="ui icon header">
|
||||
<i class="compact disc icon"></i>
|
||||
<translate translate-context="Content/Albums/Placeholder">
|
||||
No results matching your query
|
||||
</translate>
|
||||
</div>
|
||||
<router-link
|
||||
v-if="$store.state.auth.authenticated"
|
||||
:to="{name: 'content.index'}"
|
||||
class="ui green button labeled icon">
|
||||
<i class="upload icon"></i>
|
||||
<translate translate-context="Content/*/Verb">
|
||||
Add some music
|
||||
</translate>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui center aligned basic segment">
|
||||
<pagination
|
||||
|
|
|
@ -48,6 +48,23 @@
|
|||
</div>
|
||||
<artist-card :artist="artist" v-for="artist in result.results" :key="artist.id"></artist-card>
|
||||
</div>
|
||||
<div v-else-if="!isLoading" class="ui placeholder segment sixteen wide column" style="text-align: center; display: flex; align-items: center">
|
||||
<div class="ui icon header">
|
||||
<i class="compact disc icon"></i>
|
||||
<translate translate-context="Content/Artists/Placeholder">
|
||||
No results matching your query
|
||||
</translate>
|
||||
</div>
|
||||
<router-link
|
||||
v-if="$store.state.auth.authenticated"
|
||||
:to="{name: 'content.index'}"
|
||||
class="ui green button labeled icon">
|
||||
<i class="upload icon"></i>
|
||||
<translate translate-context="Content/*/Verb">
|
||||
Add some music
|
||||
</translate>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="ui center aligned basic segment">
|
||||
<pagination
|
||||
v-if="result && result.count > paginateBy"
|
||||
|
|
|
@ -60,6 +60,23 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="ui hidden divider"></div>
|
||||
<div v-if="result && !result.results.length > 0" class="ui placeholder segment">
|
||||
<div class="ui icon header">
|
||||
<i class="feed icon"></i>
|
||||
<translate translate-context="Content/Radios/Placeholder">
|
||||
No results matching your query
|
||||
</translate>
|
||||
</div>
|
||||
<router-link
|
||||
v-if="$store.state.auth.authenticated"
|
||||
:to="{name: 'library.radios.build'}"
|
||||
class="ui green button labeled icon">
|
||||
<i class="rss icon"></i>
|
||||
<translate translate-context="Content/*/Verb">
|
||||
Create a radio
|
||||
</translate>
|
||||
</router-link>
|
||||
</div>
|
||||
<div
|
||||
v-if="result"
|
||||
v-masonry
|
||||
|
@ -76,7 +93,7 @@
|
|||
v-for="radio in result.results"
|
||||
:key="radio.id"
|
||||
:custom-radio="radio"></radio-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui center aligned basic segment">
|
||||
<pagination
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div>
|
||||
<div v-if="result.count > 0">
|
||||
<div class="ui inline form">
|
||||
<div class="fields">
|
||||
<div class="ui field">
|
||||
|
@ -90,6 +90,12 @@
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="ui placeholder segment">
|
||||
<div class="ui icon header">
|
||||
<i class="server icon"></i>
|
||||
<translate translate-context="Content/Home/Placeholder">No interactions with other pods yet</translate>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
<template>
|
||||
<div class="ui placeholder segment">
|
||||
<div class="ui icon header">
|
||||
<i class="list icon"></i>
|
||||
<translate translate-context="Content/Home/Placeholder">
|
||||
No playlists have been created yet
|
||||
</translate>
|
||||
</div>
|
||||
<button
|
||||
@click="$store.commit('playlists/chooseTrack', null)"
|
||||
class="ui primary button"
|
||||
>
|
||||
<translate translate-context="Content/Home/CreatePlaylist">
|
||||
Create Playlist
|
||||
</translate>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
|
@ -38,6 +38,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="playlists.length > 0">
|
||||
<h4 class="ui header"><translate translate-context="Popup/Playlist/Title">Available playlists</translate></h4>
|
||||
<table class="ui unstackable very basic table">
|
||||
<thead>
|
||||
|
@ -72,6 +73,17 @@
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="ui placeholder segment">
|
||||
<div class="ui icon header">
|
||||
<i class="list icon"></i>
|
||||
<translate translate-context="Content/Home/Placeholder">
|
||||
No playlists have been created yet
|
||||
</translate>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
|
|
|
@ -12,9 +12,24 @@
|
|||
<template v-if="playlistsExist">
|
||||
<playlist-card v-for="playlist in objects" :key="playlist.id" :playlist="playlist"></playlist-card>
|
||||
</template>
|
||||
<template v-else>
|
||||
<placeholder-widget></placeholder-widget>
|
||||
</template>
|
||||
<div v-else class="ui placeholder segment">
|
||||
<div class="ui icon header">
|
||||
<i class="list icon"></i>
|
||||
<translate translate-context="Content/Home/Placeholder">
|
||||
No playlists have been created yet
|
||||
</translate>
|
||||
</div>
|
||||
<button
|
||||
v-if="$store.state.auth.authenticated"
|
||||
@click="$store.commit('playlists/chooseTrack', null)"
|
||||
class="ui green icon labeled button"
|
||||
>
|
||||
<i class="list icon"></i>
|
||||
<translate translate-context="Content/Home/CreatePlaylist">
|
||||
Create Playlist
|
||||
</translate>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -22,7 +37,6 @@
|
|||
import _ from '@/lodash'
|
||||
import axios from 'axios'
|
||||
import PlaylistCard from '@/components/playlists/Card'
|
||||
import PlaceholderWidget from '@/components/playlists/PlaceholderWidget'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
|
@ -30,8 +44,7 @@ export default {
|
|||
url: {type: String, required: true}
|
||||
},
|
||||
components: {
|
||||
PlaylistCard,
|
||||
PlaceholderWidget
|
||||
PlaylistCard
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
|
|
@ -3,34 +3,67 @@
|
|||
<div class="ui inline form">
|
||||
<div class="fields">
|
||||
<div class="ui six wide field">
|
||||
<label><translate translate-context="Content/Search/Input.Label/Noun">Search</translate></label>
|
||||
<label>
|
||||
<translate translate-context="Content/Search/Input.Label/Noun">Search</translate>
|
||||
</label>
|
||||
<form @submit.prevent="search.query = $refs.search.value">
|
||||
<input name="search" ref="search" type="text" :value="search.query" :placeholder="labels.searchPlaceholder" />
|
||||
<input
|
||||
name="search"
|
||||
ref="search"
|
||||
type="text"
|
||||
:value="search.query"
|
||||
:placeholder="labels.searchPlaceholder"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label><translate translate-context="Content/*/*/Noun">Import status</translate></label>
|
||||
<select class="ui dropdown" @change="addSearchToken('status', $event.target.value)" :value="getTokenValue('status', '')">
|
||||
<option value=""><translate translate-context="Content/*/Dropdown">All</translate></option>
|
||||
<option value="pending"><translate translate-context="Content/Library/*/Short">Pending</translate></option>
|
||||
<option value="skipped"><translate translate-context="Content/Library/*">Skipped</translate></option>
|
||||
<option value="errored"><translate translate-context="Content/Library/Dropdown">Failed</translate></option>
|
||||
<option value="finished"><translate translate-context="Content/Library/*">Finished</translate></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label><translate translate-context="Content/Search/Dropdown.Label/Noun">Ordering</translate></label>
|
||||
<select class="ui dropdown" v-model="ordering">
|
||||
<option v-for="option in orderingOptions" :value="option[0]">
|
||||
{{ sharedLabels.filters[option[1]] }}
|
||||
<label>
|
||||
<translate translate-context="Content/*/*/Noun">Import status</translate>
|
||||
</label>
|
||||
<select
|
||||
class="ui dropdown"
|
||||
@change="addSearchToken('status', $event.target.value)"
|
||||
:value="getTokenValue('status', '')"
|
||||
>
|
||||
<option value>
|
||||
<translate translate-context="Content/*/Dropdown">All</translate>
|
||||
</option>
|
||||
<option value="pending">
|
||||
<translate translate-context="Content/Library/*/Short">Pending</translate>
|
||||
</option>
|
||||
<option value="skipped">
|
||||
<translate translate-context="Content/Library/*">Skipped</translate>
|
||||
</option>
|
||||
<option value="errored">
|
||||
<translate translate-context="Content/Library/Dropdown">Failed</translate>
|
||||
</option>
|
||||
<option value="finished">
|
||||
<translate translate-context="Content/Library/*">Finished</translate>
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label><translate translate-context="Content/Search/Dropdown.Label/Noun">Ordering direction</translate></label>
|
||||
<label>
|
||||
<translate translate-context="Content/Search/Dropdown.Label/Noun">Ordering</translate>
|
||||
</label>
|
||||
<select class="ui dropdown" v-model="ordering">
|
||||
<option
|
||||
v-for="option in orderingOptions"
|
||||
:value="option[0]"
|
||||
>{{ sharedLabels.filters[option[1]] }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>
|
||||
<translate translate-context="Content/Search/Dropdown.Label/Noun">Ordering direction</translate>
|
||||
</label>
|
||||
<select class="ui dropdown" v-model="orderingDirection">
|
||||
<option value="+"><translate translate-context="Content/Search/Dropdown">Ascending</translate></option>
|
||||
<option value="-"><translate translate-context="Content/Search/Dropdown">Descending</translate></option>
|
||||
<option value="+">
|
||||
<translate translate-context="Content/Search/Dropdown">Ascending</translate>
|
||||
</option>
|
||||
<option value="-">
|
||||
<translate translate-context="Content/Search/Dropdown">Descending</translate>
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -38,10 +71,18 @@
|
|||
<import-status-modal :upload="detailedUpload" :show.sync="showUploadDetailModal" />
|
||||
<div class="dimmable">
|
||||
<div v-if="isLoading" class="ui active inverted dimmer">
|
||||
<div class="ui loader"></div>
|
||||
<div class="ui loader"></div>
|
||||
</div>
|
||||
<div v-else-if="!result && result.results.length === 0 && !needsRefresh" class="ui placeholder segment">
|
||||
<div class="ui icon header">
|
||||
<i class="upload icon"></i>
|
||||
<translate
|
||||
translate-context="Content/Home/Placeholder"
|
||||
>No tracks have been added to this library yet</translate>
|
||||
</div>
|
||||
</div>
|
||||
<action-table
|
||||
v-if="result"
|
||||
v-else
|
||||
@action-launched="fetchData"
|
||||
:id-field="'uuid'"
|
||||
:objects-data="result"
|
||||
|
@ -51,15 +92,30 @@
|
|||
:needs-refresh="needsRefresh"
|
||||
:action-url="'uploads/action/'"
|
||||
@refresh="fetchData"
|
||||
:filters="actionFilters">
|
||||
:filters="actionFilters"
|
||||
>
|
||||
<template slot="header-cells">
|
||||
<th><translate translate-context="*/*/*/Noun">Title</translate></th>
|
||||
<th><translate translate-context="*/*/*/Noun">Artist</translate></th>
|
||||
<th><translate translate-context="*/*/*">Album</translate></th>
|
||||
<th><translate translate-context="*/*/*/Noun">Upload date</translate></th>
|
||||
<th><translate translate-context="Content/*/*/Noun">Import status</translate></th>
|
||||
<th><translate translate-context="Content/*/*">Duration</translate></th>
|
||||
<th><translate translate-context="Content/*/*/Noun">Size</translate></th>
|
||||
<th>
|
||||
<translate translate-context="*/*/*/Noun">Title</translate>
|
||||
</th>
|
||||
<th>
|
||||
<translate translate-context="*/*/*/Noun">Artist</translate>
|
||||
</th>
|
||||
<th>
|
||||
<translate translate-context="*/*/*">Album</translate>
|
||||
</th>
|
||||
<th>
|
||||
<translate translate-context="*/*/*/Noun">Upload date</translate>
|
||||
</th>
|
||||
<th>
|
||||
<translate translate-context="Content/*/*/Noun">Import status</translate>
|
||||
</th>
|
||||
<th>
|
||||
<translate translate-context="Content/*/*">Duration</translate>
|
||||
</th>
|
||||
<th>
|
||||
<translate translate-context="Content/*/*/Noun">Size</translate>
|
||||
</th>
|
||||
</template>
|
||||
<template slot="row-cells" slot-scope="scope">
|
||||
<template v-if="scope.obj.track">
|
||||
|
@ -67,10 +123,18 @@
|
|||
<span :title="scope.obj.track.title">{{ scope.obj.track.title|truncate(25) }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="discrete link" @click="addSearchToken('artist', scope.obj.track.artist.name)" :title="scope.obj.track.artist.name">{{ scope.obj.track.artist.name|truncate(20) }}</span>
|
||||
<span
|
||||
class="discrete link"
|
||||
@click="addSearchToken('artist', scope.obj.track.artist.name)"
|
||||
:title="scope.obj.track.artist.name"
|
||||
>{{ scope.obj.track.artist.name|truncate(20) }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="discrete link" @click="addSearchToken('album', scope.obj.track.album.title)" :title="scope.obj.track.album.title">{{ scope.obj.track.album.title|truncate(20) }}</span>
|
||||
<span
|
||||
class="discrete link"
|
||||
@click="addSearchToken('album', scope.obj.track.album.title)"
|
||||
:title="scope.obj.track.album.title"
|
||||
>{{ scope.obj.track.album.title|truncate(20) }}</span>
|
||||
</td>
|
||||
</template>
|
||||
<template v-else>
|
||||
|
@ -82,22 +146,24 @@
|
|||
<human-date :date="scope.obj.creation_date"></human-date>
|
||||
</td>
|
||||
<td>
|
||||
<span class="discrete link" @click="addSearchToken('status', scope.obj.import_status)" :title="sharedLabels.fields.import_status.choices[scope.obj.import_status].help">
|
||||
{{ sharedLabels.fields.import_status.choices[scope.obj.import_status].label }}
|
||||
</span>
|
||||
<button class="ui tiny basic icon button" :title="sharedLabels.fields.import_status.detailTitle" @click="detailedUpload = scope.obj; showUploadDetailModal = true">
|
||||
<span
|
||||
class="discrete link"
|
||||
@click="addSearchToken('status', scope.obj.import_status)"
|
||||
:title="sharedLabels.fields.import_status.choices[scope.obj.import_status].help"
|
||||
>{{ sharedLabels.fields.import_status.choices[scope.obj.import_status].label }}</span>
|
||||
<button
|
||||
class="ui tiny basic icon button"
|
||||
:title="sharedLabels.fields.import_status.detailTitle"
|
||||
@click="detailedUpload = scope.obj; showUploadDetailModal = true"
|
||||
>
|
||||
<i class="question circle outline icon"></i>
|
||||
</button>
|
||||
</td>
|
||||
<td v-if="scope.obj.duration">
|
||||
{{ time.parse(scope.obj.duration) }}
|
||||
</td>
|
||||
<td v-if="scope.obj.duration">{{ time.parse(scope.obj.duration) }}</td>
|
||||
<td v-else>
|
||||
<translate translate-context="*/*/*">N/A</translate>
|
||||
</td>
|
||||
<td v-if="scope.obj.size">
|
||||
{{ scope.obj.size | humanSize }}
|
||||
</td>
|
||||
<td v-if="scope.obj.size">{{ scope.obj.size | humanSize }}</td>
|
||||
<td v-else>
|
||||
<translate translate-context="*/*/*">N/A</translate>
|
||||
</td>
|
||||
|
@ -112,44 +178,50 @@
|
|||
:current="page"
|
||||
:paginate-by="paginateBy"
|
||||
:total="result.count"
|
||||
></pagination>
|
||||
></pagination>
|
||||
|
||||
<span v-if="result && result.results.length > 0">
|
||||
<translate translate-context="Content/*/Paragraph"
|
||||
:translate-params="{start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}">
|
||||
Showing results %{ start }-%{ end } on %{ total }
|
||||
</translate>
|
||||
<translate
|
||||
translate-context="Content/*/Paragraph"
|
||||
:translate-params="{start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}"
|
||||
>Showing results %{ start }-%{ end } on %{ total }</translate>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import _ from '@/lodash'
|
||||
import time from '@/utils/time'
|
||||
import {normalizeQuery, parseTokens} from '@/search'
|
||||
import axios from "axios";
|
||||
import _ from "@/lodash";
|
||||
import time from "@/utils/time";
|
||||
import { normalizeQuery, parseTokens } from "@/search";
|
||||
|
||||
import Pagination from '@/components/Pagination'
|
||||
import ActionTable from '@/components/common/ActionTable'
|
||||
import OrderingMixin from '@/components/mixins/Ordering'
|
||||
import TranslationsMixin from '@/components/mixins/Translations'
|
||||
import SmartSearchMixin from '@/components/mixins/SmartSearch'
|
||||
import ImportStatusModal from '@/components/library/ImportStatusModal'
|
||||
import Pagination from "@/components/Pagination";
|
||||
import ActionTable from "@/components/common/ActionTable";
|
||||
import OrderingMixin from "@/components/mixins/Ordering";
|
||||
import TranslationsMixin from "@/components/mixins/Translations";
|
||||
import SmartSearchMixin from "@/components/mixins/SmartSearch";
|
||||
import ImportStatusModal from "@/components/library/ImportStatusModal";
|
||||
|
||||
export default {
|
||||
mixins: [OrderingMixin, TranslationsMixin, SmartSearchMixin],
|
||||
props: {
|
||||
filters: {type: Object, required: false},
|
||||
needsRefresh: {type: Boolean, required: false, default: false},
|
||||
customObjects: {type: Array, required: false, default: () => { return [] }}
|
||||
filters: { type: Object, required: false },
|
||||
needsRefresh: { type: Boolean, required: false, default: false },
|
||||
customObjects: {
|
||||
type: Array,
|
||||
required: false,
|
||||
default: () => {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
components: {
|
||||
Pagination,
|
||||
ActionTable,
|
||||
ImportStatusModal
|
||||
},
|
||||
data () {
|
||||
data() {
|
||||
return {
|
||||
time,
|
||||
detailedUpload: null,
|
||||
|
@ -162,100 +234,109 @@ export default {
|
|||
query: this.defaultQuery,
|
||||
tokens: parseTokens(normalizeQuery(this.defaultQuery))
|
||||
},
|
||||
orderingDirection: '-',
|
||||
ordering: 'creation_date',
|
||||
orderingDirection: "-",
|
||||
ordering: "creation_date",
|
||||
orderingOptions: [
|
||||
['creation_date', 'creation_date'],
|
||||
['title', 'track_title'],
|
||||
['size', 'size'],
|
||||
['duration', 'duration'],
|
||||
['bitrate', 'bitrate'],
|
||||
['album_title', 'album_title'],
|
||||
['artist_name', 'artist_name']
|
||||
["creation_date", "creation_date"],
|
||||
["title", "track_title"],
|
||||
["size", "size"],
|
||||
["duration", "duration"],
|
||||
["bitrate", "bitrate"],
|
||||
["album_title", "album_title"],
|
||||
["artist_name", "artist_name"]
|
||||
]
|
||||
}
|
||||
};
|
||||
},
|
||||
created () {
|
||||
this.fetchData()
|
||||
created() {
|
||||
this.fetchData();
|
||||
},
|
||||
methods: {
|
||||
fetchData () {
|
||||
this.$emit('fetch-start')
|
||||
let params = _.merge({
|
||||
'page': this.page,
|
||||
'page_size': this.paginateBy,
|
||||
'ordering': this.getOrderingAsString(),
|
||||
'q': this.search.query
|
||||
}, this.filters || {})
|
||||
let self = this
|
||||
self.isLoading = true
|
||||
self.checked = []
|
||||
axios.get('/uploads/', {params: params}).then((response) => {
|
||||
self.result = response.data
|
||||
self.isLoading = false
|
||||
}, error => {
|
||||
self.isLoading = false
|
||||
self.errors = error.backendErrors
|
||||
})
|
||||
},
|
||||
selectPage: function (page) {
|
||||
this.page = page
|
||||
fetchData() {
|
||||
this.$emit("fetch-start");
|
||||
let params = _.merge(
|
||||
{
|
||||
page: this.page,
|
||||
page_size: this.paginateBy,
|
||||
ordering: this.getOrderingAsString(),
|
||||
q: this.search.query
|
||||
},
|
||||
this.filters || {}
|
||||
);
|
||||
let self = this;
|
||||
self.isLoading = true;
|
||||
self.checked = [];
|
||||
axios.get("/uploads/", { params: params }).then(
|
||||
response => {
|
||||
self.result = response.data;
|
||||
self.isLoading = false;
|
||||
},
|
||||
error => {
|
||||
self.isLoading = false;
|
||||
self.errors = error.backendErrors;
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
labels () {
|
||||
labels() {
|
||||
return {
|
||||
searchPlaceholder: this.$pgettext('Content/Library/Input.Placeholder', 'Search by title, artist, album…'),
|
||||
}
|
||||
searchPlaceholder: this.$pgettext(
|
||||
"Content/Library/Input.Placeholder",
|
||||
"Search by title, artist, album…"
|
||||
)
|
||||
};
|
||||
},
|
||||
actionFilters () {
|
||||
actionFilters() {
|
||||
var currentFilters = {
|
||||
q: this.search.query
|
||||
}
|
||||
};
|
||||
if (this.filters) {
|
||||
return _.merge(currentFilters, this.filters)
|
||||
return _.merge(currentFilters, this.filters);
|
||||
} else {
|
||||
return currentFilters
|
||||
return currentFilters;
|
||||
}
|
||||
},
|
||||
actions () {
|
||||
let deleteMsg = this.$pgettext('*/*/*/Verb', 'Delete')
|
||||
let relaunchMsg = this.$pgettext('Content/Library/Dropdown/Verb', 'Restart import')
|
||||
actions() {
|
||||
let deleteMsg = this.$pgettext("*/*/*/Verb", "Delete");
|
||||
let relaunchMsg = this.$pgettext(
|
||||
"Content/Library/Dropdown/Verb",
|
||||
"Restart import"
|
||||
);
|
||||
return [
|
||||
{
|
||||
name: 'delete',
|
||||
name: "delete",
|
||||
label: deleteMsg,
|
||||
isDangerous: true,
|
||||
allowAll: true
|
||||
},
|
||||
{
|
||||
name: 'relaunch_import',
|
||||
name: "relaunch_import",
|
||||
label: relaunchMsg,
|
||||
isDangerous: true,
|
||||
allowAll: true,
|
||||
filterCheckable: f => {
|
||||
return f.import_status != 'finished'
|
||||
return f.import_status != "finished";
|
||||
}
|
||||
}
|
||||
]
|
||||
];
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
orderingDirection: function () {
|
||||
this.page = 1
|
||||
this.fetchData()
|
||||
orderingDirection: function() {
|
||||
this.page = 1;
|
||||
this.fetchData();
|
||||
},
|
||||
page: function () {
|
||||
this.fetchData()
|
||||
page: function() {
|
||||
this.fetchData();
|
||||
},
|
||||
ordering: function () {
|
||||
this.page = 1
|
||||
this.fetchData()
|
||||
ordering: function() {
|
||||
this.page = 1;
|
||||
this.fetchData();
|
||||
},
|
||||
search (newValue) {
|
||||
this.page = 1
|
||||
this.fetchData()
|
||||
search(newValue) {
|
||||
this.page = 1;
|
||||
this.fetchData();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -55,7 +55,6 @@
|
|||
<div class="content">
|
||||
<div class="description">
|
||||
<embed-wizard type="playlist" :id="playlist.id" />
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions">
|
||||
|
@ -64,7 +63,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</modal>
|
||||
|
||||
</section>
|
||||
<section class="ui vertical stripe segment">
|
||||
<template v-if="edit">
|
||||
|
@ -73,10 +71,20 @@
|
|||
@tracks-updated="updatePlts"
|
||||
:playlist="playlist" :playlist-tracks="playlistTracks"></playlist-editor>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-else-if="tracks.length > 0">
|
||||
<h2><translate translate-context="*/*/*">Tracks</translate></h2>
|
||||
<track-table :display-position="true" :tracks="tracks"></track-table>
|
||||
</template>
|
||||
<div v-else class="ui placeholder segment">
|
||||
<div class="ui icon header">
|
||||
<i class="list icon"></i>
|
||||
<translate translate-context="Content/Home/Placeholder">There are no tracks in this playlist yet</translate>
|
||||
</div>
|
||||
<button @click="edit = !edit" class="ui green icon labeled button">
|
||||
<i class="pencil icon"></i>
|
||||
<translate translate-context="Content/Home/CreatePlaylist">Edit</translate>
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</template>
|
||||
|
|
|
@ -40,7 +40,24 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="ui hidden divider"></div>
|
||||
<playlist-card-list v-if="result" :playlists="result.results"></playlist-card-list>
|
||||
<playlist-card-list v-if="result && result.results.length > 0" :playlists="result.results"></playlist-card-list>
|
||||
<div v-else-if="result && !result.results.length > 0" class="ui placeholder segment sixteen wide column" style="text-align: center; display: flex; align-items: center">
|
||||
<div class="ui icon header">
|
||||
<i class="list icon"></i>
|
||||
<translate translate-context="Content/Playlists/Placeholder">
|
||||
No results matching your query
|
||||
</translate>
|
||||
</div>
|
||||
<button
|
||||
v-if="$store.state.auth.authenticated"
|
||||
@click="$store.commit('playlists/chooseTrack', null)"
|
||||
class="ui green button labeled icon">
|
||||
<i class="list icon"></i>
|
||||
<translate translate-context="Content/*/Verb">
|
||||
Create a playlist
|
||||
</translate>
|
||||
</button>
|
||||
</div>
|
||||
<div class="ui center aligned basic segment">
|
||||
<pagination
|
||||
v-if="result && result.results.length > 0"
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
</template>
|
||||
</div>
|
||||
</section>
|
||||
<section class="ui vertical stripe segment">
|
||||
<section v-if="totalTracks > 0" class="ui vertical stripe segment">
|
||||
<h2><translate translate-context="*/*/*">Tracks</translate></h2>
|
||||
<track-table :tracks="tracks"></track-table>
|
||||
<div class="ui center aligned basic segment">
|
||||
|
@ -44,6 +44,21 @@
|
|||
></pagination>
|
||||
</div>
|
||||
</section>
|
||||
<div v-else-if="!isLoading && !totalTracks > 0" class="ui placeholder segment">
|
||||
<div class="ui icon header">
|
||||
<i class="rss icon"></i>
|
||||
<translate
|
||||
translate-context="Content/Radios/Placeholder"
|
||||
>No tracks have been added to this radio yet</translate>
|
||||
</div>
|
||||
<router-link
|
||||
v-if="$store.state.auth.username === radio.user.username"
|
||||
class="ui green icon labeled button"
|
||||
:to="{name: 'library.radios.edit', params: {id: radio.id}}" exact>
|
||||
<i class="pencil icon"></i>
|
||||
Edit…
|
||||
</router-link>
|
||||
</div>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
|
|
Loading…
Reference in New Issue