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

Removed dead library federation code

parent a865fcdc
No related branches found
No related tags found
No related merge requests found
<template>
<div class="ui card">
<div class="content">
<div class="header ellipsis">
<router-link
v-if="library"
:title="displayName"
:to="{name: 'federation.libraries.detail', params: {id: library.uuid }}">
{{ displayName }}
</router-link>
<span :title="displayName" v-else>{{ displayName }}</span>
</div>
</div>
<div class="content">
<span class="right floated" v-if="following">
<i class="check icon"></i><translate>Following</translate>
</span>
<span class="right floated" v-else-if="manuallyApprovesFollowers">
<i class="lock icon"></i><translate>Followers only</translate>
</span>
<span class="right floated" v-else>
<i class="open lock icon"></i><translate>Open</translate>
</span>
<span v-if="totalItems">
<i class="music icon"></i>
<translate
translate-plural="%{ count } tracks"
:translate-n="totalItems"
:translate-params="{count: totalItems}">
1 track
</translate>
</span>
</div>
<div class="extra content">
<template v-if="awaitingApproval">
<i class="clock icon"></i>
<translate>Follow request pending approval</translate>
</template>
<div
v-if="!library"
@click="follow"
:disabled="isLoading"
:class="['ui', 'basic', {loading: isLoading}, 'green', 'button']">
<translate v-if="manuallyApprovesFollowers">Send a follow request</translate>
<translate v-else>Follow</translate>
</div>
<router-link
v-else
class="ui basic button"
:to="{name: 'federation.libraries.detail', params: {id: library.uuid }}">
<translate>Detail</translate>
</router-link>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
props: ['libraryData', 'libraryInstance'],
data () {
return {
library: this.libraryInstance,
isLoading: false,
data: null,
errors: []
}
},
methods: {
follow () {
let params = {
'actor': this.libraryData['actor']['id'],
'autoimport': false,
'download_files': false,
'federation_enabled': true
}
let self = this
self.isLoading = true
axios.post('/federation/libraries/', params).then((response) => {
self.$emit('follow', {data: self.libraryData, library: response.data})
self.library = response.data
self.isLoading = false
}, error => {
self.isLoading = false
self.errors = error.backendErrors
})
}
},
computed: {
displayName () {
if (this.libraryData) {
return this.libraryData.display_name
} else {
return `${this.library.actor.preferred_username}@${this.library.actor.domain}`
}
},
manuallyApprovesFollowers () {
if (this.libraryData) {
return this.libraryData.actor.manuallyApprovesFollowers
} else {
return this.library.actor.manually_approves_followers
}
},
totalItems () {
if (this.libraryData) {
return this.libraryData.library.totalItems
} else {
return this.library.tracks_count
}
},
awaitingApproval () {
if (this.libraryData) {
return this.libraryData.local.awaiting_approval
} else {
return this.library.follow.approved === null
}
},
following () {
if (this.libraryData) {
return this.libraryData.local.following
} else {
return this.library.follow.approved
}
}
}
}
</script>
<template>
<div>
<div class="ui form">
<div class="fields">
<div class="ui six wide field">
<input type="text" v-model="search" :placeholder="labels.searchPlaceholder" />
</div>
<div class="ui four wide inline field">
<div class="ui checkbox">
<input v-model="pending" type="checkbox">
<label>
<translate>Pending approval</translate>
</label>
</div>
</div>
</div>
</div>
<div class="ui hidden divider"></div>
<table v-if="result" class="ui very basic single line unstackable table">
<thead>
<tr>
<th><translate>Actor</translate></th>
<th><translate>Creation date</translate></th>
<th><translate>Status</translate></th>
<th><translate>Actions</translate></th>
</tr>
</thead>
<tbody>
<tr v-for="follow in result.results">
<td>
{{ follow.actor.preferred_username }}@{{ follow.actor.domain }}
</td>
<td>
<human-date :date="follow.creation_date"></human-date>
</td>
<td>
<template v-if="follow.approved === true">
<i class="check icon"></i>
<translate>Approved</translate>
</template>
<template v-else-if="follow.approved === false">
<i class="x icon"></i>
<translate>Refused</translate>
</template>
<template v-else>
<i class="clock icon"></i>
<translate>Pending</translate>
</template>
</td>
<td>
<dangerous-button v-if="follow.approved !== false" class="tiny basic labeled icon" color='red' @confirm="updateFollow(follow, false)">
<i class="x icon"></i>
<translate>Deny</translate>
<p slot="modal-header">
<translate>Deny access?</translate>
</p>
<p slot="modal-content">
<translate
:translate-params="{username: follow.actor.preferred_username + '@' + follow.actor.domain}">
By confirming, %{ username } will be denied access to your library.
</translate>
</p>
<p slot="modal-confirm">
<translate>Deny</translate>
</p>
</dangerous-button>
<dangerous-button v-if="follow.approved !== true" class="tiny basic labeled icon" color='green' @confirm="updateFollow(follow, true)">
<i class="check icon"></i>
<translate>Approve</translate>
<p slot="modal-header">
<translate>Approve access?</translate>
</p>
<p slot="modal-content">
<translate
:translate-params="{username: follow.actor.preferred_username + '@' + follow.actor.domain}">
By confirming, %{ username } will be granted access to your library.
</translate>
<p slot="modal-confirm">
<translate>Approve</translate>
</p>
</dangerous-button>
</td>
</tr>
</tbody>
<tfoot class="full-width">
<tr>
<th>
<pagination
v-if="result && result.count > paginateBy"
@page-changed="selectPage"
:compact="true"
:current="page"
:paginate-by="paginateBy"
:total="result.count"
></pagination>
</th>
<th v-if="result && result.results.length > 0">
<translate
:translate-params="{start: ((page-1) * paginateBy) + 1, end: ((page-1) * paginateBy) + result.results.length, total: result.count}">
Showing results %{ start }-%{ end } on %{ total }
</translate>
</th>
<th></th>
<th></th>
</tr>
</tfoot>
</table>
</div>
</template>
<script>
import axios from 'axios'
import _ from 'lodash'
import Pagination from '@/components/Pagination'
export default {
props: {
filters: {type: Object, required: false, default: () => {}}
},
components: {
Pagination
},
data () {
return {
isLoading: false,
result: null,
page: 1,
paginateBy: 25,
search: '',
pending: false
}
},
created () {
this.fetchData()
},
computed: {
labels () {
return {
searchPlaceholder: this.$gettext('Search by username, domain...')
}
}
},
methods: {
fetchData () {
let params = _.merge({
'page': this.page,
'page_size': this.paginateBy,
'q': this.search
}, this.filters)
if (this.pending) {
params.pending = true
}
let self = this
self.isLoading = true
axios.get('/federation/libraries/followers/', {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
},
updateFollow (follow, approved) {
let payload = {
follow: follow.id,
approved: approved
}
let self = this
axios.patch('/federation/libraries/followers/', payload).then((response) => {
follow.approved = response.data.approved
self.isLoading = false
}, error => {
self.isLoading = false
self.errors = error.backendErrors
})
}
},
watch: {
search (newValue) {
if (newValue.length > 0) {
this.fetchData()
}
},
page () {
this.fetchData()
},
pending () {
this.fetchData()
}
}
}
</script>
<template>
<form class="ui form" @submit.prevent="fetchInstanceInfo">
<h3 class="ui header">
<translate>Federate with a new instance</translate>
</h3>
<p>
<translate>Use this form to scan an instance and setup federation.</translate>
</p>
<div v-if="errors.length > 0 || scanErrors.length > 0" class="ui negative message">
<div class="header">
<translate>Error while scanning library</translate>
</div>
<ul class="list">
<li v-for="error in errors">{{ error }}</li>
<li v-for="error in scanErrors">{{ error }}</li>
</ul>
</div>
<div class="ui two fields">
<div class="ui field">
<label>
<translate>Library name</translate>
</label>
<input v-model="libraryUsername" type="text" :placeholder="labels.namePlaceholder" />
</div>
<div class="ui field">
<label>&nbsp;</label>
<button
type="submit"
:disabled="isLoading"
:class="['ui', 'icon', {loading: isLoading}, 'button']">
<i class="search icon"></i>
<translate>Launch scan</translate>
</button>
</div>
</div>
</form>
</template>
<script>
import axios from 'axios'
import TrackTable from '@/components/audio/track/Table'
import RadioButton from '@/components/radios/Button'
import Pagination from '@/components/Pagination'
export default {
components: {
TrackTable,
RadioButton,
Pagination
},
data () {
return {
isLoading: false,
libraryUsername: '',
result: null,
errors: []
}
},
methods: {
follow () {
let params = {
'actor': this.result['actor']['id'],
'autoimport': false,
'download_files': false,
'federation_enabled': true
}
let self = this
self.isFollowing = false
axios.post('/federation/libraries/', params).then((response) => {
self.$emit('follow', {data: self.result, library: response.data})
self.result = response.data
self.isFollowing = false
}, error => {
self.isFollowing = false
self.errors = error.backendErrors
})
},
fetchInstanceInfo () {
let self = this
this.isLoading = true
self.errors = []
self.result = null
axios.get('/federation/libraries/fetch/', {params: {account: this.libraryUsername.trim()}}).then((response) => {
self.result = response.data
self.result.display_name = self.libraryUsername
self.isLoading = false
}, error => {
self.isLoading = false
self.errors = error.backendErrors
})
}
},
computed: {
labels () {
return {
namePlaceholder: this.$gettext('library@demo.funkwhale.audio')
}
},
scanErrors () {
let errors = []
if (!this.result) {
return errors
}
let keys = ['webfinger', 'actor', 'library']
keys.forEach(k => {
if (this.result[k]) {
if (this.result[k].errors) {
this.result[k].errors.forEach(e => {
errors.push(e)
})
}
}
})
return errors
}
},
watch: {
result (newValue, oldValue) {
this.$emit('scanned', newValue)
}
}
}
</script>
<template>
<div>
<div class="ui inline form">
<div class="fields">
<div class="ui six wide field">
<label><translate>Search</translate></label>
<input type="text" v-model="search" :placeholder="labels.searchPlaceholder" />
</div>
<div class="ui field">
<label><translate>Import status</translate></label>
<select class="ui dropdown" v-model="importedFilter">
<option :value="null"><translate>Any</translate></option>
<option :value="'imported'"><translate>Imported</translate></option>
<option :value="'not_imported'"><translate>Not imported</translate></option>
<option :value="'import_pending'"><translate>Import pending</translate></option>
</select>
</div>
<div class="field">
<label><translate>Ordering</translate></label>
<select class="ui dropdown" v-model="ordering">
<option v-for="option in orderingOptions" :value="option[0]">
{{ option[1] }}
</option>
</select>
</div>
<div class="field">
<label><translate>Ordering direction</translate></label>
<select class="ui dropdown" v-model="orderingDirection">
<option value="+"><translate>Ascending</translate></option>
<option value="-"><translate>Descending</translate></option>
</select>
</div>
</div>
</div>
<div class="dimmable">
<div v-if="isLoading" class="ui active inverted dimmer">
<div class="ui loader"></div>
</div>
<action-table
v-if="result"
@action-launched="fetchData"
:objects-data="result"
:actions="actions"
:action-url="'federation/library-tracks/action/'"
:filters="actionFilters">
<template slot="header-cells">
<th><translate>Status</translate></th>
<th><translate>Title</translate></th>
<th><translate>Artist</translate></th>
<th><translate>Album</translate></th>
<th><translate>Published date</translate></th>
<th v-if="showLibrary"><translate>Library</translate></th>
</template>
<template slot="action-success-footer" slot-scope="scope">
<router-link
v-if="scope.result.action === 'import'"
:to="{name: 'library.import.batches.detail', params: {id: scope.result.result.batch.id }}">
<translate
:translate-params="{id: scope.result.result.batch.id}">
Import #%{ id } launched
</translate>
</router-link>
</template>
<template slot="row-cells" slot-scope="scope">
<td>
<span v-if="scope.obj.status === 'imported'" class="ui basic green label"><translate>In library</translate></span>
<span v-else-if="scope.obj.status === 'import_pending'" class="ui basic yellow label"><translate>Import pending</translate></span>
<span v-else class="ui basic label"><translate>Not imported</translate></span>
</td>
<td>
<span :title="scope.obj.title">{{ scope.obj.title|truncate(30) }}</span>
</td>
<td>
<span class="discrete link" @click="updateSearch({key: 'artist', value: scope.obj.artist_name})" :title="scope.obj.artist_name">{{ scope.obj.artist_name|truncate(30) }}</span>
</td>
<td>
<span class="discrete link" @click="updateSearch({key: 'album', value: scope.obj.album_title})" :title="scope.obj.album_title">{{ scope.obj.album_title|truncate(20) }}</span>
</td>
<td>
<human-date :date="scope.obj.published_date"></human-date>
</td>
<td v-if="showLibrary">
<span class="discrete link" @click="updateSearch({key: 'domain', value: scope.obj.library.actor.domain})">{{ scope.obj.library.actor.domain }}</span>
</td>
</template>
</action-table>
</div>
<div>
<pagination
v-if="result && result.count > paginateBy"
@page-changed="selectPage"
:compact="true"
:current="page"
:paginate-by="paginateBy"
:total="result.count"
></pagination>
<span v-if="result && result.results.length > 0">
<translate
: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 Pagination from '@/components/Pagination'
import ActionTable from '@/components/common/ActionTable'
import OrderingMixin from '@/components/mixins/Ordering'
export default {
mixins: [OrderingMixin],
props: {
filters: {type: Object, required: false},
showLibrary: {type: Boolean, default: false}
},
components: {
Pagination,
ActionTable
},
data () {
return {
isLoading: false,
result: null,
page: 1,
paginateBy: 25,
search: '',
importedFilter: null,
orderingDirection: '-',
ordering: 'published_date',
orderingOptions: [
['published_date', 'Published date'],
['title', 'Title'],
['album_title', 'Album title'],
['artist_name', 'Artist name']
]
}
},
created () {
this.fetchData()
},
methods: {
updateSearch ({key, value}) {
if (value.indexOf(' ') > -1) {
value = `"${value}"`
}
this.search = `${key}:${value}`
},
fetchData () {
let params = _.merge({
'page': this.page,
'page_size': this.paginateBy,
'ordering': this.getOrderingAsString(),
'q': this.search
}, this.filters)
if (this.importedFilter !== null) {
params.status = this.importedFilter
}
let self = this
self.isLoading = true
self.checked = []
axios.get('/federation/library-tracks/', {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
}
},
computed: {
labels () {
return {
searchPlaceholder: this.$gettext('Search by title, artist, domain...')
}
},
actionFilters () {
var currentFilters = {
q: this.search
}
if (this.filters) {
return _.merge(currentFilters, this.filters)
} else {
return currentFilters
}
},
actions () {
let msg = this.$gettext('Import')
return [
{
name: 'import',
label: msg,
filterCheckable: (obj) => { return obj.status === 'not_imported' }
}
]
}
},
watch: {
orderingDirection: function () {
this.page = 1
this.fetchData()
},
ordering: function () {
this.page = 1
this.fetchData()
},
search (newValue) {
this.page = 1
this.fetchData()
},
page () {
this.fetchData()
},
importedFilter () {
this.page = 1
this.fetchData()
}
}
}
</script>
......@@ -31,12 +31,6 @@ import AdminUsersBase from '@/views/admin/users/Base'
import AdminUsersDetail from '@/views/admin/users/UsersDetail'
import AdminUsersList from '@/views/admin/users/UsersList'
import AdminInvitationsList from '@/views/admin/users/InvitationsList'
import FederationBase from '@/views/federation/Base'
import FederationScan from '@/views/federation/Scan'
import FederationLibraryDetail from '@/views/federation/LibraryDetail'
import FederationLibraryList from '@/views/federation/LibraryList'
import FederationTrackList from '@/views/federation/LibraryTrackList'
import FederationFollowersList from '@/views/federation/LibraryFollowersList'
import ContentBase from '@/views/content/Base'
import ContentHome from '@/views/content/Home'
import LibrariesHome from '@/views/content/libraries/Home'
......@@ -203,50 +197,6 @@ export default new Router({
name: 'manage.settings',
component: AdminSettings
},
{
path: '/manage/federation',
component: FederationBase,
children: [
{
path: 'scan',
name: 'federation.libraries.scan',
component: FederationScan },
{
path: 'libraries',
name: 'federation.libraries.list',
component: FederationLibraryList,
props: (route) => ({
defaultOrdering: route.query.ordering,
defaultQuery: route.query.query,
defaultPaginateBy: route.query.paginateBy,
defaultPage: route.query.page
})
},
{
path: 'tracks',
name: 'federation.tracks.list',
component: FederationTrackList,
props: (route) => ({
defaultOrdering: route.query.ordering,
defaultQuery: route.query.query,
defaultPaginateBy: route.query.paginateBy,
defaultPage: route.query.page
})
},
{
path: 'followers',
name: 'federation.followers.list',
component: FederationFollowersList,
props: (route) => ({
defaultOrdering: route.query.ordering,
defaultQuery: route.query.query,
defaultPaginateBy: route.query.paginateBy,
defaultPage: route.query.page
})
},
{ path: 'libraries/:id', name: 'federation.libraries.detail', component: FederationLibraryDetail, props: true }
]
},
{
path: '/manage/library',
component: AdminLibraryBase,
......
<template>
<div class="main pusher" v-title="labels.title">
<div class="ui secondary pointing menu">
<router-link
class="ui item"
:to="{name: 'federation.libraries.list'}"><translate>Libraries</translate></router-link>
<router-link
class="ui item"
:to="{name: 'federation.tracks.list'}"><translate>Tracks</translate></router-link>
<div class="ui secondary right menu">
<router-link
class="ui item"
:to="{name: 'federation.followers.list'}">
<translate>Followers</translate>
<div class="ui teal label" :title="labels.pendingRequests">{{ requestsCount }}</div>
</router-link>
</div>
</div>
<router-view :key="$route.fullPath"></router-view>
</div>
</template>
<script>
import axios from 'axios'
export default {
data () {
return {
requestsCount: 0
}
},
created () {
this.fetchRequestsCount()
},
computed: {
labels () {
let title = this.$gettext('Federation')
let pendingRequests = this.$gettext('Pending requests')
return {
title,
pendingRequests
}
}
},
methods: {
fetchRequestsCount () {
let self = this
axios.get('federation/libraries/followers/', {params: {pending: true}}).then(response => {
self.requestsCount = response.data.count
})
}
}
}
</script>
<style scoped>
.ui.menu .item > .label {
position: absolute;
right: -2em;
}
</style>
<template>
<div>
<div v-if="isLoading" class="ui vertical segment" v-title="labels.title">
<div :class="['ui', 'centered', 'active', 'inline', 'loader']"></div>
</div>
<template v-if="object">
<div :class="['ui', 'head', 'vertical', 'center', 'aligned', 'stripe', 'segment']" v-title="libraryUsername">
<div class="segment-content">
<h2 class="ui center aligned icon header">
<i class="circular inverted cloud olive icon"></i>
<div class="content">
{{ libraryUsername }}
</div>
</h2>
</div>
<div class="ui hidden divider"></div>
<div class="ui one column centered grid">
<table class="ui collapsing very basic table">
<tbody>
<tr>
<td >
<translate>Follow status</translate>
<span :data-tooltip="labels.statusTooltip"><i class="question circle icon"></i></span>
</td>
<td>
<template v-if="object.follow.approved === null">
<i class="loading icon"></i> <translate>Pending approval</translate>
</template>
<template v-else-if="object.follow.approved === true">
<i class="check icon"></i> <translate>Following</translate>
</template>
<template v-else-if="object.follow.approved === false">
<i class="x icon"></i> <translate>Not following</translate>
</template>
</td>
<td>
</td>
</tr>
<tr>
<td>
<translate>Federation</translate>
<span :data-tooltip="labels.federationTooltip"><i class="question circle icon"></i></span>
</td>
<td>
<div class="ui toggle checkbox">
<input
@change="update('federation_enabled')"
v-model="object.federation_enabled" type="checkbox">
<label></label>
</div>
</td>
<td>
</td>
</tr>
<tr>
<td>
<translate>Auto importing</translate>
<span :data-tooltip="labels.autoImportTooltip"><i class="question circle icon"></i></span>
</td>
<td>
<div class="ui toggle checkbox">
<input
@change="update('autoimport')"
v-model="object.autoimport" type="checkbox">
<label></label>
</div>
</td>
<td></td>
</tr>
<!-- Disabled until properly implemented on the backend
<tr>
<td><translate>File mirroring</translate></td>
<td>
<div class="ui toggle checkbox">
<input
@change="update('download_files')"
v-model="object.download_files" type="checkbox">
<label></label>
</div>
</td>
<td></td>
</tr>
-->
<tr>
<td><translate>Library size</translate></td>
<td>
<template v-if="object.tracks_count">
<translate
translate-plural="%{ count } tracks"
:translate-n="object.tracks_count"
:translate-params="{count: object.tracks_count}">
%{ count } track
</translate>
</template>
<template v-else>
<translate>Unknown</translate>
</template>
</td>
<td></td>
</tr>
<tr>
<td><translate>Last fetched</translate></td>
<td>
<human-date v-if="object.fetched_date" :date="object.fetched_date"></human-date>
<template v-else>Never</template>
<button
@click="scan"
v-if="!scanTrigerred"
:class="['ui', 'basic', {loading: isScanLoading}, 'button']">
<i class="sync icon"></i> <translate>Trigger scan</translate>
</button>
<button v-else class="ui success button">
<i class="check icon"></i> <translate>Scan triggered!</translate>
</button>
</td>
<td></td>
</tr>
</tbody>
</table>
</div>
<div class="ui hidden divider"></div>
<button @click="fetchData" class="ui basic button"><translate>Refresh</translate></button>
</div>
<div class="ui vertical stripe segment">
<h2><translate>Tracks available in this library</translate></h2>
<library-track-table v-if="!isLoading" :filters="{library: id}"></library-track-table>
</div>
</template>
</div>
</template>
<script>
import axios from 'axios'
import logger from '@/logging'
import LibraryTrackTable from '@/components/federation/LibraryTrackTable'
export default {
props: ['id'],
components: {
LibraryTrackTable
},
data () {
return {
isLoading: true,
isScanLoading: false,
object: null,
scanTrigerred: false
}
},
created () {
this.fetchData()
},
methods: {
fetchData () {
var self = this
this.scanTrigerred = false
this.isLoading = true
let url = 'federation/libraries/' + this.id + '/'
logger.default.debug('Fetching library "' + this.id + '"')
axios.get(url).then((response) => {
self.object = response.data
self.isLoading = false
})
},
scan (until) {
var self = this
this.isScanLoading = true
let data = {}
let url = 'federation/libraries/' + this.id + '/scan/'
logger.default.debug('Triggering scan for library "' + this.id + '"')
axios.post(url, data).then((response) => {
self.scanTrigerred = true
logger.default.debug('Scan triggered with id', response.data)
self.isScanLoading = false
})
},
update (attr) {
let newValue = this.object[attr]
let params = {}
let self = this
params[attr] = newValue
axios.patch('federation/libraries/' + this.id + '/', params).then((response) => {
logger.default.info(`${attr} was updated succcessfully to ${newValue}`)
}, (error) => {
logger.default.error(`Error while setting ${attr} to ${newValue}`, error)
self.object[attr] = !newValue
})
}
},
computed: {
labels () {
let title = this.$gettext('Library')
let statusTooltip = this.$gettext('This indicate if the remote library granted you access')
let federationTooltip = this.$gettext('Use this flag to enable/disable federation with this library')
let autoImportTooltip = this.$gettext('When enabled, auto importing will automatically import new tracks published in this library')
return {
title,
statusTooltip,
federationTooltip,
autoImportTooltip
}
},
libraryUsername () {
let actor = this.object.actor
return `${actor.preferred_username}@${actor.domain}`
}
},
watch: {
id () {
this.fetchData()
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
<template>
<div v-title="labels.title">
<div class="ui vertical stripe segment">
<h2 class="ui header"><translate>Browsing followers</translate></h2>
<p>
<translate>Be careful when accepting follow requests, as it means the follower will have access to your entire library.</translate>
</p>
<div class="ui hidden divider"></div>
<library-follow-table></library-follow-table>
</div>
</div>
</template>
<script>
import LibraryFollowTable from '@/components/federation/LibraryFollowTable'
export default {
components: {
LibraryFollowTable
},
computed: {
labels () {
return {
title: this.$gettext('Followers')
}
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
<template>
<div v-title="labels.title">
<div class="ui vertical stripe segment">
<h2 class="ui header"><translate>Browsing libraries</translate></h2>
<router-link
class="ui basic green button"
:to="{name: 'federation.libraries.scan'}">
<i class="plus icon"></i>
<translate>Add a new library</translate>
</router-link>
<div class="ui hidden divider"></div>
<div :class="['ui', {'loading': isLoading}, 'form']">
<div class="fields">
<div class="field">
<label><translate>Search</translate></label>
<input class="search" type="text" v-model="query" :placeholder="labels.searchPlaceholder"/>
</div>
<div class="field">
<label><translate>Ordering</translate></label>
<select class="ui dropdown" v-model="ordering">
<option v-for="option in orderingOptions" :value="option[0]">
{{ option[1] }}
</option>
</select>
</div>
<div class="field">
<label><translate>Ordering direction</translate></label>
<select class="ui dropdown" v-model="orderingDirection">
<option value="+"><translate>Ascending</translate></option>
<option value="-"><translate>Descending</translate></option>
</select>
</div>
<div class="field">
<label><translate>Results per page</translate></label>
<select class="ui dropdown" v-model="paginateBy">
<option :value="parseInt(12)">12</option>
<option :value="parseInt(25)">25</option>
<option :value="parseInt(50)">50</option>
</select>
</div>
</div>
</div>
<div class="ui hidden divider"></div>
<div
v-if="result"
v-masonry
transition-duration="0"
item-selector=".column"
percent-position="true"
stagger="0"
class="ui stackable three column doubling grid">
<div
v-masonry-tile
v-if="result.results.length > 0"
v-for="library in result.results"
:key="library.id"
class="column">
<library-card class="fluid" :library-instance="library"></library-card>
</div>
</div>
<div class="ui center aligned basic segment">
<pagination
v-if="result && result.results.length > 0"
@page-changed="selectPage"
:current="page"
:paginate-by="paginateBy"
:total="result.count"
></pagination>
</div>
</div>
</div>
</template>
<script>
import axios from 'axios'
import _ from 'lodash'
import $ from 'jquery'
import logger from '@/logging'
import OrderingMixin from '@/components/mixins/Ordering'
import PaginationMixin from '@/components/mixins/Pagination'
import LibraryCard from '@/components/federation/LibraryCard'
import Pagination from '@/components/Pagination'
const FETCH_URL = 'federation/libraries/'
export default {
mixins: [OrderingMixin, PaginationMixin],
props: {
defaultQuery: {type: String, required: false, default: ''}
},
components: {
LibraryCard,
Pagination
},
data () {
let defaultOrdering = this.getOrderingFromString(this.defaultOrdering || '-creation_date')
return {
isLoading: true,
result: null,
page: parseInt(this.defaultPage),
query: this.defaultQuery,
paginateBy: parseInt(this.defaultPaginateBy || 50),
orderingDirection: defaultOrdering.direction || '+',
ordering: defaultOrdering.field,
orderingOptions: [
['creation_date', 'Creation date'],
['tracks_count', 'Available tracks']
]
}
},
created () {
this.fetchData()
},
mounted () {
$('.ui.dropdown').dropdown()
$(this.$el).find('.field .search').focus()
},
computed: {
labels () {
let searchPlaceholder = this.$gettext('Enter a library domain name...')
let title = this.$gettext('Libraries')
return {
searchPlaceholder,
title
}
}
},
methods: {
updateQueryString: _.debounce(function () {
this.$router.replace({
query: {
query: this.query,
page: this.page,
paginateBy: this.paginateBy,
ordering: this.getOrderingAsString()
}
})
}, 500),
fetchData: _.debounce(function () {
var self = this
this.isLoading = true
let url = FETCH_URL
let params = {
page: this.page,
q: this.query,
ordering: this.getOrderingAsString()
}
logger.default.debug('Fetching libraries')
axios.get(url, {params: params}).then((response) => {
self.result = response.data
self.isLoading = false
})
}, 500),
selectPage: function (page) {
this.page = page
}
},
watch: {
page () {
this.updateQueryString()
this.fetchData()
},
ordering () {
this.updateQueryString()
this.fetchData()
},
orderingDirection () {
this.updateQueryString()
this.fetchData()
},
query () {
this.updateQueryString()
this.fetchData()
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
<template>
<div v-title="labels.title">
<div class="ui vertical stripe segment">
<h2 class="ui header"><translate>Browsing federated tracks</translate></h2>
<div class="ui hidden divider"></div>
<library-track-table :show-library="true"></library-track-table>
</div>
</div>
</template>
<script>
import LibraryTrackTable from '@/components/federation/LibraryTrackTable'
export default {
components: {
LibraryTrackTable
},
computed: {
labels () {
return {
title: this.$gettext('Federated tracks')
}
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>
<template>
<div>
<div class="ui vertical stripe segment">
<library-form @scanned="updateLibraryData"></library-form>
<library-card v-if="libraryData" :library-data="libraryData"></library-card>
</div>
<div class="ui vertical stripe segment">
</div>
</div>
</template>
<script>
// import axios from 'axios'
import TrackTable from '@/components/audio/track/Table'
import RadioButton from '@/components/radios/Button'
import Pagination from '@/components/Pagination'
import LibraryForm from '@/components/federation/LibraryForm'
import LibraryCard from '@/components/federation/LibraryCard'
export default {
components: {
TrackTable,
RadioButton,
Pagination,
LibraryForm,
LibraryCard
},
data () {
return {
libraryData: null
}
},
methods: {
updateLibraryData (data) {
this.libraryData = data
}
}
}
</script>
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