forked from vikunja/frontend
Compare commits
6 Commits
main
...
feature/re
Author | SHA1 | Date |
---|---|---|
kolaente | 8edae1114f | |
kolaente | a7a7c75dc5 | |
kolaente | acc315b581 | |
kolaente | e2cc505564 | |
kolaente | dc30de9176 | |
kolaente | eef2a3d7cc |
11
src/App.vue
11
src/App.vue
|
@ -1,4 +1,5 @@
|
|||
<template>
|
||||
<ready>
|
||||
<div :class="{'is-touch': isTouch}">
|
||||
<div :class="{'is-hidden': !online}">
|
||||
<!-- This is a workaround to get the sw to "see" the to-be-cached version of the offline background image -->
|
||||
|
@ -20,6 +21,7 @@
|
|||
<keyboard-shortcuts v-if="keyboardShortcutsActive"/>
|
||||
</transition>
|
||||
</div>
|
||||
</ready>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -36,6 +38,7 @@ import ContentLinkShare from './components/home/contentLinkShare'
|
|||
import ContentNoAuth from './components/home/contentNoAuth'
|
||||
import {setLanguage} from './i18n'
|
||||
import AccountDeleteService from '@/services/accountDelete'
|
||||
import Ready from '@/components/misc/ready'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'app',
|
||||
|
@ -46,6 +49,7 @@ export default defineComponent({
|
|||
TopNavigation,
|
||||
KeyboardShortcuts,
|
||||
Notification,
|
||||
Ready,
|
||||
},
|
||||
beforeMount() {
|
||||
this.setupOnlineStatus()
|
||||
|
@ -54,13 +58,6 @@ export default defineComponent({
|
|||
this.setupAccountDeletionVerification()
|
||||
},
|
||||
beforeCreate() {
|
||||
// FIXME: async action in beforeCreate, might be not finished when component mounts
|
||||
this.$store.dispatch('config/update')
|
||||
.then(() => {
|
||||
this.$store.dispatch('auth/checkAuth')
|
||||
})
|
||||
this.$store.dispatch('auth/checkAuth')
|
||||
|
||||
setLanguage()
|
||||
},
|
||||
created() {
|
||||
|
|
|
@ -1,40 +1,20 @@
|
|||
<template>
|
||||
<div class="no-auth-wrapper">
|
||||
<div class="noauth-container">
|
||||
<img alt="Vikunja" :src="logoUrl" width="400" height="117" />
|
||||
<div class="message is-info" v-if="motd !== ''">
|
||||
<div class="message-header">
|
||||
<p>{{ $t('misc.info') }}</p>
|
||||
</div>
|
||||
<div class="message-body">
|
||||
{{ motd }}
|
||||
</div>
|
||||
</div>
|
||||
<no-auth-wrapper>
|
||||
<router-view/>
|
||||
</div>
|
||||
</div>
|
||||
</no-auth-wrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
import logoUrl from '@/assets/logo-full.svg'
|
||||
import {saveLastVisited} from '@/helpers/saveLastVisited'
|
||||
import NoAuthWrapper from '@/components/misc/no-auth-wrapper'
|
||||
|
||||
export default {
|
||||
name: 'contentNoAuth',
|
||||
data() {
|
||||
return {
|
||||
logoUrl,
|
||||
}
|
||||
},
|
||||
components: {NoAuthWrapper},
|
||||
computed: {
|
||||
routeName() {
|
||||
return this.$route.name
|
||||
},
|
||||
...mapState({
|
||||
motd: state => state.config.motd,
|
||||
}),
|
||||
},
|
||||
watch: {
|
||||
routeName: {
|
||||
|
@ -65,17 +45,3 @@ export default {
|
|||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.no-auth-wrapper {
|
||||
background: url('@/assets/llama.svg') no-repeat bottom left fixed $light-background;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.noauth-container {
|
||||
max-width: 450px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
padding: 1rem;
|
||||
}
|
||||
</style>
|
|
@ -48,7 +48,7 @@
|
|||
</ul>
|
||||
</div>
|
||||
|
||||
<aside class="menu namespaces-lists loader-container" :class="{'is-loading': loading}">
|
||||
<aside class="menu namespaces-lists loader-container is-loading-small" :class="{'is-loading': loading}">
|
||||
<template v-for="(n, nk) in namespaces" :key="n.id" >
|
||||
<div class="namespace-title" :class="{'has-menu': n.id > 0}">
|
||||
<span
|
||||
|
@ -105,7 +105,7 @@
|
|||
>
|
||||
<template #item="{element: l}">
|
||||
<li
|
||||
class="loader-container"
|
||||
class="loader-container is-loading-small"
|
||||
:class="{'is-loading': listUpdating[l.id]}"
|
||||
>
|
||||
<router-link
|
||||
|
@ -449,14 +449,6 @@ $vikunja-nav-selected-width: 0.4rem;
|
|||
&:hover :deep(.dropdown-trigger) {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.loader-container.is-loading:after {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
top: calc(50% - .75rem);
|
||||
left: calc(50% - .75rem);
|
||||
border-width: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.flip-list-move {
|
||||
|
@ -530,14 +522,6 @@ $vikunja-nav-selected-width: 0.4rem;
|
|||
padding-top: math.div($navbar-padding, 2);
|
||||
}
|
||||
|
||||
&.loader-container.is-loading:after {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
top: calc(50% - .75rem);
|
||||
left: calc(50% - .75rem);
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
color: $grey-400 !important;
|
||||
}
|
||||
|
|
|
@ -47,8 +47,7 @@
|
|||
|
||||
<script>
|
||||
import {parseURL} from 'ufo'
|
||||
|
||||
const API_DEFAULT_PORT = 3456
|
||||
import {checkAndSetApiUrl} from '../../helpers/checkAndSetApiUrl'
|
||||
|
||||
export default {
|
||||
name: 'apiConfig',
|
||||
|
@ -71,128 +70,45 @@ export default {
|
|||
return parseURL(this.apiUrl).host
|
||||
},
|
||||
},
|
||||
props: {
|
||||
configureOpen: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
configureOpen: {
|
||||
handler(value) {
|
||||
this.configureApi = value
|
||||
},
|
||||
immediate: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setApiUrl() {
|
||||
async setApiUrl() {
|
||||
if (this.apiUrl === '') {
|
||||
return
|
||||
}
|
||||
|
||||
let urlToCheck = this.apiUrl
|
||||
try {
|
||||
const url = await checkAndSetApiUrl(this.apiUrl, () => this.$store.dispatch('config/update'))
|
||||
|
||||
// Check if the url has an http prefix
|
||||
if (
|
||||
!urlToCheck.startsWith('http://') &&
|
||||
!urlToCheck.startsWith('https://')
|
||||
) {
|
||||
urlToCheck = `http://${urlToCheck}`
|
||||
if (url === '') {
|
||||
return
|
||||
}
|
||||
|
||||
urlToCheck = new URL(urlToCheck)
|
||||
const origUrlToCheck = urlToCheck
|
||||
|
||||
const oldUrl = window.API_URL
|
||||
window.API_URL = urlToCheck.toString()
|
||||
|
||||
// Check if the api is reachable at the provided url
|
||||
this.$store
|
||||
.dispatch('config/update')
|
||||
.catch((e) => {
|
||||
// Check if it is reachable at /api/v1 and http
|
||||
if (
|
||||
!urlToCheck.pathname.endsWith('/api/v1') &&
|
||||
!urlToCheck.pathname.endsWith('/api/v1/')
|
||||
) {
|
||||
urlToCheck.pathname = `${urlToCheck.pathname}api/v1`
|
||||
window.API_URL = urlToCheck.toString()
|
||||
return this.$store.dispatch('config/update')
|
||||
}
|
||||
throw e
|
||||
})
|
||||
.catch((e) => {
|
||||
// Check if it has a port and if not check if it is reachable at https
|
||||
if (urlToCheck.protocol === 'http:') {
|
||||
urlToCheck.protocol = 'https:'
|
||||
window.API_URL = urlToCheck.toString()
|
||||
return this.$store.dispatch('config/update')
|
||||
}
|
||||
throw e
|
||||
})
|
||||
.catch((e) => {
|
||||
// Check if it is reachable at /api/v1 and https
|
||||
urlToCheck.pathname = origUrlToCheck.pathname
|
||||
if (
|
||||
!urlToCheck.pathname.endsWith('/api/v1') &&
|
||||
!urlToCheck.pathname.endsWith('/api/v1/')
|
||||
) {
|
||||
urlToCheck.pathname = `${urlToCheck.pathname}api/v1`
|
||||
window.API_URL = urlToCheck.toString()
|
||||
return this.$store.dispatch('config/update')
|
||||
}
|
||||
throw e
|
||||
})
|
||||
.catch((e) => {
|
||||
// Check if it is reachable at port API_DEFAULT_PORT and https
|
||||
if (urlToCheck.port !== API_DEFAULT_PORT) {
|
||||
urlToCheck.protocol = 'https:'
|
||||
urlToCheck.port = API_DEFAULT_PORT
|
||||
window.API_URL = urlToCheck.toString()
|
||||
return this.$store.dispatch('config/update')
|
||||
}
|
||||
throw e
|
||||
})
|
||||
.catch((e) => {
|
||||
// Check if it is reachable at :API_DEFAULT_PORT and /api/v1 and https
|
||||
urlToCheck.pathname = origUrlToCheck.pathname
|
||||
if (
|
||||
!urlToCheck.pathname.endsWith('/api/v1') &&
|
||||
!urlToCheck.pathname.endsWith('/api/v1/')
|
||||
) {
|
||||
urlToCheck.pathname = `${urlToCheck.pathname}api/v1`
|
||||
window.API_URL = urlToCheck.toString()
|
||||
return this.$store.dispatch('config/update')
|
||||
}
|
||||
throw e
|
||||
})
|
||||
.catch((e) => {
|
||||
// Check if it is reachable at port API_DEFAULT_PORT and http
|
||||
if (urlToCheck.port !== API_DEFAULT_PORT) {
|
||||
urlToCheck.protocol = 'http:'
|
||||
urlToCheck.port = API_DEFAULT_PORT
|
||||
window.API_URL = urlToCheck.toString()
|
||||
return this.$store.dispatch('config/update')
|
||||
}
|
||||
throw e
|
||||
})
|
||||
.catch((e) => {
|
||||
// Check if it is reachable at :API_DEFAULT_PORT and /api/v1 and http
|
||||
urlToCheck.pathname = origUrlToCheck.pathname
|
||||
if (
|
||||
!urlToCheck.pathname.endsWith('/api/v1') &&
|
||||
!urlToCheck.pathname.endsWith('/api/v1/')
|
||||
) {
|
||||
urlToCheck.pathname = `${urlToCheck.pathname}api/v1`
|
||||
window.API_URL = urlToCheck.toString()
|
||||
return this.$store.dispatch('config/update')
|
||||
}
|
||||
throw e
|
||||
})
|
||||
.catch(() => {
|
||||
// Still not found, url is still invalid
|
||||
this.successMsg = ''
|
||||
this.errorMsg = this.$t('apiConfig.error', {domain: this.apiDomain})
|
||||
window.API_URL = oldUrl
|
||||
})
|
||||
.then((r) => {
|
||||
if (typeof r !== 'undefined') {
|
||||
// Set it + save it to local storage to save us the hoops
|
||||
this.errorMsg = ''
|
||||
this.successMsg = this.$t('apiConfig.success', {domain: this.apiDomain})
|
||||
localStorage.setItem('API_URL', window.API_URL)
|
||||
this.configureApi = false
|
||||
this.apiUrl = window.API_URL
|
||||
this.apiUrl = url
|
||||
this.$emit('foundApi', this.apiUrl)
|
||||
} catch (e) {
|
||||
// Still not found, url is still invalid
|
||||
this.successMsg = ''
|
||||
this.errorMsg = this.$t('apiConfig.error', {domain: this.apiDomain})
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
<template>
|
||||
<div class="no-auth-wrapper">
|
||||
<div class="noauth-container">
|
||||
<img alt="Vikunja" :src="logoUrl" width="400" height="117"/>
|
||||
<div class="message is-info" v-if="motd !== ''">
|
||||
<div class="message-header">
|
||||
<p>{{ $t('misc.info') }}</p>
|
||||
</div>
|
||||
<div class="message-body">
|
||||
{{ motd }}
|
||||
</div>
|
||||
</div>
|
||||
<slot/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import logoUrl from '@/assets/logo-full.svg'
|
||||
import {mapState} from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'no-auth-wrapper',
|
||||
data() {
|
||||
return {
|
||||
logoUrl,
|
||||
}
|
||||
},
|
||||
computed: mapState({
|
||||
motd: state => state.config.motd,
|
||||
}),
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.no-auth-wrapper {
|
||||
background: url('@/assets/llama.svg') no-repeat bottom left fixed $light-background;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.noauth-container {
|
||||
max-width: 450px;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
padding: 1rem;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,111 @@
|
|||
<template>
|
||||
<template v-if="ready">
|
||||
<slot/>
|
||||
</template>
|
||||
<section v-else-if="error !== ''">
|
||||
<no-auth-wrapper>
|
||||
<card>
|
||||
<p v-if="error === errorNoApiUrl">
|
||||
{{ $t('ready.noApiUrlConfigured') }}
|
||||
</p>
|
||||
<div class="notification is-danger" v-else>
|
||||
<p>
|
||||
{{ $t('ready.errorOccured') }}<br/>
|
||||
{{ error }}
|
||||
</p>
|
||||
<p>
|
||||
{{ $t('ready.checkApiUrl') }}
|
||||
</p>
|
||||
</div>
|
||||
<api-config :configure-open="true" @found-api="load"/>
|
||||
</card>
|
||||
</no-auth-wrapper>
|
||||
</section>
|
||||
<transition name="fade">
|
||||
<section class="vikunja-loading" v-if="showLoading">
|
||||
<img alt="Vikunja" :src="logoUrl" width="100" height="100"/>
|
||||
<p>
|
||||
<span class="loader-container is-loading-small is-loading"></span>
|
||||
{{ $t('ready.loading') }}
|
||||
</p>
|
||||
</section>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import logoUrl from '@/assets/logo.svg'
|
||||
import ApiConfig from '@/components/misc/api-config'
|
||||
import NoAuthWrapper from '@/components/misc/no-auth-wrapper'
|
||||
|
||||
const ERROR_NO_API_URL = 'noApiUrlProvided'
|
||||
|
||||
export default {
|
||||
name: 'ready',
|
||||
components: {
|
||||
NoAuthWrapper,
|
||||
ApiConfig,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
logoUrl,
|
||||
error: '',
|
||||
errorNoApiUrl: ERROR_NO_API_URL,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.load()
|
||||
},
|
||||
computed: {
|
||||
ready() {
|
||||
return this.$store.state.vikunjaReady
|
||||
},
|
||||
showLoading() {
|
||||
return !this.ready && this.error === ''
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
load() {
|
||||
if (window.API_URL === '') {
|
||||
this.error = ERROR_NO_API_URL
|
||||
return
|
||||
}
|
||||
|
||||
this.$store.dispatch('loadApp')
|
||||
.catch(e => {
|
||||
this.error = e
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.vikunja-loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
flex-direction: column;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background: $grey-100;
|
||||
z-index: 99;
|
||||
|
||||
img {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.loader-container {
|
||||
margin-right: 1rem;
|
||||
|
||||
&.is-loading:after {
|
||||
border-left-color: $grey-400;
|
||||
border-bottom-color: $grey-400;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,111 @@
|
|||
const API_DEFAULT_PORT = '3456'
|
||||
|
||||
export const checkAndSetApiUrl = (url: string, updateConfig: () => Promise<void>): Promise<string> => {
|
||||
// Check if the url has an http prefix
|
||||
if (
|
||||
!url.startsWith('http://') &&
|
||||
!url.startsWith('https://')
|
||||
) {
|
||||
url = `http://${url}`
|
||||
}
|
||||
|
||||
const urlToCheck: URL = new URL(url)
|
||||
const origUrlToCheck = urlToCheck
|
||||
|
||||
const oldUrl = window.API_URL
|
||||
window.API_URL = urlToCheck.toString()
|
||||
|
||||
// Check if the api is reachable at the provided url
|
||||
return updateConfig()
|
||||
.catch(e => {
|
||||
// Check if it is reachable at /api/v1 and http
|
||||
if (
|
||||
!urlToCheck.pathname.endsWith('/api/v1') &&
|
||||
!urlToCheck.pathname.endsWith('/api/v1/')
|
||||
) {
|
||||
urlToCheck.pathname = `${urlToCheck.pathname}api/v1`
|
||||
window.API_URL = urlToCheck.toString()
|
||||
return updateConfig()
|
||||
}
|
||||
throw e
|
||||
})
|
||||
.catch(e => {
|
||||
// Check if it has a port and if not check if it is reachable at https
|
||||
if (urlToCheck.protocol === 'http:') {
|
||||
urlToCheck.protocol = 'https:'
|
||||
window.API_URL = urlToCheck.toString()
|
||||
return updateConfig()
|
||||
}
|
||||
throw e
|
||||
})
|
||||
.catch(e => {
|
||||
// Check if it is reachable at /api/v1 and https
|
||||
urlToCheck.pathname = origUrlToCheck.pathname
|
||||
if (
|
||||
!urlToCheck.pathname.endsWith('/api/v1') &&
|
||||
!urlToCheck.pathname.endsWith('/api/v1/')
|
||||
) {
|
||||
urlToCheck.pathname = `${urlToCheck.pathname}api/v1`
|
||||
window.API_URL = urlToCheck.toString()
|
||||
return updateConfig()
|
||||
}
|
||||
throw e
|
||||
})
|
||||
.catch(e => {
|
||||
// Check if it is reachable at port API_DEFAULT_PORT and https
|
||||
if (urlToCheck.port !== API_DEFAULT_PORT) {
|
||||
urlToCheck.protocol = 'https:'
|
||||
urlToCheck.port = API_DEFAULT_PORT
|
||||
window.API_URL = urlToCheck.toString()
|
||||
return updateConfig()
|
||||
}
|
||||
throw e
|
||||
})
|
||||
.catch(e => {
|
||||
// Check if it is reachable at :API_DEFAULT_PORT and /api/v1 and https
|
||||
urlToCheck.pathname = origUrlToCheck.pathname
|
||||
if (
|
||||
!urlToCheck.pathname.endsWith('/api/v1') &&
|
||||
!urlToCheck.pathname.endsWith('/api/v1/')
|
||||
) {
|
||||
urlToCheck.pathname = `${urlToCheck.pathname}api/v1`
|
||||
window.API_URL = urlToCheck.toString()
|
||||
return updateConfig()
|
||||
}
|
||||
throw e
|
||||
})
|
||||
.catch(e => {
|
||||
// Check if it is reachable at port API_DEFAULT_PORT and http
|
||||
if (urlToCheck.port !== API_DEFAULT_PORT) {
|
||||
urlToCheck.protocol = 'http:'
|
||||
urlToCheck.port = API_DEFAULT_PORT
|
||||
window.API_URL = urlToCheck.toString()
|
||||
return updateConfig()
|
||||
}
|
||||
throw e
|
||||
})
|
||||
.catch(e => {
|
||||
// Check if it is reachable at :API_DEFAULT_PORT and /api/v1 and http
|
||||
urlToCheck.pathname = origUrlToCheck.pathname
|
||||
if (
|
||||
!urlToCheck.pathname.endsWith('/api/v1') &&
|
||||
!urlToCheck.pathname.endsWith('/api/v1/')
|
||||
) {
|
||||
urlToCheck.pathname = `${urlToCheck.pathname}api/v1`
|
||||
window.API_URL = urlToCheck.toString()
|
||||
return updateConfig()
|
||||
}
|
||||
throw e
|
||||
})
|
||||
.catch(e => {
|
||||
window.API_URL = oldUrl
|
||||
throw e
|
||||
})
|
||||
.then(r => {
|
||||
if (typeof r !== 'undefined') {
|
||||
localStorage.setItem('API_URL', window.API_URL)
|
||||
return window.API_URL
|
||||
}
|
||||
return ''
|
||||
})
|
||||
}
|
|
@ -16,6 +16,12 @@
|
|||
"title": "Not found",
|
||||
"text": "The page you requested does not exist."
|
||||
},
|
||||
"ready": {
|
||||
"loading": "Vikunja is loading…",
|
||||
"errorOccured": "An error occured:",
|
||||
"checkApiUrl": "Please check if the api url is correct.",
|
||||
"noApiUrlConfigured": "No API url was configured. Please set one below:"
|
||||
},
|
||||
"user": {
|
||||
"auth": {
|
||||
"username": "Username",
|
||||
|
@ -776,7 +782,7 @@
|
|||
"urlPlaceholder": "eg. https://localhost:3456",
|
||||
"change": "change",
|
||||
"signInOn": "Sign in to your Vikunja account on {0}",
|
||||
"error": "Could not find or use Vikunja installation at \"{domain}\".",
|
||||
"error": "Could not find or use Vikunja installation at \"{domain}\". Please try a different url.",
|
||||
"success": "Using Vikunja installation at \"{domain}\"."
|
||||
},
|
||||
"loadingError": {
|
||||
|
|
|
@ -19,6 +19,7 @@ import attachments from './modules/attachments'
|
|||
import labels from './modules/labels'
|
||||
|
||||
import ListService from '../services/list'
|
||||
import {checkAndSetApiUrl} from '../helpers/checkAndSetApiUrl'
|
||||
|
||||
export const store = createStore({
|
||||
strict: import.meta.env.DEV,
|
||||
|
@ -43,6 +44,7 @@ export const store = createStore({
|
|||
menuActive: true,
|
||||
keyboardShortcutsActive: false,
|
||||
quickActionsActive: false,
|
||||
vikunjaReady: false,
|
||||
},
|
||||
mutations: {
|
||||
[LOADING](state, loading) {
|
||||
|
@ -84,6 +86,9 @@ export const store = createStore({
|
|||
[BACKGROUND](state, background) {
|
||||
state.background = background
|
||||
},
|
||||
vikunjaReady(state, ready) {
|
||||
state.vikunjaReady = ready
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
async [CURRENT_LIST]({state, commit}, currentList) {
|
||||
|
@ -138,5 +143,10 @@ export const store = createStore({
|
|||
|
||||
commit(CURRENT_LIST, currentList)
|
||||
},
|
||||
async loadApp({commit, dispatch}) {
|
||||
await checkAndSetApiUrl(window.API_URL, () => dispatch('config/update'))
|
||||
await dispatch('auth/checkAuth')
|
||||
commit('vikunjaReady', true)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// FIXME: move to loading.vue
|
||||
.loader-container.is-loading {
|
||||
.loader-container {
|
||||
&.is-loading {
|
||||
position: relative;
|
||||
pointer-events: none;
|
||||
opacity: 0.5;
|
||||
|
@ -15,6 +16,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.is-loading-small.is-loading::after {
|
||||
width: 1.5rem;
|
||||
height: 1.5rem;
|
||||
top: calc(50% - .75rem);
|
||||
left: calc(50% - .75rem);
|
||||
border-width: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: move to ShowTasks.vue
|
||||
.spinner.is-loading {
|
||||
pointer-events: none;
|
||||
|
|
Loading…
Reference in New Issue