Feature: Added pull to refresh and websocket indicator

This commit is contained in:
Thomas Basler 2024-01-06 20:03:52 +01:00
parent 7b5d31efca
commit 024ee26705
7 changed files with 147 additions and 18 deletions

View File

@ -28,6 +28,7 @@
"@tsconfig/node18": "^18.2.2",
"@types/bootstrap": "^5.2.10",
"@types/node": "^20.10.6",
"@types/pulltorefreshjs": "^0.1.7",
"@types/sortablejs": "^1.15.7",
"@types/spark-md5": "^3.0.4",
"@vitejs/plugin-vue": "^5.0.2",
@ -36,6 +37,7 @@
"eslint": "^8.56.0",
"eslint-plugin-vue": "^9.19.2",
"npm-run-all": "^4.1.5",
"pulltorefreshjs": "^0.1.22",
"sass": "^1.69.7",
"terser": "^5.26.0",
"typescript": "^5.3.3",

View File

@ -4,7 +4,12 @@
<div class="page-header">
<div class="row">
<div class="col-sm-11">
<h1>{{ title }}</h1>
<h1>{{ title }}
<span v-if="showWebSocket" :class="{
'onlineMarker': isWebsocketConnected,
'offlineMarker': !isWebsocketConnected,
}"></span>
</h1>
</div>
<div class="col-sm-1" v-if="showReload">
<button type="button" class="float-end btn btn-outline-primary"
@ -28,6 +33,7 @@
<script lang="ts">
import { defineComponent } from 'vue';
import { BIconArrowClockwise } from 'bootstrap-icons-vue';
import PullToRefresh from 'pulltorefreshjs';
export default defineComponent({
components: {
@ -37,7 +43,81 @@ export default defineComponent({
title: { type: String, required: true },
isLoading: { type: Boolean, required: false, default: false },
isWideScreen: { type: Boolean, required: false, default: false },
isWebsocketConnected: { type: Boolean, required: false, default: false },
showWebSocket: { type: Boolean, required: false, default: false },
showReload: { type: Boolean, required: false, default: false },
},
mounted() {
var self = this;
console.log("init");
PullToRefresh.init({
mainElement: 'main', // above which element?
instructionsPullToRefresh: this.$t('base.Pull'),
instructionsReleaseToRefresh: this.$t('base.Release'),
instructionsRefreshing: this.$t('base.Refreshing'),
onRefresh: function() {
self.$emit('reload');
}
});
},
unmounted() {
console.log("destroy");
PullToRefresh.destroyAll();
},
});
</script>
<style>
.ptr--text {
color: var(--bs-primary-text-emphasis) !important;
}
.ptr--icon {
color: var(--bs-primary-text-emphasis) !important;
}
.offlineMarker:before {
content: '';
position: absolute;
width: 8px;
height: 8px;
background: #ff0000;
border-color: #ff0000;
border-radius: 50%;
}
.onlineMarker:before {
content: '';
position: absolute;
width: 8px;
height: 8px;
background: #00bb00;
border-color: #00bb00;
border-radius: 50%;
}
.onlineMarker:after {
content: '';
position: absolute;
width: 32px;
height: 32px;
margin: -12px 0 0 -12px;
border: 1px solid #00bb00;
border-radius: 50%;
box-shadow: 0 0 4px #00bb00, inset 0 0 4px rgb(56, 111, 169);
transform: scale(0);
animation: online 2.5s ease-in-out infinite;
}
@keyframes online {
0% {
transform: scale(.1);
opacity: 1;
}
70% {
transform: scale(2.5);
opacity: 0;
}
100% {
opacity: 0;
}
}
</style>

View File

@ -26,7 +26,10 @@
"Loading": "Lade...",
"Reload": "Aktualisieren",
"Cancel": "Abbrechen",
"Save": "Speichern"
"Save": "Speichern",
"Refreshing": "Aktualisieren",
"Pull": "Zum Aktualisieren nach unten ziehen",
"Release": "Loslassen zum Aktualisieren"
},
"localeswitcher": {
"Dark": "Dunkel",

View File

@ -26,7 +26,10 @@
"Loading": "Loading...",
"Reload": "Reload",
"Cancel": "Cancel",
"Save": "Save"
"Save": "Save",
"Refreshing": "Refreshing",
"Pull": "Pull down to refresh",
"Release": "Release to refresh"
},
"localeswitcher": {
"Dark": "Dark",

View File

@ -26,7 +26,10 @@
"Loading": "Chargement...",
"Reload": "Reload",
"Cancel": "Annuler",
"Save": "Sauvegarder"
"Save": "Sauvegarder",
"Refreshing": "Refreshing",
"Pull": "Pull down to refresh",
"Release": "Release to refresh"
},
"localeswitcher": {
"Dark": "Sombre",

View File

@ -1,5 +1,5 @@
<template>
<BasePage :title="$t('home.LiveData')" :isLoading="dataLoading" :isWideScreen="true">
<BasePage :title="$t('home.LiveData')" :isLoading="dataLoading" :isWideScreen="true" :showWebSocket="true" :isWebsocketConnected="isWebsocketConnected" @reload="reloadData">
<HintView :hints="liveData.hints" />
<InverterTotalInfo :totalData="liveData.total" /><br />
<div class="row gy-3">
@ -448,6 +448,8 @@ export default defineComponent({
alertTypePower: "info",
showAlertPower: false,
successCommandPower: "",
isWebsocketConnected: false,
};
},
created() {
@ -475,17 +477,23 @@ export default defineComponent({
this.closeSocket();
},
updated() {
console.log("Updated");
// Select first tab
if (this.isFirstFetchAfterConnect) {
this.isFirstFetchAfterConnect = false;
console.log("isFirstFetchAfterConnect");
this.$nextTick(() => {
console.log("nextTick");
const firstTabEl = document.querySelector(
"#v-pills-tab:first-child button"
);
if (firstTabEl != null) {
this.isFirstFetchAfterConnect = false;
console.log("Show");
const firstTab = new bootstrap.Tab(firstTabEl);
firstTab.show();
}
});
}
},
computed: {
@ -508,15 +516,27 @@ export default defineComponent({
},
methods: {
isLoggedIn,
getInitialData() {
getInitialData(triggerLoading : boolean = true) {
if (triggerLoading) {
this.dataLoading = true;
}
fetch("/api/livedata/status", { headers: authHeader() })
.then((response) => handleResponse(response, this.$emitter, this.$router))
.then((data) => {
this.liveData = data;
if (triggerLoading) {
this.dataLoading = false;
}
});
},
reloadData() {
this.closeSocket();
setTimeout(() => {
this.getInitialData(false);
this.initSocket();
}, 1000);
},
initSocket() {
console.log("Starting connection to WebSocket Server");
@ -540,11 +560,19 @@ export default defineComponent({
}
};
var self = this;
this.socket.onopen = function (event) {
console.log(event);
console.log("Successfully connected to the echo websocket server...");
self.isWebsocketConnected = true;
};
this.socket.onclose = function() {
console.log("Connection to websocket closed...")
self.isWebsocketConnected = false;
}
// Listen to window events , When the window closes , Take the initiative to disconnect websocket Connect
window.onbeforeunload = () => {
this.closeSocket();

View File

@ -442,6 +442,11 @@
dependencies:
undici-types "~5.26.4"
"@types/pulltorefreshjs@^0.1.7":
version "0.1.7"
resolved "https://registry.yarnpkg.com/@types/pulltorefreshjs/-/pulltorefreshjs-0.1.7.tgz#1948638b0c7071282e47bd236d2ccb88bdf66753"
integrity sha512-Y0g/yfuycIvpvUmP97n5NE2+HDAOwfREGVERjhMWw2Y0ODh5wvbflcQ5gXPZ+ihgoq+BQZjA1DL8apw2wAsJXA==
"@types/semver@^7.5.0":
version "7.5.1"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.1.tgz#0480eeb7221eb9bc398ad7432c9d7e14b1a5a367"
@ -2142,6 +2147,11 @@ prelude-ls@~1.1.2:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==
pulltorefreshjs@^0.1.22:
version "0.1.22"
resolved "https://registry.yarnpkg.com/pulltorefreshjs/-/pulltorefreshjs-0.1.22.tgz#ddb5e3feee0b2a49fd46e1b18e84fffef2c47ac0"
integrity sha512-haxNVEHnS4NCQA7NeG7TSV69z4uqy/N7nfPRuc4dPWe8H6ygUrMjdNeohE+6v0lVVX/ukSjbLYwPUGUYtFKfvQ==
punycode@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"