Add offline indicator (#3516)

This commit is contained in:
Michael Geers 2022-05-27 15:19:02 +02:00 • committed by GitHub
parent 78e6ed0388
commit 22ecf15331
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 120 additions and 41 deletions

View file

@ -13,10 +13,12 @@ const api = axios.create({
api.interceptors.response.use(
(response) => response,
(error) => {
const url = error.config.baseURL + error.config.url;
const message = `${error.message}: API request failed ${url}`;
window.app.error({ message });
if (error.config.url !== "health") {
const url = error.config.baseURL + error.config.url;
const message = `${error.message}: API request failed ${url}`;
window.app.error({ message });
}
return Promise.reject(error);
}
);
export default api;

View file

@ -14,7 +14,12 @@ smoothscroll.polyfill();
const app = createApp({
data() {
return { notifications: [] };
return { notifications: [], offline: false };
},
watch: {
offline: function (value) {
console.log(`we are ${value ? "offline" : "online"}`);
},
},
methods: {
raise: function (msg) {
@ -42,13 +47,19 @@ const app = createApp({
msg.type = "error";
this.raise(msg);
},
setOnline: function () {
this.offline = false;
},
setOffline: function () {
this.offline = true;
},
warn: function (msg) {
msg.type = "warn";
this.raise(msg);
},
},
render: function () {
return h(App, { notifications: this.notifications });
return h(App, { notifications: this.notifications, offline: this.offline });
},
});
@ -60,7 +71,5 @@ app.use(featureflags);
window.app = app.mount("#app");
window.setInterval(function () {
api.get("health").catch(function () {
window.app.error({ message: "Server unavailable" });
});
api.get("health").then(window.app.setOnline).catch(window.app.setOffline);
}, 5000);

View file

@ -48,7 +48,7 @@
'text-danger': msg.type === 'error',
'text-warning': msg.type === 'warn',
}"
class="flex-grow-0 d-block"
class="flex-grow-0 flex-shrink-0 d-block"
></shopicon-regular-exclamationtriangle>
<span class="flex-grow-1 px-2 py-1 text-break">
{{ msg.message }}

View file

@ -0,0 +1,25 @@
<template>
<div
class="fixed-bottom alert alert-secondary d-flex justify-content-center align-items-center mb-0 rounded-0"
role="alert"
>
<shopicon-regular-cloud class="me-2"></shopicon-regular-cloud>
{{ $t("offline.message") }}
<button class="btn btn-sm btn-link text-dark" @click="reload">
{{ $t("offline.reload") }}
</button>
</div>
</template>
<script>
import "@h2d2/shopicons/es/regular/cloud";
export default {
name: "OfflineIndicator",
methods: {
reload() {
window.location.reload();
},
},
};
</script>

View file

@ -1,5 +1,7 @@
<template>
<div class="d-flex flex-column site">
<OfflineIndicator v-if="offline" />
<div class="container px-4 top-area">
<div class="d-flex justify-content-between align-items-center my-3">
<h1 class="d-block my-0">
@ -23,6 +25,7 @@
<script>
import "@h2d2/shopicons/es/regular/arrowup";
import TopNavigation from "./TopNavigation.vue";
import OfflineIndicator from "./OfflineIndicator.vue";
import Notifications from "./Notifications.vue";
import Energyflow from "./Energyflow/Energyflow.vue";
import Loadpoints from "./Loadpoints.vue";
@ -33,12 +36,21 @@ import collector from "../mixins/collector";
export default {
name: "Site",
components: { Loadpoints, Energyflow, Footer, Notifications, TopNavigation, Vehicles },
components: {
Loadpoints,
Energyflow,
Footer,
OfflineIndicator,
Notifications,
TopNavigation,
Vehicles,
},
mixins: [formatter, collector],
props: {
loadpoints: Array,
notifications: Array,
offline: Boolean,
// details
gridConfigured: Boolean,

View file

@ -137,4 +137,8 @@ export default {
`,
},
},
offline: {
message: "Keine Verbindung zum Server.",
reload: "Reload?",
},
};

View file

@ -137,4 +137,8 @@ export default {
`,
},
},
offline: {
message: "No connection to server.",
reload: "Reload?",
},
};

View file

@ -3,7 +3,7 @@
<metainfo>
<template #title="{ content }">{{ content ? `${content} | evcc` : `evcc` }}</template>
</metainfo>
<router-view :notifications="notifications"></router-view>
<router-view :notifications="notifications" :offline="offline"></router-view>
</div>
</template>
@ -14,6 +14,10 @@ export default {
name: "App",
props: {
notifications: Array,
offline: Boolean,
},
data: () => {
return { reconnectTimeout: null };
},
created: function () {
const urlParams = new URLSearchParams(window.location.search);
@ -21,7 +25,12 @@ export default {
setTimeout(this.connect, 0);
},
methods: {
reconnect: function () {
window.clearTimeout(this.reconnectTimeout);
this.reconnectTimeout = window.setTimeout(this.connect, 1000);
},
connect: function () {
console.log("connecting websocket");
const supportsWebSockets = "WebSocket" in window;
if (!supportsWebSockets) {
window.app.error({
@ -39,12 +48,20 @@ export default {
(loc.port ? ":" + loc.port : "") +
loc.pathname +
"ws";
const ws = new WebSocket(uri);
ws.onerror = () => {
console.error({ message: "Websocket error. Trying to reconnect." });
ws.close();
};
ws.onopen = () => {
console.log("websocket connected");
window.app.setOnline();
};
ws.onclose = () => {
window.setTimeout(this.connect, 1000);
console.log("websocket disconnected");
window.app.setOffline();
this.reconnect();
};
ws.onmessage = (evt) => {
try {

View file

@ -1,6 +1,11 @@
<template>
<div>
<Site v-if="configured" :notifications="notifications" v-bind="state"></Site>
<Site
v-if="configured"
:notifications="notifications"
:offline="offline"
v-bind="state"
></Site>
<div v-else class="container">
<div class="row py-5">
<div class="col12">
@ -88,6 +93,7 @@ export default {
components: { Site },
props: {
notifications: Array,
offline: Boolean,
},
data: function () {
return store;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
dist/index.html vendored
View file

@ -20,8 +20,8 @@
<meta name="theme-color" content="#28293e" />
<title>evcc</title>
<script type="module" crossorigin src="./assets/index.61d9e798.js"></script>
<link rel="stylesheet" href="./assets/index.a4ef9a54.css">
<script type="module" crossorigin src="./assets/index.e9c8c81b.js"></script>
<link rel="stylesheet" href="./assets/index.dca955c6.css">
</head>
<body>
<script>