See #327: can now use the front-end with any API server
This commit is contained in:
parent
ec76034bf8
commit
f3e2193782
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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',
|
||||||
|
|
|
@ -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 => {
|
||||||
|
|
Loading…
Reference in New Issue