mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-06 00:09:22 +00:00
fix: UI Improvements (#1148)
1. Refactored date time component and updated same in logs, traces and metrics 2. Added composable for notification
This commit is contained in:
+317
-154
@@ -14,7 +14,7 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div icon="info" class="justify-between">
|
||||
<div icon="info" class="justify-between date-time-container">
|
||||
<q-btn
|
||||
data-test="date-time-btn"
|
||||
id="date-time-button"
|
||||
@@ -26,34 +26,40 @@
|
||||
icon="schedule"
|
||||
icon-right="arrow_drop_down"
|
||||
class="date-time-button"
|
||||
:class="selectedType + 'type'"
|
||||
>
|
||||
<q-menu
|
||||
id="date-time-menu"
|
||||
class="date-time-dialog"
|
||||
anchor="bottom left"
|
||||
self="top left"
|
||||
@before-show="onBeforeShow"
|
||||
>
|
||||
<div class="flex justify-evenly q-py-sm">
|
||||
<q-btn
|
||||
size="md"
|
||||
class="tab-button no-border"
|
||||
color="primary"
|
||||
:flat="selectedDate.tab !== 'relative'"
|
||||
@click="selectedDate.tab = 'relative'"
|
||||
no-caps
|
||||
:flat="selectedType !== 'relative'"
|
||||
@click="selectedType = 'relative'"
|
||||
>
|
||||
RELATIVE
|
||||
Relative
|
||||
</q-btn>
|
||||
<q-separator vertical inset />
|
||||
<q-btn
|
||||
size="md"
|
||||
class="tab-button no-border"
|
||||
color="primary"
|
||||
:flat="selectedDate.tab !== 'absolute'"
|
||||
@click="selectedDate.tab = 'absolute'"
|
||||
no-caps
|
||||
:flat="selectedType !== 'absolute'"
|
||||
@click="selectedType = 'absolute'"
|
||||
>
|
||||
ABSOLUTE
|
||||
Absolute
|
||||
</q-btn>
|
||||
</div>
|
||||
<q-separator />
|
||||
<q-tab-panels v-model="selectedDate.tab" animated>
|
||||
<q-tab-panels v-model="selectedType" animated>
|
||||
<q-tab-panel name="relative" class="q-pa-none">
|
||||
<div class="date-time-table relative column">
|
||||
<div
|
||||
@@ -62,7 +68,7 @@
|
||||
:key="'date_' + index"
|
||||
>
|
||||
<div class="relative-period-name">
|
||||
{{ period.value }}
|
||||
{{ period.label }}
|
||||
</div>
|
||||
<div
|
||||
v-for="(item, item_index) in relativeDates[period.value]"
|
||||
@@ -71,17 +77,17 @@
|
||||
<q-btn
|
||||
:data-test="`date-time-relative-${item}-${period.value}-btn`"
|
||||
:class="
|
||||
selectedDate.tab == 'relative' &&
|
||||
selectedDate.relative.period.value == period.value &&
|
||||
selectedDate.relative.value == item
|
||||
selectedType == 'relative' &&
|
||||
relativePeriod == period.value &&
|
||||
relativeValue == item
|
||||
? 'rp-selector-selected'
|
||||
: `rp-selector ${selectedDate.relative.period.value}`
|
||||
: `rp-selector ${relativePeriod}`
|
||||
"
|
||||
:label="item"
|
||||
outline
|
||||
dense
|
||||
flat
|
||||
@click="setRelativeDate(period, item)"
|
||||
@click="setRelativeDate(period.value, item)"
|
||||
:key="'period_' + item_index"
|
||||
/>
|
||||
</div>
|
||||
@@ -93,22 +99,27 @@
|
||||
<div class="row q-gutter-sm">
|
||||
<div class="col">
|
||||
<q-input
|
||||
v-model="selectedDate.relative.value"
|
||||
v-model="relativeValue"
|
||||
type="number"
|
||||
dense
|
||||
filled
|
||||
min="1"
|
||||
@change="calculateMaxValue"
|
||||
></q-input>
|
||||
@update:model-value="onCustomPeriodSelect"
|
||||
/>
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-select
|
||||
v-model="selectedDate.relative.period"
|
||||
v-model="relativePeriod"
|
||||
:options="relativePeriods"
|
||||
dense
|
||||
filled
|
||||
emit-value
|
||||
@update:modelValue="onCustomPeriodSelect"
|
||||
></q-select>
|
||||
>
|
||||
<template v-slot:selected-item>
|
||||
<div>{{ getPeriodLabel }}</div>
|
||||
</template>
|
||||
</q-select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -118,7 +129,8 @@
|
||||
<div class="date-time-table">
|
||||
<div class="flex justify-center q-pa-none">
|
||||
<q-date
|
||||
v-model="selectedDate.absolute.date"
|
||||
size="sm"
|
||||
v-model="selectedDate"
|
||||
class="absolute-calendar"
|
||||
range
|
||||
:locale="{
|
||||
@@ -137,7 +149,7 @@
|
||||
<tr>
|
||||
<td>
|
||||
<q-input
|
||||
v-model="selectedDate.absolute.startTime"
|
||||
v-model="selectedTime.startTime"
|
||||
dense
|
||||
filled
|
||||
mask="time"
|
||||
@@ -149,7 +161,7 @@
|
||||
transition-show="scale"
|
||||
transition-hide="scale"
|
||||
>
|
||||
<q-time v-model="selectedDate.absolute.startTime">
|
||||
<q-time v-model="selectedTime.startTime">
|
||||
<div class="row items-center justify-end">
|
||||
<q-btn
|
||||
v-close-popup
|
||||
@@ -166,7 +178,7 @@
|
||||
</td>
|
||||
<td>
|
||||
<q-input
|
||||
v-model="selectedDate.absolute.endTime"
|
||||
v-model="selectedTime.endTime"
|
||||
dense
|
||||
filled
|
||||
mask="time"
|
||||
@@ -178,7 +190,7 @@
|
||||
transition-show="scale"
|
||||
transition-hide="scale"
|
||||
>
|
||||
<q-time v-model="selectedDate.absolute.endTime">
|
||||
<q-time v-model="selectedTime.endTime">
|
||||
<div class="row items-center justify-end">
|
||||
<q-btn
|
||||
v-close-popup
|
||||
@@ -198,6 +210,19 @@
|
||||
</div>
|
||||
</q-tab-panel>
|
||||
</q-tab-panels>
|
||||
<div v-if="!autoApply" class="flex justify-end q-py-sm q-px-md">
|
||||
<q-separator class="q-my-sm" />
|
||||
<q-btn
|
||||
class="no-border q-py-xs"
|
||||
color="secondary"
|
||||
no-caps
|
||||
size="md"
|
||||
@click="saveDate(null)"
|
||||
v-close-popup
|
||||
>
|
||||
Apply
|
||||
</q-btn>
|
||||
</div>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
</div>
|
||||
@@ -205,153 +230,295 @@
|
||||
|
||||
<script lang="ts">
|
||||
// @ts-nocheck
|
||||
import { ref, defineComponent } from "vue";
|
||||
import {
|
||||
ref,
|
||||
defineComponent,
|
||||
computed,
|
||||
onMounted,
|
||||
onBeforeMount,
|
||||
watch,
|
||||
} from "vue";
|
||||
import { getImageURL } from "../utils/zincutils";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { date } from "quasar";
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
defaultDate: {
|
||||
defaultType: {
|
||||
type: String,
|
||||
default: "relative",
|
||||
},
|
||||
defaultAbsoluteTime: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
relativePeriods: [
|
||||
{ label: "Minutes", value: "Minutes" },
|
||||
{ label: "Hours", value: "Hours" },
|
||||
{ label: "Days", value: "Days" },
|
||||
{ label: "Weeks", value: "Weeks" },
|
||||
{ label: "Months", value: "Months" },
|
||||
],
|
||||
relativeDates: {
|
||||
Minutes: [1, 5, 10, 15, 30, 45],
|
||||
Hours: [1, 2, 3, 6, 8, 12],
|
||||
Days: [1, 2, 3, 4, 5, 6],
|
||||
Weeks: [1, 2, 3, 4, 5, 6],
|
||||
Months: [1, 2, 3, 4, 5, 6],
|
||||
},
|
||||
selectedDate: {
|
||||
tab: "relative",
|
||||
relative: {
|
||||
period: { label: "Minutes", value: "Minutes" },
|
||||
value: 15,
|
||||
},
|
||||
absolute: {
|
||||
date: {
|
||||
from: new Date().toLocaleDateString("en-ZA"),
|
||||
to: new Date().toLocaleDateString("en-ZA"),
|
||||
},
|
||||
startTime: "00:00",
|
||||
endTime: "23:59",
|
||||
},
|
||||
userChangedValue: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
setRelativeDate(period, value) {
|
||||
this.selectedDate.tab = "relative";
|
||||
this.selectedDate.relative.period = period;
|
||||
this.selectedDate.relative.value = value;
|
||||
this.$refs.datetimeBtn.$el.click();
|
||||
defaultRelativeTime: {
|
||||
type: String,
|
||||
default: "15m",
|
||||
},
|
||||
onCustomPeriodSelect() {
|
||||
this.selectedDate.relative.value = 1;
|
||||
autoApply: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: ["date-change"],
|
||||
setup() {
|
||||
const getDate = () => {
|
||||
return this.selectedDate;
|
||||
|
||||
emits: ["on:date-change"],
|
||||
|
||||
setup(props, { emit }) {
|
||||
const selectedType = ref("relative");
|
||||
const selectedTime = ref({
|
||||
startTime: "00:00",
|
||||
endTime: "23:59",
|
||||
});
|
||||
const selectedDate = ref({
|
||||
from: "",
|
||||
to: "",
|
||||
});
|
||||
const relativePeriod = ref("m");
|
||||
const relativeValue = ref(15);
|
||||
|
||||
const relativePeriods = [
|
||||
{ label: "Minutes", value: "m" },
|
||||
{ label: "Hours", value: "h" },
|
||||
{ label: "Days", value: "d" },
|
||||
{ label: "Weeks", value: "w" },
|
||||
{ label: "Months", value: "M" },
|
||||
];
|
||||
const relativeDates = {
|
||||
m: [1, 5, 10, 15, 30, 45],
|
||||
h: [1, 2, 3, 6, 8, 12],
|
||||
d: [1, 2, 3, 4, 5, 6],
|
||||
w: [1, 2, 3, 4, 5, 6],
|
||||
M: [1, 2, 3, 4, 5, 6],
|
||||
};
|
||||
|
||||
const setDate = (date: Object) => {
|
||||
this.selectedDate = date;
|
||||
const datetimeBtn = ref(null);
|
||||
|
||||
const displayValue = ref("");
|
||||
|
||||
onMounted(() => {
|
||||
// updateDisplayValue();
|
||||
try {
|
||||
selectedType.value = props.defaultType;
|
||||
setAbsoluteTime(
|
||||
props.defaultAbsoluteTime?.startTime,
|
||||
props.defaultAbsoluteTime?.endTime
|
||||
);
|
||||
setRelativeTime(props.defaultRelativeTime);
|
||||
displayValue.value = getDisplayValue();
|
||||
if (props.autoApply) saveDate(props.defaultType);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
() => selectedType.value,
|
||||
() => {
|
||||
displayValue.value = getDisplayValue();
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => {
|
||||
selectedTime.value.startTime;
|
||||
selectedTime.value.endTime;
|
||||
selectedDate.value.from;
|
||||
selectedDate.value.to;
|
||||
},
|
||||
() => {
|
||||
if (props.autoApply) saveDate("absolute");
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
const setRelativeDate = (period, value) => {
|
||||
selectedType.value = "relative";
|
||||
relativePeriod.value = period;
|
||||
relativeValue.value = value;
|
||||
if (props.autoApply) saveDate("relative");
|
||||
};
|
||||
|
||||
const datetimeBtn = ref();
|
||||
const onCustomPeriodSelect = () => {
|
||||
if (props.autoApply) saveDate("relative-custom");
|
||||
};
|
||||
|
||||
return { getDate, setDate, datetimeBtn, getImageURL };
|
||||
},
|
||||
beforeMount() {
|
||||
if (this.defaultDate) this.selectedDate = cloneDeep(this.defaultDate);
|
||||
},
|
||||
computed: {
|
||||
displayValue() {
|
||||
if (this.selectedDate.tab === "relative") {
|
||||
this.$emit("date-change", this.selectedDate);
|
||||
return `${this.selectedDate.relative.value} ${this.selectedDate.relative.period.label}`;
|
||||
} else {
|
||||
if (this.selectedDate.absolute.date != null) {
|
||||
if (typeof this.selectedDate.absolute.date != "object") {
|
||||
if (this.selectedDate.absolute.date != "") {
|
||||
this.selectedDate.absolute.date = {
|
||||
from: this.selectedDate.absolute.date,
|
||||
to: this.selectedDate.absolute.date,
|
||||
};
|
||||
} else {
|
||||
const todayDate = new Date().toLocaleDateString("en-ZA");
|
||||
this.selectedDate.absolute.date = {
|
||||
from: todayDate,
|
||||
to: todayDate,
|
||||
};
|
||||
}
|
||||
}
|
||||
const setRelativeTime = (period) => {
|
||||
const periodString = period?.match(/(\d+)([mhdwM])/);
|
||||
|
||||
this.$emit("date-change", this.selectedDate);
|
||||
return `${this.selectedDate.absolute.date.from} ${this.selectedDate.absolute.startTime} - ${this.selectedDate.absolute.date.to} ${this.selectedDate.absolute.endTime}`;
|
||||
} else {
|
||||
const todayDate = new Date().toLocaleDateString("en-ZA");
|
||||
this.selectedDate.absolute.date = {
|
||||
from: todayDate,
|
||||
to: todayDate,
|
||||
};
|
||||
if (periodString) {
|
||||
const periodValue = periodString[1];
|
||||
const periodUnit = periodString[2];
|
||||
|
||||
this.$emit("date-change", this.selectedDate);
|
||||
return `${todayDate} ${this.selectedDate.absolute.startTime} - ${todayDate} ${this.selectedDate.absolute.endTime}`;
|
||||
const periodUnits = ["m", "h", "d", "w", "M"];
|
||||
|
||||
if (periodUnits.includes(periodUnit)) {
|
||||
relativePeriod.value = periodUnit;
|
||||
}
|
||||
|
||||
if (periodValue) {
|
||||
relativeValue.value = parseInt(periodValue);
|
||||
}
|
||||
}
|
||||
},
|
||||
calculateMaxValue() {
|
||||
if (
|
||||
this.selectedDate.relative.period.value == "Minutes" &&
|
||||
this.selectedDate.relative.value > 60
|
||||
) {
|
||||
this.selectedDate.relative.value = 60;
|
||||
return false;
|
||||
} else if (
|
||||
this.selectedDate.relative.period.value == "Hours" &&
|
||||
this.selectedDate.relative.value > 24
|
||||
) {
|
||||
this.selectedDate.relative.value = 24;
|
||||
return false;
|
||||
} else if (
|
||||
this.selectedDate.relative.period.value == "Days" &&
|
||||
this.selectedDate.relative.value > 31
|
||||
) {
|
||||
this.selectedDate.relative.value = 31;
|
||||
return false;
|
||||
} else if (
|
||||
this.selectedDate.relative.period.value == "Weeks" &&
|
||||
this.selectedDate.relative.value > 6
|
||||
) {
|
||||
this.selectedDate.relative.value = 6;
|
||||
return false;
|
||||
} else if (
|
||||
this.selectedDate.relative.period.value == "Months" &&
|
||||
this.selectedDate.relative.value > 6
|
||||
) {
|
||||
this.selectedDate.relative.value = 6;
|
||||
return false;
|
||||
};
|
||||
|
||||
const setAbsoluteTime = (startTime, endTime) => {
|
||||
if (!startTime || !endTime) {
|
||||
var dateString = new Date().toLocaleDateString("en-ZA");
|
||||
selectedDate.value.from = dateString;
|
||||
selectedDate.value.to = dateString;
|
||||
selectedTime.value.startTime = "00:00";
|
||||
selectedTime.value.endTime = "23:59";
|
||||
return;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
const startDateTime = convertUnixTime(startTime);
|
||||
const endDateTime = convertUnixTime(endTime);
|
||||
|
||||
selectedDate.value.from = startDateTime.date;
|
||||
selectedDate.value.to = endDateTime.date;
|
||||
|
||||
selectedTime.value.startTime = startDateTime.time;
|
||||
selectedTime.value.endTime = endDateTime.time;
|
||||
};
|
||||
|
||||
function convertUnixTime(unixTimeMicros) {
|
||||
// Convert microseconds to milliseconds and create a new Date object
|
||||
var date = new Date(unixTimeMicros / 1000);
|
||||
|
||||
// Extract hour, minute, day, month, and year
|
||||
const hours = ("0" + date.getHours()).slice(-2); // pad with leading zero if needed
|
||||
const minutes = ("0" + date.getMinutes()).slice(-2); // pad with leading zero if needed
|
||||
|
||||
// Build formatted strings
|
||||
var dateString = new Date(date).toLocaleDateString("en-ZA");
|
||||
var timeString = hours + ":" + minutes;
|
||||
|
||||
// Return both strings
|
||||
return { date: dateString, time: timeString };
|
||||
}
|
||||
|
||||
const refresh = () => {
|
||||
saveDate();
|
||||
};
|
||||
|
||||
const saveDate = (dateType) => {
|
||||
displayValue.value = getDisplayValue();
|
||||
const date = getConsumableDateTime();
|
||||
date["valueType"] = dateType || selectedType.value;
|
||||
emit("on:date-change", date);
|
||||
};
|
||||
|
||||
const onBeforeShow = () => {
|
||||
// if (props.modelValue) selectedDate.value = cloneDeep(props.modelValue);
|
||||
};
|
||||
|
||||
const getPeriodLabel = computed(() => {
|
||||
const periodMapping = {
|
||||
m: "Minutes",
|
||||
h: "Hours",
|
||||
d: "Days",
|
||||
w: "Weeks",
|
||||
M: "Months",
|
||||
};
|
||||
return periodMapping[relativePeriod.value];
|
||||
});
|
||||
|
||||
const getConsumableDateTime = () => {
|
||||
if (selectedType.value == "relative") {
|
||||
let period = getPeriodLabel.value.toLowerCase();
|
||||
let periodValue = relativeValue.value;
|
||||
|
||||
// quasar does not support arithmetic on weeks. convert to days.
|
||||
if (relativePeriod.value == "w") {
|
||||
period = "days";
|
||||
periodValue = periodValue * 7;
|
||||
}
|
||||
const subtractObject = '{"' + period + '":' + periodValue + "}";
|
||||
|
||||
const endTimeStamp = new Date();
|
||||
|
||||
const startTimeStamp = date.subtractFromDate(
|
||||
endTimeStamp,
|
||||
JSON.parse(subtractObject)
|
||||
);
|
||||
|
||||
return {
|
||||
startTime: new Date(startTimeStamp).getTime() * 1000,
|
||||
endTime: new Date(endTimeStamp).getTime() * 1000,
|
||||
relativeTimePeriod: relativeValue.value + relativePeriod.value,
|
||||
};
|
||||
} else {
|
||||
let start, end;
|
||||
if (!selectedDate.value.from && !selectedTime.value.startTime) {
|
||||
start = new Date();
|
||||
} else {
|
||||
start = new Date(
|
||||
selectedDate.value.from + " " + selectedTime.value.startTime
|
||||
);
|
||||
}
|
||||
|
||||
if (selectedDate.value.to == "" && selectedTime.value.endTime == "") {
|
||||
end = new Date();
|
||||
} else {
|
||||
end = new Date(
|
||||
selectedDate.value.to + " " + selectedTime.value.endTime
|
||||
);
|
||||
}
|
||||
const rVal = {
|
||||
startTime: new Date(start).getTime() * 1000,
|
||||
endTime: new Date(end).getTime() * 1000,
|
||||
relativeTimePeriod: null,
|
||||
};
|
||||
return rVal;
|
||||
}
|
||||
};
|
||||
|
||||
const getDisplayValue = () => {
|
||||
if (selectedType.value === "relative") {
|
||||
return `Past ${relativeValue.value} ${getPeriodLabel.value}`;
|
||||
} else {
|
||||
if (selectedDate.value != null) {
|
||||
return `${selectedDate.value.from} ${selectedTime.value.startTime} - ${selectedDate.value.to} ${selectedTime.value.endTime}`;
|
||||
} else {
|
||||
const todayDate = new Date().toLocaleDateString("en-ZA");
|
||||
return `${todayDate} ${selectedTime.value.startTime} - ${todayDate} ${selectedTime.value.endTime}`;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
datetimeBtn,
|
||||
getImageURL,
|
||||
onCustomPeriodSelect,
|
||||
setRelativeDate,
|
||||
relativePeriods,
|
||||
relativeDates,
|
||||
saveDate,
|
||||
onBeforeShow,
|
||||
selectedType,
|
||||
selectedTime,
|
||||
selectedDate,
|
||||
relativePeriod,
|
||||
relativeValue,
|
||||
getPeriodLabel,
|
||||
displayValue,
|
||||
refresh,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.date-time-container {
|
||||
.date-time-button {
|
||||
&.relativetype {
|
||||
}
|
||||
&.absolutetype {
|
||||
min-width: 286px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="scss">
|
||||
.q-btn--rectangle {
|
||||
border-radius: 3px;
|
||||
@@ -375,10 +542,6 @@ export default defineComponent({
|
||||
|
||||
.block {
|
||||
font-weight: 600;
|
||||
|
||||
&::before {
|
||||
content: "Past ";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -388,8 +551,8 @@ export default defineComponent({
|
||||
|
||||
.tab-button {
|
||||
&.q-btn {
|
||||
padding-bottom: 0.6rem;
|
||||
padding-top: 0.6rem;
|
||||
padding-bottom: 0.1rem;
|
||||
padding-top: 0.1rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
|
||||
@@ -452,7 +615,7 @@ export default defineComponent({
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
// border: $secondary;
|
||||
background: rgba(0,0,0,0.07);
|
||||
background: rgba(0, 0, 0, 0.07);
|
||||
}
|
||||
|
||||
.rp-selector-selected {
|
||||
|
||||
@@ -97,22 +97,10 @@ const defaultObject = {
|
||||
histogram: <any>{},
|
||||
editorValue: "",
|
||||
datetime: {
|
||||
tab: "relative",
|
||||
relative: {
|
||||
period: {
|
||||
label: "Minutes",
|
||||
value: "Minutes",
|
||||
},
|
||||
value: 15,
|
||||
},
|
||||
absolute: {
|
||||
date: {
|
||||
from: "",
|
||||
to: "",
|
||||
},
|
||||
startTime: "00:00",
|
||||
endTime: "23:59",
|
||||
},
|
||||
startTime: 0,
|
||||
endTime: 0,
|
||||
relativeTimePeriod: "15m",
|
||||
type: "relative",
|
||||
},
|
||||
searchAround: {
|
||||
indexTimestamp: 0,
|
||||
|
||||
@@ -62,22 +62,10 @@ const defaultObject = {
|
||||
streamResults: <any>[],
|
||||
histogram: <any>{},
|
||||
datetime: {
|
||||
tab: "relative",
|
||||
relative: {
|
||||
period: {
|
||||
label: "Minutes",
|
||||
value: "Minutes",
|
||||
},
|
||||
value: 15,
|
||||
},
|
||||
absolute: {
|
||||
date: {
|
||||
from: "",
|
||||
to: "",
|
||||
},
|
||||
startTime: "00:00",
|
||||
endTime: "23:59",
|
||||
},
|
||||
startTime: "",
|
||||
endTime: "",
|
||||
relativeTimePeriod: "15m",
|
||||
type: "relative",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { useQuasar } from "quasar";
|
||||
|
||||
const useNotifications = () => {
|
||||
const quasar = useQuasar();
|
||||
|
||||
const showErrorNotification = (message: string) => {
|
||||
return quasar.notify({
|
||||
type: "negative",
|
||||
message: message,
|
||||
timeout: 5000,
|
||||
actions: [
|
||||
{
|
||||
icon: "close",
|
||||
color: "white",
|
||||
handler: () => {
|
||||
/* ... */
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
showErrorNotification,
|
||||
};
|
||||
};
|
||||
|
||||
export default useNotifications;
|
||||
@@ -15,7 +15,10 @@ const usePromlqSuggestions = () => {
|
||||
open: (val: string) => {},
|
||||
close: (val: string) => {},
|
||||
},
|
||||
dateTime: null,
|
||||
dateTime: {
|
||||
startTime: new Date().getTime() * 1000,
|
||||
endTime: new Date().getTime() * 1000,
|
||||
},
|
||||
});
|
||||
const autoCompleteKeywords: any = ref([]);
|
||||
const store = useStore();
|
||||
@@ -129,11 +132,8 @@ const usePromlqSuggestions = () => {
|
||||
autoCompleteData.value.query
|
||||
);
|
||||
autoCompletePromqlKeywords.value = [];
|
||||
const timestamps = getConsumableDateTime(autoCompleteData.value.dateTime);
|
||||
const startISOTimestamp: any =
|
||||
new Date(timestamps.start_time.toISOString()).getTime() * 1000;
|
||||
const endISOTimestamp: any =
|
||||
new Date(timestamps.end_time.toISOString()).getTime() * 1000;
|
||||
const startISOTimestamp: any = autoCompleteData.value.dateTime.startTime;
|
||||
const endISOTimestamp: any = autoCompleteData.value.dateTime.endTime;
|
||||
// import search service and call search.get_promql_series
|
||||
if (metricName) labels["__name__"] = metricName;
|
||||
|
||||
|
||||
@@ -94,22 +94,10 @@ const defaultObject = {
|
||||
histogram: <any>{},
|
||||
editorValue: "",
|
||||
datetime: {
|
||||
tab: "relative",
|
||||
relative: {
|
||||
period: {
|
||||
label: "Minutes",
|
||||
value: "Minutes",
|
||||
},
|
||||
value: 15,
|
||||
},
|
||||
absolute: {
|
||||
date: {
|
||||
from: "",
|
||||
to: "",
|
||||
},
|
||||
startTime: "00:00",
|
||||
endTime: "23:59",
|
||||
},
|
||||
startTime: 0,
|
||||
endTime: 0,
|
||||
relativeTimePeriod: "15m",
|
||||
type: "relative",
|
||||
},
|
||||
searchAround: {
|
||||
indexTimestamp: 0,
|
||||
|
||||
@@ -213,7 +213,7 @@ import {
|
||||
} from "@/utils/zincutils";
|
||||
import segment from "@/services/segment_analytics";
|
||||
import config from "@/aws-exports";
|
||||
import { logsErrorMessage, showErrorNotification } from "@/utils/common";
|
||||
import { logsErrorMessage } from "@/utils/common";
|
||||
import {
|
||||
verifyOrganizationStatus,
|
||||
convertTimeFromMicroToMilli,
|
||||
@@ -221,7 +221,11 @@ import {
|
||||
import {
|
||||
getQueryParamsForDuration,
|
||||
getDurationObjectFromParams,
|
||||
getConsumableRelativeTime,
|
||||
} from "@/utils/date";
|
||||
import useNotifications from "@/composables/useNotifications";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { d } from "msw/lib/SetupApi-8ab693f7";
|
||||
|
||||
export default defineComponent({
|
||||
name: "PageSearch",
|
||||
@@ -294,7 +298,7 @@ export default defineComponent({
|
||||
const searchBarRef = ref(null);
|
||||
const parser = new Parser();
|
||||
const expandedLogs = ref({});
|
||||
|
||||
const { showErrorNotification } = useNotifications();
|
||||
const fieldValues = ref({});
|
||||
|
||||
searchObj.organizationIdetifier =
|
||||
@@ -302,11 +306,11 @@ export default defineComponent({
|
||||
|
||||
const getStreamType = computed(() => searchObj.data.stream.streamType);
|
||||
|
||||
function Notify() {
|
||||
return $q.notify({
|
||||
function Notify(timeout: number | undefined | null = 0) {
|
||||
const notify = {
|
||||
type: "positive",
|
||||
message: "Waiting for response...",
|
||||
timeout: 10000,
|
||||
timeout: timeout,
|
||||
actions: [
|
||||
{
|
||||
icon: "close",
|
||||
@@ -316,7 +320,9 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
return $q.notify(notify);
|
||||
}
|
||||
|
||||
function getQueryTransform() {
|
||||
@@ -588,68 +594,47 @@ export default defineComponent({
|
||||
},
|
||||
};
|
||||
|
||||
var timestamps: any = getConsumableDateTime();
|
||||
var timestamps: any = searchObj.data.datetime.relativeTimePeriod
|
||||
? getConsumableRelativeTime(
|
||||
searchObj.data.datetime.relativeTimePeriod
|
||||
)
|
||||
: cloneDeep(searchObj.data.datetime);
|
||||
|
||||
if (
|
||||
timestamps.start_time != "Invalid Date" &&
|
||||
timestamps.end_time != "Invalid Date"
|
||||
timestamps.startTime != "Invalid Date" &&
|
||||
timestamps.endTime != "Invalid Date"
|
||||
) {
|
||||
searchObj.meta.resultGrid.chartKeyFormat = "HH:mm:ss";
|
||||
|
||||
const startISOTimestamp: any =
|
||||
new Date(timestamps.start_time.toISOString()).getTime() * 1000;
|
||||
const endISOTimestamp: any =
|
||||
new Date(timestamps.end_time.toISOString()).getTime() * 1000;
|
||||
// let timeRangeFilter: String =
|
||||
// "(_timestamp >= [START_TIME] AND _timestamp < [END_TIME])";
|
||||
// // let timeRangeFilter: String =
|
||||
// // "time_range(\"_timestamp\", '[START_TIME]','[END_TIME]')";
|
||||
// timeRangeFilter = timeRangeFilter.replace(
|
||||
// "[START_TIME]",
|
||||
// startISOTimestamp
|
||||
// );
|
||||
// timeRangeFilter = timeRangeFilter.replace(
|
||||
// "[END_TIME]",
|
||||
// endISOTimestamp
|
||||
// );
|
||||
|
||||
// if (query.trim() != "") {
|
||||
// query += " and " + timeRangeFilter;
|
||||
// } else {
|
||||
// query = timeRangeFilter;
|
||||
// }
|
||||
|
||||
req.query.start_time = startISOTimestamp;
|
||||
req.query.end_time = endISOTimestamp;
|
||||
req.query.start_time = timestamps.startTime;
|
||||
req.query.end_time = timestamps.endTime;
|
||||
|
||||
searchObj.meta.resultGrid.chartInterval = "10 second";
|
||||
if (timestamps.end_time - timestamps.start_time >= 1000 * 60 * 30) {
|
||||
if (req.query.end_time - req.query.start_time >= 1000 * 60 * 30) {
|
||||
searchObj.meta.resultGrid.chartInterval = "15 second";
|
||||
searchObj.meta.resultGrid.chartKeyFormat = "HH:mm:ss";
|
||||
}
|
||||
if (timestamps.end_time - timestamps.start_time >= 1000 * 60 * 60) {
|
||||
if (req.query.end_time - req.query.start_time >= 1000 * 60 * 60) {
|
||||
searchObj.meta.resultGrid.chartInterval = "30 second";
|
||||
searchObj.meta.resultGrid.chartKeyFormat = "HH:mm:ss";
|
||||
}
|
||||
if (timestamps.end_time - timestamps.start_time >= 1000 * 3600 * 2) {
|
||||
if (req.query.end_time - req.query.start_time >= 1000 * 3600 * 2) {
|
||||
searchObj.meta.resultGrid.chartInterval = "1 minute";
|
||||
searchObj.meta.resultGrid.chartKeyFormat = "MM-DD HH:mm";
|
||||
}
|
||||
if (timestamps.end_time - timestamps.start_time >= 1000 * 3600 * 6) {
|
||||
if (req.query.end_time - req.query.start_time >= 1000 * 3600 * 6) {
|
||||
searchObj.meta.resultGrid.chartInterval = "5 minute";
|
||||
searchObj.meta.resultGrid.chartKeyFormat = "MM-DD HH:mm";
|
||||
}
|
||||
if (timestamps.end_time - timestamps.start_time >= 1000 * 3600 * 24) {
|
||||
if (req.query.end_time - req.query.start_time >= 1000 * 3600 * 24) {
|
||||
searchObj.meta.resultGrid.chartInterval = "30 minute";
|
||||
searchObj.meta.resultGrid.chartKeyFormat = "MM-DD HH:mm";
|
||||
}
|
||||
if (timestamps.end_time - timestamps.start_time >= 1000 * 86400 * 7) {
|
||||
if (req.query.end_time - req.query.start_time >= 1000 * 86400 * 7) {
|
||||
searchObj.meta.resultGrid.chartInterval = "1 hour";
|
||||
searchObj.meta.resultGrid.chartKeyFormat = "MM-DD HH:mm";
|
||||
}
|
||||
if (
|
||||
timestamps.end_time - timestamps.start_time >=
|
||||
1000 * 86400 * 30
|
||||
) {
|
||||
if (req.query.end_time - req.query.start_time >= 1000 * 86400 * 30) {
|
||||
searchObj.meta.resultGrid.chartInterval = "1 day";
|
||||
searchObj.meta.resultGrid.chartKeyFormat = "YYYY-MM-DD";
|
||||
}
|
||||
@@ -762,13 +747,22 @@ export default defineComponent({
|
||||
return req;
|
||||
} catch (e) {
|
||||
searchObj.loading = false;
|
||||
console.log(e);
|
||||
showErrorNotification("Invalid SQL Syntax");
|
||||
}
|
||||
}
|
||||
|
||||
function restoreUrlQueryParams() {
|
||||
const queryParams = router.currentRoute.value.query;
|
||||
const date = getDurationObjectFromParams(queryParams);
|
||||
if (!queryParams.stream) {
|
||||
return;
|
||||
}
|
||||
const date = {
|
||||
startTime: queryParams.from,
|
||||
endTime: queryParams.to,
|
||||
relativeTimePeriod: queryParams.period || null,
|
||||
type: queryParams.period ? "relative" : "absolute",
|
||||
};
|
||||
if (date) {
|
||||
searchObj.data.datetime = date;
|
||||
}
|
||||
@@ -783,17 +777,19 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
function updateUrlQueryParams() {
|
||||
const date = getQueryParamsForDuration(searchObj.data.datetime);
|
||||
const date = searchObj.data.datetime;
|
||||
|
||||
const query = {
|
||||
stream: searchObj.data.stream.selectedStream.label,
|
||||
};
|
||||
if (date.period) {
|
||||
query["period"] = date.period;
|
||||
}
|
||||
if (date.from && date.to) {
|
||||
query["from"] = date.from;
|
||||
query["to"] = date.to;
|
||||
|
||||
if (date.type == "relative") {
|
||||
query["period"] = date.relativeTimePeriod;
|
||||
} else {
|
||||
query["from"] = date.startTime;
|
||||
query["to"] = date.endTime;
|
||||
}
|
||||
|
||||
query["refresh"] = searchObj.meta.refreshInterval;
|
||||
|
||||
if (searchObj.data.query) {
|
||||
@@ -807,6 +803,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
function getQueryData() {
|
||||
const dismiss = Notify();
|
||||
try {
|
||||
if (searchObj.data.stream.selectedStream.value == "") {
|
||||
return false;
|
||||
@@ -834,7 +831,6 @@ export default defineComponent({
|
||||
};
|
||||
// searchObj.data.editorValue = "";
|
||||
}
|
||||
dismiss = Notify();
|
||||
|
||||
const queryReq = buildSearch();
|
||||
|
||||
@@ -904,15 +900,12 @@ export default defineComponent({
|
||||
// });
|
||||
});
|
||||
} catch (e) {
|
||||
dismiss();
|
||||
searchObj.loading = false;
|
||||
showErrorNotification("Error while searching");
|
||||
}
|
||||
}
|
||||
|
||||
const resetFieldValues = () => {
|
||||
fieldValues.value = {};
|
||||
};
|
||||
|
||||
const updateFieldValues = (data) => {
|
||||
const excludedFields = [
|
||||
store.state.zoConfig.timestamp_column,
|
||||
@@ -937,6 +930,10 @@ export default defineComponent({
|
||||
});
|
||||
};
|
||||
|
||||
const resetFieldValues = () => {
|
||||
fieldValues.value = {};
|
||||
};
|
||||
|
||||
function extractFields() {
|
||||
try {
|
||||
searchObj.data.stream.selectedStreamFields = [];
|
||||
@@ -1220,7 +1217,7 @@ export default defineComponent({
|
||||
document.getElementById("secondLevel");
|
||||
if (secondWrapperElement != null) {
|
||||
rect = secondWrapperElement.getBoundingClientRect();
|
||||
secondWrapperElement.style.height = `calc(100vh - ${Math.round(
|
||||
secondWrapperElement.style.height = `calc(100vh - ${Math.ceil(
|
||||
rect.top
|
||||
)}px)`;
|
||||
}
|
||||
@@ -1228,7 +1225,7 @@ export default defineComponent({
|
||||
const thirdWrapperElement: any = document.getElementById("thirdLevel");
|
||||
if (thirdWrapperElement != null) {
|
||||
rect = thirdWrapperElement.getBoundingClientRect();
|
||||
thirdWrapperElement.style.height = `calc(100vh - ${Math.round(
|
||||
thirdWrapperElement.style.height = `calc(100vh - ${Math.ceil(
|
||||
rect.top
|
||||
)}px)`;
|
||||
}
|
||||
@@ -1236,23 +1233,23 @@ export default defineComponent({
|
||||
const GridElement: any = document.getElementById("searchGridComponent");
|
||||
if (GridElement != null) {
|
||||
rect = GridElement.getBoundingClientRect();
|
||||
GridElement.style.height = `calc(100vh - ${Math.round(rect.top)}px)`;
|
||||
GridElement.style.height = `calc(100vh - ${Math.ceil(rect.top)}px)`;
|
||||
}
|
||||
|
||||
const FLElement = document.getElementById("fieldList");
|
||||
if (FLElement != null) {
|
||||
rect = FLElement.getBoundingClientRect();
|
||||
FLElement.style.height = `calc(100vh - ${Math.round(rect.top)}px)`;
|
||||
FLElement.style.height = `calc(100vh - ${Math.ceil(rect.top)}px)`;
|
||||
}
|
||||
|
||||
const logPagesecondWrapperElement: any =
|
||||
document.getElementById("logPage");
|
||||
if (logPagesecondWrapperElement != null) {
|
||||
rect = logPagesecondWrapperElement.getBoundingClientRect();
|
||||
logPagesecondWrapperElement.style.height = `calc(100vh - ${Math.round(
|
||||
rect.top
|
||||
logPagesecondWrapperElement.style.height = `calc(100vh - ${Math.ceil(
|
||||
rect.top + 1
|
||||
)}px)`;
|
||||
logPagesecondWrapperElement.style.minHeight = `calc(100vh - ${Math.round(
|
||||
logPagesecondWrapperElement.style.minHeight = `calc(100vh - ${Math.ceil(
|
||||
rect.top + 20
|
||||
)}px)`;
|
||||
}
|
||||
@@ -1323,8 +1320,8 @@ export default defineComponent({
|
||||
};
|
||||
|
||||
const searchAroundData = (obj: any) => {
|
||||
const dismiss = Notify();
|
||||
try {
|
||||
dismiss = Notify();
|
||||
searchObj.data.errorCode = 0;
|
||||
let query_context = "";
|
||||
let query = searchObj.data.query;
|
||||
@@ -1450,6 +1447,7 @@ export default defineComponent({
|
||||
// });
|
||||
});
|
||||
} catch (e) {
|
||||
dismiss();
|
||||
console.log(e.message);
|
||||
searchObj.loading = false;
|
||||
showErrorNotification("Search around request failed.");
|
||||
@@ -1597,21 +1595,19 @@ export default defineComponent({
|
||||
this.loadPageData();
|
||||
}
|
||||
},
|
||||
changeStream() {
|
||||
if (this.searchObj.data.stream.selectedStream.hasOwnProperty("value")) {
|
||||
this.searchObj.data.tempFunctionContent = "";
|
||||
this.searchBarRef.resetFunctionContent();
|
||||
this.searchObj.data.query = "";
|
||||
this.setQuery(this.searchObj.meta.sqlMode);
|
||||
setTimeout(() => {
|
||||
this.runQueryFn();
|
||||
}, 500);
|
||||
}
|
||||
},
|
||||
changeRelativeDate() {
|
||||
if (this.searchObj.data.datetime.tab == "relative") {
|
||||
this.runQueryFn();
|
||||
}
|
||||
changeStream: {
|
||||
handler(stream, streamOld) {
|
||||
if (this.searchObj.data.stream.selectedStream.hasOwnProperty("value")) {
|
||||
this.searchObj.data.tempFunctionContent = "";
|
||||
this.searchBarRef.resetFunctionContent();
|
||||
if (streamOld.value) this.searchObj.data.query = "";
|
||||
if (streamOld.value) this.setQuery(this.searchObj.meta.sqlMode);
|
||||
setTimeout(() => {
|
||||
this.runQueryFn();
|
||||
}, 500);
|
||||
}
|
||||
},
|
||||
immediate: false,
|
||||
},
|
||||
updateSelectedColumns() {
|
||||
this.searchObj.meta.resultGrid.manualRemoveFields = true;
|
||||
@@ -1629,6 +1625,7 @@ export default defineComponent({
|
||||
this.refreshData();
|
||||
},
|
||||
fullSQLMode(newVal) {
|
||||
this.reDrawGrid();
|
||||
this.setQuery(newVal);
|
||||
},
|
||||
getStreamType() {
|
||||
|
||||
@@ -14,7 +14,10 @@
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div class="column index-menu" :class="store.state.theme == 'dark' ? 'theme-dark' : 'theme-light'">
|
||||
<div
|
||||
class="column index-menu"
|
||||
:class="store.state.theme == 'dark' ? 'theme-dark' : 'theme-light'"
|
||||
>
|
||||
<div>
|
||||
<q-select
|
||||
data-test="log-search-index-list-select-stream"
|
||||
@@ -98,9 +101,7 @@
|
||||
props.row.name
|
||||
)
|
||||
"
|
||||
:name="
|
||||
outlinedVisibility
|
||||
"
|
||||
:name="outlinedVisibility"
|
||||
size="1.1rem"
|
||||
title="Add field to table"
|
||||
@click.stop="clickFieldFn(props.row, props.pageIndex)"
|
||||
@@ -228,7 +229,14 @@
|
||||
{{ value.count }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex row" :class="store.state.theme ==='dark'?'text-white':'text-black'">
|
||||
<div
|
||||
class="flex row"
|
||||
:class="
|
||||
store.state.theme === 'dark'
|
||||
? 'text-white'
|
||||
: 'text-black'
|
||||
"
|
||||
>
|
||||
<q-btn
|
||||
class="q-mr-xs"
|
||||
size="6px"
|
||||
@@ -254,10 +262,10 @@
|
||||
title="Exclude Term"
|
||||
round
|
||||
>
|
||||
<q-icon>
|
||||
<NotEqualIcon></NotEqualIcon>
|
||||
</q-icon>
|
||||
</q-btn>
|
||||
<q-icon>
|
||||
<NotEqualIcon></NotEqualIcon>
|
||||
</q-icon>
|
||||
</q-btn>
|
||||
</div>
|
||||
</q-item>
|
||||
</q-list>
|
||||
@@ -292,7 +300,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onActivated, ref, type Ref, watch } from "vue";
|
||||
import { defineComponent, ref, type Ref, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useStore } from "vuex";
|
||||
import { useQuasar } from "quasar";
|
||||
@@ -305,11 +313,15 @@ import {
|
||||
formatLargeNumber,
|
||||
} from "../../utils/zincutils";
|
||||
import streamService from "../../services/stream";
|
||||
import { getConsumableDateTime } from "@/utils/commons";
|
||||
import { Parser } from "node-sql-parser";
|
||||
import { outlinedAdd, outlinedVisibility, outlinedVisibilityOff } from '@quasar/extras/material-icons-outlined'
|
||||
import {
|
||||
outlinedAdd,
|
||||
outlinedVisibility,
|
||||
outlinedVisibilityOff,
|
||||
} from "@quasar/extras/material-icons-outlined";
|
||||
import EqualIcon from "@/components/icons/EqualIcon.vue";
|
||||
import NotEqualIcon from "@/components/icons/NotEqualIcon.vue";
|
||||
import { getConsumableRelativeTime } from "@/utils/date";
|
||||
|
||||
interface Filter {
|
||||
fieldName: string;
|
||||
@@ -318,7 +330,7 @@ interface Filter {
|
||||
}
|
||||
export default defineComponent({
|
||||
name: "ComponentSearchIndexSelect",
|
||||
components:{ EqualIcon, NotEqualIcon },
|
||||
components: { EqualIcon, NotEqualIcon },
|
||||
setup() {
|
||||
const store = useStore();
|
||||
const router = useRouter();
|
||||
@@ -394,7 +406,9 @@ export default defineComponent({
|
||||
return;
|
||||
}
|
||||
|
||||
let timestamps = getConsumableDateTime(searchObj.data.datetime);
|
||||
let timestamps = getConsumableRelativeTime(
|
||||
searchObj.data.datetime.relativeTimePeriod
|
||||
);
|
||||
|
||||
if (searchObj.data.stream.streamType === "enrichment_tables") {
|
||||
const stream = searchObj.data.streamResults.list.find(
|
||||
@@ -403,20 +417,24 @@ export default defineComponent({
|
||||
);
|
||||
if (stream.stats) {
|
||||
timestamps = {
|
||||
start_time: new Date(
|
||||
convertTimeFromMicroToMilli(stream.stats.doc_time_min - 300000000)
|
||||
),
|
||||
end_time: new Date(
|
||||
convertTimeFromMicroToMilli(stream.stats.doc_time_max + 300000000)
|
||||
),
|
||||
startTime:
|
||||
new Date(
|
||||
convertTimeFromMicroToMilli(
|
||||
stream.stats.doc_time_min - 300000000
|
||||
)
|
||||
).getTime() * 1000,
|
||||
endTime:
|
||||
new Date(
|
||||
convertTimeFromMicroToMilli(
|
||||
stream.stats.doc_time_max + 300000000
|
||||
)
|
||||
).getTime() * 1000,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const startISOTimestamp: any =
|
||||
new Date(timestamps.start_time.toISOString()).getTime() * 1000;
|
||||
const endISOTimestamp: any =
|
||||
new Date(timestamps.end_time.toISOString()).getTime() * 1000;
|
||||
const startISOTimestamp: number = timestamps?.startTime || 0;
|
||||
const endISOTimestamp: number = timestamps?.endTime || 0;
|
||||
|
||||
fieldValues.value[name] = {
|
||||
isLoading: true,
|
||||
@@ -657,10 +675,10 @@ export default defineComponent({
|
||||
&:hover {
|
||||
.field-container {
|
||||
// background-color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.theme-dark {
|
||||
.field_list {
|
||||
|
||||
@@ -107,9 +107,19 @@
|
||||
></q-btn>
|
||||
<div class="float-left">
|
||||
<date-time
|
||||
:default-date="searchObj.data.datetime"
|
||||
auto-apply
|
||||
:default-type="
|
||||
searchObj.data.datetime.relativeTimePeriod
|
||||
? 'relative'
|
||||
: 'absolute'
|
||||
"
|
||||
:default-absolute-time="{
|
||||
startTime: searchObj.data.datetime.startTime,
|
||||
endTime: searchObj.data.datetime.endTime,
|
||||
}"
|
||||
:default-relative-time="searchObj.data.datetime.relativeTimePeriod"
|
||||
data-test="logs-search-bar-date-time-dropdown"
|
||||
@date-change="updateDateTime"
|
||||
@on:date-change="updateDateTime"
|
||||
/>
|
||||
</div>
|
||||
<div class="search-time q-pl-sm float-left q-mr-sm">
|
||||
@@ -208,6 +218,7 @@ import AutoRefreshInterval from "@/components/AutoRefreshInterval.vue";
|
||||
import stream from "@/services/stream";
|
||||
import { getConsumableDateTime } from "@/utils/commons";
|
||||
import useSqlSuggestions from "@/composables/useSuggestions";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
|
||||
const defaultValue: any = () => {
|
||||
return {
|
||||
@@ -289,7 +300,7 @@ export default defineComponent({
|
||||
getSuggestions,
|
||||
updateFieldKeywords,
|
||||
updateFunctionKeywords,
|
||||
} = useSqlSuggestions(searchObj.data.datetime);
|
||||
} = useSqlSuggestions();
|
||||
|
||||
const refreshTimeChange = (item) => {
|
||||
searchObj.meta.refreshInterval = item.value;
|
||||
@@ -367,26 +378,28 @@ export default defineComponent({
|
||||
};
|
||||
|
||||
const updateDateTime = (value: object) => {
|
||||
searchObj.data.datetime = value;
|
||||
searchObj.data.datetime = {
|
||||
startTime: value.startTime,
|
||||
endTime: value.endTime,
|
||||
relativeTimePeriod: value.relativeTimePeriod
|
||||
? value.relativeTimePeriod
|
||||
: searchObj.data.datetime.relativeTimePeriod,
|
||||
type: value.relativeTimePeriod ? "relative" : "absolute",
|
||||
};
|
||||
|
||||
if (config.isCloud == "true" && value.userChangedValue) {
|
||||
let dateTimeVal;
|
||||
if (value.tab === "relative") {
|
||||
dateTimeVal = value.relative;
|
||||
} else {
|
||||
dateTimeVal = value.absolute;
|
||||
}
|
||||
|
||||
segment.track("Button Click", {
|
||||
button: "Date Change",
|
||||
tab: value.tab,
|
||||
value: dateTimeVal,
|
||||
value: value,
|
||||
//user_org: this.store.state.selectedOrganization.identifier,
|
||||
//user_id: this.store.state.userInfo.email,
|
||||
stream_name: searchObj.data.stream.selectedStream.value,
|
||||
page: "Search Logs",
|
||||
});
|
||||
}
|
||||
|
||||
if (value.valueType === "relative") emit("searchdata");
|
||||
};
|
||||
|
||||
const udpateQuery = () => {
|
||||
|
||||
@@ -114,7 +114,8 @@
|
||||
? column.prop(row)
|
||||
: searchObj.data.resultGrid.columns.length > 2 &&
|
||||
(column.prop(row, column.name)?.length || 0) > 100
|
||||
? (column.prop(row, column.name)?.substr(0, 100) || '') + '...'
|
||||
? (column.prop(row, column.name)?.substr(0, 100) || '') +
|
||||
'...'
|
||||
: column.name != '@timestamp'
|
||||
? row[column.name]
|
||||
: column.prop(row, column.name)
|
||||
@@ -345,23 +346,10 @@ export default defineComponent({
|
||||
},
|
||||
onChartUpdate({ start, end }: { start: any; end: any }) {
|
||||
this.searchObj.meta.showDetailTab = false;
|
||||
this.searchObj.runQuery = true;
|
||||
this.searchObj.data.datetime.tab = "absolute";
|
||||
this.searchObj.data.datetime.absolute.date.from = start.split(" ")[0];
|
||||
this.searchObj.data.datetime.absolute.date.to = end.split(" ")[0];
|
||||
this.searchObj.data.datetime.absolute.startTime =
|
||||
start.split(" ")[1].split(":")[0] +
|
||||
":" +
|
||||
start.split(" ")[1].split(":")[1] +
|
||||
":" +
|
||||
start.split(" ")[1].split(":")[2];
|
||||
this.searchObj.data.datetime.absolute.endTime =
|
||||
end.split(" ")[1].split(":")[0] +
|
||||
":" +
|
||||
end.split(" ")[1].split(":")[1] +
|
||||
":" +
|
||||
end.split(" ")[1].split(":")[2];
|
||||
|
||||
this.searchObj.data.datetime.type = "absolute";
|
||||
this.searchObj.data.datetime.startTime = new Date(start).getTime() * 1000;
|
||||
this.searchObj.data.datetime.endTime = new Date(end).getTime() * 1000;
|
||||
console.log("onChartUpdate", this.searchObj.data.datetime);
|
||||
this.searchObj.runQuery = true;
|
||||
this.$emit("update:datetime");
|
||||
},
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<!-- eslint-disable vue/attribute-hyphenation -->
|
||||
<!-- eslint-disable vue/v-on-event-hyphenation -->
|
||||
<template>
|
||||
<q-page class="metrics-page" id="logPage">
|
||||
<q-page class="metrics-page" id="metricsPage">
|
||||
<div class="row scroll" style="width: 100%">
|
||||
<!-- Note: Splitter max-height to be dynamically calculated with JS -->
|
||||
<q-splitter
|
||||
@@ -44,9 +44,22 @@
|
||||
class="text-right q-px-lg q-py-sm flex align-center justify-end metrics-date-time"
|
||||
>
|
||||
<date-time
|
||||
:default-date="searchObj.data.datetime"
|
||||
ref="metricsDateTimeRef"
|
||||
auto-apply
|
||||
:default-type="
|
||||
searchObj.data.datetime.relativeTimePeriod
|
||||
? 'relative'
|
||||
: 'absolute'
|
||||
"
|
||||
:default-absolute-time="{
|
||||
startTime: searchObj.data.datetime.startTime,
|
||||
endTime: searchObj.data.datetime.endTime,
|
||||
}"
|
||||
:default-relative-time="
|
||||
searchObj.data.datetime.relativeTimePeriod
|
||||
"
|
||||
data-test="logs-search-bar-date-time-dropdown"
|
||||
@date-change="updateDateTime"
|
||||
@on:date-change="updateDateTime"
|
||||
/>
|
||||
<auto-refresh-interval
|
||||
class="q-pr-sm"
|
||||
@@ -188,7 +201,7 @@ import useMetrics from "@/composables/useMetrics";
|
||||
import { Parser } from "node-sql-parser";
|
||||
|
||||
import streamService from "@/services/stream";
|
||||
import { b64EncodeUnicode } from "@/utils/zincutils";
|
||||
import { b64DecodeUnicode, b64EncodeUnicode } from "@/utils/zincutils";
|
||||
import segment from "@/services/segment_analytics";
|
||||
import config from "@/aws-exports";
|
||||
import DateTime from "@/components/DateTime.vue";
|
||||
@@ -201,12 +214,9 @@ import { cloneDeep } from "lodash-es";
|
||||
import AddToDashboard from "./AddToDashboard.vue";
|
||||
import { addPanel, getPanelId } from "@/utils/commons";
|
||||
import usePromqlSuggestions from "@/composables/usePromqlSuggestions";
|
||||
import {
|
||||
getQueryParamsForDuration,
|
||||
getDurationObjectFromParams,
|
||||
} from "@/utils/date";
|
||||
import { showErrorNotification } from "@/utils/common";
|
||||
import { b64DecodeUnicode } from "@/utils/zincutils";
|
||||
import useNotifications from "@/composables/useNotifications";
|
||||
import { getConsumableRelativeTime } from "@/utils/date";
|
||||
import { on } from "events";
|
||||
|
||||
export default defineComponent({
|
||||
name: "AppMetrics",
|
||||
@@ -258,6 +268,7 @@ export default defineComponent({
|
||||
const promqlKeywords = ref([]);
|
||||
|
||||
const chartData = ref({});
|
||||
const { showErrorNotification } = useNotifications();
|
||||
|
||||
searchObj.organizationIdetifier =
|
||||
store.state.selectedOrganization.identifier;
|
||||
@@ -541,7 +552,12 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
// dismiss = Notify();
|
||||
dashboardPanelData.meta.dateTime = {
|
||||
start_time: new Date(searchObj.data.datetime.startTime / 1000),
|
||||
end_time: new Date(searchObj.data.datetime.endTime / 1000),
|
||||
};
|
||||
chartData.value = cloneDeep(dashboardPanelData.data);
|
||||
console.log(chartData.value);
|
||||
updateUrlQueryParams();
|
||||
} catch (e) {
|
||||
searchObj.loading = false;
|
||||
@@ -598,27 +614,28 @@ export default defineComponent({
|
||||
const setQuery = () => {};
|
||||
|
||||
const updateDateTime = (value: any) => {
|
||||
searchObj.data.datetime = value;
|
||||
|
||||
const timestamp = getConsumableDateTime(searchObj.data.datetime);
|
||||
dashboardPanelData.meta.dateTime = timestamp;
|
||||
searchObj.data.datetime = {
|
||||
startTime: value.startTime,
|
||||
endTime: value.endTime,
|
||||
relativeTimePeriod: value.relativeTimePeriod
|
||||
? value.relativeTimePeriod
|
||||
: searchObj.data.datetime.relativeTimePeriod,
|
||||
type: value.relativeTimePeriod ? "relative" : "absolute",
|
||||
};
|
||||
|
||||
if (config.isCloud == "true" && value.userChangedValue) {
|
||||
let dateTimeVal;
|
||||
if (value.tab === "relative") {
|
||||
dateTimeVal = value.relative;
|
||||
} else {
|
||||
dateTimeVal = value.absolute;
|
||||
}
|
||||
|
||||
segment.track("Button Click", {
|
||||
button: "Date Change",
|
||||
tab: value.tab,
|
||||
value: dateTimeVal,
|
||||
metric_name: searchObj.data.metrics.selectedMetric,
|
||||
page: "Search Metrics",
|
||||
value: value,
|
||||
//user_org: this.store.state.selectedOrganization.identifier,
|
||||
//user_id: this.store.state.userInfo.email,
|
||||
stream_name: searchObj.data.stream.selectedStream.value,
|
||||
page: "Search Logs",
|
||||
});
|
||||
}
|
||||
|
||||
if (value.valueType === "relative") runQuery();
|
||||
};
|
||||
|
||||
const updateQueryValue = async (event, value) => {
|
||||
@@ -674,12 +691,23 @@ export default defineComponent({
|
||||
});
|
||||
};
|
||||
|
||||
const onMetricChange = async (metric) => {
|
||||
metricsQueryEditorRef.value.setValue(metric);
|
||||
};
|
||||
|
||||
function restoreUrlQueryParams() {
|
||||
const queryParams = router.currentRoute.value.query;
|
||||
const date = getDurationObjectFromParams(queryParams);
|
||||
if (!queryParams.stream) {
|
||||
return;
|
||||
}
|
||||
const date = {
|
||||
startTime: queryParams.from,
|
||||
endTime: queryParams.to,
|
||||
relativeTimePeriod: queryParams.period || null,
|
||||
type: queryParams.period ? "relative" : "absolute",
|
||||
};
|
||||
if (date) {
|
||||
searchObj.data.datetime = date;
|
||||
updateDateTime(date);
|
||||
}
|
||||
if (queryParams.query) {
|
||||
searchObj.data.query = b64DecodeUnicode(queryParams.query);
|
||||
@@ -689,24 +717,28 @@ export default defineComponent({
|
||||
searchObj.meta.refreshInterval = queryParams.refresh;
|
||||
}
|
||||
}
|
||||
|
||||
function updateUrlQueryParams() {
|
||||
try {
|
||||
const date = getQueryParamsForDuration(searchObj.data.datetime);
|
||||
const date = searchObj.data.datetime;
|
||||
const query = {
|
||||
stream: searchObj.data.metrics.selectedMetric,
|
||||
};
|
||||
if (date.period) {
|
||||
query["period"] = date.period;
|
||||
}
|
||||
if (date.from && date.to) {
|
||||
query["from"] = date.from;
|
||||
query["to"] = date.to;
|
||||
|
||||
if (date.type == "relative") {
|
||||
query["period"] = date.relativeTimePeriod;
|
||||
} else {
|
||||
query["from"] = date.startTime;
|
||||
query["to"] = date.endTime;
|
||||
}
|
||||
|
||||
query["refresh"] = searchObj.meta.refreshInterval;
|
||||
|
||||
if (searchObj.data.query) {
|
||||
query["query"] = b64EncodeUnicode(searchObj.data.query);
|
||||
}
|
||||
query["org_identifier"] = store.state.selectedOrganization.identifier;
|
||||
|
||||
router.push({ query });
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
@@ -735,6 +767,7 @@ export default defineComponent({
|
||||
addPanelToDashboard,
|
||||
promqlKeywords,
|
||||
autoCompletePromqlKeywords,
|
||||
onMetricChange,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -744,7 +777,7 @@ export default defineComponent({
|
||||
changeOrganization() {
|
||||
return this.store.state.selectedOrganization.identifier;
|
||||
},
|
||||
selectedMetrics() {
|
||||
selectedMetric() {
|
||||
return this.searchObj.data.metrics.selectedMetric;
|
||||
},
|
||||
changeRelativeDate() {
|
||||
@@ -766,10 +799,16 @@ export default defineComponent({
|
||||
);
|
||||
this.loadPageData();
|
||||
},
|
||||
changeRelativeDate() {
|
||||
if (this.searchObj.data.datetime.tab == "relative") {
|
||||
this.runQuery();
|
||||
}
|
||||
selectedMetric: {
|
||||
deep: true,
|
||||
handler: function (metric) {
|
||||
if (this.searchObj.data.metrics.selectedMetric) {
|
||||
this.onMetricChange(metric);
|
||||
setTimeout(() => {
|
||||
this.runQuery();
|
||||
}, 500);
|
||||
}
|
||||
},
|
||||
},
|
||||
changeRefreshInterval() {
|
||||
this.updateUrlQueryParams();
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
hide-selected
|
||||
fill-input
|
||||
@filter="filterMetrics"
|
||||
@update:model-value="onMetricChange"
|
||||
>
|
||||
<template #no-option>
|
||||
<q-item>
|
||||
@@ -194,12 +195,12 @@ import { useRouter } from "vue-router";
|
||||
import useMetrics from "../../composables/useMetrics";
|
||||
import { formatLargeNumber, getImageURL } from "../../utils/zincutils";
|
||||
import { getConsumableDateTime } from "@/utils/commons";
|
||||
import useDashboardPanelData from "@/composables/useDashboardPanel";
|
||||
import stream from "@/services/stream";
|
||||
|
||||
export default defineComponent({
|
||||
name: "MetricsList",
|
||||
setup() {
|
||||
emits: ["update:change-metric"],
|
||||
setup(props, { emit }) {
|
||||
const store = useStore();
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
@@ -215,7 +216,6 @@ export default defineComponent({
|
||||
values: { key: string; count: number | string }[];
|
||||
};
|
||||
}> = ref({});
|
||||
const { dashboardPanelData } = useDashboardPanelData();
|
||||
|
||||
watch(
|
||||
() => searchObj.data.metrics.metricList.length,
|
||||
@@ -263,19 +263,14 @@ export default defineComponent({
|
||||
};
|
||||
|
||||
const openFilterCreator = (event: any, { name }: any) => {
|
||||
console.log("open filter creator", name);
|
||||
|
||||
let timestamps = getConsumableDateTime(searchObj.data.datetime);
|
||||
|
||||
const startISOTimestamp: any =
|
||||
new Date(timestamps.start_time.toISOString()).getTime() * 1000;
|
||||
const endISOTimestamp: any =
|
||||
new Date(timestamps.end_time.toISOString()).getTime() * 1000;
|
||||
const startISOTimestamp: any = searchObj.data.datetime.startTime;
|
||||
const endISOTimestamp: any = searchObj.data.datetime.endTime;
|
||||
|
||||
metricLabelValues.value[name] = {
|
||||
isLoading: true,
|
||||
values: [],
|
||||
};
|
||||
|
||||
try {
|
||||
stream
|
||||
.fieldValues({
|
||||
@@ -310,6 +305,10 @@ export default defineComponent({
|
||||
}
|
||||
};
|
||||
|
||||
const onMetricChange = () => {
|
||||
updateMetricLabels();
|
||||
};
|
||||
|
||||
return {
|
||||
quasar,
|
||||
t,
|
||||
@@ -324,6 +323,7 @@ export default defineComponent({
|
||||
filterMetricLabels,
|
||||
openFilterCreator,
|
||||
metricLabelValues,
|
||||
onMetricChange,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,303 +0,0 @@
|
||||
<!-- Copyright 2022 Zinc Labs Inc. and Contributors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http:www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<!-- eslint-disable vue/v-on-event-hyphenation -->
|
||||
<!-- eslint-disable vue/attribute-hyphenation -->
|
||||
<template>
|
||||
<div ref="resultContainer" class="col column oveflow-hidden q-px-md q-pt-sm">
|
||||
<div class="text-semi-bold text-h6 q-pl-sm q-pb-sm">
|
||||
{{ searchObj.data.metrics.selectedMetric }}
|
||||
</div>
|
||||
<div class="search-list" style="width: 100%">
|
||||
<MetricLineChart
|
||||
data-test="logs-search-result-bar-chart"
|
||||
ref="plotChart"
|
||||
:data="searchObj.data.histogram.data"
|
||||
:title="searchObj.data.histogram.layout.title"
|
||||
@updated:chart="onChartUpdate"
|
||||
></MetricLineChart>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, ref } from "vue";
|
||||
import { useQuasar } from "quasar";
|
||||
import { useStore } from "vuex";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
import { byString } from "../../utils/json";
|
||||
import useMetrics from "../../composables/useMetrics";
|
||||
import { getImageURL } from "../../utils/zincutils";
|
||||
import MetricLineChart from "../../components/MetricLineChart.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "MetricsViewer",
|
||||
components: {
|
||||
MetricLineChart,
|
||||
},
|
||||
emits: [
|
||||
"update:scroll",
|
||||
"update:datetime",
|
||||
"remove:searchTerm",
|
||||
"search:timeboxed",
|
||||
],
|
||||
methods: {
|
||||
onChartUpdate({ start, end }: { start: any; end: any }) {
|
||||
this.searchObj.data.datetime.tab = "absolute";
|
||||
this.searchObj.data.datetime.absolute.date.from = start.split(" ")[0];
|
||||
this.searchObj.data.datetime.absolute.date.to = end.split(" ")[0];
|
||||
this.searchObj.data.datetime.absolute.startTime =
|
||||
start.split(" ")[1].split(":")[0] +
|
||||
":" +
|
||||
start.split(" ")[1].split(":")[1] +
|
||||
":" +
|
||||
start.split(" ")[1].split(":")[2];
|
||||
this.searchObj.data.datetime.absolute.endTime =
|
||||
end.split(" ")[1].split(":")[0] +
|
||||
":" +
|
||||
end.split(" ")[1].split(":")[1] +
|
||||
":" +
|
||||
end.split(" ")[1].split(":")[2];
|
||||
|
||||
this.$emit("update:datetime");
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
// Accessing nested JavaScript objects and arrays by string path
|
||||
// https://stackoverflow.com/questions/6491463/accessing-nested-javascript-objects-and-arrays-by-string-path
|
||||
const { t } = useI18n();
|
||||
const store = useStore();
|
||||
const $q = useQuasar();
|
||||
|
||||
const { searchObj } = useMetrics();
|
||||
const totalHeight = ref(0);
|
||||
|
||||
const searchTableRef: any = ref(null);
|
||||
|
||||
const plotChart: any = ref(null);
|
||||
|
||||
const resultContainer = ref(null);
|
||||
|
||||
const reDrawChart = () => {
|
||||
if (searchObj.data.histogram.data.length) {
|
||||
plotChart.value.reDraw(searchObj.data.histogram);
|
||||
plotChart.value.forceReLayout();
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
reDrawChart();
|
||||
});
|
||||
|
||||
return {
|
||||
t,
|
||||
store,
|
||||
plotChart,
|
||||
searchObj,
|
||||
byString,
|
||||
searchTableRef,
|
||||
totalHeight,
|
||||
reDrawChart,
|
||||
getImageURL,
|
||||
resultContainer,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.max-result {
|
||||
width: 170px;
|
||||
}
|
||||
|
||||
.search-list {
|
||||
width: 100%;
|
||||
|
||||
.chart {
|
||||
width: 100%;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.my-sticky-header-table {
|
||||
.q-table__top,
|
||||
.q-table__bottom,
|
||||
thead tr:first-child th {
|
||||
/* bg color is important for th; just specify one */
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
thead tr th {
|
||||
position: sticky;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
thead tr:first-child th {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
/* this is when the loading indicator appears */
|
||||
&.q-table--loading thead tr:last-child th {
|
||||
/* height of all previous header rows */
|
||||
top: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.q-table__top {
|
||||
padding-left: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.q-table thead tr,
|
||||
.q-table tbody td,
|
||||
.q-table th,
|
||||
.q-table td {
|
||||
height: 25px;
|
||||
padding: 0px 5px;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.q-table__bottom {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.q-table__bottom {
|
||||
min-height: 40px;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.q-td {
|
||||
overflow: hidden;
|
||||
min-width: 100px;
|
||||
|
||||
.expanded {
|
||||
margin: 0;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: rgb(255, 213, 0);
|
||||
}
|
||||
|
||||
.table-header {
|
||||
// text-transform: capitalize;
|
||||
|
||||
.table-head-chip {
|
||||
background-color: $accent;
|
||||
padding: 0px;
|
||||
|
||||
.q-chip__content {
|
||||
margin-right: 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
color: $dark;
|
||||
}
|
||||
|
||||
.q-chip__icon--remove {
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
opacity: 1;
|
||||
margin: 0;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
.q-table th.sortable {
|
||||
cursor: pointer;
|
||||
text-transform: capitalize;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
&.isClosable {
|
||||
padding-right: 26px;
|
||||
position: relative;
|
||||
|
||||
.q-table-col-close {
|
||||
transform: translateX(26px);
|
||||
position: absolute;
|
||||
margin-top: 2px;
|
||||
color: grey;
|
||||
transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.5, 1);
|
||||
}
|
||||
}
|
||||
|
||||
.q-table th.sortable {
|
||||
cursor: pointer;
|
||||
text-transform: capitalize;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
.thead-sticky tr > *,
|
||||
.tfoot-sticky tr > * {
|
||||
position: sticky;
|
||||
opacity: 1;
|
||||
z-index: 1;
|
||||
background: #f5f5f5;
|
||||
color: #090909;
|
||||
}
|
||||
.thead-sticky tr:last-child > * {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.tfoot-sticky tr:first-child > * {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.field_list {
|
||||
padding: 0px;
|
||||
margin-bottom: 0.125rem;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
cursor: default;
|
||||
|
||||
.field_overlay {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
right: 0;
|
||||
top: 0;
|
||||
background-color: #ffffff;
|
||||
border-radius: 6px;
|
||||
padding: 0 6px;
|
||||
visibility: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: all 0.3s linear;
|
||||
|
||||
.q-icon {
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: all 0.3s linear;
|
||||
margin: 0 1px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.field_overlay {
|
||||
visibility: visible;
|
||||
|
||||
.q-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -180,9 +180,12 @@ import {
|
||||
} from "@/utils/zincutils";
|
||||
import segment from "@/services/segment_analytics";
|
||||
import config from "@/aws-exports";
|
||||
import { logsErrorMessage, showErrorNotification } from "@/utils/common";
|
||||
import { logsErrorMessage } from "@/utils/common";
|
||||
import { number } from "@intlify/core-base";
|
||||
import { stringLiteral } from "@babel/types";
|
||||
import useNotifications from "@/composables/useNotifications";
|
||||
import { getConsumableRelativeTime } from "@/utils/date";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import {
|
||||
getDurationObjectFromParams,
|
||||
getQueryParamsForDuration,
|
||||
@@ -260,6 +263,7 @@ export default defineComponent({
|
||||
const searchBarRef = ref(null);
|
||||
const parser = new Parser();
|
||||
const fieldValues = ref({});
|
||||
const { showErrorNotification } = useNotifications();
|
||||
|
||||
searchObj.organizationIdetifier =
|
||||
store.state.selectedOrganization.identifier;
|
||||
@@ -570,21 +574,16 @@ export default defineComponent({
|
||||
searchObj.meta.resultGrid.rowsPerPage;
|
||||
req.query.size = parseInt(searchObj.meta.resultGrid.rowsPerPage, 10);
|
||||
|
||||
var timestamps: any = getConsumableDateTime();
|
||||
req.query.start_time = getISOTimestamp(timestamps.start_time);
|
||||
req.query.end_time = getISOTimestamp(timestamps.end_time);
|
||||
var timestamps: any =
|
||||
searchObj.data.datetime.type == "relative"
|
||||
? getConsumableRelativeTime(
|
||||
searchObj.data.datetime.relativeTimePeriod
|
||||
)
|
||||
: cloneDeep(searchObj.data.datetime);
|
||||
|
||||
const chartSettings = getChartSettings(timestamps);
|
||||
// if (chartSettings) {
|
||||
// searchObj.meta.resultGrid.chartKeyFormat =
|
||||
// chartSettings.chartKeyFormat;
|
||||
// searchObj.meta.resultGrid.chartInterval = chartSettings.chartInterval;
|
||||
req.query.start_time = timestamps.startTime;
|
||||
req.query.end_time = timestamps.endTime;
|
||||
|
||||
// req.aggs.histogram = req.aggs.histogram.replaceAll(
|
||||
// "[INTERVAL]",
|
||||
// searchObj.meta.resultGrid.chartInterval
|
||||
// );
|
||||
// }
|
||||
req.query["sql_mode"] = "full";
|
||||
|
||||
let parseQuery = query.split("|");
|
||||
@@ -648,6 +647,7 @@ export default defineComponent({
|
||||
updateUrlQueryParams();
|
||||
return req;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
searchObj.loading = false;
|
||||
showErrorNotification("Invalid SQL Syntax");
|
||||
}
|
||||
@@ -1223,7 +1223,16 @@ export default defineComponent({
|
||||
|
||||
function restoreUrlQueryParams() {
|
||||
const queryParams = router.currentRoute.value.query;
|
||||
const date = getDurationObjectFromParams(queryParams);
|
||||
if (!queryParams.stream) {
|
||||
return;
|
||||
}
|
||||
const date = {
|
||||
startTime: queryParams.from,
|
||||
endTime: queryParams.to,
|
||||
relativeTimePeriod: queryParams.period || null,
|
||||
type: queryParams.period ? "relative" : "absolute",
|
||||
};
|
||||
|
||||
if (date) {
|
||||
searchObj.data.datetime = date;
|
||||
}
|
||||
@@ -1233,7 +1242,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
function updateUrlQueryParams() {
|
||||
const date = getQueryParamsForDuration(searchObj.data.datetime);
|
||||
const date = searchObj.data.datetime;
|
||||
const query = {};
|
||||
|
||||
if (date.period) {
|
||||
@@ -1353,17 +1362,17 @@ export default defineComponent({
|
||||
this.loadPageData();
|
||||
}
|
||||
},
|
||||
changeStream() {
|
||||
if (this.searchObj.data.stream.selectedStream.hasOwnProperty("value")) {
|
||||
setTimeout(() => {
|
||||
this.runQueryFn();
|
||||
}, 500);
|
||||
}
|
||||
},
|
||||
changeRelativeDate() {
|
||||
if (this.searchObj.data.datetime.tab == "relative") {
|
||||
this.runQueryFn();
|
||||
}
|
||||
changeStream: {
|
||||
handler(stream, oldStream) {
|
||||
if (this.searchObj.data.stream.selectedStream.hasOwnProperty("value")) {
|
||||
if (oldStream.value) this.searchObj.data.query = "";
|
||||
if (oldStream.value) this.setQuery(this.searchObj.meta.sqlMode);
|
||||
setTimeout(() => {
|
||||
this.runQueryFn();
|
||||
}, 500);
|
||||
}
|
||||
},
|
||||
immediate: false,
|
||||
},
|
||||
updateSelectedColumns() {
|
||||
this.searchObj.meta.resultGrid.manualRemoveFields = true;
|
||||
|
||||
@@ -34,9 +34,19 @@
|
||||
></q-btn>
|
||||
<div class="float-left">
|
||||
<date-time
|
||||
:default-date="searchObj.data.datetime"
|
||||
auto-apply
|
||||
:default-type="
|
||||
searchObj.data.datetime.relativeTimePeriod
|
||||
? 'relative'
|
||||
: 'absolute'
|
||||
"
|
||||
:default-absolute-time="{
|
||||
startTime: searchObj.data.datetime.startTime,
|
||||
endTime: searchObj.data.datetime.endTime,
|
||||
}"
|
||||
:default-relative-time="searchObj.data.datetime.relativeTimePeriod"
|
||||
data-test="logs-search-bar-date-time-dropdown"
|
||||
@date-change="updateDateTime"
|
||||
@on:date-change="updateDateTime"
|
||||
/>
|
||||
</div>
|
||||
<div class="search-time q-pl-sm float-left">
|
||||
@@ -111,7 +121,7 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
setup(props, { emit }) {
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
const $q = useQuasar();
|
||||
@@ -198,26 +208,28 @@ export default defineComponent({
|
||||
};
|
||||
|
||||
const updateDateTime = (value: object) => {
|
||||
searchObj.data.datetime = value;
|
||||
searchObj.data.datetime = {
|
||||
startTime: value.startTime,
|
||||
endTime: value.endTime,
|
||||
relativeTimePeriod: value.relativeTimePeriod
|
||||
? value.relativeTimePeriod
|
||||
: searchObj.data.datetime.relativeTimePeriod,
|
||||
type: value.relativeTimePeriod ? "relative" : "absolute",
|
||||
};
|
||||
|
||||
if (config.isCloud == "true" && value.userChangedValue) {
|
||||
let dateTimeVal;
|
||||
if (value.tab === "relative") {
|
||||
dateTimeVal = value.relative;
|
||||
} else {
|
||||
dateTimeVal = value.absolute;
|
||||
}
|
||||
|
||||
segment.track("Button Click", {
|
||||
button: "Date Change",
|
||||
tab: value.tab,
|
||||
value: dateTimeVal,
|
||||
value: value,
|
||||
//user_org: this.store.state.selectedOrganization.identifier,
|
||||
//user_id: this.store.state.userInfo.email,
|
||||
stream_name: searchObj.data.stream.selectedStream.value,
|
||||
page: "Search Logs",
|
||||
});
|
||||
}
|
||||
|
||||
if (value.valueType === "relative") emit("searchdata");
|
||||
};
|
||||
|
||||
const udpateQuery = () => {
|
||||
|
||||
@@ -168,8 +168,6 @@ import useTraces from "../../composables/useTraces";
|
||||
import { getImageURL } from "../../utils/zincutils";
|
||||
import TraceDetails from "./TraceDetails.vue";
|
||||
import TraceChart from "./TraceChart.vue";
|
||||
import { redraw } from "plotly.js";
|
||||
import { cloneDeep } from "lodash";
|
||||
|
||||
export default defineComponent({
|
||||
name: "SearchResult",
|
||||
@@ -202,23 +200,9 @@ export default defineComponent({
|
||||
onChartUpdate({ start, end }: { start: any; end: any }) {
|
||||
if (!(start && end)) return;
|
||||
this.searchObj.meta.showDetailTab = false;
|
||||
this.searchObj.runQuery = true;
|
||||
this.searchObj.data.datetime.tab = "absolute";
|
||||
this.searchObj.data.datetime.absolute.date.from = start.split(" ")[0];
|
||||
this.searchObj.data.datetime.absolute.date.to = end.split(" ")[0];
|
||||
this.searchObj.data.datetime.absolute.startTime =
|
||||
start.split(" ")[1].split(":")[0] +
|
||||
":" +
|
||||
start.split(" ")[1].split(":")[1] +
|
||||
":" +
|
||||
start.split(" ")[1].split(":")[2];
|
||||
this.searchObj.data.datetime.absolute.endTime =
|
||||
end.split(" ")[1].split(":")[0] +
|
||||
":" +
|
||||
end.split(" ")[1].split(":")[1] +
|
||||
":" +
|
||||
end.split(" ")[1].split(":")[2];
|
||||
|
||||
this.searchObj.data.datetime.type = "absolute";
|
||||
this.searchObj.data.datetime.startTime = new Date(start).getTime() * 1000;
|
||||
this.searchObj.data.datetime.endTime = new Date(end).getTime() * 1000;
|
||||
this.searchObj.runQuery = true;
|
||||
this.$emit("update:datetime");
|
||||
},
|
||||
|
||||
@@ -15,11 +15,9 @@
|
||||
import { ref } from "vue";
|
||||
import organizationsService from "../services/organizations";
|
||||
import { useLocalOrganization, getPath } from "./zincutils";
|
||||
import { useQuasar } from "quasar";
|
||||
|
||||
const selectedOrg = ref("");
|
||||
const orgOptions = ref([{ label: Number, value: String }]);
|
||||
const $q = useQuasar();
|
||||
|
||||
export const getDefaultOrganization = async (
|
||||
userInfo: any,
|
||||
@@ -106,20 +104,3 @@ export const logsErrorMessage = (code: number) => {
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
export const showErrorNotification = (message: string) => {
|
||||
$q.notify({
|
||||
type: "negative",
|
||||
message: message,
|
||||
timeout: 5000,
|
||||
actions: [
|
||||
{
|
||||
icon: "close",
|
||||
color: "white",
|
||||
handler: () => {
|
||||
/* ... */
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
+96
-35
@@ -1,5 +1,7 @@
|
||||
// Copyright 2022 Zinc Labs Inc. and Contributors
|
||||
|
||||
import { date } from "quasar";
|
||||
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
@@ -52,7 +54,7 @@ export const generateDurationLabel = (seconds: number) => {
|
||||
{ label: "y", value: 31536000 },
|
||||
];
|
||||
|
||||
let duration = seconds;
|
||||
const duration = seconds;
|
||||
let label = "";
|
||||
|
||||
for (let i = units.length - 1; i >= 0; i--) {
|
||||
@@ -79,50 +81,50 @@ export const generateDurationLabel = (seconds: number) => {
|
||||
return label;
|
||||
};
|
||||
|
||||
export const getQueryParamsForDuration = (obj : any) => {
|
||||
let params : any = {};
|
||||
let tab = obj.tab;
|
||||
let period = obj.relative.period;
|
||||
let from = obj.absolute.date.from + " " + obj.absolute.startTime;
|
||||
let to = obj.absolute.date.to + " " + obj.absolute.endTime;
|
||||
export const getQueryParamsForDuration = (obj: any) => {
|
||||
const params: any = {};
|
||||
const tab = obj.tab;
|
||||
const period = obj.relative.period;
|
||||
const from = obj.absolute.date.from + " " + obj.absolute.startTime;
|
||||
const to = obj.absolute.date.to + " " + obj.absolute.endTime;
|
||||
|
||||
if (tab === "relative") {
|
||||
const labelsToUnitMapping : any = {
|
||||
const labelsToUnitMapping: any = {
|
||||
Minutes: "m",
|
||||
Hours: "h",
|
||||
Days: "d",
|
||||
Weeks: "w",
|
||||
Months: "M"
|
||||
}
|
||||
Months: "M",
|
||||
};
|
||||
|
||||
let periodValue = obj.relative.value;
|
||||
let periodLabel = period.label;
|
||||
let periodUnit = labelsToUnitMapping[periodLabel];
|
||||
const periodValue = obj.relative.value;
|
||||
const periodLabel = period.label;
|
||||
const periodUnit = labelsToUnitMapping[periodLabel];
|
||||
|
||||
if (periodLabel === "Minutes" && periodUnit === "m") {
|
||||
params['period'] = `${periodValue}${periodUnit}`;
|
||||
params["period"] = `${periodValue}${periodUnit}`;
|
||||
} else if (periodLabel === "Hours" && periodUnit === "h") {
|
||||
params['period'] = `${periodValue}${periodUnit}`;
|
||||
params["period"] = `${periodValue}${periodUnit}`;
|
||||
} else if (periodLabel === "Days" && periodUnit === "d") {
|
||||
params['period'] = `${periodValue}${periodUnit}`;
|
||||
params["period"] = `${periodValue}${periodUnit}`;
|
||||
} else if (periodLabel === "Weeks" && periodUnit === "w") {
|
||||
params['period'] = `${periodValue}${periodUnit}`;
|
||||
params["period"] = `${periodValue}${periodUnit}`;
|
||||
} else if (periodLabel === "Months" && periodUnit === "M") {
|
||||
params['period'] = `${periodValue}${periodUnit}`;
|
||||
params["period"] = `${periodValue}${periodUnit}`;
|
||||
}
|
||||
} else if (tab === "absolute") {
|
||||
let fromTime = new Date(from).getTime();
|
||||
let toTime = new Date(to).getTime();
|
||||
const fromTime = new Date(from).getTime();
|
||||
const toTime = new Date(to).getTime();
|
||||
|
||||
params['from'] = `${fromTime}`;
|
||||
params['to'] = `${toTime}`;
|
||||
params["from"] = `${fromTime}`;
|
||||
params["to"] = `${toTime}`;
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
};
|
||||
|
||||
export const getDurationObjectFromParams = (params: any) => {
|
||||
let obj = {
|
||||
const obj = {
|
||||
tab: "relative",
|
||||
relative: {
|
||||
period: { label: "Minutes", value: "Minutes" },
|
||||
@@ -138,13 +140,13 @@ export const getDurationObjectFromParams = (params: any) => {
|
||||
},
|
||||
};
|
||||
|
||||
let period = params?.period?.match(/(\d+)([mhdwM])/);
|
||||
let from = params?.from?.match(/(\d+)/);
|
||||
let to = params?.to?.match(/(\d+)/);
|
||||
const period = params?.period?.match(/(\d+)([mhdwM])/);
|
||||
const from = params?.from?.match(/(\d+)/);
|
||||
const to = params?.to?.match(/(\d+)/);
|
||||
|
||||
if (period) {
|
||||
let periodValue = period[1];
|
||||
let periodUnit = period[2];
|
||||
const periodValue = period[1];
|
||||
const periodUnit = period[2];
|
||||
|
||||
if (periodUnit === "m") {
|
||||
obj.relative.period = { label: "Minutes", value: "Minutes" };
|
||||
@@ -160,19 +162,78 @@ export const getDurationObjectFromParams = (params: any) => {
|
||||
|
||||
obj.relative.value = parseInt(periodValue);
|
||||
} else if (from && to) {
|
||||
let fromTime = parseInt(from[1]);
|
||||
let toTime = parseInt(to[1]);
|
||||
const fromTime = parseInt(from[1]);
|
||||
const toTime = parseInt(to[1]);
|
||||
|
||||
obj.tab = "absolute";
|
||||
obj.absolute.date.from = new Date(fromTime).toLocaleDateString("en-ZA");
|
||||
obj.absolute.date.to = new Date(toTime).toLocaleDateString("en-ZA");
|
||||
|
||||
const startTimeDateObj = new Date(fromTime);
|
||||
obj.absolute.startTime = `${startTimeDateObj.getHours().toString().padStart(2, '0')}:${startTimeDateObj.getMinutes().toString().padStart(2, '0')}`
|
||||
|
||||
obj.absolute.startTime = `${startTimeDateObj
|
||||
.getHours()
|
||||
.toString()
|
||||
.padStart(2, "0")}:${startTimeDateObj
|
||||
.getMinutes()
|
||||
.toString()
|
||||
.padStart(2, "0")}`;
|
||||
|
||||
const toTimeDateObj = new Date(toTime);
|
||||
obj.absolute.endTime = `${toTimeDateObj.getHours().toString().padStart(2, '0')}:${toTimeDateObj.getMinutes().toString().padStart(2, '0')}`
|
||||
obj.absolute.endTime = `${toTimeDateObj
|
||||
.getHours()
|
||||
.toString()
|
||||
.padStart(2, "0")}:${toTimeDateObj
|
||||
.getMinutes()
|
||||
.toString()
|
||||
.padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
|
||||
export const getConsumableRelativeTime = (period: string) => {
|
||||
const periodString = period?.match(/(\d+)([mhdwM])/);
|
||||
|
||||
if (periodString) {
|
||||
let periodValue: number = parseInt(periodString[1]);
|
||||
let periodUnit: string = periodString[2];
|
||||
|
||||
const periodUnits = ["m", "h", "d", "w", "M"];
|
||||
|
||||
// quasar does not support arithmetic on weeks. convert to days.
|
||||
if (periodUnit == "w") {
|
||||
periodUnit = "days";
|
||||
periodValue = periodValue * 7;
|
||||
}
|
||||
|
||||
const subtractObject =
|
||||
'{"' +
|
||||
getRelativePeriod(periodUnit).toLowerCase() +
|
||||
'":' +
|
||||
periodValue +
|
||||
"}";
|
||||
|
||||
const endTimeStamp = new Date();
|
||||
|
||||
const startTimeStamp = date.subtractFromDate(
|
||||
endTimeStamp,
|
||||
JSON.parse(subtractObject)
|
||||
);
|
||||
|
||||
return {
|
||||
startTime: new Date(startTimeStamp).getTime() * 1000,
|
||||
endTime: new Date(endTimeStamp).getTime() * 1000,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const getRelativePeriod = (period: string) => {
|
||||
const mapping: { [key: string]: string } = {
|
||||
m: "Minutes",
|
||||
h: "Hours",
|
||||
d: "Days",
|
||||
w: "Weeks",
|
||||
M: "Months",
|
||||
};
|
||||
return mapping[period];
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user