diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 206bb50cc..4005c8911 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,11 +7,53 @@ variables: stages: + - review - lint - test - build - deploy +review: + stage: review + image: node:9 + when: manual + allow_failure: true + before_script: + - cd front + script: + - yarn install + # this is to ensure we don't have any errors in the output, + # cf https://code.eliotberriot.com/funkwhale/funkwhale/issues/169 + - INSTANCE_URL=$REVIEW_INSTANCE_URL yarn run build | tee /dev/stderr | (! grep -i 'ERROR in') + - mkdir -p /static/$CI_BUILD_REF_SLUG + - cp -r dist/* /static/$CI_BUILD_REF_SLUG + cache: + key: "$CI_PROJECT_ID__front_dependencies" + paths: + - front/node_modules + - front/yarn.lock + environment: + name: review/$CI_BUILD_REF_NAME + url: http://$CI_BUILD_REF_SLUG.$REVIEW_DOMAIN + on_stop: stop_review + only: + - branches@funkwhale/funkwhale + tags: + - funkwhale-review + +stop_review: + stage: review + script: + - rm -rf /static/$CI_BUILD_REF_SLUG/ + variables: + GIT_STRATEGY: none + when: manual + environment: + name: review/$CI_BUILD_REF_NAME + action: stop + tags: + - funkwhale-review + black: image: python:3.6 stage: lint diff --git a/CONTRIBUTING b/CONTRIBUTING index 33f2c0747..6fb76a56c 100644 --- a/CONTRIBUTING +++ b/CONTRIBUTING @@ -12,6 +12,42 @@ This document will guide you through common operations such as: - Writing unit tests to validate your work - Submit your work +A quick path to contribute on the front-end +------------------------------------------- + +The next sections of this document include a full installation guide to help +you setup a local, development version of Funkwhale. If you only want to fix small things +on the front-end, and don't want to manage a full development environment, there is anoter way. + +As the front-end can work with any Funkwhale server, you can work with the front-end only, +and make it talk with an existing instance (like the demo one, or you own instance, if you have one). + +If even that is too much for you, you can also make your changes without any development environment, +and open a merge request. We will be able to to review your work easily by spawning automatically a +live version of your changes, thanks to Gitlab Review apps. + +Setup front-end only development environment +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +1. Clone the repository:: + + git clone ssh://git@code.eliotberriot.com:2222/funkwhale/funkwhale.git + cd funkwhale + cd front + +2. Install [nodejs](https://nodejs.org/en/download/package-manager/) and [yarn](https://yarnpkg.com/lang/en/docs/install/#debian-stable) +3. Install the dependencies:: + + yarn install + +4. Launch the development server:: + + # this will serve the front-end on http://localhost:8000 + WEBPACK_DEVSERVER_PORT=8000 yarn dev + +5. Make the front-end talk with an existing server (like https://demo.funkwhale.audio), + by clicking on the corresponding link in the footer +6. Start hacking! Setup your development environment ---------------------------------- diff --git a/changes/changelog.d/327.feature b/changes/changelog.d/327.feature new file mode 100644 index 000000000..8e22e6542 --- /dev/null +++ b/changes/changelog.d/327.feature @@ -0,0 +1,22 @@ +Funkwhale's front-end can now point to any instance (#327) + +Removed front-end and back-end coupling +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Eventhough Funkwhale's front-end has always been a Single Page Application, +talking to an API, it was only able to talk to an API on the same domain. + +There was no real technical justification behind this (only lazyness), and it was +also blocking interesting use cases: + +- Use multiple customized versions of the front-end with the same instance +- Use a customized version of the front-end with multiple instances +- Use a locally hosted front-end with a remote API, which is especially useful in development + +From now on, Funkwhale's front-end can connect to any Funkwhale server. You can +change the server you are connecting to in the footer. + +Fixing this also unlocked a really interesting feature in our development/review workflow: +by leveraging Gitlab CI and review apps, we are now able to deploy automatically live versions of +a merge request, making it possible for anyone to review front-end changes easily, without +the need to install a local environment. diff --git a/front/config/prod.env.js b/front/config/prod.env.js index decfe3615..40cf48973 100644 --- a/front/config/prod.env.js +++ b/front/config/prod.env.js @@ -1,4 +1,5 @@ +let url = process.env.INSTANCE_URL || '/' module.exports = { NODE_ENV: '"production"', - BACKEND_URL: '"/"' + INSTANCE_URL: `"${url}"` } diff --git a/front/src/App.vue b/front/src/App.vue index 2eb673ab4..56dbe0aad 100644 --- a/front/src/App.vue +++ b/front/src/App.vue @@ -1,44 +1,71 @@ @@ -63,17 +90,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 +113,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 +168,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 +230,7 @@ html, body { .ui.icon.header .circular.icon { display: flex; justify-content: center; - + } .segment-content .button{ 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 065a0a03a..5415e1b0e 100644 --- a/front/src/components/Sidebar.vue +++ b/front/src/components/Sidebar.vue @@ -120,7 +120,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 @@