mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-05 08:09:22 +00:00
fix: UI fixes in alert list and DateTime selection (#4449)
fix #4427 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced a new event handler for managing component state when hiding. - Enhanced styling for the alert list component with a new CSS class. - Added a new reactive variable for handling function error messages in the TenstackTable component. - **Improvements** - Streamlined logic for setting absolute and relative time in the DateTime component. - Improved error handling and notifications for alert duplication in the AlertList component. - Adjusted layout and spacing for better user interface consistency. - Enhanced functionality to dynamically update start and end times based on relative datetime selection. - Improved robustness of the QueryEditor and SearchBar components with optional chaining. - Simplified loading strategy for the SearchBar and QueryEditor components to enhance performance. - **Bug Fixes** - Refined handling of selected date and time to prevent unnecessary overwriting of values. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Bhargav <BJP232004@GMAIL.COM>
This commit is contained in:
co-authored by
Bhargav
parent
7680952cdd
commit
304a0f7895
@@ -36,6 +36,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
self="top left"
|
||||
no-route-dismiss
|
||||
@before-show="onBeforeShow"
|
||||
@before-hide="onBeforeHide"
|
||||
>
|
||||
<div class="flex justify-evenly q-py-sm">
|
||||
<q-btn
|
||||
@@ -320,6 +321,7 @@ import {
|
||||
watch,
|
||||
nextTick,
|
||||
onActivated,
|
||||
onBeforeUnmount,
|
||||
} from "vue";
|
||||
import {
|
||||
getImageURL,
|
||||
@@ -500,13 +502,9 @@ export default defineComponent({
|
||||
|
||||
selectedType.value = props.defaultType;
|
||||
|
||||
// if type is absolute
|
||||
if (selectedType.value == "absolute") {
|
||||
setAbsoluteTime(startTime, endTime);
|
||||
} else {
|
||||
// else type is relative
|
||||
setRelativeTime(props.defaultRelativeTime);
|
||||
}
|
||||
setAbsoluteTime(startTime, endTime);
|
||||
|
||||
setRelativeTime(props.defaultRelativeTime);
|
||||
|
||||
if (props.queryRangeRestrictionInHour) computeRelativePeriod();
|
||||
// displayValue.value = getDisplayValue();
|
||||
@@ -536,60 +534,6 @@ export default defineComponent({
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
watch(
|
||||
() => {
|
||||
router.currentRoute.value.query?.from;
|
||||
},
|
||||
() => {
|
||||
if (
|
||||
router.currentRoute.value.query.hasOwnProperty("from") &&
|
||||
router.currentRoute.value.query.hasOwnProperty("to")
|
||||
) {
|
||||
selectedType.value = "absolute";
|
||||
selectedTime.value.startTime = timestampToTimezoneDate(
|
||||
router.currentRoute.value.query?.from / 1000,
|
||||
store.state.timezone,
|
||||
"HH:mm",
|
||||
);
|
||||
selectedTime.value.endTime = timestampToTimezoneDate(
|
||||
router.currentRoute.value.query?.to / 1000,
|
||||
store.state.timezone,
|
||||
"HH:mm",
|
||||
);
|
||||
selectedDate.value.from = timestampToTimezoneDate(
|
||||
router.currentRoute.value.query?.from / 1000,
|
||||
store.state.timezone,
|
||||
"yyyy/MM/dd",
|
||||
);
|
||||
selectedDate.value.to = timestampToTimezoneDate(
|
||||
router.currentRoute.value.query?.to / 1000,
|
||||
store.state.timezone,
|
||||
"yyyy/MM/dd",
|
||||
);
|
||||
saveDate("absolute");
|
||||
}
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
// watch(
|
||||
// () => props.defaultAbsoluteTime,
|
||||
// (value) => {
|
||||
// console.log("defaultAbsoluteTime", value);
|
||||
// if (
|
||||
// (value.startTime !== datePayload.value.startTime ||
|
||||
// value.endTime !== datePayload.value.endTime) &&
|
||||
// store.state.savedViewFlag == false
|
||||
// ) {
|
||||
// selectedType.value = props.defaultType;
|
||||
// setAbsoluteTime(value.startTime, value.endTime);
|
||||
// }
|
||||
// },
|
||||
// {
|
||||
// deep: true,
|
||||
// }
|
||||
// );
|
||||
|
||||
const setRelativeDate = (period, value) => {
|
||||
selectedType.value = "relative";
|
||||
relativePeriod.value = period;
|
||||
@@ -629,19 +573,28 @@ export default defineComponent({
|
||||
if (periodValue) {
|
||||
relativeValue.value = parseInt(periodValue);
|
||||
}
|
||||
|
||||
selectedType.value = "relative";
|
||||
}
|
||||
};
|
||||
|
||||
const resetTime = (startTime, endTime) => {
|
||||
if (!startTime || !endTime) {
|
||||
var dateString = new Date().toLocaleDateString("en-ZA");
|
||||
selectedDate.value.from = dateString;
|
||||
selectedDate.value.to = dateString;
|
||||
|
||||
if (!selectedDate.value.from) selectedDate.value.from = dateString;
|
||||
|
||||
if (!selectedDate.value.to) selectedDate.value.to = dateString;
|
||||
|
||||
if (!startTime) selectedTime.value.startTime = "00:00";
|
||||
|
||||
if (!endTime) selectedTime.value.endTime = "23:59";
|
||||
if (!endTime) {
|
||||
const endDateTime = convertUnixTime(new Date().getTime() * 1000);
|
||||
|
||||
// If the selected date is today, set the end time to the current time
|
||||
if (selectedDate.value.to === endDateTime.date) {
|
||||
selectedTime.value.endTime = endDateTime.time;
|
||||
} else selectedTime.value.endTime = "23:59";
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
@@ -731,6 +684,11 @@ export default defineComponent({
|
||||
// if (props.modelValue) selectedDate.value = cloneDeep(props.modelValue);
|
||||
};
|
||||
|
||||
const onBeforeHide = () => {
|
||||
if (selectedType.value === "absolute")
|
||||
resetTime(selectedTime.value.startTime, selectedTime.value.endTime);
|
||||
};
|
||||
|
||||
const getPeriodLabel = computed(() => {
|
||||
const periodMapping = {
|
||||
m: "Minutes",
|
||||
@@ -828,6 +786,7 @@ export default defineComponent({
|
||||
|
||||
if (dateobj.type === "relative") {
|
||||
setRelativeTime(dateobj.relativeTimePeriod);
|
||||
selectedType.value = "relative";
|
||||
} else {
|
||||
if (
|
||||
dateobj.hasOwnProperty("selectedDate") &&
|
||||
@@ -1030,6 +989,7 @@ export default defineComponent({
|
||||
relativePeriodsMaxValue,
|
||||
relativePeriodsSelect,
|
||||
computeRelativePeriod,
|
||||
onBeforeHide,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -209,12 +209,12 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
window.addEventListener("click", () => {
|
||||
editorObj.layout();
|
||||
editorObj?.layout();
|
||||
});
|
||||
|
||||
window.addEventListener("resize", async () => {
|
||||
await nextTick();
|
||||
editorObj.layout();
|
||||
editorObj?.layout();
|
||||
// queryEditorRef.value.resetEditorLayout();
|
||||
});
|
||||
};
|
||||
@@ -307,7 +307,7 @@ export default defineComponent({
|
||||
const setValue = (value: string) => {
|
||||
if (editorObj?.setValue) {
|
||||
editorObj.setValue(value);
|
||||
editorObj.layout();
|
||||
editorObj?.layout();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -361,7 +361,7 @@ export default defineComponent({
|
||||
};
|
||||
|
||||
const resetEditorLayout = () => {
|
||||
editorObj.layout();
|
||||
editorObj?.layout();
|
||||
};
|
||||
|
||||
const triggerAutoComplete = async (value: string) => {
|
||||
|
||||
@@ -21,8 +21,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
data-test="alert-list-page"
|
||||
class="q-pa-none flex"
|
||||
style="height: calc(100vh - 57px)"
|
||||
:class="store.state.theme === 'dark' ? 'dark-theme' : 'light-theme'"
|
||||
>
|
||||
<div v-if="!showAddAlertDialog" class="full-width">
|
||||
<div v-if="!showAddAlertDialog" class="full-width alert-list-table">
|
||||
<q-table
|
||||
data-test="alert-list-table"
|
||||
ref="qTable"
|
||||
@@ -130,17 +131,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
@click="showAddUpdateFn(props)"
|
||||
></q-btn>
|
||||
<q-btn
|
||||
icon="content_copy"
|
||||
:title="t('alerts.clone')"
|
||||
class="q-ml-xs"
|
||||
padding="sm"
|
||||
unelevated
|
||||
size="sm"
|
||||
round
|
||||
flat
|
||||
@click.stop="duplicateAlert(props.row)"
|
||||
data-test="alert-clone"
|
||||
></q-btn>
|
||||
icon="content_copy"
|
||||
:title="t('alerts.clone')"
|
||||
class="q-ml-xs"
|
||||
padding="sm"
|
||||
unelevated
|
||||
size="sm"
|
||||
round
|
||||
flat
|
||||
@click.stop="duplicateAlert(props.row)"
|
||||
data-test="alert-clone"
|
||||
></q-btn>
|
||||
<q-btn
|
||||
:data-test="`alert-list-${props.row.name}-delete-alert`"
|
||||
:icon="outlinedDelete"
|
||||
@@ -164,6 +165,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<pre style="white-space: break-spaces">{{ props.row.sql }}</pre>
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
<template #top="scope">
|
||||
<div class="q-table__title" data-test="alerts-list-title">
|
||||
{{ t("alerts.header") }}
|
||||
@@ -231,76 +233,73 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
v-model="confirmDelete"
|
||||
/>
|
||||
<template>
|
||||
<q-dialog class="q-pa-md " v-model="showForm" persistent>
|
||||
<q-card class="clone-alert-popup">
|
||||
<div class="row items-center no-wrap q-mx-md q-my-sm">
|
||||
<div class="flex items-center">
|
||||
<div
|
||||
data-test="add-alert-back-btn"
|
||||
class="flex justify-center items-center q-mr-md cursor-pointer"
|
||||
style="
|
||||
border: 1.5px solid;
|
||||
border-radius: 50%;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
"
|
||||
title="Go Back"
|
||||
@click="showForm = false"
|
||||
>
|
||||
<q-icon name="arrow_back_ios_new" size="14px" />
|
||||
</div>
|
||||
<div class="text-h6" data-test="clone-alert-title">
|
||||
{{ t("alerts.cloneTitle") }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<q-card-section>
|
||||
<q-form @submit="submitForm">
|
||||
<q-input v-model="toBeCloneAlertName" label="Alert Name" />
|
||||
<q-select
|
||||
v-model="toBeClonestreamType"
|
||||
label="Stream Type"
|
||||
:options="streamTypes"
|
||||
@update:model-value="updateStreams()"
|
||||
/>
|
||||
<q-select
|
||||
v-model="toBeClonestreamName"
|
||||
:loading="isFetchingStreams"
|
||||
:disable="!toBeClonestreamType"
|
||||
label="Stream Name"
|
||||
:options="streamNames"
|
||||
@change="updateStreamName"
|
||||
@filter="filterStreams"
|
||||
/>
|
||||
<div class="flex justify-center q-mt-lg">
|
||||
<q-btn
|
||||
data-test="add-alert-cancel-btn"
|
||||
v-close-popup="true"
|
||||
class="q-mb-md text-bold"
|
||||
:label="t('alerts.cancel')"
|
||||
text-color="light-text"
|
||||
padding="sm md"
|
||||
no-caps
|
||||
/>
|
||||
<q-btn
|
||||
data-test="add-alert-submit-btn"
|
||||
:label="t('alerts.save')"
|
||||
class="q-mb-md text-bold no-border q-ml-md"
|
||||
color="secondary"
|
||||
padding="sm xl"
|
||||
type="submit"
|
||||
:disable="isSubmitting"
|
||||
no-caps
|
||||
/>
|
||||
<q-dialog class="q-pa-md" v-model="showForm" persistent>
|
||||
<q-card class="clone-alert-popup">
|
||||
<div class="row items-center no-wrap q-mx-md q-my-sm">
|
||||
<div class="flex items-center">
|
||||
<div
|
||||
data-test="add-alert-back-btn"
|
||||
class="flex justify-center items-center q-mr-md cursor-pointer"
|
||||
style="
|
||||
border: 1.5px solid;
|
||||
border-radius: 50%;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
"
|
||||
title="Go Back"
|
||||
@click="showForm = false"
|
||||
>
|
||||
<q-icon name="arrow_back_ios_new" size="14px" />
|
||||
</div>
|
||||
<div class="text-h6" data-test="clone-alert-title">
|
||||
{{ t("alerts.cloneTitle") }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</q-form>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
</div>
|
||||
<q-card-section>
|
||||
<q-form @submit="submitForm">
|
||||
<q-input v-model="toBeCloneAlertName" label="Alert Name" />
|
||||
<q-select
|
||||
v-model="toBeClonestreamType"
|
||||
label="Stream Type"
|
||||
:options="streamTypes"
|
||||
@update:model-value="updateStreams()"
|
||||
/>
|
||||
<q-select
|
||||
v-model="toBeClonestreamName"
|
||||
:loading="isFetchingStreams"
|
||||
:disable="!toBeClonestreamType"
|
||||
label="Stream Name"
|
||||
:options="streamNames"
|
||||
@change="updateStreamName"
|
||||
@filter="filterStreams"
|
||||
/>
|
||||
<div class="flex justify-center q-mt-lg">
|
||||
<q-btn
|
||||
data-test="add-alert-cancel-btn"
|
||||
v-close-popup="true"
|
||||
class="q-mb-md text-bold"
|
||||
:label="t('alerts.cancel')"
|
||||
text-color="light-text"
|
||||
padding="sm md"
|
||||
no-caps
|
||||
/>
|
||||
<q-btn
|
||||
data-test="add-alert-submit-btn"
|
||||
:label="t('alerts.save')"
|
||||
class="q-mb-md text-bold no-border q-ml-md"
|
||||
color="secondary"
|
||||
padding="sm xl"
|
||||
type="submit"
|
||||
:disable="isSubmitting"
|
||||
no-caps
|
||||
/>
|
||||
</div>
|
||||
</q-form>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -346,7 +345,7 @@ export default defineComponent({
|
||||
components: {
|
||||
QTablePagination,
|
||||
AddAlert: defineAsyncComponent(
|
||||
() => import("@/components/alerts/AddAlert.vue")
|
||||
() => import("@/components/alerts/AddAlert.vue"),
|
||||
),
|
||||
NoData,
|
||||
ConfirmDialog,
|
||||
@@ -371,21 +370,21 @@ export default defineComponent({
|
||||
const isUpdated: any = ref(false);
|
||||
const confirmDelete = ref<boolean>(false);
|
||||
const splitterModel = ref(220);
|
||||
const showForm = ref(false);
|
||||
const showForm = ref(false);
|
||||
const indexOptions = ref([]);
|
||||
const schemaList = ref([]);
|
||||
const streams: any = ref({});
|
||||
const isFetchingStreams = ref(false);
|
||||
const isSubmitting = ref(false);
|
||||
const isSubmitting = ref(false);
|
||||
|
||||
const { getStreams } = useStreams();
|
||||
|
||||
const toBeCloneAlertName = ref ("");
|
||||
const toBeCloneUUID = ref("");
|
||||
const toBeClonestreamType = ref('');
|
||||
const toBeClonestreamName = ref('');
|
||||
const streamTypes = ref(['logs', 'metrics', 'traces']);
|
||||
const streamNames : Ref<string[]> = ref([]);
|
||||
const toBeCloneAlertName = ref("");
|
||||
const toBeCloneUUID = ref("");
|
||||
const toBeClonestreamType = ref("");
|
||||
const toBeClonestreamName = ref("");
|
||||
const streamTypes = ref(["logs", "metrics", "traces"]);
|
||||
const streamNames: Ref<string[]> = ref([]);
|
||||
const alertStateLoadingMap: Ref<{ [key: string]: boolean }> = ref({});
|
||||
const folders = ref([
|
||||
{
|
||||
@@ -409,27 +408,6 @@ export default defineComponent({
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "alert_type",
|
||||
field: "alert_type",
|
||||
label: t("alerts.alertType"),
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "stream_type",
|
||||
field: "stream_type",
|
||||
label: t("alerts.streamType"),
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "stream_name",
|
||||
field: "stream_name",
|
||||
label: t("alerts.stream_name"),
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "owner",
|
||||
field: "owner",
|
||||
@@ -488,7 +466,7 @@ export default defineComponent({
|
||||
"name",
|
||||
false,
|
||||
"",
|
||||
store.state.selectedOrganization.identifier
|
||||
store.state.selectedOrganization.identifier,
|
||||
)
|
||||
.then((res) => {
|
||||
var counter = 1;
|
||||
@@ -526,8 +504,12 @@ export default defineComponent({
|
||||
description: data.description,
|
||||
uuid: data.uuid,
|
||||
owner: data.owner,
|
||||
last_triggered_at:convertUnixToQuasarFormat(data.last_triggered_at),
|
||||
last_satisfied_at:convertUnixToQuasarFormat(data.last_satisfied_at),
|
||||
last_triggered_at: convertUnixToQuasarFormat(
|
||||
data.last_triggered_at,
|
||||
),
|
||||
last_satisfied_at: convertUnixToQuasarFormat(
|
||||
data.last_satisfied_at,
|
||||
),
|
||||
};
|
||||
});
|
||||
alertsRows.value.forEach((alert: AlertListItem) => {
|
||||
@@ -569,7 +551,7 @@ export default defineComponent({
|
||||
() => router.currentRoute.value.query.action,
|
||||
(action) => {
|
||||
if (!action) showAddAlertDialog.value = false;
|
||||
}
|
||||
},
|
||||
);
|
||||
const getDestinations = () => {
|
||||
destinationService
|
||||
@@ -584,7 +566,7 @@ export default defineComponent({
|
||||
type: "negative",
|
||||
message: "Error while fetching destinations.",
|
||||
timeout: 3000,
|
||||
})
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -601,7 +583,7 @@ export default defineComponent({
|
||||
type: "negative",
|
||||
message: "Error while fetching templates.",
|
||||
timeout: 3000,
|
||||
})
|
||||
}),
|
||||
);
|
||||
};
|
||||
const perPageOptions: any = [
|
||||
@@ -626,35 +608,37 @@ export default defineComponent({
|
||||
const changeMaxRecordToReturn = (val: any) => {
|
||||
maxRecordToReturn.value = val;
|
||||
};
|
||||
|
||||
function convertUnixToQuasarFormat(unixMicroseconds : any) {
|
||||
if(!unixMicroseconds) return "";
|
||||
const unixSeconds = unixMicroseconds / 1e6;
|
||||
const dateToFormat = new Date(unixSeconds * 1000);
|
||||
const formattedDate = dateToFormat.toISOString();
|
||||
return date.formatDate(formattedDate, "YYYY-MM-DDTHH:mm:ssZ");
|
||||
}
|
||||
|
||||
function convertUnixToQuasarFormat(unixMicroseconds: any) {
|
||||
if (!unixMicroseconds) return "";
|
||||
const unixSeconds = unixMicroseconds / 1e6;
|
||||
const dateToFormat = new Date(unixSeconds * 1000);
|
||||
const formattedDate = dateToFormat.toISOString();
|
||||
return date.formatDate(formattedDate, "YYYY-MM-DDTHH:mm:ssZ");
|
||||
}
|
||||
|
||||
const addAlert = () => {
|
||||
showAddAlertDialog.value = true;
|
||||
};
|
||||
|
||||
const duplicateAlert = (row : any) =>{
|
||||
toBeCloneUUID.value = row.uuid
|
||||
const duplicateAlert = (row: any) => {
|
||||
toBeCloneUUID.value = row.uuid;
|
||||
toBeCloneAlertName.value = row.name;
|
||||
toBeClonestreamName.value = "";
|
||||
toBeClonestreamType.value = "";
|
||||
|
||||
|
||||
showForm.value = true;
|
||||
}
|
||||
const submitForm = async () =>{
|
||||
const alertToBeCloned = alerts.value.find((alert) => alert.uuid === toBeCloneUUID.value) as Alert;
|
||||
};
|
||||
const submitForm = async () => {
|
||||
const alertToBeCloned = alerts.value.find(
|
||||
(alert) => alert.uuid === toBeCloneUUID.value,
|
||||
) as Alert;
|
||||
|
||||
const dismiss = $q.notify({
|
||||
spinner: true,
|
||||
message: "Please wait...",
|
||||
timeout: 2000,
|
||||
});
|
||||
spinner: true,
|
||||
message: "Please wait...",
|
||||
timeout: 2000,
|
||||
});
|
||||
|
||||
if (!alertToBeCloned) {
|
||||
$q.notify({
|
||||
@@ -664,7 +648,7 @@ export default defineComponent({
|
||||
});
|
||||
return;
|
||||
}
|
||||
if(!toBeClonestreamType.value){
|
||||
if (!toBeClonestreamType.value) {
|
||||
$q.notify({
|
||||
type: "negative",
|
||||
message: "Please select stream type ",
|
||||
@@ -672,7 +656,7 @@ export default defineComponent({
|
||||
});
|
||||
return;
|
||||
}
|
||||
if(!toBeClonestreamName.value){
|
||||
if (!toBeClonestreamName.value) {
|
||||
$q.notify({
|
||||
type: "negative",
|
||||
message: "Please select stream name",
|
||||
@@ -682,22 +666,24 @@ export default defineComponent({
|
||||
}
|
||||
isSubmitting.value = true;
|
||||
|
||||
alertToBeCloned.name = toBeCloneAlertName.value;
|
||||
alertToBeCloned.stream_name = toBeClonestreamName.value;
|
||||
alertToBeCloned.stream_type = toBeClonestreamType.value;
|
||||
|
||||
try{
|
||||
alertsService.create(
|
||||
alertToBeCloned.name = toBeCloneAlertName.value;
|
||||
alertToBeCloned.stream_name = toBeClonestreamName.value;
|
||||
alertToBeCloned.stream_type = toBeClonestreamType.value;
|
||||
|
||||
try {
|
||||
alertsService
|
||||
.create(
|
||||
store.state.selectedOrganization.identifier,
|
||||
alertToBeCloned.stream_name,
|
||||
alertToBeCloned.stream_type,
|
||||
alertToBeCloned,
|
||||
).then((res) => {
|
||||
)
|
||||
.then((res) => {
|
||||
dismiss();
|
||||
if (res.data.code == 200) {
|
||||
$q.notify({
|
||||
type: "positive",
|
||||
message: "Alert Cloned Successfully",
|
||||
message: "Alert Cloned Successfully",
|
||||
timeout: 2000,
|
||||
});
|
||||
showForm.value = false;
|
||||
@@ -716,27 +702,24 @@ export default defineComponent({
|
||||
type: "negative",
|
||||
message: e.response.data.message,
|
||||
timeout: 2000,
|
||||
});
|
||||
}).finally(() => {
|
||||
isSubmitting.value = false;
|
||||
});
|
||||
})
|
||||
|
||||
}
|
||||
catch(e : any) {
|
||||
.finally(() => {
|
||||
isSubmitting.value = false;
|
||||
});
|
||||
} catch (e: any) {
|
||||
showForm.value = true;
|
||||
isSubmitting.value = false;
|
||||
$q.notify({
|
||||
type: "negative",
|
||||
message: e.data.message,
|
||||
timeout: 2000,
|
||||
});
|
||||
$q.notify({
|
||||
type: "negative",
|
||||
message: e.data.message,
|
||||
timeout: 2000,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
const showAddUpdateFn = (props: any) => {
|
||||
formData.value = alerts.value.find(
|
||||
(alert: any) => alert.uuid === props.row?.uuid
|
||||
(alert: any) => alert.uuid === props.row?.uuid,
|
||||
) as Alert;
|
||||
let action;
|
||||
if (!props.row) {
|
||||
@@ -790,7 +773,7 @@ export default defineComponent({
|
||||
store.state.selectedOrganization.identifier,
|
||||
selectedDelete.value.stream_name,
|
||||
selectedDelete.value.name,
|
||||
selectedDelete.value.stream_type
|
||||
selectedDelete.value.stream_type,
|
||||
)
|
||||
.then((res: any) => {
|
||||
if (res.data.code == 200) {
|
||||
@@ -845,9 +828,9 @@ export default defineComponent({
|
||||
});
|
||||
return filteredOptions;
|
||||
};
|
||||
const updateStreamName = (selectedOption : any)=> {
|
||||
toBeClonestreamName.value = selectedOption;
|
||||
}
|
||||
const updateStreamName = (selectedOption: any) => {
|
||||
toBeClonestreamName.value = selectedOption;
|
||||
};
|
||||
const updateStreams = (resetStream = true) => {
|
||||
if (resetStream) toBeClonestreamName.value = "";
|
||||
if (streams.value[toBeClonestreamType.value]) {
|
||||
@@ -865,7 +848,7 @@ export default defineComponent({
|
||||
if (!toBeClonestreamType) return Promise.resolve();
|
||||
|
||||
isFetchingStreams.value = true;
|
||||
return getStreams (toBeClonestreamType.value, false)
|
||||
return getStreams(toBeClonestreamType.value, false)
|
||||
.then((res: any) => {
|
||||
streams.value[toBeClonestreamType.value] = res.list;
|
||||
schemaList.value = res.list;
|
||||
@@ -879,14 +862,13 @@ export default defineComponent({
|
||||
.finally(() => (isFetchingStreams.value = false));
|
||||
};
|
||||
const filterStreams = (val: string, update: any) => {
|
||||
streamNames.value = filterColumns(indexOptions.value, val, update)
|
||||
|
||||
streamNames.value = filterColumns(indexOptions.value, val, update);
|
||||
};
|
||||
|
||||
const toggleAlertState = (row: any) => {
|
||||
alertStateLoadingMap.value[row.uuid] = true;
|
||||
const alert: Alert = alerts.value.find(
|
||||
(alert) => alert.uuid === row.uuid
|
||||
(alert) => alert.uuid === row.uuid,
|
||||
) as Alert;
|
||||
alertsService
|
||||
.toggleState(
|
||||
@@ -894,7 +876,7 @@ export default defineComponent({
|
||||
alert.stream_name,
|
||||
alert.name,
|
||||
!alert?.enabled,
|
||||
alert.stream_type
|
||||
alert.stream_type,
|
||||
)
|
||||
.then(() => {
|
||||
alert.enabled = !alert.enabled;
|
||||
@@ -999,7 +981,31 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
.alert-list-table {
|
||||
th:last-child,
|
||||
td:last-child {
|
||||
position: sticky;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
background: #ffffff;
|
||||
box-shadow: -4px 0px 4px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.dark-theme {
|
||||
th:last-child,
|
||||
td:last-child {
|
||||
background: var(--q-dark);
|
||||
box-shadow: -4px 0px 4px 0 rgba(144, 144, 144, 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
.light-theme {
|
||||
th:last-child,
|
||||
td:last-child {
|
||||
background: #ffffff;
|
||||
}
|
||||
}
|
||||
.alerts-tabs {
|
||||
.q-tabs {
|
||||
&--vertical {
|
||||
@@ -1027,7 +1033,7 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
}
|
||||
.clone-alert-popup{
|
||||
.clone-alert-popup {
|
||||
width: 400px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -707,6 +707,11 @@ const useLogs = () => {
|
||||
)
|
||||
: cloneDeep(searchObj.data.datetime);
|
||||
|
||||
if (searchObj.data.datetime.type === "relative") {
|
||||
searchObj.data.datetime.startTime = timestamps.startTime;
|
||||
searchObj.data.datetime.endTime = timestamps.endTime;
|
||||
}
|
||||
|
||||
if (
|
||||
timestamps.startTime != "Invalid Date" &&
|
||||
timestamps.endTime != "Invalid Date"
|
||||
|
||||
@@ -287,13 +287,12 @@ import { getConsumableRelativeTime } from "@/utils/date";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { buildSqlQuery, getFieldsFromQuery } from "@/utils/query/sqlUtils";
|
||||
import useNotifications from "@/composables/useNotifications";
|
||||
import SearchBar from "@/plugins/logs/SearchBar.vue";
|
||||
|
||||
export default defineComponent({
|
||||
name: "PageSearch",
|
||||
components: {
|
||||
SearchBar: defineAsyncComponent(
|
||||
() => import("@/plugins/logs/SearchBar.vue"),
|
||||
),
|
||||
SearchBar,
|
||||
IndexList: defineAsyncComponent(
|
||||
() => import("@/plugins/logs/IndexList.vue"),
|
||||
),
|
||||
|
||||
@@ -920,6 +920,7 @@ import ConfirmDialog from "@/components/ConfirmDialog.vue";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import useDashboardPanelData from "@/composables/useDashboardPanel";
|
||||
import { inject } from "vue";
|
||||
import QueryEditor from "@/components/QueryEditor.vue";
|
||||
|
||||
const defaultValue: any = () => {
|
||||
return {
|
||||
@@ -934,9 +935,7 @@ export default defineComponent({
|
||||
name: "ComponentSearchSearchBar",
|
||||
components: {
|
||||
DateTime,
|
||||
QueryEditor: defineAsyncComponent(
|
||||
() => import("@/components/QueryEditor.vue"),
|
||||
),
|
||||
QueryEditor,
|
||||
SyntaxGuide,
|
||||
AutoRefreshInterval,
|
||||
ConfirmDialog,
|
||||
@@ -1155,10 +1154,10 @@ export default defineComponent({
|
||||
const updateAutoComplete = (value) => {
|
||||
autoCompleteData.value.query = value;
|
||||
autoCompleteData.value.cursorIndex =
|
||||
queryEditorRef.value.getCursorIndex();
|
||||
queryEditorRef?.value?.getCursorIndex();
|
||||
autoCompleteData.value.fieldValues = props.fieldValues;
|
||||
autoCompleteData.value.popup.open =
|
||||
queryEditorRef.value.triggerAutoComplete;
|
||||
queryEditorRef?.value?.triggerAutoComplete;
|
||||
getSuggestions();
|
||||
};
|
||||
|
||||
@@ -2350,7 +2349,7 @@ export default defineComponent({
|
||||
searchObj.data.query = "";
|
||||
}
|
||||
searchObj.data.editorValue = "";
|
||||
queryEditorRef.value.setValue(searchObj.data.query);
|
||||
queryEditorRef.value?.setValue(searchObj.data.query);
|
||||
if (store.state.zoConfig.query_on_stream_selection == false) {
|
||||
handleRunQueryFn();
|
||||
}
|
||||
|
||||
@@ -162,46 +162,54 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr
|
||||
data-test="log-search-result-function-error"
|
||||
v-if="functionErrorMsg != ''"
|
||||
>
|
||||
<td
|
||||
:colspan="columnOrder.length"
|
||||
class="text-bold"
|
||||
style="opacity: 0.6"
|
||||
<tr
|
||||
data-test="log-search-result-function-error"
|
||||
v-if="functionErrorMsg != ''"
|
||||
>
|
||||
<div class="text-subtitle2 text-weight-bold bg-warning">
|
||||
<q-btn
|
||||
:icon="
|
||||
expandedRowIndices.includes(-1)
|
||||
? 'expand_more'
|
||||
: 'chevron_right'
|
||||
<td
|
||||
:colspan="columnOrder.length"
|
||||
class="text-bold"
|
||||
style="opacity: 0.6"
|
||||
>
|
||||
<div
|
||||
class="text-subtitle2 text-weight-bold q-pl-sm"
|
||||
:class="
|
||||
store.state.theme === 'dark'
|
||||
? 'tw-bg-yellow-600'
|
||||
: 'tw-bg-amber-300'
|
||||
"
|
||||
dense
|
||||
size="xs"
|
||||
flat
|
||||
class="q-mr-xs"
|
||||
data-test="table-row-expand-menu"
|
||||
@click.self.stop="expandRow(-1)"
|
||||
></q-btn
|
||||
><b>
|
||||
<q-icon name="warning" size="15px"></q-icon>
|
||||
{{ t("search.functionErrorLabel") }}</b
|
||||
>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="expandedRowIndices.includes(-1)">
|
||||
<td
|
||||
:colspan="columnOrder.length"
|
||||
class="bg-warning"
|
||||
style="opacity: 0.7"
|
||||
>
|
||||
<pre>{{ functionErrorMsg }}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
<q-btn
|
||||
:icon="isFunctionErrorOpen ? 'expand_more' : 'chevron_right'"
|
||||
dense
|
||||
size="xs"
|
||||
flat
|
||||
class="q-mr-xs"
|
||||
data-test="table-row-expand-menu"
|
||||
@click.capture.stop="expandFunctionError"
|
||||
></q-btn
|
||||
><b>
|
||||
<q-icon name="warning" size="15px"></q-icon>
|
||||
{{ t("search.functionErrorLabel") }}</b
|
||||
>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="functionErrorMsg != '' && isFunctionErrorOpen">
|
||||
<td
|
||||
:colspan="columnOrder.length"
|
||||
style="opacity: 0.7"
|
||||
class="q-px-sm"
|
||||
:class="
|
||||
store.state.theme === 'dark'
|
||||
? 'tw-bg-yellow-600'
|
||||
: 'tw-bg-amber-300'
|
||||
"
|
||||
>
|
||||
<pre>{{ functionErrorMsg }}</pre>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody
|
||||
data-test="logs-search-result-table-body"
|
||||
ref="tableBodyRef"
|
||||
@@ -347,6 +355,7 @@ import {
|
||||
useVueTable,
|
||||
getCoreRowModel,
|
||||
getSortedRowModel,
|
||||
isFunction,
|
||||
} from "@tanstack/vue-table";
|
||||
import JsonPreview from "./JsonPreview.vue";
|
||||
import { useStore } from "vuex";
|
||||
@@ -435,6 +444,8 @@ const columnOrder = ref<any>([]);
|
||||
|
||||
const tableRows = ref(props.rows);
|
||||
|
||||
const isFunctionErrorOpen = ref(false);
|
||||
|
||||
watch(
|
||||
() => props.columns,
|
||||
async (newVal) => {
|
||||
@@ -652,6 +663,7 @@ const expandRow = async (index: number) => {
|
||||
isCollapseOperation = true;
|
||||
} else {
|
||||
expandedRowIndices.value.push(index);
|
||||
|
||||
tableRows.value.splice(index + 1, 0, {
|
||||
isExpandedRow: true,
|
||||
...(props.rows[index] as {}),
|
||||
@@ -694,6 +706,10 @@ const handleDataRowClick = (row: any, index: number) => {
|
||||
}
|
||||
};
|
||||
|
||||
const expandFunctionError = () => {
|
||||
isFunctionErrorOpen.value = !isFunctionErrorOpen.value;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
parentRef,
|
||||
});
|
||||
|
||||
+12
-11
@@ -46,7 +46,7 @@ const enterpriseResolverPlugin = {
|
||||
|
||||
const enterprisePath = path.resolve(
|
||||
__dirname,
|
||||
`./src/enterprise/${fileName}`
|
||||
`./src/enterprise/${fileName}`,
|
||||
);
|
||||
const defaultPath = path.resolve(__dirname, `./src/${fileName}`);
|
||||
|
||||
@@ -119,7 +119,7 @@ export default defineConfig({
|
||||
alias: {
|
||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||
"@enterprise": fileURLToPath(
|
||||
new URL("./src/enterprise", import.meta.url)
|
||||
new URL("./src/enterprise", import.meta.url),
|
||||
),
|
||||
stream: "rollup-plugin-node-polyfills/polyfills/stream",
|
||||
events: "rollup-plugin-node-polyfills/polyfills/events",
|
||||
@@ -142,20 +142,21 @@ export default defineConfig({
|
||||
brotliSize: true,
|
||||
}),
|
||||
],
|
||||
manualChunks: {
|
||||
"o2cs-analytics": ["rudder-sdk-js"],
|
||||
"o2cs-oo-rum": [
|
||||
"@openobserve/browser-logs",
|
||||
"@openobserve/browser-rum",
|
||||
],
|
||||
"o2cs-date-fns": ["date-fns", "date-fns-tz"],
|
||||
},
|
||||
output: {
|
||||
manualChunks: {
|
||||
"o2cs-analytics": ["rudder-sdk-js"],
|
||||
"o2cs-oo-rum": [
|
||||
"@openobserve/browser-logs",
|
||||
"@openobserve/browser-rum",
|
||||
],
|
||||
"o2cs-date-fns": ["date-fns", "date-fns-tz"],
|
||||
"editor.api": ["monaco-editor"],
|
||||
},
|
||||
chunkFileNames: ({ name }) => {
|
||||
if (name.startsWith("o2cs-")) {
|
||||
return `assets/vendor/${name}.[hash].js`;
|
||||
}
|
||||
|
||||
|
||||
if (name.includes("editor.api")) {
|
||||
return `assets/${name}.v1.js`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user