See #327: can now use the front-end with any API server

This commit is contained in:
Eliot Berriot 2018-06-23 07:24:34 +02:00
parent ec76034bf8
commit f3e2193782
No known key found for this signature in database
GPG Key ID: DD6965E2476E5C27
4 changed files with 128 additions and 43 deletions

View File

@ -1,5 +1,24 @@
<template> <template>
<div id="app"> <div id="app">
<div class="ui main text container instance-chooser" v-if="!$store.state.instance.instanceUrl">
<div class="ui padded segment">
<h1 class="ui header">{{ $t('Choose your instance') }}</h1>
<form class="ui form" @submit.prevent="$store.dispatch('instance/setUrl', instanceUrl)">
<p>{{ $t('You need to select an instance in order to continue') }}</p>
<div class="ui action input">
<input type="text" v-model="instanceUrl">
<button type="submit" class="ui button">{{ $t('Submit') }}</button>
</div>
<p>{{ $t('Suggested choices') }}</p>
<div class="ui bulleted list">
<div class="ui item" v-for="url in suggestedInstances">
<a @click="instanceUrl = url">{{ url }}</a>
</div>
</div>
</form>
</div>
</div>
<template v-else>
<sidebar></sidebar> <sidebar></sidebar>
<service-messages v-if="messages.length > 0" /> <service-messages v-if="messages.length > 0" />
<router-view :key="$route.fullPath"></router-view> <router-view :key="$route.fullPath"></router-view>
@ -20,6 +39,7 @@
<template v-else>{{ $t('Source code') }}</template> <template v-else>{{ $t('Source code') }}</template>
</a> </a>
<a href="https://code.eliotberriot.com/funkwhale/funkwhale/issues" class="item" target="_blank">{{ $t('Issue tracker') }}</a> <a href="https://code.eliotberriot.com/funkwhale/funkwhale/issues" class="item" target="_blank">{{ $t('Issue tracker') }}</a>
<a @click="switchInstance" class="item" target="_blank">{{ $t('Use another instance') }}</a>
</div> </div>
</div> </div>
<div class="ten wide column"> <div class="ten wide column">
@ -39,6 +59,7 @@
:dsn="$store.state.instance.settings.raven.front_dsn.value"> :dsn="$store.state.instance.settings.raven.front_dsn.value">
</raven> </raven>
<playlist-modal v-if="$store.state.auth.authenticated"></playlist-modal> <playlist-modal v-if="$store.state.auth.authenticated"></playlist-modal>
</template>
</div> </div>
</template> </template>
@ -63,17 +84,22 @@ export default {
}, },
data () { data () {
return { return {
nodeinfo: null nodeinfo: null,
instanceUrl: null
} }
}, },
created () { created () {
this.$store.dispatch('instance/fetchSettings')
let self = this let self = this
setInterval(() => { setInterval(() => {
// used to redraw ago dates every minute // used to redraw ago dates every minute
self.$store.commit('ui/computeLastDate') self.$store.commit('ui/computeLastDate')
}, 1000 * 60) }, 1000 * 60)
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() this.fetchNodeInfo()
}
}, },
methods: { methods: {
fetchNodeInfo () { fetchNodeInfo () {
@ -81,18 +107,38 @@ export default {
axios.get('instance/nodeinfo/2.0/').then(response => { axios.get('instance/nodeinfo/2.0/').then(response => {
self.nodeinfo = response.data 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: { computed: {
...mapState({ ...mapState({
messages: state => state.ui.messages 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 () { version () {
if (!this.nodeinfo) { if (!this.nodeinfo) {
return null return null
} }
return _.get(this.nodeinfo, 'software.version') return _.get(this.nodeinfo, 'software.version')
} }
},
watch: {
'$store.state.instance.instanceUrl' () {
this.$store.dispatch('instance/fetchSettings')
this.fetchNodeInfo()
}
} }
} }
</script> </script>
@ -116,6 +162,11 @@ html, body {
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.instance-chooser {
margin-top: 2em;
}
.main.pusher, .footer { .main.pusher, .footer {
@include media(">desktop") { @include media(">desktop") {
margin-left: 350px !important; margin-left: 350px !important;

View File

@ -15,7 +15,6 @@ import i18next from 'i18next'
import i18nextFetch from 'i18next-fetch-backend' import i18nextFetch from 'i18next-fetch-backend'
import VueI18Next from '@panter/vue-i18next' import VueI18Next from '@panter/vue-i18next'
import store from './store' import store from './store'
import config from './config'
import { sync } from 'vuex-router-sync' import { sync } from 'vuex-router-sync'
import filters from '@/filters' // eslint-disable-line import filters from '@/filters' // eslint-disable-line
import globals from '@/components/globals' // eslint-disable-line import globals from '@/components/globals' // eslint-disable-line
@ -56,8 +55,6 @@ Vue.directive('title', {
document.title = parts.join(' - ') document.title = parts.join(' - ')
} }
}) })
axios.defaults.baseURL = config.API_URL
axios.interceptors.request.use(function (config) { axios.interceptors.request.use(function (config) {
// Do something before request is sent // Do something before request is sent
if (store.state.auth.token) { if (store.state.auth.token) {
@ -104,7 +101,6 @@ axios.interceptors.response.use(function (response) {
// Do something with response error // Do something with response error
return Promise.reject(error) return Promise.reject(error)
}) })
store.dispatch('auth/check')
// i18n // i18n
i18next i18next

View File

@ -34,7 +34,7 @@ export default new Vuex.Store({
}), }),
createPersistedState({ createPersistedState({
key: 'instance', key: 'instance',
paths: ['instance.events'] paths: ['instance.events', 'instance.instanceUrl']
}), }),
createPersistedState({ createPersistedState({
key: 'radios', key: 'radios',

View File

@ -6,6 +6,7 @@ export default {
namespaced: true, namespaced: true,
state: { state: {
maxEvents: 200, maxEvents: 200,
instanceUrl: process.env.INSTANCE_URL,
events: [], events: [],
settings: { settings: {
instance: { instance: {
@ -51,9 +52,46 @@ export default {
}, },
events: (state, value) => { events: (state, value) => {
state.events = 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: { 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 // Send a request to the login URL and save the returned JWT
fetchSettings ({commit}, payload) { fetchSettings ({commit}, payload) {
return axios.get('instance/settings/').then(response => { return axios.get('instance/settings/').then(response => {