diff --git a/front/src/components/federation/LibraryCard.vue b/front/src/components/federation/LibraryCard.vue deleted file mode 100644 index 277606871cc383b4502724cc4e02f4cfa43f041a..0000000000000000000000000000000000000000 --- a/front/src/components/federation/LibraryCard.vue +++ /dev/null @@ -1,128 +0,0 @@ -<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> diff --git a/front/src/components/federation/LibraryFollowTable.vue b/front/src/components/federation/LibraryFollowTable.vue deleted file mode 100644 index a5dd08ced47936718c070570772209d4c42d8805..0000000000000000000000000000000000000000 --- a/front/src/components/federation/LibraryFollowTable.vue +++ /dev/null @@ -1,196 +0,0 @@ -<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> diff --git a/front/src/components/federation/LibraryForm.vue b/front/src/components/federation/LibraryForm.vue deleted file mode 100644 index 7039cb524b04330bcf5f913516d24726bb58c6c7..0000000000000000000000000000000000000000 --- a/front/src/components/federation/LibraryForm.vue +++ /dev/null @@ -1,123 +0,0 @@ -<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> </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> diff --git a/front/src/components/federation/LibraryTrackTable.vue b/front/src/components/federation/LibraryTrackTable.vue deleted file mode 100644 index b24e1109987c7b8b8149b9921f7ed098f0033078..0000000000000000000000000000000000000000 --- a/front/src/components/federation/LibraryTrackTable.vue +++ /dev/null @@ -1,228 +0,0 @@ -<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> diff --git a/front/src/router/index.js b/front/src/router/index.js index 489ca2242093b731b855057d2ae8f91ed5856626..148e45b8a2297c5404ce712f45b5804af4a86d77 100644 --- a/front/src/router/index.js +++ b/front/src/router/index.js @@ -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, diff --git a/front/src/views/federation/Base.vue b/front/src/views/federation/Base.vue deleted file mode 100644 index 75628d53e0995f93172f9b8eea99e4b606f9dfb0..0000000000000000000000000000000000000000 --- a/front/src/views/federation/Base.vue +++ /dev/null @@ -1,61 +0,0 @@ -<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> diff --git a/front/src/views/federation/LibraryDetail.vue b/front/src/views/federation/LibraryDetail.vue deleted file mode 100644 index 708156c1984857f601320c7cf8577371c562cf29..0000000000000000000000000000000000000000 --- a/front/src/views/federation/LibraryDetail.vue +++ /dev/null @@ -1,220 +0,0 @@ -<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> diff --git a/front/src/views/federation/LibraryFollowersList.vue b/front/src/views/federation/LibraryFollowersList.vue deleted file mode 100644 index 0a9267a85acdfa8b1e4d14d3b128fa6752118bfc..0000000000000000000000000000000000000000 --- a/front/src/views/federation/LibraryFollowersList.vue +++ /dev/null @@ -1,33 +0,0 @@ -<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> diff --git a/front/src/views/federation/LibraryList.vue b/front/src/views/federation/LibraryList.vue deleted file mode 100644 index d627d65f4f99de273cabc24bca80c89b205b1a82..0000000000000000000000000000000000000000 --- a/front/src/views/federation/LibraryList.vue +++ /dev/null @@ -1,183 +0,0 @@ -<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> diff --git a/front/src/views/federation/LibraryTrackList.vue b/front/src/views/federation/LibraryTrackList.vue deleted file mode 100644 index 55f9e46af49444c62b2733242ae5e44edad59055..0000000000000000000000000000000000000000 --- a/front/src/views/federation/LibraryTrackList.vue +++ /dev/null @@ -1,30 +0,0 @@ -<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> diff --git a/front/src/views/federation/Scan.vue b/front/src/views/federation/Scan.vue deleted file mode 100644 index 5caa2f5405b43a4194e9571edd22c2277a9adc36..0000000000000000000000000000000000000000 --- a/front/src/views/federation/Scan.vue +++ /dev/null @@ -1,39 +0,0 @@ -<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>