Migrate to vuex@4 and vue-router@4
This commit is contained in:
parent
7c5d259c2b
commit
74ca3b1725
|
@ -39,11 +39,11 @@
|
|||
"vue-gettext": "2.1.12",
|
||||
"vue-lazyload": "1.3.4",
|
||||
"vue-plyr": "7.0.0",
|
||||
"vue-router": "3.5.4",
|
||||
"vue-router": "4.0.14",
|
||||
"vue-upload-component": "2.8.22",
|
||||
"vue3-gettext": "2.2.0-alpha.1",
|
||||
"vuedraggable": "2.24.3",
|
||||
"vuex": "3.6.2",
|
||||
"vuex": "4.0.2",
|
||||
"vuex-persistedstate": "4.1.0",
|
||||
"vuex-router-sync": "5.0.0"
|
||||
},
|
||||
|
|
|
@ -144,10 +144,21 @@ const showSetInstanceModal = ref(false)
|
|||
@touch-progress="player.setCurrentTime($event)"
|
||||
/>
|
||||
</transition>
|
||||
|
||||
<router-view
|
||||
role="main"
|
||||
:class="{hidden: store.state.ui.queueFocused}"
|
||||
/>
|
||||
v-slot="{ Component }"
|
||||
>
|
||||
<Suspense v-if="Component">
|
||||
<component :is="Component" />
|
||||
<template #fallback>
|
||||
<!-- TODO (wvffle): Add loader -->
|
||||
Loading...
|
||||
</template>
|
||||
</Suspense>
|
||||
</router-view>
|
||||
|
||||
<audio-player ref="player" />
|
||||
<playlist-modal v-if="store.state.auth.authenticated" />
|
||||
<channel-upload-modal v-if="store.state.auth.authenticated" />
|
||||
|
|
|
@ -481,6 +481,8 @@ import Modal from '~/components/semantic/Modal.vue'
|
|||
import $ from 'jquery'
|
||||
import useThemeList from '~/composables/useThemeList'
|
||||
import useTheme from '~/composables/useTheme'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'Sidebar',
|
||||
|
@ -498,7 +500,14 @@ export default {
|
|||
const theme = useTheme()
|
||||
const themes = useThemeList()
|
||||
|
||||
return { theme, themes }
|
||||
const route = useRoute()
|
||||
const url = computed(() => route.path)
|
||||
|
||||
return {
|
||||
theme,
|
||||
themes,
|
||||
url
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
@ -521,7 +530,6 @@ export default {
|
|||
computed: {
|
||||
...mapState({
|
||||
queue: state => state.queue,
|
||||
url: state => state.route.path
|
||||
}),
|
||||
...mapGetters({
|
||||
additionalNotifications: 'ui/additionalNotifications'
|
||||
|
|
|
@ -145,12 +145,21 @@
|
|||
import Modal from '~/components/semantic/Modal.vue'
|
||||
import ChannelUploadForm from '~/components/channels/UploadForm.vue'
|
||||
import { humanSize } from '~/init/filters'
|
||||
import {onBeforeRouteLeave, onBeforeRouteUpdate} from 'vue-router'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Modal,
|
||||
ChannelUploadForm
|
||||
},
|
||||
setup () {
|
||||
const guard = () => {
|
||||
this.$store.commit('channels/showUploadModal', { show: false })
|
||||
}
|
||||
|
||||
onBeforeRouteUpdate(guard)
|
||||
onBeforeRouteLeave(guard)
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
step: 1,
|
||||
|
@ -186,11 +195,6 @@ export default {
|
|||
return info
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$store.state.route.path' () {
|
||||
this.$store.commit('channels/showUploadModal', { show: false })
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
update (v) {
|
||||
this.$store.commit('channels/showUploadModal', { show: v })
|
||||
|
|
|
@ -77,24 +77,36 @@
|
|||
<div class="row">
|
||||
<router-link
|
||||
v-if="$store.state.auth.authenticated"
|
||||
tag="div"
|
||||
class="column"
|
||||
:to="{name: 'notifications'}"
|
||||
role="button"
|
||||
v-slot="{ navigate }"
|
||||
custom
|
||||
:to="{ name: 'notifications' }"
|
||||
>
|
||||
<i class="user-modal list-icon bell icon" />
|
||||
<span class="user-modal list-item">{{ labels.notifications }}</span>
|
||||
<div
|
||||
class="column"
|
||||
role="button"
|
||||
@click="navigate"
|
||||
@keypress.enter="navigate"
|
||||
>
|
||||
<i class="user-modal list-icon bell icon" />
|
||||
<span class="user-modal list-item">{{ labels.notifications }}</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="row">
|
||||
<router-link
|
||||
tag="div"
|
||||
class="column"
|
||||
v-slot="{ navigate }"
|
||||
custom
|
||||
:to="{ path: '/settings' }"
|
||||
role="button"
|
||||
>
|
||||
<i class="user-modal list-icon cog icon" />
|
||||
<span class="user-modal list-item">{{ labels.settings }}</span>
|
||||
<div
|
||||
class="column"
|
||||
role="button"
|
||||
@click="navigate"
|
||||
@keypress.enter="navigate"
|
||||
>
|
||||
<i class="user-modal list-icon cog icon" />
|
||||
<span class="user-modal list-item">{{ labels.settings }}</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="ui divider" />
|
||||
|
@ -121,53 +133,71 @@
|
|||
</div>
|
||||
<div class="row">
|
||||
<router-link
|
||||
tag="div"
|
||||
class="column"
|
||||
v-slot="{ navigate }"
|
||||
custom
|
||||
:to="{ name: 'about' }"
|
||||
role="button"
|
||||
>
|
||||
<i class="user-modal list-icon question circle outline icon" />
|
||||
<span class="user-modal list-item">{{ labels.about }}</span>
|
||||
<div
|
||||
class="column"
|
||||
role="button"
|
||||
@click="navigate"
|
||||
@keypress.enter="navigate"
|
||||
>
|
||||
<i class="user-modal list-icon question circle outline icon" />
|
||||
<span class="user-modal list-item">{{ labels.about }}</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="ui divider" />
|
||||
<template v-if="$store.state.auth.authenticated">
|
||||
<router-link
|
||||
tag="div"
|
||||
|
||||
<router-link
|
||||
v-if="$store.state.auth.authenticated"
|
||||
v-slot="{ navigate }"
|
||||
custom
|
||||
:to="{ name: 'logout' }"
|
||||
>
|
||||
<div
|
||||
class="column"
|
||||
:to="{ name: 'logout' }"
|
||||
role="button"
|
||||
@click="navigate"
|
||||
@keypress.enter="navigate"
|
||||
>
|
||||
<i class="user-modal list-icon sign out alternate icon" />
|
||||
<span class="user-modal list-item">{{ labels.logout }}</span>
|
||||
</router-link>
|
||||
</template>
|
||||
<template v-if="!$store.state.auth.authenticated">
|
||||
<router-link
|
||||
tag="div"
|
||||
</div>
|
||||
</router-link>
|
||||
<router-link
|
||||
v-else
|
||||
v-slot="{ navigate }"
|
||||
custom
|
||||
:to="{ name: 'login' }"
|
||||
>
|
||||
<div
|
||||
class="column"
|
||||
:to="{ name: 'login' }"
|
||||
role="button"
|
||||
@click="navigate"
|
||||
@keypress.enter="navigate"
|
||||
>
|
||||
<i class="user-modal list-icon sign in alternate icon" />
|
||||
<span class="user-modal list-item">{{ labels.login }}</span>
|
||||
</router-link>
|
||||
</template>
|
||||
<template
|
||||
v-if="!$store.state.auth.authenticated"
|
||||
&&
|
||||
$store.state.instance.settings.users.registration_enabled.value
|
||||
</div>
|
||||
</router-link>
|
||||
<router-link
|
||||
v-if="!$store.state.auth.authenticated && $store.state.instance.settings.users.registration_enabled.value"
|
||||
v-slot="{ navigate }"
|
||||
custom
|
||||
:to="{ name: 'signup' }"
|
||||
>
|
||||
<router-link
|
||||
tag="div"
|
||||
<div
|
||||
class="column"
|
||||
:to="{ name: 'signup' }"
|
||||
role="button"
|
||||
@click="navigate"
|
||||
@keypress.enter="navigate"
|
||||
>
|
||||
<i class="user-modal list-item user icon" />
|
||||
<span class="user-modal list-item">{{ labels.signup }}</span>
|
||||
</router-link>
|
||||
</template>
|
||||
</div>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</modal>
|
||||
|
|
|
@ -9,11 +9,17 @@
|
|||
<td>
|
||||
<router-link
|
||||
v-if="notificationData.detailUrl"
|
||||
tag="span"
|
||||
class="link"
|
||||
v-slot="{ navigate }"
|
||||
custom
|
||||
:to="notificationData.detailUrl"
|
||||
v-html="notificationData.message"
|
||||
/>
|
||||
>
|
||||
<span
|
||||
class="link"
|
||||
@click="navigate"
|
||||
@keypress.enter="navigate"
|
||||
v-html="notificationData.message"
|
||||
/>
|
||||
</router-link>
|
||||
<template
|
||||
v-else
|
||||
v-html="notificationData.message"
|
||||
|
|
|
@ -200,12 +200,22 @@ import { mapState } from 'vuex'
|
|||
import logger from '~/logging'
|
||||
import Modal from '~/components/semantic/Modal.vue'
|
||||
import PlaylistForm from '~/components/playlists/Form.vue'
|
||||
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Modal,
|
||||
PlaylistForm
|
||||
},
|
||||
setup () {
|
||||
const guard = () => {
|
||||
this.$store.commit('playlists/showModal', false)
|
||||
this.showDuplicateTrackAddConfirmation = false
|
||||
}
|
||||
|
||||
onBeforeRouteUpdate(guard)
|
||||
onBeforeRouteLeave(guard)
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
formKey: String(new Date()),
|
||||
|
@ -238,10 +248,6 @@ export default {
|
|||
}
|
||||
},
|
||||
watch: {
|
||||
'$store.state.route.path' () {
|
||||
this.$store.commit('playlists/showModal', false)
|
||||
this.showDuplicateTrackAddConfirmation = false
|
||||
},
|
||||
'$store.state.playlists.showModal' () {
|
||||
this.formKey = String(new Date())
|
||||
this.showDuplicateTrackAddConfirmation = false
|
||||
|
|
|
@ -2,21 +2,14 @@ import logger from '~/logging'
|
|||
import router from '~/router'
|
||||
import VueLazyload from 'vue-lazyload'
|
||||
import store from '~/store'
|
||||
import { sync } from 'vuex-router-sync'
|
||||
import Vue, { createApp } from 'vue'
|
||||
import { createApp } from 'vue'
|
||||
import useTheme from '~/composables/useTheme'
|
||||
useTheme()
|
||||
|
||||
Vue.config.devtools = true
|
||||
|
||||
logger.default.info('Loading environment:', import.meta.env.MODE)
|
||||
logger.default.debug('Environment variables:', import.meta.env)
|
||||
|
||||
sync(store, router)
|
||||
|
||||
const app = createApp({
|
||||
store,
|
||||
router,
|
||||
components: {
|
||||
App: () => import('~/App.vue')
|
||||
},
|
||||
|
@ -34,6 +27,8 @@ const app = createApp({
|
|||
}
|
||||
})
|
||||
|
||||
app.use(router)
|
||||
app.use(store)
|
||||
app.use(VueLazyload)
|
||||
|
||||
const modules: Promise<unknown>[] = []
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
import Vue from 'vue'
|
||||
import Router from 'vue-router'
|
||||
import {createRouter, createWebHistory} from 'vue-router'
|
||||
import store from '~/store'
|
||||
|
||||
Vue.use(Router)
|
||||
|
||||
function adminPermissions (to, from, next) {
|
||||
if (store.state.auth.authenticated === true && store.state.auth.availablePermissions.settings === true) {
|
||||
next()
|
||||
|
@ -32,10 +29,9 @@ function libraryPermissions (to, from, next) {
|
|||
}
|
||||
|
||||
console.log('PROCESS', import.meta.env)
|
||||
export default new Router({
|
||||
mode: 'history',
|
||||
export default createRouter({
|
||||
history: createWebHistory(import.meta.env.VUE_APP_ROUTER_BASE_URL as string ?? '/'),
|
||||
linkActiveClass: 'active',
|
||||
base: import.meta.env.VUE_APP_ROUTER_BASE_URL || '/',
|
||||
scrollBehavior (to, from, savedPosition) {
|
||||
if (to.meta.preserveScrollPosition) {
|
||||
return savedPosition
|
||||
|
@ -1018,11 +1014,11 @@ export default new Router({
|
|||
)
|
||||
},
|
||||
{
|
||||
path: '*/index.html',
|
||||
path: '/index.html',
|
||||
redirect: '/'
|
||||
},
|
||||
{
|
||||
path: '*',
|
||||
path: '/:pathMatch(.*)*',
|
||||
name: '404',
|
||||
component: () =>
|
||||
import('~/components/PageNotFound.vue')
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import Vue from 'vue'
|
||||
import Vuex, { Store } from 'vuex'
|
||||
import { createStore, Store } from 'vuex'
|
||||
import createPersistedState from 'vuex-persistedstate'
|
||||
|
||||
import favorites from './favorites'
|
||||
|
@ -14,9 +13,7 @@ import player from './player'
|
|||
import playlists from './playlists'
|
||||
import ui from './ui'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
export default <Store<any>> new Vuex.Store({
|
||||
export default <Store<any>> createStore({
|
||||
modules: {
|
||||
ui,
|
||||
auth,
|
||||
|
|
|
@ -46,11 +46,24 @@ import axios from 'axios'
|
|||
import $ from 'jquery'
|
||||
|
||||
import SettingsGroup from '~/components/admin/SettingsGroup.vue'
|
||||
import { nextTick } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
SettingsGroup
|
||||
},
|
||||
async setup () {
|
||||
await this.fetchSettings()
|
||||
await nextTick()
|
||||
|
||||
const route = useRoute()
|
||||
if (route.hash) {
|
||||
this.scrollTo(route.hash.slice(1))
|
||||
}
|
||||
|
||||
$('select.dropdown').dropdown()
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
isLoading: false,
|
||||
|
@ -189,23 +202,12 @@ export default {
|
|||
})
|
||||
}
|
||||
},
|
||||
created () {
|
||||
const self = this
|
||||
this.fetchSettings().then(r => {
|
||||
self.$nextTick(() => {
|
||||
if (self.$store.state.route.hash) {
|
||||
self.scrollTo(self.$store.state.route.hash.substr(1))
|
||||
}
|
||||
$('select.dropdown').dropdown()
|
||||
})
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
scrollTo (id) {
|
||||
this.current = id
|
||||
document.getElementById(id).scrollIntoView()
|
||||
},
|
||||
fetchSettings () {
|
||||
async fetchSettings () {
|
||||
const self = this
|
||||
self.isLoading = true
|
||||
return axios.get('instance/admin/settings/').then(response => {
|
||||
|
|
|
@ -1,3 +1,28 @@
|
|||
<script setup lang="ts">
|
||||
import LoginForm from '~/components/auth/LoginForm.vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { computed } from 'vue'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
import { useStore } from 'vuex'
|
||||
|
||||
const { $pgettext } = useGettext()
|
||||
const labels = computed(() => ({
|
||||
title: $pgettext('Head/Login/Title', 'Log In')
|
||||
}))
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{ next?: string }>(),
|
||||
{ next: '/library' }
|
||||
)
|
||||
|
||||
const store = useStore()
|
||||
if (store.state.auth.authenticated) {
|
||||
const router = useRouter()
|
||||
const resolved = router.resolve(props.next)
|
||||
router.push(resolved.name === '404' ? '/library' : props.next)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<main
|
||||
v-title="labels.title"
|
||||
|
@ -15,39 +40,3 @@
|
|||
</section>
|
||||
</main>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import LoginForm from '~/components/auth/LoginForm.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
LoginForm
|
||||
},
|
||||
props: {
|
||||
next: { type: String, default: '/library' }
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
redirectTo: this.next
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
labels () {
|
||||
const title = this.$pgettext('Head/Login/Title', 'Log In')
|
||||
return {
|
||||
title
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
const resolved = this.$router.resolve(this.redirectTo)
|
||||
console.log(resolved.route.name)
|
||||
if (resolved.route.name === '404') {
|
||||
this.redirectTo = '/library'
|
||||
}
|
||||
if (this.$store.state.auth.authenticated) {
|
||||
this.$router.push(this.redirectTo)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1858,7 +1858,7 @@
|
|||
"@vue/compiler-dom" "3.2.38"
|
||||
"@vue/shared" "3.2.38"
|
||||
|
||||
"@vue/devtools-api@^6.2.1":
|
||||
"@vue/devtools-api@^6.0.0", "@vue/devtools-api@^6.0.0-beta.11", "@vue/devtools-api@^6.2.1":
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.2.1.tgz#6f2948ff002ec46df01420dfeff91de16c5b4092"
|
||||
integrity sha512-OEgAMeQXvCoJ+1x8WyQuVZzFo0wcyCmUR3baRVLmKBo1LmYZWMlRiXlux5jd0fqVJu6PfDbOrZItVqUEzLobeQ==
|
||||
|
@ -6748,10 +6748,12 @@ vue-plyr@7.0.0:
|
|||
plyr "github:sampotts/plyr#develop"
|
||||
vue "^2.6.12"
|
||||
|
||||
vue-router@3.5.4:
|
||||
version "3.5.4"
|
||||
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.5.4.tgz#c453c0b36bc75554de066fefc3f2a9c3212aca70"
|
||||
integrity sha512-x+/DLAJZv2mcQ7glH2oV9ze8uPwcI+H+GgTgTmb5I55bCgY3+vXWIsqbYUzbBSZnwFHEJku4eoaH/x98veyymQ==
|
||||
vue-router@4.0.14:
|
||||
version "4.0.14"
|
||||
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.0.14.tgz#ce2028c1c5c33e30c7287950c973f397fce1bd65"
|
||||
integrity sha512-wAO6zF9zxA3u+7AkMPqw9LjoUCjSxfFvINQj3E/DceTt6uEz1XZLraDhdg2EYmvVwTBSGlLYsUw8bDmx0754Mw==
|
||||
dependencies:
|
||||
"@vue/devtools-api" "^6.0.0"
|
||||
|
||||
vue-template-compiler@2.6.14:
|
||||
version "2.6.14"
|
||||
|
@ -6823,10 +6825,12 @@ vuex-router-sync@5.0.0:
|
|||
resolved "https://registry.yarnpkg.com/vuex-router-sync/-/vuex-router-sync-5.0.0.tgz#1a225c17a1dd9e2f74af0a1b2c62072e9492b305"
|
||||
integrity sha512-Mry2sO4kiAG64714X1CFpTA/shUH1DmkZ26DFDtwoM/yyx6OtMrc+MxrU+7vvbNLO9LSpgwkiJ8W+rlmRtsM+w==
|
||||
|
||||
vuex@3.6.2:
|
||||
version "3.6.2"
|
||||
resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.6.2.tgz#236bc086a870c3ae79946f107f16de59d5895e71"
|
||||
integrity sha512-ETW44IqCgBpVomy520DT5jf8n0zoCac+sxWnn+hMe/CzaSejb/eVw2YToiXYX+Ex/AuHHia28vWTq4goAexFbw==
|
||||
vuex@4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/vuex/-/vuex-4.0.2.tgz#f896dbd5bf2a0e963f00c67e9b610de749ccacc9"
|
||||
integrity sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==
|
||||
dependencies:
|
||||
"@vue/devtools-api" "^6.0.0-beta.11"
|
||||
|
||||
w3c-hr-time@^1.0.2:
|
||||
version "1.0.2"
|
||||
|
|
Loading…
Reference in New Issue