mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-06 00:09:22 +00:00
fix: fixed traces and alerts UI issues (#2350)
This commit is contained in:
@@ -161,7 +161,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-12 flex justify-start items-center q-mt-md">
|
||||
<div class="col-12 flex justify-start items-center q-mt-xs">
|
||||
<div
|
||||
class="q-py-sm showLabelOnTop text-bold text-h7"
|
||||
data-test="add-alert-delay-title"
|
||||
@@ -169,39 +169,45 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
>
|
||||
{{ t("alerts.silenceNotification") + " *" }}
|
||||
</div>
|
||||
<div class="col-8 row justify-left align-center q-gutter-sm">
|
||||
<div style="min-height: 58px">
|
||||
<div class="col-8 row justify-left align-center q-gutter-sm">
|
||||
<div
|
||||
class="flex items-center"
|
||||
style="border: 1px solid rgba(0, 0, 0, 0.05)"
|
||||
>
|
||||
<div
|
||||
style="width: 87px; margin-left: 0 !important"
|
||||
class="silence-notification-input"
|
||||
>
|
||||
<q-input
|
||||
data-test="add-alert-delay-input"
|
||||
v-model="formData.trigger_condition.silence"
|
||||
type="number"
|
||||
dense
|
||||
filled
|
||||
min="1"
|
||||
style="background: none"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style="
|
||||
min-width: 90px;
|
||||
margin-left: 0 !important;
|
||||
background: #f2f2f2;
|
||||
height: 40px;
|
||||
"
|
||||
class="flex justify-center items-center"
|
||||
>
|
||||
{{ t("alerts.minutes") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center"
|
||||
style="border: 1px solid rgba(0, 0, 0, 0.05)"
|
||||
v-if="formData.trigger_condition.silence < 1"
|
||||
class="text-red-8 q-pt-xs"
|
||||
style="font-size: 11px; line-height: 12px"
|
||||
>
|
||||
<div
|
||||
style="width: 87px; margin-left: 0 !important"
|
||||
class="silence-notification-input"
|
||||
>
|
||||
<q-input
|
||||
data-test="add-alert-delay-input"
|
||||
v-model="formData.trigger_condition.silence"
|
||||
type="number"
|
||||
dense
|
||||
filled
|
||||
min="1"
|
||||
style="background: none"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style="
|
||||
min-width: 90px;
|
||||
margin-left: 0 !important;
|
||||
background: #f2f2f2;
|
||||
height: 40px;
|
||||
"
|
||||
class="flex justify-center items-center"
|
||||
:class="
|
||||
store.state.theme === 'dark' ? 'bg-grey-10' : 'bg-grey-2'
|
||||
"
|
||||
>
|
||||
{{ t("alerts.minutes") }}
|
||||
</div>
|
||||
Field is required!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -332,7 +338,7 @@ import ScheduledAlert from "./ScheduledAlert.vue";
|
||||
import RealTimeAlert from "./RealTimeAlert.vue";
|
||||
import VariablesInput from "./VariablesInput.vue";
|
||||
import { getUUID } from "@/utils/zincutils";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { clone, cloneDeep } from "lodash-es";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
const defaultValue: any = () => {
|
||||
@@ -719,11 +725,6 @@ export default defineComponent({
|
||||
});
|
||||
return false;
|
||||
}
|
||||
const dismiss = this.q.notify({
|
||||
spinner: true,
|
||||
message: "Please wait...",
|
||||
timeout: 2000,
|
||||
});
|
||||
|
||||
this.addAlertForm.validate().then((valid: any) => {
|
||||
if (!valid) {
|
||||
@@ -767,6 +768,14 @@ export default defineComponent({
|
||||
payload.query_condition.conditions = [];
|
||||
}
|
||||
|
||||
if (!this.validateInputs(payload)) return;
|
||||
|
||||
const dismiss = this.q.notify({
|
||||
spinner: true,
|
||||
message: "Please wait...",
|
||||
timeout: 2000,
|
||||
});
|
||||
|
||||
callAlert = alertsService.create(
|
||||
this.store.state.selectedOrganization.identifier,
|
||||
payload.stream_name,
|
||||
@@ -802,6 +811,71 @@ export default defineComponent({
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
validateInputs(input: any) {
|
||||
if (
|
||||
Number(input.trigger_condition.silence) < 1 ||
|
||||
isNaN(Number(input.trigger_condition.silence))
|
||||
) {
|
||||
this.q.notify({
|
||||
type: "negative",
|
||||
message: "Silence Notification should be greater than 0",
|
||||
timeout: 1500,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input.is_real_time) return true;
|
||||
|
||||
if (
|
||||
Number(input.trigger_condition.period) < 1 ||
|
||||
isNaN(Number(input.trigger_condition.period))
|
||||
) {
|
||||
this.q.notify({
|
||||
type: "negative",
|
||||
message: "Period should be greater than 0",
|
||||
timeout: 1500,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input.query_condition.aggregation) {
|
||||
if (
|
||||
!input.query_condition.aggregation.having.value.toString().trim()
|
||||
.length ||
|
||||
!input.query_condition.aggregation.having.column ||
|
||||
!input.query_condition.aggregation.having.operator
|
||||
) {
|
||||
this.q.notify({
|
||||
type: "negative",
|
||||
message: "Threshold should not be empty",
|
||||
timeout: 1500,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
console.log(
|
||||
input.trigger_condition.threshold.toString().trim().length,
|
||||
input.query_condition.operator
|
||||
);
|
||||
|
||||
if (
|
||||
!input.trigger_condition.threshold.toString().trim().length ||
|
||||
!input.trigger_condition.operator
|
||||
) {
|
||||
this.q.notify({
|
||||
type: "negative",
|
||||
message: "Threshold should not be empty",
|
||||
timeout: 1500,
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -113,127 +113,190 @@
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-start items-center q-mb-md">
|
||||
<div class="flex justify-start items-center q-mb-xs">
|
||||
<div class="text-bold" style="width: 180px">
|
||||
{{ t("alerts.threshold") + " *" }}
|
||||
</div>
|
||||
<template v-if="_isAggregationEnabled && aggregationData">
|
||||
<div class="threshould-input q-mr-xs">
|
||||
<q-select
|
||||
data-test="add-alert-stream-select"
|
||||
v-model="aggregationData.function"
|
||||
:options="aggFunctions"
|
||||
color="input-border"
|
||||
bg-color="input-bg"
|
||||
class="showLabelOnTop no-case q-py-none"
|
||||
filled
|
||||
borderless
|
||||
dense
|
||||
use-input
|
||||
hide-selected
|
||||
fill-input
|
||||
:rules="[(val: any) => !!val || 'Field is required!']"
|
||||
style="width: 88px; border: 1px solid rgba(0, 0, 0, 0.05)"
|
||||
@update:model-value="updateTrigger"
|
||||
/>
|
||||
</div>
|
||||
<div class="threshould-input q-mr-xs">
|
||||
<q-select
|
||||
data-test="add-alert-stream-select"
|
||||
v-model="aggregationData.having.column"
|
||||
:options="filteredNumericColumns"
|
||||
color="input-border"
|
||||
bg-color="input-bg"
|
||||
class="showLabelOnTop no-case q-py-none"
|
||||
filled
|
||||
borderless
|
||||
dense
|
||||
use-input
|
||||
emit-value
|
||||
hide-selected
|
||||
fill-input
|
||||
:rules="[(val: any) => !!val || 'Field is required!']"
|
||||
@filter="filterNumericColumns"
|
||||
style="width: 250px; border: 1px solid rgba(0, 0, 0, 0.05)"
|
||||
@update:model-value="updateTrigger"
|
||||
/>
|
||||
</div>
|
||||
<div class="threshould-input q-mr-xs">
|
||||
<q-select
|
||||
data-test="add-alert-stream-select"
|
||||
v-model="aggregationData.having.operator"
|
||||
:options="triggerOperators"
|
||||
color="input-border"
|
||||
bg-color="input-bg"
|
||||
class="showLabelOnTop no-case q-py-none"
|
||||
filled
|
||||
borderless
|
||||
dense
|
||||
use-input
|
||||
hide-selected
|
||||
fill-input
|
||||
:rules="[(val: any) => !!val || 'Field is required!']"
|
||||
style="width: 88px; border: 1px solid rgba(0, 0, 0, 0.05)"
|
||||
@update:model-value="updateTrigger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center"
|
||||
style="border: 1px solid rgba(0, 0, 0, 0.05)"
|
||||
>
|
||||
<div
|
||||
style="width: 150px; margin-left: 0 !important"
|
||||
class="silence-notification-input"
|
||||
>
|
||||
<q-input
|
||||
data-test="add-alert-delay-input"
|
||||
v-model="aggregationData.having.value"
|
||||
type="number"
|
||||
dense
|
||||
filled
|
||||
min="0"
|
||||
style="background: none"
|
||||
placeholder="Value"
|
||||
@update:model-value="updateTrigger"
|
||||
/>
|
||||
<div style="min-height: 58px">
|
||||
<template v-if="_isAggregationEnabled && aggregationData">
|
||||
<div class="flex justify-start items-center">
|
||||
<div class="threshould-input q-mr-xs">
|
||||
<q-select
|
||||
data-test="add-alert-stream-select"
|
||||
v-model="aggregationData.function"
|
||||
:options="aggFunctions"
|
||||
color="input-border"
|
||||
bg-color="input-bg"
|
||||
class="showLabelOnTop no-case q-py-none"
|
||||
filled
|
||||
borderless
|
||||
dense
|
||||
use-input
|
||||
hide-selected
|
||||
fill-input
|
||||
style="width: 88px; border: 1px solid rgba(0, 0, 0, 0.05)"
|
||||
@update:model-value="updateTrigger"
|
||||
/>
|
||||
</div>
|
||||
<div class="threshould-input q-mr-xs">
|
||||
<q-select
|
||||
data-test="add-alert-stream-select"
|
||||
v-model="aggregationData.having.column"
|
||||
:options="filteredNumericColumns"
|
||||
color="input-border"
|
||||
bg-color="input-bg"
|
||||
class="showLabelOnTop no-case q-py-none"
|
||||
filled
|
||||
borderless
|
||||
dense
|
||||
use-input
|
||||
emit-value
|
||||
hide-selected
|
||||
fill-input
|
||||
@filter="filterNumericColumns"
|
||||
style="width: 250px; border: 1px solid rgba(0, 0, 0, 0.05)"
|
||||
@update:model-value="updateTrigger"
|
||||
/>
|
||||
</div>
|
||||
<div class="threshould-input q-mr-xs">
|
||||
<q-select
|
||||
data-test="add-alert-stream-select"
|
||||
v-model="aggregationData.having.operator"
|
||||
:options="triggerOperators"
|
||||
color="input-border"
|
||||
bg-color="input-bg"
|
||||
class="showLabelOnTop no-case q-py-none"
|
||||
filled
|
||||
borderless
|
||||
dense
|
||||
use-input
|
||||
hide-selected
|
||||
fill-input
|
||||
style="width: 88px; border: 1px solid rgba(0, 0, 0, 0.05)"
|
||||
@update:model-value="updateTrigger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center"
|
||||
style="border: 1px solid rgba(0, 0, 0, 0.05)"
|
||||
>
|
||||
<div
|
||||
style="width: 150px; margin-left: 0 !important"
|
||||
class="silence-notification-input"
|
||||
>
|
||||
<q-input
|
||||
data-test="add-alert-delay-input"
|
||||
v-model="aggregationData.having.value"
|
||||
type="number"
|
||||
dense
|
||||
filled
|
||||
min="0"
|
||||
style="background: none"
|
||||
placeholder="Value"
|
||||
@update:model-value="updateTrigger"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="threshould-input">
|
||||
<q-select
|
||||
data-test="add-alert-stream-select"
|
||||
v-model="triggerData.operator"
|
||||
:options="triggerOperators"
|
||||
color="input-border"
|
||||
bg-color="input-bg"
|
||||
class="showLabelOnTop no-case q-py-none"
|
||||
filled
|
||||
borderless
|
||||
dense
|
||||
use-input
|
||||
hide-selected
|
||||
fill-input
|
||||
:rules="[(val: any) => !!val || 'Field is required!']"
|
||||
style="width: 88px; border: 1px solid rgba(0, 0, 0, 0.05)"
|
||||
@update:model-value="updateTrigger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
!aggregationData.function ||
|
||||
!aggregationData.having.column ||
|
||||
!aggregationData.having.operator ||
|
||||
!aggregationData.having.value.toString().trim().length
|
||||
"
|
||||
class="text-red-8 q-pt-xs"
|
||||
style="font-size: 11px; line-height: 12px"
|
||||
>
|
||||
Field is required!
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="flex justify-start items-center">
|
||||
<div class="threshould-input">
|
||||
<q-select
|
||||
data-test="add-alert-stream-select"
|
||||
v-model="triggerData.operator"
|
||||
:options="triggerOperators"
|
||||
color="input-border"
|
||||
bg-color="input-bg"
|
||||
class="showLabelOnTop no-case q-py-none"
|
||||
filled
|
||||
borderless
|
||||
dense
|
||||
use-input
|
||||
hide-selected
|
||||
fill-input
|
||||
:rules="[(val: any) => !!val || 'Field is required!']"
|
||||
style="width: 88px; border: 1px solid rgba(0, 0, 0, 0.05)"
|
||||
@update:model-value="updateTrigger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center"
|
||||
style="border: 1px solid rgba(0, 0, 0, 0.05); border-left: none"
|
||||
>
|
||||
<div
|
||||
style="width: 89px; margin-left: 0 !important"
|
||||
class="silence-notification-input"
|
||||
>
|
||||
<q-input
|
||||
data-test="add-alert-delay-input"
|
||||
v-model="triggerData.threshold"
|
||||
type="number"
|
||||
dense
|
||||
filled
|
||||
min="0"
|
||||
style="background: none"
|
||||
@update:model-value="updateTrigger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style="
|
||||
min-width: 90px;
|
||||
margin-left: 0 !important;
|
||||
height: 40px;
|
||||
font-weight: normal;
|
||||
"
|
||||
:class="
|
||||
store.state.theme === 'dark' ? 'bg-grey-10' : 'bg-grey-2'
|
||||
"
|
||||
class="flex justify-center items-center"
|
||||
>
|
||||
{{ t("alerts.times") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
v-if="!triggerData.operator || !Number(triggerData.threshold)"
|
||||
class="text-red-8 q-pt-xs"
|
||||
style="font-size: 11px; line-height: 12px"
|
||||
>
|
||||
Field is required!
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center q-mr-sm">
|
||||
<div class="text-bold" style="width: 180px">
|
||||
{{ t("alerts.period") + " *" }}
|
||||
</div>
|
||||
<div style="min-height: 58px">
|
||||
<div
|
||||
class="flex items-center"
|
||||
style="border: 1px solid rgba(0, 0, 0, 0.05); border-left: none"
|
||||
class="flex items-center q-mr-sm"
|
||||
style="border: 1px solid rgba(0, 0, 0, 0.05); width: fit-content"
|
||||
>
|
||||
<div
|
||||
style="width: 89px; margin-left: 0 !important"
|
||||
style="width: 87px; margin-left: 0 !important"
|
||||
class="silence-notification-input"
|
||||
>
|
||||
<q-input
|
||||
data-test="add-alert-delay-input"
|
||||
v-model="triggerData.threshold"
|
||||
v-model="triggerData.period"
|
||||
type="number"
|
||||
dense
|
||||
filled
|
||||
min="0"
|
||||
min="1"
|
||||
style="background: none"
|
||||
@update:model-value="updateTrigger"
|
||||
/>
|
||||
@@ -248,45 +311,15 @@
|
||||
:class="store.state.theme === 'dark' ? 'bg-grey-10' : 'bg-grey-2'"
|
||||
class="flex justify-center items-center"
|
||||
>
|
||||
{{ t("alerts.times") }}
|
||||
{{ t("alerts.minutes") }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="flex items-center q-mr-sm">
|
||||
<div class="text-bold" style="width: 180px">
|
||||
{{ t("alerts.period") + " *" }}
|
||||
</div>
|
||||
<div
|
||||
class="flex items-center q-mr-sm"
|
||||
style="border: 1px solid rgba(0, 0, 0, 0.05); width: fit-content"
|
||||
>
|
||||
<div
|
||||
style="width: 87px; margin-left: 0 !important"
|
||||
class="silence-notification-input"
|
||||
v-if="!Number(triggerData.period)"
|
||||
class="text-red-8 q-pt-xs"
|
||||
style="font-size: 11px; line-height: 12px"
|
||||
>
|
||||
<q-input
|
||||
data-test="add-alert-delay-input"
|
||||
v-model="triggerData.period"
|
||||
type="number"
|
||||
dense
|
||||
filled
|
||||
min="1"
|
||||
style="background: none"
|
||||
@update:model-value="updateTrigger"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style="
|
||||
min-width: 90px;
|
||||
margin-left: 0 !important;
|
||||
height: 40px;
|
||||
font-weight: normal;
|
||||
"
|
||||
:class="store.state.theme === 'dark' ? 'bg-grey-10' : 'bg-grey-2'"
|
||||
class="flex justify-center items-center"
|
||||
>
|
||||
{{ t("alerts.minutes") }}
|
||||
Field is required!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -104,6 +104,10 @@ export default defineComponent({
|
||||
return {};
|
||||
},
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
components: {
|
||||
DateTime,
|
||||
@@ -112,7 +116,7 @@ export default defineComponent({
|
||||
emits: ["searchdata", "update-query", "change:date-time"],
|
||||
methods: {
|
||||
searchData() {
|
||||
if (this.searchObj.loading == false) {
|
||||
if (!this.isLoading) {
|
||||
// this.searchObj.runQuery = true;
|
||||
this.$emit("searchdata");
|
||||
}
|
||||
|
||||
@@ -82,7 +82,8 @@
|
||||
"savedViewsNotFound": "Saved view not found!",
|
||||
"savedViewAction": "Create/Update Saved View",
|
||||
"savedViewDropdownLabel": "Saved Views",
|
||||
"savedViewName": "View Name"
|
||||
"savedViewName": "View Name",
|
||||
"shareLink": "Share Link"
|
||||
},
|
||||
"menu": {
|
||||
"home": "Home",
|
||||
|
||||
@@ -29,6 +29,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
v-model="searchObj.meta.sqlMode"
|
||||
:label="t('search.sqlModeLabel')"
|
||||
/>
|
||||
<q-btn
|
||||
label="Reset Filters"
|
||||
no-caps
|
||||
size="sm"
|
||||
icon="restart_alt"
|
||||
class="q-pr-sm q-pl-xs reset-filters q-ml-md"
|
||||
@click="resetFilters"
|
||||
/>
|
||||
<syntax-guide
|
||||
data-test="logs-search-bar-sql-mode-toggle-btn"
|
||||
:sqlmode="searchObj.meta.sqlMode"
|
||||
@@ -71,8 +79,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
side
|
||||
@click.stop="handleDeleteSavedView(item)"
|
||||
>
|
||||
<q-icon name="delete"
|
||||
color="grey" size="xs" />
|
||||
<q-icon name="delete" color="grey" size="xs" />
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</div>
|
||||
@@ -879,7 +886,7 @@ export default defineComponent({
|
||||
fnEditorobj.layout();
|
||||
searchObj.config.fnSplitterModel = 60;
|
||||
}
|
||||
|
||||
|
||||
window.addEventListener("click", () => {
|
||||
fnEditorobj.layout();
|
||||
// queryEditorRef.value.resetEditorLayout();
|
||||
@@ -1495,6 +1502,11 @@ export default defineComponent({
|
||||
});
|
||||
};
|
||||
|
||||
const resetFilters = () => {
|
||||
searchObj.data.query = "";
|
||||
searchObj.data.editorValue = "";
|
||||
};
|
||||
|
||||
return {
|
||||
t,
|
||||
store,
|
||||
@@ -1547,6 +1559,7 @@ export default defineComponent({
|
||||
saveFunctionLoader,
|
||||
shareLink,
|
||||
getImageURL,
|
||||
resetFilters,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -424,8 +424,6 @@ export default defineComponent({
|
||||
() => searchObj.data.metrics.metricList,
|
||||
(metrics) => {
|
||||
updateMetricKeywords(metrics);
|
||||
// on page load run query
|
||||
runQuery();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
@@ -26,6 +26,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
:isLoading="searchObj.loading"
|
||||
@searchdata="searchData"
|
||||
@onChangeTimezone="refreshTimezone"
|
||||
@shareLink="copyTracesUrl"
|
||||
/>
|
||||
<div
|
||||
id="tracesThirdLevel"
|
||||
@@ -143,6 +144,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
@update:datetime="setHistogramDate"
|
||||
@update:scroll="getMoreData"
|
||||
@get:traceDetails="getTraceDetails"
|
||||
@shareLink="copyTracesUrl"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@@ -162,7 +164,7 @@ import {
|
||||
onBeforeMount,
|
||||
nextTick,
|
||||
} from "vue";
|
||||
import { useQuasar, date } from "quasar";
|
||||
import { useQuasar, date, copyToClipboard } from "quasar";
|
||||
import { useStore } from "vuex";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useRouter } from "vue-router";
|
||||
@@ -556,7 +558,9 @@ export default defineComponent({
|
||||
|
||||
req.query.sql = b64EncodeUnicode(req.query.sql);
|
||||
|
||||
updateUrlQueryParams();
|
||||
const queryParams = getUrlQueryParams();
|
||||
console.log(queryParams);
|
||||
router.push({ query: queryParams });
|
||||
return req;
|
||||
} catch (e) {
|
||||
searchObj.loading = false;
|
||||
@@ -732,8 +736,6 @@ export default defineComponent({
|
||||
|
||||
const durationFilter = indexListRef.value.duration.input;
|
||||
|
||||
console.log(durationFilter);
|
||||
|
||||
let filter = searchObj.data.editorValue.trim();
|
||||
|
||||
let duration = "";
|
||||
@@ -1193,11 +1195,49 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
function updateUrlQueryParams() {
|
||||
const copyTracesUrl = (customTimeRange = null) => {
|
||||
const queryParams = getUrlQueryParams(true);
|
||||
|
||||
if (customTimeRange) {
|
||||
queryParams.from = customTimeRange.from;
|
||||
queryParams.to = customTimeRange.to;
|
||||
}
|
||||
|
||||
const queryString = Object.entries(queryParams)
|
||||
.map(
|
||||
([key, value]) =>
|
||||
`${encodeURIComponent(key)}=${encodeURIComponent(value)}`
|
||||
)
|
||||
.join("&");
|
||||
|
||||
let shareURL = window.location.origin + window.location.pathname;
|
||||
|
||||
if (queryString != "") {
|
||||
shareURL += "?" + queryString;
|
||||
}
|
||||
|
||||
copyToClipboard(shareURL)
|
||||
.then(() => {
|
||||
$q.notify({
|
||||
type: "positive",
|
||||
message: "Link Copied Successfully!",
|
||||
timeout: 5000,
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
$q.notify({
|
||||
type: "negative",
|
||||
message: "Error while copy link.",
|
||||
timeout: 5000,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function getUrlQueryParams(getShareLink: false) {
|
||||
const date = searchObj.data.datetime;
|
||||
const query = {};
|
||||
|
||||
if (date.type == "relative") {
|
||||
if (date.type == "relative" && !getShareLink) {
|
||||
query["period"] = date.relativeTimePeriod;
|
||||
} else {
|
||||
query["from"] = date.startTime;
|
||||
@@ -1212,7 +1252,7 @@ export default defineComponent({
|
||||
|
||||
query["trace_id"] = router.currentRoute.value.query.trace_id;
|
||||
|
||||
router.push({ query });
|
||||
return query;
|
||||
}
|
||||
|
||||
const onSplitterUpdate = () => {
|
||||
@@ -1302,6 +1342,7 @@ export default defineComponent({
|
||||
onSplitterUpdate,
|
||||
refreshTimezone,
|
||||
indexListRef,
|
||||
copyTracesUrl,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -301,17 +301,13 @@ export default defineComponent({
|
||||
const getFieldValues = (name: string) => {
|
||||
fieldValues.value[name].size *= 2;
|
||||
|
||||
let query_context = "SELECT * FROM 'default'";
|
||||
let query_context = `SELECT * FROM 'default' WHERE ${name} is not null`;
|
||||
|
||||
if (searchObj.data.editorValue) {
|
||||
query_context += " WHERE " + searchObj.data.editorValue;
|
||||
}
|
||||
if (searchObj.data.editorValue.trim().length)
|
||||
query_context += " AND " + searchObj.data.editorValue;
|
||||
|
||||
if (searchObj.data.editorValue && fieldValues.value[name].searchKeyword) {
|
||||
if (fieldValues.value[name].searchKeyword.trim().length)
|
||||
query_context += ` AND ${name} ILIKE '%${fieldValues.value[name].searchKeyword}%'`;
|
||||
} else if (fieldValues.value[name].searchKeyword) {
|
||||
query_context += ` WHERE ${name} ILIKE '%${fieldValues.value[name].searchKeyword}%'`;
|
||||
}
|
||||
|
||||
fieldValues.value[name]["isLoading"] = true;
|
||||
|
||||
@@ -330,26 +326,7 @@ export default defineComponent({
|
||||
query_context: b64EncodeUnicode(query_context),
|
||||
})
|
||||
.then((res: any) => {
|
||||
const values: any = new Set([]);
|
||||
|
||||
fieldValues.value[name]["values"] =
|
||||
res.data.hits
|
||||
.find((field: any) => field.field === name)
|
||||
?.values.map((value: any) => {
|
||||
return {
|
||||
key: value.zo_sql_key ? value.zo_sql_key : "null",
|
||||
count: formatLargeNumber(value.zo_sql_num),
|
||||
};
|
||||
}) || [];
|
||||
|
||||
fieldValues.value[name].selectedValues.forEach((value: string) => {
|
||||
if (values.has(value)) return;
|
||||
else
|
||||
fieldValues.value[name]["values"].unshift({
|
||||
key: value,
|
||||
count: "0",
|
||||
});
|
||||
});
|
||||
updateSelectedValues(res.data.hits);
|
||||
})
|
||||
.catch(() => {
|
||||
$q.notify({
|
||||
@@ -473,12 +450,6 @@ export default defineComponent({
|
||||
};
|
||||
|
||||
const filterExpandedFieldValues = () => {
|
||||
let query_context = "SELECT * FROM 'default'";
|
||||
|
||||
if (searchObj.data.editorValue) {
|
||||
query_context += " WHERE " + searchObj.data.editorValue;
|
||||
}
|
||||
|
||||
const fields =
|
||||
[
|
||||
...expandedFilters.value.filter(
|
||||
@@ -494,6 +465,17 @@ export default defineComponent({
|
||||
getSpecialFieldsValues("service_name");
|
||||
}
|
||||
|
||||
let query_context = "SELECT * FROM 'default'";
|
||||
|
||||
fields.forEach((field, index) => {
|
||||
if (index) query_context += ` AND ${field} is not null `;
|
||||
else query_context += ` WHERE ${field} is not null `;
|
||||
});
|
||||
|
||||
if (searchObj.data.editorValue) {
|
||||
query_context += " AND " + searchObj.data.editorValue;
|
||||
}
|
||||
|
||||
if (!fields.length) return;
|
||||
|
||||
streamService
|
||||
@@ -508,23 +490,21 @@ export default defineComponent({
|
||||
query_context: b64EncodeUnicode(query_context),
|
||||
})
|
||||
.then((res: any) => {
|
||||
let fieldsToUpdate = [];
|
||||
|
||||
fields.forEach((field) => {
|
||||
fieldValues.value[field]["values"] = [];
|
||||
fieldValues.value[field].size = 10;
|
||||
});
|
||||
|
||||
if (res.data.hits.length) {
|
||||
res.data.hits.forEach((field: { field: string; values: any[] }) => {
|
||||
fieldValues.value[field.field]["values"] = field.values.map(
|
||||
(value: any) => {
|
||||
return {
|
||||
key: value.zo_sql_key ? value.zo_sql_key : "null",
|
||||
count: formatLargeNumber(value.zo_sql_num),
|
||||
};
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
fieldsToUpdate = fields.map((field) => ({
|
||||
field,
|
||||
values: [],
|
||||
}));
|
||||
|
||||
fieldsToUpdate.push(...res.data.hits);
|
||||
|
||||
updateSelectedValues(fieldsToUpdate);
|
||||
})
|
||||
.catch(() => {
|
||||
$q.notify({
|
||||
@@ -612,6 +592,34 @@ export default defineComponent({
|
||||
}
|
||||
};
|
||||
|
||||
// Update the values of the selected fields and add the values which are not present in the selected values
|
||||
// Also we filter out null values from the values array
|
||||
const updateSelectedValues = (hits: any[]) => {
|
||||
hits.forEach((field: any) => {
|
||||
const values: any = new Set([]);
|
||||
|
||||
fieldValues.value[field.field]["values"] =
|
||||
field.values.map((value: any) => {
|
||||
values.add(value.zo_sql_key);
|
||||
return {
|
||||
key: value.zo_sql_key ? value.zo_sql_key : "null",
|
||||
count: formatLargeNumber(value.zo_sql_num),
|
||||
};
|
||||
}) || [];
|
||||
|
||||
fieldValues.value[field.field].selectedValues.forEach(
|
||||
(value: string) => {
|
||||
if (values.has(value)) return;
|
||||
else
|
||||
fieldValues.value[field.field]["values"].unshift({
|
||||
key: value,
|
||||
count: "0",
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
// const getFullQuery = () => {
|
||||
// let query = "SELECT * FROM 'default'";
|
||||
// if (searchObj.data.editorValue)
|
||||
|
||||
@@ -74,8 +74,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
size="sm"
|
||||
icon="restart_alt"
|
||||
class="q-pr-sm q-pl-xs reset-filters q-ml-md"
|
||||
@click="resetFilters()"
|
||||
></q-btn>
|
||||
@click="resetFilters"
|
||||
/>
|
||||
</div>
|
||||
<div class="float-right col-auto">
|
||||
<div class="float-left">
|
||||
@@ -113,7 +113,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
icon="download"
|
||||
title="Export Traces"
|
||||
@click="downloadLogs"
|
||||
></q-btn>
|
||||
/>
|
||||
<q-btn
|
||||
data-test="logs-search-bar-share-link-btn"
|
||||
class="q-mr-sm download-logs-btn q-px-sm"
|
||||
size="sm"
|
||||
icon="share"
|
||||
:title="t('search.shareLink')"
|
||||
@click="shareLink"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -175,7 +183,7 @@ export default defineComponent({
|
||||
AppTabs,
|
||||
ConfirmDialog,
|
||||
},
|
||||
emits: ["searchdata"],
|
||||
emits: ["searchdata", "shareLink"],
|
||||
props: {
|
||||
fieldValues: {
|
||||
type: Object,
|
||||
@@ -378,12 +386,17 @@ export default defineComponent({
|
||||
|
||||
const resetFilters = () => {
|
||||
searchObj.data.editorValue = "";
|
||||
searchObj.data.advanceFiltersQuery = "";
|
||||
Object.values(searchObj.data.stream.fieldValues).forEach((field) => {
|
||||
field.selectedValues = [];
|
||||
field.searchKeyword = "";
|
||||
});
|
||||
};
|
||||
|
||||
const shareLink = () => {
|
||||
emit("shareLink");
|
||||
};
|
||||
|
||||
return {
|
||||
t,
|
||||
router,
|
||||
@@ -404,6 +417,7 @@ export default defineComponent({
|
||||
showWarningDialog,
|
||||
changeToggle,
|
||||
resetFilters,
|
||||
shareLink,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -62,7 +62,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
maximized
|
||||
@hide="closeTraceDetails"
|
||||
>
|
||||
<trace-details />
|
||||
<trace-details @shareLink="shareLink" />
|
||||
</q-dialog>
|
||||
</div>
|
||||
</div>
|
||||
@@ -97,6 +97,7 @@ export default defineComponent({
|
||||
"remove:searchTerm",
|
||||
"search:timeboxed",
|
||||
"get:traceDetails",
|
||||
"shareLink",
|
||||
],
|
||||
methods: {
|
||||
closeColumn(col: any) {
|
||||
@@ -239,6 +240,15 @@ export default defineComponent({
|
||||
expandRowDetail(searchObj.data.queryResults.hits[data.dataIndex]);
|
||||
};
|
||||
|
||||
const shareLink = () => {
|
||||
if (!searchObj.data.traceDetails.selectedTrace) return;
|
||||
const trace = searchObj.data.traceDetails.selectedTrace as any;
|
||||
emit("shareLink", {
|
||||
from: trace.trace_start_time - 60000000,
|
||||
to: trace.trace_end_time + 60000000,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
t,
|
||||
store,
|
||||
@@ -258,6 +268,7 @@ export default defineComponent({
|
||||
showTraceDetails,
|
||||
closeTraceDetails,
|
||||
onChartClick,
|
||||
shareLink,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -16,8 +16,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
<template>
|
||||
<div
|
||||
class="flex wrap justify-start items-center bg-white"
|
||||
:class="defocusSpan ? 'defocus' : ''"
|
||||
class="flex wrap justify-start items-center"
|
||||
:class="[
|
||||
defocusSpan ? 'defocus' : '',
|
||||
store.state.theme === 'dark' ? 'bg-dark' : 'bg-white',
|
||||
]"
|
||||
:style="{
|
||||
zIndex: 2,
|
||||
borderBottom:
|
||||
@@ -25,7 +28,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
}"
|
||||
>
|
||||
<div
|
||||
class="flex justify-between items-end cursor-pointer span-block relative-position bg-white"
|
||||
class="flex justify-between items-end cursor-pointer span-block relative-position"
|
||||
:class="[store.state.theme === 'dark' ? 'bg-dark' : 'bg-white']"
|
||||
:style="{
|
||||
height: spanDimensions.height + 'px',
|
||||
width: '100%',
|
||||
@@ -106,6 +110,7 @@ import { defineComponent, computed, ref } from "vue";
|
||||
import useTraces from "@/composables/useTraces";
|
||||
import { getImageURL, formatTimeWithSuffix } from "@/utils/zincutils";
|
||||
import SpanDetails from "./SpanDetails.vue";
|
||||
import { useStore } from "vuex";
|
||||
|
||||
export default defineComponent({
|
||||
name: "SpanBlock",
|
||||
@@ -146,6 +151,7 @@ export default defineComponent({
|
||||
emits: ["toggleCollapse"],
|
||||
components: { SpanDetails },
|
||||
setup(props, { emit }) {
|
||||
const store = useStore();
|
||||
const { searchObj } = useTraces();
|
||||
const spanBlock: any = ref(null);
|
||||
const spanBlockWidth = ref(0);
|
||||
@@ -256,6 +262,7 @@ export default defineComponent({
|
||||
toggleSpanDetails,
|
||||
defocusSpan,
|
||||
isSpanSelected,
|
||||
store,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -267,7 +274,6 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
.collapse-btn {
|
||||
background-color: #ffffff;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<template v-for="(val, key) in tags" :key="key">
|
||||
<span class="text-grey-8">{{ key }}</span>
|
||||
<span class="text-grey-8">: </span>
|
||||
<span class="text-grey-10">{{ val }}</span>
|
||||
<span class="">{{ val }}</span>
|
||||
<span class="q-mx-xs bg-grey-5" style="padding-left: 1px"></span>
|
||||
</template>
|
||||
</div>
|
||||
@@ -66,8 +66,17 @@
|
||||
<tbody>
|
||||
<template v-for="(val, key) in tags" :key="key">
|
||||
<tr>
|
||||
<td class="q-py-xs q-px-sm text-grey-9">{{ key }}</td>
|
||||
<td class="q-py-xs q-px-sm text-primary">
|
||||
<td
|
||||
class="q-py-xs q-px-sm"
|
||||
:class="
|
||||
store.state.theme === 'dark'
|
||||
? 'text-red-5'
|
||||
: 'text-red-10'
|
||||
"
|
||||
>
|
||||
{{ key }}
|
||||
</td>
|
||||
<td class="q-py-xs q-px-sm">
|
||||
{{ val }}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -100,7 +109,7 @@
|
||||
<template v-for="(val, key) in processes" :key="key">
|
||||
<span class="text-grey-8">{{ key }}</span>
|
||||
<span class="text-grey-8">: </span>
|
||||
<span class="text-grey-10">{{ val }}</span>
|
||||
<span class="">{{ val }}</span>
|
||||
<span class="q-mx-xs bg-grey-5" style="padding-left: 1px"></span>
|
||||
</template>
|
||||
</div>
|
||||
@@ -110,8 +119,17 @@
|
||||
<tbody>
|
||||
<template v-for="(val, key) in processes" :key="key">
|
||||
<tr>
|
||||
<td class="q-py-xs q-px-sm text-grey-9">{{ key }}</td>
|
||||
<td class="q-py-xs q-px-sm text-primary">
|
||||
<td
|
||||
class="q-py-xs q-px-sm"
|
||||
:class="
|
||||
store.state.theme === 'dark'
|
||||
? 'text-red-5'
|
||||
: 'text-red-10'
|
||||
"
|
||||
>
|
||||
{{ key }}
|
||||
</td>
|
||||
<td class="q-py-xs q-px-sm">
|
||||
{{ val }}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -218,7 +236,7 @@
|
||||
</div>
|
||||
<div class="text-right flex items-center justify-end">
|
||||
<span class="text-grey-7 q-mr-xs">Span Id: </span
|
||||
><span class="text-grey-10">{{ span.spanId }}</span>
|
||||
><span class="">{{ span.spanId }}</span>
|
||||
<q-icon
|
||||
class="q-ml-xs text-grey-8 cursor-pointer trace-copy-icon"
|
||||
size="12px"
|
||||
|
||||
@@ -46,7 +46,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
<div class="q-pb-xs">Spans: {{ spanList.length }}</div>
|
||||
</div>
|
||||
<q-btn v-close-popup="true" round flat icon="cancel" size="md" />
|
||||
<div class="flex items-center">
|
||||
<q-btn
|
||||
data-test="logs-search-bar-share-link-btn"
|
||||
class="q-mr-sm download-logs-btn q-px-sm"
|
||||
size="sm"
|
||||
icon="share"
|
||||
round
|
||||
flat
|
||||
no-outline
|
||||
:title="t('search.shareLink')"
|
||||
@click="shareLink"
|
||||
/>
|
||||
<q-btn v-close-popup="true" round flat icon="cancel" size="md" />
|
||||
</div>
|
||||
</div>
|
||||
<q-separator style="width: 100%" />
|
||||
<div class="col-12 flex justify-between items-end q-pr-sm q-pt-sm">
|
||||
@@ -195,6 +208,7 @@ import {
|
||||
import ChartRenderer from "@/components/dashboards/panels/ChartRenderer.vue";
|
||||
import { throttle } from "lodash";
|
||||
import { copyToClipboard, useQuasar } from "quasar";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
export default defineComponent({
|
||||
name: "TraceDetails",
|
||||
@@ -214,8 +228,8 @@ export default defineComponent({
|
||||
ServiceMapIcon,
|
||||
ChartRenderer,
|
||||
},
|
||||
|
||||
setup() {
|
||||
emits: ["shareLink"],
|
||||
setup(props, { emit }) {
|
||||
const traceTree: any = ref([]);
|
||||
const spanMap: any = ref({});
|
||||
const { searchObj } = useTraces();
|
||||
@@ -242,6 +256,8 @@ export default defineComponent({
|
||||
colors: ["#b7885e", "#1ab8be", "#ffcb99", "#f89570", "#839ae2"],
|
||||
};
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const $q = useQuasar();
|
||||
|
||||
const traceVisuals = [
|
||||
@@ -696,7 +712,12 @@ export default defineComponent({
|
||||
copyToClipboard(spanList.value[0]["trace_id"]);
|
||||
};
|
||||
|
||||
const shareLink = () => {
|
||||
emit("shareLink");
|
||||
};
|
||||
|
||||
return {
|
||||
t,
|
||||
traceTree,
|
||||
collapseMapping,
|
||||
traceRootSpan,
|
||||
@@ -726,6 +747,7 @@ export default defineComponent({
|
||||
toggleTimeline,
|
||||
copyToClipboard,
|
||||
copyTraceId,
|
||||
shareLink,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -36,14 +36,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
class="q-px-sm q-pb-none ellipsis non-selectable"
|
||||
style="font-size: 14px"
|
||||
>
|
||||
<span class="text-grey-9">Operation Name: </span>{{ span.operation_name }}
|
||||
<span class="text-grey-7">Operation Name: </span>{{ span.operation_name }}
|
||||
</div>
|
||||
<div
|
||||
class="q-px-sm ellipsis non-selectable"
|
||||
:title="span.service_name"
|
||||
style="font-size: 14px"
|
||||
>
|
||||
<span class="text-grey-9">Service Name: </span> {{ span.service_name }}
|
||||
<span class="text-grey-7">Service Name: </span> {{ span.service_name }}
|
||||
</div>
|
||||
</div>
|
||||
<q-tabs
|
||||
@@ -80,8 +80,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<tbody>
|
||||
<template v-for="(val, key) in tags" :key="key">
|
||||
<tr>
|
||||
<td class="q-py-xs q-px-sm text-grey-9">{{ key }}</td>
|
||||
<td class="q-py-xs q-px-sm text-primary">
|
||||
<td
|
||||
class="q-py-xs q-px-sm"
|
||||
:class="
|
||||
store.state.theme === 'dark' ? 'text-red-5' : 'text-red-10'
|
||||
"
|
||||
>
|
||||
{{ key }}
|
||||
</td>
|
||||
<td class="q-py-xs q-px-sm">
|
||||
{{ val }}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -94,8 +101,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<tbody>
|
||||
<template v-for="(val, key) in processes" :key="key">
|
||||
<tr>
|
||||
<td class="q-py-xs q-px-sm text-grey-9">{{ key }}</td>
|
||||
<td class="q-py-xs q-px-sm text-primary">
|
||||
<td
|
||||
class="q-py-xs q-px-sm"
|
||||
:class="
|
||||
store.state.theme === 'dark' ? 'text-red-5' : 'text-red-10'
|
||||
"
|
||||
>
|
||||
{{ key }}
|
||||
</td>
|
||||
<td class="q-py-xs q-px-sm">
|
||||
{{ val }}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -104,18 +118,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
</table>
|
||||
</q-tab-panel>
|
||||
<q-tab-panel name="attributes">
|
||||
<table class="q-my-sm">
|
||||
<tbody>
|
||||
<template v-for="(val, key) in spanDetails.attrs" :key="key">
|
||||
<tr>
|
||||
<td class="q-py-xs q-px-sm text-grey-9">{{ key }}</td>
|
||||
<td class="q-py-xs q-px-sm text-primary">
|
||||
{{ val }}
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
<pre class="attr-text">{{
|
||||
JSON.stringify(spanDetails.attrs, null, 2)
|
||||
}}</pre>
|
||||
</q-tab-panel>
|
||||
<q-tab-panel name="events">
|
||||
<q-virtual-scroll
|
||||
|
||||
@@ -25,6 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
}"
|
||||
style="top: 0; z-index: 999; position: sticky"
|
||||
class="flex justify-start items-center header-bg bg-grey-2"
|
||||
:class="store.state.theme === 'dark' ? 'bg-grey-9' : 'bg-grey-2'"
|
||||
>
|
||||
<div
|
||||
class="flex justify-start items-center no-wrap row q-px-sm"
|
||||
|
||||
@@ -41,7 +41,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
:title="span.operationName"
|
||||
>
|
||||
<div
|
||||
class="flex no-wrap q-pt-sm bg-white full-width"
|
||||
class="flex no-wrap q-pt-sm full-width"
|
||||
:class="store.state.theme === 'dark' ? 'bg-dark' : 'bg-white'"
|
||||
:style="{ height: '30px' }"
|
||||
>
|
||||
<div
|
||||
|
||||
@@ -74,6 +74,7 @@ const stream = {
|
||||
return http().get(url);
|
||||
},
|
||||
|
||||
// Thia API is just used for service_name and operation_name fields
|
||||
tracesFieldValues: ({
|
||||
org_identifier,
|
||||
stream_name,
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
<template>
|
||||
<div>
|
||||
<SearchBar ref="searchBarRef" :query-data="queryData" @searchdata="getQueryData" @update-query="updateQuery"
|
||||
@change:date-time="updateDateTime"></SearchBar>
|
||||
<SearchBar
|
||||
ref="searchBarRef"
|
||||
:query-data="queryData"
|
||||
@searchdata="getQueryData"
|
||||
@update-query="updateQuery"
|
||||
:is-loading="!!isLoading.length"
|
||||
@change:date-time="updateDateTime"
|
||||
></SearchBar>
|
||||
<div class="stream-data-table">
|
||||
<template v-if="isLoading.length">
|
||||
<div class="full-height flex justify-center items-center">
|
||||
<div class="q-pb-lg">
|
||||
<q-spinner-hourglass color="primary" size="40px" style="margin: 0 auto; display: block" />
|
||||
<q-spinner-hourglass
|
||||
color="primary"
|
||||
size="40px"
|
||||
style="margin: 0 auto; display: block"
|
||||
/>
|
||||
<span class="text-center">
|
||||
Hold on tight, we're fetching your stream data.
|
||||
</span>
|
||||
@@ -14,7 +24,11 @@
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<StreamDataTable :rows="tableData.rows" :columns="tableData.columns" :is-loading="!!isLoading.length" />
|
||||
<StreamDataTable
|
||||
:rows="tableData.rows"
|
||||
:columns="tableData.columns"
|
||||
:is-loading="!!isLoading.length"
|
||||
/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -226,8 +240,8 @@ export default defineComponent({
|
||||
} | null =
|
||||
queryData.value.dateTime.type === "relative"
|
||||
? getConsumableRelativeTime(
|
||||
queryData.value.dateTime.relativeTimePeriod
|
||||
) || null
|
||||
queryData.value.dateTime.relativeTimePeriod
|
||||
) || null
|
||||
: cloneDeep(queryData.value.dateTime);
|
||||
|
||||
if (streamData?.value?.stream_type === "enrichment_tables") {
|
||||
|
||||
Reference in New Issue
Block a user