From b52938aa42d361072444650a0e11eb61a8180545 Mon Sep 17 00:00:00 2001 From: James Lyne Date: Sat, 15 May 2021 21:09:01 +0100 Subject: [PATCH] Improve initial load error handling --- index.html | 12 +++++++++++- public/index.html | 4 ++++ src/App.vue | 22 ++++++++++++++++------ src/api.ts | 32 +++++++++++++++++++++++++++++++- src/main.ts | 22 +++++++++++++++++++--- 5 files changed, 81 insertions(+), 11 deletions(-) diff --git a/index.html b/index.html index a20c199..8026cb3 100644 --- a/index.html +++ b/index.html @@ -79,6 +79,14 @@ #splash__error { margin-top: 2rem; transition: opacity 0.5s ease-in; + display: flex; + flex-direction: column; + text-align: center; + max-width: 60rem; + } + + #splash__error-message { + font-family: monospace; } #splash__error[aria-hidden=true] { @@ -125,7 +133,9 @@ diff --git a/public/index.html b/public/index.html index 2c23521..935daf8 100644 --- a/public/index.html +++ b/public/index.html @@ -81,6 +81,10 @@ transition: opacity 0.5s ease-in; } + #splash__error-message { + font-family: monospace; + } + #splash__error[aria-hidden=true] { opacity: 0; } diff --git a/src/App.vue b/src/App.vue index 5d4d6b0..3d8615b 100644 --- a/src/App.vue +++ b/src/App.vue @@ -29,6 +29,7 @@ import {useStore} from "@/store"; import {ActionTypes} from "@/store/action-types"; import {parseUrl} from '@/util'; import {MutationTypes} from "@/store/mutation-types"; +import API from '@/api'; export default defineComponent({ name: 'App', @@ -50,15 +51,24 @@ export default defineComponent({ configAttempts = ref(0), loadConfiguration = () => { - store.dispatch(ActionTypes.LOAD_CONFIGURATION, undefined).then(() => { - startUpdates(); - window.hideSplash(); + let validated = false; + + API.validateConfiguration().then(() => { + validated = true; + + return store.dispatch(ActionTypes.LOAD_CONFIGURATION, undefined).then(() => { + startUpdates(); + window.hideSplash(); + }); }).catch(e => { console.error('Failed to load server configuration: ', e); - window.showSplashError(++configAttempts.value); + window.showSplashError(e, !validated, ++configAttempts.value); - setTimeout(() => loadConfiguration(), 1000); - }); + //Don't retry if config isn't valid + if(validated) { + setTimeout(() => loadConfiguration(), 1000); + } + }) }, startUpdates = () => { diff --git a/src/api.ts b/src/api.ts index 4c8fa66..d041342 100644 --- a/src/api.ts +++ b/src/api.ts @@ -553,10 +553,40 @@ function buildUpdates(data: Array): DynmapUpdates { } export default { + validateConfiguration(): Promise { + const check = '\nCheck your standalone/config.js file exists and is being loaded correctly.'; + + if(!window.config || !window.config.url) { + return Promise.reject(`Dynmap's configuration is missing. ${check}`); + } + + if(!window.config.url.configuration) { + return Promise.reject(`Dynmap's configuration URL is missing. ${check}`); + } + + if(!window.config.url.update) { + return Promise.reject(`Dynmap's update URL is missing. ${check}`); + } + + if(!window.config.url.markers) { + return Promise.reject(`Dynmap's markers URL is missing. ${check}`); + } + + if(!window.config.url.tiles) { + return Promise.reject(`Dynmap's tiles URL is missing. ${check}`); + } + + if(!window.config.url.sendmessage) { + return Promise.reject(`Dynmap's sendmessage URL is missing. ${check}`); + } + + return Promise.resolve(); + }, + getConfiguration(): Promise { return fetch(window.config.url.configuration).then(response => { if (!response.ok) { - throw new Error('Network request failed'); + throw new Error('Network request failed: ' + response.statusText); } return response.json(); diff --git a/src/main.ts b/src/main.ts index bf14e20..63bbc4d 100644 --- a/src/main.ts +++ b/src/main.ts @@ -23,7 +23,10 @@ import 'normalize-scss/sass/normalize/_import-now.scss'; import '@/scss/style.scss'; const splash = document.getElementById('splash'), + splashSpinner = document.getElementById('splash__spinner'), splashError = document.getElementById('splash__error'), + splashErrorMessage = document.getElementById('splash__error-message'), + splashRetry = document.getElementById('splash__error-retry'), splashAttempt = document.getElementById('splash__error-attempt'), svgs = import.meta.globEager('/assets/icons/*.svg'); @@ -35,13 +38,26 @@ window.hideSplash = function() { }); }; -window.showSplashError = function(attempts: number) { +window.showSplashError = function(message: string, fatal: boolean, attempts: number) { if(splashError) { splashError.setAttribute('aria-hidden', 'false'); } - if(splashAttempt) { - splashAttempt.textContent = attempts.toString(); + if(splashErrorMessage) { + splashErrorMessage.innerText = message || 'Unknown error'; + } + + if(splashSpinner && fatal) { + splashSpinner.style.visibility = 'hidden'; + } + + if(splashAttempt && splashRetry) { + if(fatal) { + splashAttempt.hidden = splashRetry.hidden = true; + } else if(attempts) { + splashAttempt.hidden = splashRetry.hidden = false; + splashAttempt.textContent = attempts.toString(); + } } };