Date range picker for querying by timestamp
This commit is contained in:
parent
6485e66931
commit
87dee71a8c
@ -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"
|
||||
|
81
src/components/Grid/Main/Filter/Datepicker.vue
Normal file
81
src/components/Grid/Main/Filter/Datepicker.vue
Normal 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>
|
@ -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)
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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
|
||||
},
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user