From f3e21937824d0db1d19684f4cc9d18574e638417 Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Sat, 23 Jun 2018 07:24:34 +0200 Subject: [PATCH 1/4] See #327: can now use the front-end with any API server --- front/src/App.vue | 127 +++++++++++++++++++++++++----------- front/src/main.js | 4 -- front/src/store/index.js | 2 +- front/src/store/instance.js | 38 +++++++++++ 4 files changed, 128 insertions(+), 43 deletions(-) diff --git a/front/src/App.vue b/front/src/App.vue index 2eb673ab4..73e46328a 100644 --- a/front/src/App.vue +++ b/front/src/App.vue @@ -1,44 +1,65 @@ @@ -63,17 +84,22 @@ export default { }, data () { return { - nodeinfo: null + nodeinfo: null, + instanceUrl: null } }, created () { - this.$store.dispatch('instance/fetchSettings') let self = this setInterval(() => { // used to redraw ago dates every minute self.$store.commit('ui/computeLastDate') }, 1000 * 60) - this.fetchNodeInfo() + if (this.$store.state.instance.instanceUrl) { + this.$store.commit('instance/instanceUrl', this.$store.state.instance.instanceUrl) + this.$store.dispatch('auth/check') + this.$store.dispatch('instance/fetchSettings') + this.fetchNodeInfo() + } }, methods: { fetchNodeInfo () { @@ -81,18 +107,38 @@ export default { axios.get('instance/nodeinfo/2.0/').then(response => { self.nodeinfo = response.data }) + }, + switchInstance () { + let confirm = window.confirm(this.$t('This will erase your local data and disconnect you, do you want to continue?')) + if (confirm) { + this.$store.commit('instance/instanceUrl', null) + } } }, computed: { ...mapState({ messages: state => state.ui.messages }), + suggestedInstances () { + let rootUrl = ( + window.location.protocol + '//' + window.location.hostname + + (window.location.port ? ':' + window.location.port : '') + ) + let instances = [rootUrl, 'https://demo.funkwhale.audio'] + return instances + }, version () { if (!this.nodeinfo) { return null } return _.get(this.nodeinfo, 'software.version') } + }, + watch: { + '$store.state.instance.instanceUrl' () { + this.$store.dispatch('instance/fetchSettings') + this.fetchNodeInfo() + } } } @@ -116,6 +162,11 @@ html, body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } + +.instance-chooser { + margin-top: 2em; +} + .main.pusher, .footer { @include media(">desktop") { margin-left: 350px !important; @@ -173,7 +224,7 @@ html, body { .ui.icon.header .circular.icon { display: flex; justify-content: center; - + } .segment-content .button{ diff --git a/front/src/main.js b/front/src/main.js index 7973e4bb7..181fd66b3 100644 --- a/front/src/main.js +++ b/front/src/main.js @@ -15,7 +15,6 @@ import i18next from 'i18next' import i18nextFetch from 'i18next-fetch-backend' import VueI18Next from '@panter/vue-i18next' import store from './store' -import config from './config' import { sync } from 'vuex-router-sync' import filters from '@/filters' // eslint-disable-line import globals from '@/components/globals' // eslint-disable-line @@ -56,8 +55,6 @@ Vue.directive('title', { document.title = parts.join(' - ') } }) - -axios.defaults.baseURL = config.API_URL axios.interceptors.request.use(function (config) { // Do something before request is sent if (store.state.auth.token) { @@ -104,7 +101,6 @@ axios.interceptors.response.use(function (response) { // Do something with response error return Promise.reject(error) }) -store.dispatch('auth/check') // i18n i18next diff --git a/front/src/store/index.js b/front/src/store/index.js index 298fa04ec..0c2908d83 100644 --- a/front/src/store/index.js +++ b/front/src/store/index.js @@ -34,7 +34,7 @@ export default new Vuex.Store({ }), createPersistedState({ key: 'instance', - paths: ['instance.events'] + paths: ['instance.events', 'instance.instanceUrl'] }), createPersistedState({ key: 'radios', diff --git a/front/src/store/instance.js b/front/src/store/instance.js index e78e80489..555bd8239 100644 --- a/front/src/store/instance.js +++ b/front/src/store/instance.js @@ -6,6 +6,7 @@ export default { namespaced: true, state: { maxEvents: 200, + instanceUrl: process.env.INSTANCE_URL, events: [], settings: { instance: { @@ -51,9 +52,46 @@ export default { }, events: (state, value) => { state.events = value + }, + instanceUrl: (state, value) => { + state.instanceUrl = value + if (!value) { + axios.defaults.baseURL = null + return + } + let apiUrl + let suffix = 'api/v1/' + if (state.instanceUrl.endsWith('/')) { + apiUrl = state.instanceUrl + suffix + } else { + apiUrl = state.instanceUrl + '/' + suffix + } + axios.defaults.baseURL = apiUrl + } + }, + getters: { + absoluteUrl: (state) => (relativeUrl) => { + if (relativeUrl.startsWith('http')) { + return relativeUrl + } + return state.instanceUrl + relativeUrl } }, actions: { + setUrl ({commit, dispatch}, url) { + commit('instanceUrl', url) + let modules = [ + 'auth', + 'favorites', + 'player', + 'playlists', + 'queue', + 'radios' + ] + modules.forEach(m => { + commit(`${m}/reset`, null, {root: true}) + }) + }, // Send a request to the login URL and save the returned JWT fetchSettings ({commit}, payload) { return axios.get('instance/settings/').then(response => { From 2e3a2cd6dd0c25f0b069f9b4b64d212203cb24f1 Mon Sep 17 00:00:00 2001 From: Eliot Berriot Date: Sat, 23 Jun 2018 07:25:27 +0200 Subject: [PATCH 2/4] See #327: Cleaned now unused backend.absoluteUrl and config module --- front/config/prod.env.js | 3 +-- front/src/App.vue | 8 +++++++- front/src/audio/backend.js | 17 ----------------- front/src/audio/track.js | 7 ------- front/src/components/Sidebar.vue | 2 +- front/src/components/audio/Player.vue | 4 +--- front/src/components/audio/SearchBar.vue | 5 +---- front/src/components/audio/Track.vue | 2 +- front/src/components/audio/album/Card.vue | 2 +- front/src/components/audio/artist/Card.vue | 2 +- front/src/components/audio/track/Row.vue | 2 +- front/src/components/audio/track/Table.vue | 2 +- front/src/components/library/Album.vue | 2 +- front/src/components/library/Artist.vue | 2 +- front/src/components/library/Track.vue | 5 ++--- front/src/components/library/radios/Filter.vue | 3 +-- .../components/manage/users/InvitationForm.vue | 4 +--- front/src/components/metadata/Search.vue | 3 +-- front/src/config.js | 8 -------- front/src/store/instance.js | 2 +- 20 files changed, 24 insertions(+), 61 deletions(-) delete mode 100644 front/src/audio/track.js delete mode 100644 front/src/config.js diff --git a/front/config/prod.env.js b/front/config/prod.env.js index decfe3615..773d263d3 100644 --- a/front/config/prod.env.js +++ b/front/config/prod.env.js @@ -1,4 +1,3 @@ module.exports = { - NODE_ENV: '"production"', - BACKEND_URL: '"/"' + NODE_ENV: '"production"' } diff --git a/front/src/App.vue b/front/src/App.vue index 73e46328a..56dbe0aad 100644 --- a/front/src/App.vue +++ b/front/src/App.vue @@ -39,7 +39,13 @@ {{ $t('Issue tracker') }} - {{ $t('Use another instance') }} + + {{ $t('Use another instance') }} + +
diff --git a/front/src/audio/backend.js b/front/src/audio/backend.js index 619f3cefd..5a82719a3 100644 --- a/front/src/audio/backend.js +++ b/front/src/audio/backend.js @@ -1,5 +1,3 @@ -import config from '@/config' - var Album = { clean (album) { // we manually rebind the album and artist to each child track @@ -21,21 +19,6 @@ var Artist = { } } export default { - absoluteUrl (url) { - if (url.startsWith('http')) { - return url - } - if (url.startsWith('/')) { - let rootUrl = ( - window.location.protocol + '//' + window.location.hostname + - (window.location.port ? ':' + window.location.port : '') - ) - return rootUrl + url - } else { - return config.BACKEND_URL + url - } - }, Artist: Artist, Album: Album - } diff --git a/front/src/audio/track.js b/front/src/audio/track.js deleted file mode 100644 index 9873b74ec..000000000 --- a/front/src/audio/track.js +++ /dev/null @@ -1,7 +0,0 @@ -import backend from './backend' - -export default { - getCover (track) { - return backend.absoluteUrl(track.album.cover) - } -} diff --git a/front/src/components/Sidebar.vue b/front/src/components/Sidebar.vue index 87c374a33..de018907b 100644 --- a/front/src/components/Sidebar.vue +++ b/front/src/components/Sidebar.vue @@ -125,7 +125,7 @@ {{ index + 1}} - + diff --git a/front/src/components/audio/Player.vue b/front/src/components/audio/Player.vue index 3c922e14a..1cc27970b 100644 --- a/front/src/components/audio/Player.vue +++ b/front/src/components/audio/Player.vue @@ -14,7 +14,7 @@
- +
@@ -143,7 +143,6 @@ import {mapState, mapGetters, mapActions} from 'vuex' import GlobalEvents from '@/components/utils/global-events' import ColorThief from '@/vendor/color-thief' -import Track from '@/audio/track' import AudioTrack from '@/components/audio/Track' import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon' import TrackPlaylistIcon from '@/components/playlists/TrackPlaylistIcon' @@ -162,7 +161,6 @@ export default { isShuffling: false, renderAudio: true, sliderVolume: this.volume, - Track: Track, defaultAmbiantColors: defaultAmbiantColors, ambiantColors: defaultAmbiantColors } diff --git a/front/src/components/audio/SearchBar.vue b/front/src/components/audio/SearchBar.vue index 99896d04b..9b6dc50e2 100644 --- a/front/src/components/audio/SearchBar.vue +++ b/front/src/components/audio/SearchBar.vue @@ -11,11 +11,8 @@