Moved Header into separate component, added ConnectionMonitor
continuous-integration/drone Build is failing Details

This commit is contained in:
Erki Aas 2022-11-17 14:37:20 +02:00
parent 4452819aed
commit 9fb5d34118
5 changed files with 168 additions and 28 deletions

View File

@ -0,0 +1,85 @@
<template>
<v-tooltip :text="`Last ping from server received at ${secondsFromLastPing} seconds ago`" location="bottom">
<template v-slot:activator="{ props }">
<v-icon :color="(secondsFromLastPing > pingThreshold || secondsFromLastPing === null) ? 'red' : 'green'" v-bind="props" class="mr-6">mdi-server</v-icon>
</template>
</v-tooltip>
</template>
<script>
import { VTooltip } from 'vuetify/components/VTooltip'
import { VIcon } from 'vuetify/components/VIcon'
import {mapGetters} from "vuex";
export default {
name: "ConnectionMonitor",
components: {
VTooltip,
VIcon
},
data() {
return {
pingThreshold: 10,
pingError: false,
secondsFromLastPing: null,
setupStreamInterval: null,
}
},
computed: {
...mapGetters([
'lastPingReceived'
])
},
mounted() {
// window.setInterval(() => {
// this.monitorServerConnection()
// }, 10000)
window.setInterval(() => {
this.secondsFromLastPing = Math.floor(((new Date()).getTime() - this.lastPingReceived) / 1000)
this.pingError = this.secondsFromLastPing > this.pingThreshold
}, 1000)
},
watch: {
pingError(error) {
if (error) {
this.$toast.error(`Connection with server lost, attempting to reconnect...`, {
position: "top-right",
duration: false,
});
this.setupStreamInterval = window.setInterval(() => {
this.$emit('setupStream')
}, 3000)
} else {
window.clearTimeout(this.setupStreamInterval);
this.$toast.clear();
this.$toast.success(`Connection with server reestablished`, {
position: "top-right",
});
}
},
},
methods: {
monitorServerConnection () {
if (this.secondsFromLastPing > this.pingThreshold) {
this.pingError = true;
this.$toast.error(`Connection with server lost, attempting to reconnect...`, {
position: "top-right",
});
this.setupStream();
} else {
if (this.pingError) {
this.$toast.success(`Connection with server reestablished`, {
position: "top-right",
});
setTimeout(this.$toast.clear, 3000);
}
this.pingError = false;
}
}
}
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,58 @@
<template>
<v-row no-gutters>
<v-col cols="12" sm="5" class="d-flex justify-start flex-wrap" >
<Datepicker class="ma-2" :refresh="refreshFilterState" />
</v-col>
<v-col cols="12" sm="2" class="d-flex justify-center flex-wrap">
<h1 class="app-title"> Logmower </h1>
</v-col>
<v-col cols="12" sm="5" class="d-flex justify-end flex-wrap align-center">
<ConnectionMonitor @setup-stream="setupStream" />
<v-btn
color="blue-grey"
class="ma-2"
:prepend-icon="streaming ? 'mdi-pause' :'mdi-play'"
@click="toggleFilterQueryStreaming"
>
Stream new lines
</v-btn>
</v-col>
</v-row>
</template>
<script>
import { VRow, VCol } from 'vuetify/components/VGrid'
import { VBtn } from 'vuetify/components/VBtn'
import Datepicker from "../Grid/Main/Filter/Datepicker.vue";
import {mapActions, mapGetters} from "vuex";
import ConnectionMonitor from "./ConnectionMonitor.vue";
export default {
components: {
ConnectionMonitor,
Datepicker,
VRow,
VCol,
VBtn
},
props: {
refreshFilterState: Function
},
computed: {
...mapGetters([
'streaming'
]),
},
methods: {
...mapActions({
toggleFilterQueryStreaming: 'toggleFilterQueryStreaming',
}),
setupStream () {
this.$emit('setupStream')
}
}
}
</script>
<style scoped>
</style>

View File

@ -1,23 +1,6 @@
<template>
<div style="height: 100%; width: 100%;" v-resize="onResize">
<v-row no-gutters>
<v-col cols="12" sm="5" class="d-flex justify-start flex-wrap">
<Datepicker class="ma-2" :refresh="refreshFilterState" />
</v-col>
<v-col cols="12" sm="2" class="d-flex justify-center flex-wrap">
<h1 class="app-title"> Logmower </h1>
</v-col>
<v-col cols="12" sm="5" class="d-flex justify-end flex-wrap">
<v-btn
color="blue-grey"
class="ma-2"
:prepend-icon="streaming ? 'mdi-pause' :'mdi-play'"
@click="toggleFilterQueryStreaming"
>
Stream new lines
</v-btn>
</v-col>
</v-row>
<Header :refresh-filter-state="refreshFilterState" @setup-stream="setupStream" />
<ag-grid-vue
style="width: 100%; height: calc(100% - 52px);"
class="ag-theme-material"
@ -44,8 +27,6 @@
import { AgGridVue } from "ag-grid-vue3";
import "ag-grid-community/styles//ag-grid.css";
import "ag-grid-community/styles//ag-theme-material.css";
import { VBtn } from 'vuetify/components/VBtn'
import { VRow, VCol } from 'vuetify/components/VGrid'
import { Resize } from 'vuetify/directives';
import ExamineLogModal from "./Modal/ExamineLogModal.vue";
import ComboboxFilter from "./Grid/Main/Filter/ComboboxFilter.js";
@ -54,19 +35,16 @@ import flattenObj from "../helpers/flattenObj";
import parseEventData from "../helpers/parseEventData";
import {mapActions, mapGetters} from 'vuex';
import config from "./Grid/Main/config";
import Datepicker from "./Grid/Main/Filter/Datepicker.vue";
import loadingOverlay from "./Grid/Main/loadingOverlay";
import Header from "./Header/Header.vue";
export default {
components: {
Datepicker,
Header,
ExamineLogModal,
AgGridVue,
ComboboxFilter,
MessageWithLevelRenderer,
VBtn,
VRow,
VCol,
loadingOverlay
},
directives: {
@ -110,7 +88,7 @@ export default {
...mapActions({
setFilterOptions: 'setFilterOptions',
setFilterQuery: 'setFilterQuery',
toggleFilterQueryStreaming: 'toggleFilterQueryStreaming',
setLastPingReceived: 'setLastPingReceived',
}),
onResize () {
if (this.gridApi) {
@ -129,6 +107,7 @@ export default {
if (url.searchParams.keys().next()) {
let es = new EventSource(url.toString());
es.onmessage = (e) => this.handleReceiveMessage(e)
es.addEventListener("ping", (e) => this.handleReceivePing())
es.addEventListener("filters", (e) => this.handleReceiveFilters(e))
es.addEventListener("timeout", (e) => this.handleReceiveTimeout(e))
es.addEventListener("completed", (e) => this.handleAllReceived(e))
@ -247,6 +226,9 @@ export default {
handleAllReceived () {
this.gridApi.hideOverlay();
},
handleReceivePing () {
this.setLastPingReceived()
},
doesExternalFilterPass(node) {
if (node.data && this.filterQuery.from && this.filterQuery.to) {
let ts = new Date(node.data['@timestamp']).getTime()

View File

@ -4,6 +4,7 @@ const store = createStore({
state: {
filterOptions: {},
filterQuery: {},
lastPingReceived: null,
},
getters: {
streaming (state) {
@ -11,7 +12,10 @@ const store = createStore({
},
filterQuery (state) {
return state.filterQuery
}
},
lastPingReceived (state) {
return state.lastPingReceived
},
},
actions: {
setFilterOptions(context, payload) {
@ -30,6 +34,9 @@ const store = createStore({
query.streaming = false
commit("SET_FILTER_QUERY", query);
},
setLastPingReceived(context) {
context.commit("SET_LAST_PING_RECEIVED");
},
},
mutations: {
SET_FILTER_OPTIONS(state, payload) {
@ -55,6 +62,9 @@ const store = createStore({
state.filterQuery = query
},
SET_LAST_PING_RECEIVED(state) {
state.lastPingReceived = (new Date()).getTime()
}
},
});

View File

@ -22,5 +22,10 @@ export default {
vuetify: {
// https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vuetify-loader
}
}
},
optimizeDeps: {
exclude: [
"@meforma/vue-toaster"
]
},
}