Date range picker for querying by timestamp

This commit is contained in:
Erki Aas 2022-11-11 15:35:42 +02:00
parent 6485e66931
commit 87dee71a8c
5 changed files with 143 additions and 14 deletions

View File

@ -21,6 +21,7 @@
"vue": "^3.2.39",
"vuex": "next",
"vue-select": "beta",
"v-calendar": "next",
"@meforma/vue-toaster": "^1.3.0",
"vuetify": "^3.0.0-beta.0",
"webfontloader": "^1.0.0"

View File

@ -0,0 +1,81 @@
<template>
<v-date-picker mode="dateTime" v-model="dateRange" locale="et" :is24hr="true" is-range timezone="UTC">
<template v-slot="{ inputValue, inputEvents }">
<div class="flex justify-center items-center">
<input
:value="inputValue.start"
v-on="inputEvents.start"
class="border px-2 py-1 w-32 rounded focus:outline-none focus:border-indigo-300"
/>
<svg
class="w-4 h-4 mx-2"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
width="20"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M14 5l7 7m0 0l-7 7m7-7H3"
/>
</svg>
<input
:value="inputValue.end"
v-on="inputEvents.end"
class="border px-2 py-1 w-32 rounded focus:outline-none focus:border-indigo-300"
/>
</div>
</template>
</v-date-picker>
</template>
<script>
import {mapActions, mapGetters} from "vuex";
export default {
name: "Datepicker",
props: {
refresh: {}
},
data() {
return {
}
},
computed: {
...mapGetters([
'filterQuery',
]),
dateRange: {
get() {
return {
start: this.filterQuery.from ? new Date(this.filterQuery.from) : null,
end: this.filterQuery.to ? new Date(this.filterQuery.to) : null,
}
},
set(value) {
if (value) {
let toDate = new Date(value.end);
toDate.setSeconds(59, 999);
this.setFilterQueryTimeRange({
from: (new Date(value.start).getTime()),
to: (toDate.getTime()),
})
this.refresh()
}
}
}
},
methods: {
...mapActions({
setFilterQueryTimeRange: 'setFilterQueryTimeRange',
}),
}
}
</script>
<style scoped>
</style>

View File

@ -1,14 +1,24 @@
<template>
<div style="height: 100%; width: 100%; text-align: right">
<v-btn
color="blue-grey"
class="ma-2"
:prepend-icon="streaming ? 'mdi-pause' :'mdi-play'"
@click="toggleFilterQueryStreaming"
>
Stream new lines
</v-btn>
<ag-grid-vue
<div style="height: 100%; width: 100%;">
<v-row no-gutters>
<v-col cols="12" sm="4" class="d-flex justify-start flex-wrap">
<Datepicker class="ma-2" :refresh="refreshFilterState" />
</v-col>
<v-col cols="12" sm="4" class="d-flex justify-center flex-wrap">
<h1 class="app-title"> Logmower </h1>
</v-col>
<v-col cols="12" sm="4" 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>
<ag-grid-vue
style="width: 100%; height: calc(100% - 52px);"
class="ag-theme-material"
@grid-ready="onGridReady"
@ -22,6 +32,8 @@
:onRowSelected="openExamineLog"
:supress-horisontal-scroll="true"
:enable-scrolling="true"
:isExternalFilterPresent="() => {return true}"
:doesExternalFilterPass="doesExternalFilterPass"
></ag-grid-vue>
<ExamineLogModal :examine-log-content="examineLogContent" :close-modal="closeExamineLog" />
</div>
@ -32,6 +44,7 @@ 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 ExamineLogModal from "./Modal/ExamineLogModal.vue";
import ComboboxFilter from "./Grid/Main/Filter/ComboboxFilter.js";
import ErrLevelRenderer from "./Grid/Main/ErrLevelRenderer";
@ -39,14 +52,18 @@ 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";
export default {
components: {
Datepicker,
ExamineLogModal,
AgGridVue,
ComboboxFilter,
ErrLevelRenderer,
VBtn
VBtn,
VRow,
VCol
},
data() {
return {
@ -62,7 +79,7 @@ export default {
computed: {
...mapGetters([
'filterQuery',
'streaming',
'streaming'
]),
},
watch: {
@ -78,6 +95,8 @@ export default {
queryParams = Object.fromEntries(queryParams);
this.initialFilter = queryParams
queryParams['initial'] = true
queryParams['from'] && (queryParams['from'] = Number(queryParams['from']))
queryParams['to'] && (queryParams['to'] = Number(queryParams['to']))
this.setFilterQuery(queryParams)
},
methods: {
@ -86,6 +105,9 @@ export default {
setFilterQuery: 'setFilterQuery',
toggleFilterQueryStreaming: 'toggleFilterQueryStreaming',
}),
refreshFilterState() {
this.gridApi.onFilterChanged();
},
setupStream() {
this.es && this.es.close();
let url = new URL('/events', window.location.href);
@ -143,6 +165,8 @@ export default {
}
})
query['streaming'] = this.streaming
this.filterQuery.from && (query['from'] = this.filterQuery.from)
this.filterQuery.to && (query['to'] = this.filterQuery.to)
this.setFilterQuery(query)
}
});
@ -203,6 +227,13 @@ export default {
});
setTimeout(this.$toast.clear, 3000);
},
doesExternalFilterPass(node) {
if (node.data && this.filterQuery.from && this.filterQuery.to) {
let ts = new Date(node.data['@timestamp']).getTime()
return (ts >= this.filterQuery.from && ts <= this.filterQuery.to)
}
return true;
},
openExamineLog (row) {
const selectedRow = row.data
row.node.setSelected(false)

View File

@ -3,14 +3,17 @@ import store from "./stores";
import App from './App.vue'
import vuetify from './plugins/vuetify'
import Toaster from "@meforma/vue-toaster";
import VCalendar from 'v-calendar';
import { loadFonts } from './plugins/webfontloader'
import './assets/main.css'
import 'vue-select/dist/vue-select.css';
import 'v-calendar/dist/style.css';
loadFonts()
const app = createApp(App);
app.use(store);
app.use(vuetify);
app.use(Toaster);
app.use(VCalendar, {});
app.mount("#app");

View File

@ -23,6 +23,13 @@ const store = createStore({
toggleFilterQueryStreaming(context) {
context.commit("TOGGLE_FILTER_QUERY_STREAMING");
},
setFilterQueryTimeRange({commit, state}, {from, to}) {
let query = state.filterQuery
query.from = from
query.to = to
query.streaming = false
commit("SET_FILTER_QUERY", query);
},
},
mutations: {
SET_FILTER_OPTIONS(state, payload) {
@ -37,9 +44,15 @@ const store = createStore({
},
TOGGLE_FILTER_QUERY_STREAMING(state) {
let query = state.filterQuery
query['streaming'] = (query['streaming'] === undefined) ? false : query['streaming']
query['streaming'] = !(query['streaming'])
let streaming = (query['streaming'] === undefined) ? false : query['streaming']
query['streaming'] = !(streaming)
query['initial'] = false
if (!streaming) {
delete query['from']
delete query['to']
}
state.filterQuery = query
},
},