From eef2a3d7cccdd4c4c2f4d0ab74210361373271ba Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 31 Oct 2021 20:42:09 +0100 Subject: [PATCH 01/24] feat: add loading spinner splash screen while loading --- src/App.vue | 52 ++++++++++++------------- src/components/home/navigation.vue | 20 +--------- src/components/misc/vikunja-loading.vue | 46 ++++++++++++++++++++++ src/i18n/lang/en.json | 1 + src/store/index.js | 9 +++++ src/styles/theme/loading.scss | 34 ++++++++++------ 6 files changed, 105 insertions(+), 57 deletions(-) create mode 100644 src/components/misc/vikunja-loading.vue diff --git a/src/App.vue b/src/App.vue index dec28560a..2f91fda2e 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,5 +1,5 @@ + + diff --git a/src/i18n/lang/en.json b/src/i18n/lang/en.json index 3d684db7e..79886d36b 100644 --- a/src/i18n/lang/en.json +++ b/src/i18n/lang/en.json @@ -1,5 +1,6 @@ { "home": { + "vikunjaLoading": "Vikunja is loading…", "welcomeNight": "Good Night {username}", "welcomeMorning": "Good Morning {username}", "welcomeDay": "Hi {username}", diff --git a/src/store/index.js b/src/store/index.js index c60e0ebf9..79c7d0177 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -43,6 +43,7 @@ export const store = createStore({ menuActive: true, keyboardShortcutsActive: false, quickActionsActive: false, + vikunjaReady: false, }, mutations: { [LOADING](state, loading) { @@ -84,6 +85,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 +142,10 @@ export const store = createStore({ commit(CURRENT_LIST, currentList) }, + async loadApp({commit, dispatch}) { + await dispatch('config/update') + await dispatch('auth/checkAuth') + commit('vikunjaReady', true) + }, }, }) diff --git a/src/styles/theme/loading.scss b/src/styles/theme/loading.scss index a4a76a4c4..687e7c0e6 100644 --- a/src/styles/theme/loading.scss +++ b/src/styles/theme/loading.scss @@ -1,17 +1,27 @@ // FIXME: move to loading.vue -.loader-container.is-loading { - position: relative; - pointer-events: none; - opacity: 0.5; +.loader-container { + &.is-loading { + position: relative; + pointer-events: none; + opacity: 0.5; - &::after { - @include loader; - position: absolute; - top: calc(50% - 2.5rem); - left: calc(50% - 2.5rem); - width: 5rem; - height: 5rem; - border-width: 0.25rem; + &::after { + @include loader; + position: absolute; + top: calc(50% - 2.5rem); + left: calc(50% - 2.5rem); + width: 5rem; + height: 5rem; + border-width: 0.25rem; + } + } + + &.is-loading-small.is-loading::after { + width: 1.5rem; + height: 1.5rem; + top: calc(50% - .75rem); + left: calc(50% - .75rem); + border-width: 2px; } } -- 2.40.1 From dc30de9176249f5f3cdf9881444afe7ba4ebe7f2 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 31 Oct 2021 21:04:00 +0100 Subject: [PATCH 02/24] feat: do api url check before anything else and move ready check to wrapper component --- src/App.vue | 47 +++--- src/components/misc/api-config.vue | 139 +++--------------- .../misc/{vikunja-loading.vue => ready.vue} | 29 +++- src/helpers/checkAndSetApiUrl.ts | 111 ++++++++++++++ src/store/index.js | 3 +- 5 files changed, 180 insertions(+), 149 deletions(-) rename src/components/misc/{vikunja-loading.vue => ready.vue} (63%) create mode 100644 src/helpers/checkAndSetApiUrl.ts diff --git a/src/App.vue b/src/App.vue index 2f91fda2e..34b975aa7 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,26 +1,27 @@ @@ -29,14 +48,14 @@ export default { height: 100vh; width: 100vw; flex-direction: column; - + img { margin-bottom: 1rem; } - + .loader-container { margin-right: 1rem; - + &.is-loading:after { border-left-color: $grey-400; border-bottom-color: $grey-400; diff --git a/src/helpers/checkAndSetApiUrl.ts b/src/helpers/checkAndSetApiUrl.ts new file mode 100644 index 000000000..8cab0f73f --- /dev/null +++ b/src/helpers/checkAndSetApiUrl.ts @@ -0,0 +1,111 @@ +const API_DEFAULT_PORT = '3456' + +export const checkAndSetApiUrl = (url: string, updateConfig: () => Promise): Promise => { + // 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 '' + }) +} diff --git a/src/store/index.js b/src/store/index.js index 79c7d0177..b0589f774 100644 --- a/src/store/index.js +++ b/src/store/index.js @@ -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, @@ -143,7 +144,7 @@ export const store = createStore({ commit(CURRENT_LIST, currentList) }, async loadApp({commit, dispatch}) { - await dispatch('config/update') + await checkAndSetApiUrl(window.API_URL, () => dispatch('config/update')) await dispatch('auth/checkAuth') commit('vikunjaReady', true) }, -- 2.40.1 From e2cc505564a8b4552628f02c07afb49b3aac5802 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 31 Oct 2021 21:41:30 +0100 Subject: [PATCH 03/24] feat: add error handling when calling the api failed --- src/components/home/contentNoAuth.vue | 46 +++------------------- src/components/misc/api-config.vue | 51 ++++++++++++++++--------- src/components/misc/no-auth-wrapper.vue | 47 +++++++++++++++++++++++ src/components/misc/ready.vue | 37 ++++++++++++++---- src/i18n/lang/en.json | 8 +++- 5 files changed, 122 insertions(+), 67 deletions(-) create mode 100644 src/components/misc/no-auth-wrapper.vue diff --git a/src/components/home/contentNoAuth.vue b/src/components/home/contentNoAuth.vue index b95739067..f6b473c35 100644 --- a/src/components/home/contentNoAuth.vue +++ b/src/components/home/contentNoAuth.vue @@ -1,40 +1,20 @@ - - \ No newline at end of file diff --git a/src/components/misc/api-config.vue b/src/components/misc/api-config.vue index 8e3e1606d..f37e08491 100644 --- a/src/components/misc/api-config.vue +++ b/src/components/misc/api-config.vue @@ -70,30 +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 } - checkAndSetApiUrl(this.apiUrl, () => this.$store.dispatch('config/update')) - .catch(() => { - // Still not found, url is still invalid - this.successMsg = '' - this.errorMsg = this.$t('apiConfig.error', {domain: this.apiDomain}) - }) - .then(url => { - if (url === '') { - return - } + try { + const url = await checkAndSetApiUrl(this.apiUrl, () => this.$store.dispatch('config/update')) - // Set it + save it to local storage to save us the hoops - this.errorMsg = '' - this.successMsg = this.$t('apiConfig.success', {domain: this.apiDomain}) - this.configureApi = false - this.apiUrl = url - this.$emit('foundApi', this.apiUrl) - }) + if (url === '') { + return + } + + // Set it + save it to local storage to save us the hoops + this.errorMsg = '' + this.successMsg = this.$t('apiConfig.success', {domain: this.apiDomain}) + this.configureApi = false + 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}) + } }, }, } diff --git a/src/components/misc/no-auth-wrapper.vue b/src/components/misc/no-auth-wrapper.vue new file mode 100644 index 000000000..4fefb7f25 --- /dev/null +++ b/src/components/misc/no-auth-wrapper.vue @@ -0,0 +1,47 @@ + + + + + diff --git a/src/components/misc/ready.vue b/src/components/misc/ready.vue index f31f5421b..06f76903d 100644 --- a/src/components/misc/ready.vue +++ b/src/components/misc/ready.vue @@ -3,23 +3,41 @@
- {{ error }} + + +
+

+ {{ $t('ready.errorOccured') }}
+ {{ error }} +

+

+ {{ $t('ready.checkApiUrl') }} +

+
+ +
+
Vikunja

- {{ $t('home.vikunjaLoading') }} + {{ $t('ready.loading') }}

diff --git a/src/i18n/lang/en.json b/src/i18n/lang/en.json index 79886d36b..acc4e2fae 100644 --- a/src/i18n/lang/en.json +++ b/src/i18n/lang/en.json @@ -1,6 +1,5 @@ { "home": { - "vikunjaLoading": "Vikunja is loading…", "welcomeNight": "Good Night {username}", "welcomeMorning": "Good Morning {username}", "welcomeDay": "Hi {username}", @@ -17,6 +16,11 @@ "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 below." + }, "user": { "auth": { "username": "Username", @@ -777,7 +781,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": { -- 2.40.1 From acc315b581f2faae3b0ea5d2e7b43d49338c7317 Mon Sep 17 00:00:00 2001 From: kolaente Date: Sun, 31 Oct 2021 21:48:07 +0100 Subject: [PATCH 04/24] feat: add fade to loading spinner --- src/components/misc/ready.vue | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/components/misc/ready.vue b/src/components/misc/ready.vue index 06f76903d..24a52e9c2 100644 --- a/src/components/misc/ready.vue +++ b/src/components/misc/ready.vue @@ -18,13 +18,15 @@ -
- Vikunja -

- - {{ $t('ready.loading') }} -

-
+ +
+ Vikunja +

+ + {{ $t('ready.loading') }} +

+
+