diff --git a/frontend/src/components/DropDown/DropDown.tsx b/frontend/src/components/DropDown/DropDown.tsx index df845b7084..e847e895be 100644 --- a/frontend/src/components/DropDown/DropDown.tsx +++ b/frontend/src/components/DropDown/DropDown.tsx @@ -5,7 +5,13 @@ import { Button, Dropdown, MenuProps } from 'antd'; import { useIsDarkMode } from 'hooks/useDarkMode'; import { useState } from 'react'; -function DropDown({ element }: { element: JSX.Element[] }): JSX.Element { +function DropDown({ + element, + onDropDownItemClick, +}: { + element: JSX.Element[]; + onDropDownItemClick?: MenuProps['onClick']; +}): JSX.Element { const isDarkMode = useIsDarkMode(); const items: MenuProps['items'] = element.map( @@ -23,6 +29,7 @@ function DropDown({ element }: { element: JSX.Element[] }): JSX.Element { items, onMouseEnter: (): void => setDdOpen(true), onMouseLeave: (): void => setDdOpen(false), + onClick: (item): void => onDropDownItemClick?.(item), }} open={isDdOpen} > @@ -40,4 +47,8 @@ function DropDown({ element }: { element: JSX.Element[] }): JSX.Element { ); } +DropDown.defaultProps = { + onDropDownItemClick: (): void => {}, +}; + export default DropDown; diff --git a/frontend/src/components/ResizeTable/DynamicColumnTable.tsx b/frontend/src/components/ResizeTable/DynamicColumnTable.tsx index fb5d734ee8..5a3dfd39dd 100644 --- a/frontend/src/components/ResizeTable/DynamicColumnTable.tsx +++ b/frontend/src/components/ResizeTable/DynamicColumnTable.tsx @@ -2,7 +2,9 @@ import './DynamicColumnTable.syles.scss'; import { Button, Dropdown, Flex, MenuProps, Switch } from 'antd'; +import { ColumnGroupType, ColumnType } from 'antd/es/table'; import { ColumnsType } from 'antd/lib/table'; +import logEvent from 'api/common/logEvent'; import FacingIssueBtn from 'components/facingIssueBtn/FacingIssueBtn'; import { SlidersHorizontal } from 'lucide-react'; import { memo, useEffect, useState } from 'react'; @@ -22,6 +24,7 @@ function DynamicColumnTable({ dynamicColumns, onDragColumn, facingIssueBtn, + shouldSendAlertsLogEvent, ...restProps }: DynamicColumnTableProps): JSX.Element { const [columnsData, setColumnsData] = useState( @@ -47,11 +50,18 @@ function DynamicColumnTable({ // eslint-disable-next-line react-hooks/exhaustive-deps }, [columns, dynamicColumns]); - const onToggleHandler = (index: number) => ( - checked: boolean, - event: React.MouseEvent, - ): void => { + const onToggleHandler = ( + index: number, + column: ColumnGroupType | ColumnType, + ) => (checked: boolean, event: React.MouseEvent): void => { event.stopPropagation(); + + if (shouldSendAlertsLogEvent) { + logEvent('Alert: Column toggled', { + column: column?.title, + action: checked ? 'Enable' : 'Disable', + }); + } setVisibleColumns({ tablesource, dynamicColumns, @@ -75,7 +85,7 @@ function DynamicColumnTable({
{column.title?.toString()}
c.key === column.key) !== -1} - onChange={onToggleHandler(index)} + onChange={onToggleHandler(index, column)} /> ), diff --git a/frontend/src/components/ResizeTable/types.ts b/frontend/src/components/ResizeTable/types.ts index 35a13127a8..693e5ffda1 100644 --- a/frontend/src/components/ResizeTable/types.ts +++ b/frontend/src/components/ResizeTable/types.ts @@ -14,6 +14,7 @@ export interface DynamicColumnTableProps extends TableProps { dynamicColumns: TableProps['columns']; onDragColumn?: (fromIndex: number, toIndex: number) => void; facingIssueBtn?: FacingIssueBtnProps; + shouldSendAlertsLogEvent?: boolean; } export type GetVisibleColumnsFunction = ( diff --git a/frontend/src/container/AllAlertChannels/index.tsx b/frontend/src/container/AllAlertChannels/index.tsx index 5f34264a60..85b42de094 100644 --- a/frontend/src/container/AllAlertChannels/index.tsx +++ b/frontend/src/container/AllAlertChannels/index.tsx @@ -1,13 +1,15 @@ import { PlusOutlined } from '@ant-design/icons'; import { Tooltip, Typography } from 'antd'; import getAll from 'api/channels/getAll'; +import logEvent from 'api/common/logEvent'; import Spinner from 'components/Spinner'; import TextToolTip from 'components/TextToolTip'; import ROUTES from 'constants/routes'; import useComponentPermission from 'hooks/useComponentPermission'; import useFetch from 'hooks/useFetch'; import history from 'lib/history'; -import { useCallback } from 'react'; +import { isUndefined } from 'lodash-es'; +import { useCallback, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; import { AppState } from 'store/reducers'; @@ -31,6 +33,14 @@ function AlertChannels(): JSX.Element { const { loading, payload, error, errorMessage } = useFetch(getAll); + useEffect(() => { + if (!isUndefined(payload)) { + logEvent('Alert Channel: Channel list page visited', { + number: payload?.length, + }); + } + }, [payload]); + if (error) { return {errorMessage}; } diff --git a/frontend/src/container/CreateAlertChannels/index.tsx b/frontend/src/container/CreateAlertChannels/index.tsx index d10b6fb225..85d609c24c 100644 --- a/frontend/src/container/CreateAlertChannels/index.tsx +++ b/frontend/src/container/CreateAlertChannels/index.tsx @@ -11,11 +11,12 @@ import testOpsGenie from 'api/channels/testOpsgenie'; import testPagerApi from 'api/channels/testPager'; import testSlackApi from 'api/channels/testSlack'; import testWebhookApi from 'api/channels/testWebhook'; +import logEvent from 'api/common/logEvent'; import ROUTES from 'constants/routes'; import FormAlertChannels from 'container/FormAlertChannels'; import { useNotifications } from 'hooks/useNotifications'; import history from 'lib/history'; -import { useCallback, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { @@ -43,6 +44,10 @@ function CreateAlertChannels({ const [formInstance] = Form.useForm(); + useEffect(() => { + logEvent('Alert Channel: Create channel page visited', {}); + }, []); + const [selectedConfig, setSelectedConfig] = useState< Partial< SlackChannel & @@ -139,19 +144,25 @@ function CreateAlertChannels({ description: t('channel_creation_done'), }); history.replace(ROUTES.ALL_CHANNELS); - } else { - notifications.error({ - message: 'Error', - description: response.error || t('channel_creation_failed'), - }); + return { status: 'success', statusMessage: t('channel_creation_done') }; } + notifications.error({ + message: 'Error', + description: response.error || t('channel_creation_failed'), + }); + return { + status: 'failed', + statusMessage: response.error || t('channel_creation_failed'), + }; } catch (error) { notifications.error({ message: 'Error', description: t('channel_creation_failed'), }); + return { status: 'failed', statusMessage: t('channel_creation_failed') }; + } finally { + setSavingState(false); } - setSavingState(false); }, [prepareSlackRequest, t, notifications]); const prepareWebhookRequest = useCallback(() => { @@ -200,19 +211,25 @@ function CreateAlertChannels({ description: t('channel_creation_done'), }); history.replace(ROUTES.ALL_CHANNELS); - } else { - notifications.error({ - message: 'Error', - description: response.error || t('channel_creation_failed'), - }); + return { status: 'success', statusMessage: t('channel_creation_done') }; } + notifications.error({ + message: 'Error', + description: response.error || t('channel_creation_failed'), + }); + return { + status: 'failed', + statusMessage: response.error || t('channel_creation_failed'), + }; } catch (error) { notifications.error({ message: 'Error', description: t('channel_creation_failed'), }); + return { status: 'failed', statusMessage: t('channel_creation_failed') }; + } finally { + setSavingState(false); } - setSavingState(false); }, [prepareWebhookRequest, t, notifications]); const preparePagerRequest = useCallback(() => { @@ -245,8 +262,8 @@ function CreateAlertChannels({ setSavingState(true); const request = preparePagerRequest(); - if (request) { - try { + try { + if (request) { const response = await createPagerApi(request); if (response.statusCode === 200) { @@ -255,20 +272,31 @@ function CreateAlertChannels({ description: t('channel_creation_done'), }); history.replace(ROUTES.ALL_CHANNELS); - } else { - notifications.error({ - message: 'Error', - description: response.error || t('channel_creation_failed'), - }); + return { status: 'success', statusMessage: t('channel_creation_done') }; } - } catch (e) { notifications.error({ message: 'Error', - description: t('channel_creation_failed'), + description: response.error || t('channel_creation_failed'), }); + return { + status: 'failed', + statusMessage: response.error || t('channel_creation_failed'), + }; } + notifications.error({ + message: 'Error', + description: t('channel_creation_failed'), + }); + return { status: 'failed', statusMessage: t('channel_creation_failed') }; + } catch (error) { + notifications.error({ + message: 'Error', + description: t('channel_creation_failed'), + }); + return { status: 'failed', statusMessage: t('channel_creation_failed') }; + } finally { + setSavingState(false); } - setSavingState(false); }, [t, notifications, preparePagerRequest]); const prepareOpsgenieRequest = useCallback( @@ -295,19 +323,25 @@ function CreateAlertChannels({ description: t('channel_creation_done'), }); history.replace(ROUTES.ALL_CHANNELS); - } else { - notifications.error({ - message: 'Error', - description: response.error || t('channel_creation_failed'), - }); + return { status: 'success', statusMessage: t('channel_creation_done') }; } + notifications.error({ + message: 'Error', + description: response.error || t('channel_creation_failed'), + }); + return { + status: 'failed', + statusMessage: response.error || t('channel_creation_failed'), + }; } catch (error) { notifications.error({ message: 'Error', description: t('channel_creation_failed'), }); + return { status: 'failed', statusMessage: t('channel_creation_failed') }; + } finally { + setSavingState(false); } - setSavingState(false); }, [prepareOpsgenieRequest, t, notifications]); const prepareEmailRequest = useCallback( @@ -332,19 +366,25 @@ function CreateAlertChannels({ description: t('channel_creation_done'), }); history.replace(ROUTES.ALL_CHANNELS); - } else { - notifications.error({ - message: 'Error', - description: response.error || t('channel_creation_failed'), - }); + return { status: 'success', statusMessage: t('channel_creation_done') }; } + notifications.error({ + message: 'Error', + description: response.error || t('channel_creation_failed'), + }); + return { + status: 'failed', + statusMessage: response.error || t('channel_creation_failed'), + }; } catch (error) { notifications.error({ message: 'Error', description: t('channel_creation_failed'), }); + return { status: 'failed', statusMessage: t('channel_creation_failed') }; + } finally { + setSavingState(false); } - setSavingState(false); }, [prepareEmailRequest, t, notifications]); const prepareMsTeamsRequest = useCallback( @@ -370,19 +410,25 @@ function CreateAlertChannels({ description: t('channel_creation_done'), }); history.replace(ROUTES.ALL_CHANNELS); - } else { - notifications.error({ - message: 'Error', - description: response.error || t('channel_creation_failed'), - }); + return { status: 'success', statusMessage: t('channel_creation_done') }; } + notifications.error({ + message: 'Error', + description: response.error || t('channel_creation_failed'), + }); + return { + status: 'failed', + statusMessage: response.error || t('channel_creation_failed'), + }; } catch (error) { notifications.error({ message: 'Error', description: t('channel_creation_failed'), }); + return { status: 'failed', statusMessage: t('channel_creation_failed') }; + } finally { + setSavingState(false); } - setSavingState(false); }, [prepareMsTeamsRequest, t, notifications]); const onSaveHandler = useCallback( @@ -400,7 +446,15 @@ function CreateAlertChannels({ const functionToCall = functionMapper[value as keyof typeof functionMapper]; if (functionToCall) { - functionToCall(); + const result = await functionToCall(); + logEvent('Alert Channel: Save channel', { + type: value, + sendResolvedAlert: selectedConfig.send_resolved, + name: selectedConfig.name, + new: 'true', + status: result?.status, + statusMessage: result?.statusMessage, + }); } else { notifications.error({ message: 'Error', @@ -409,6 +463,7 @@ function CreateAlertChannels({ } } }, + // eslint-disable-next-line react-hooks/exhaustive-deps [ onSlackHandler, onWebhookHandler, @@ -472,14 +527,25 @@ function CreateAlertChannels({ description: t('channel_test_failed'), }); } + + logEvent('Alert Channel: Test notification', { + type: channelType, + sendResolvedAlert: selectedConfig.send_resolved, + name: selectedConfig.name, + new: 'true', + status: + response && response.statusCode === 200 ? 'Test success' : 'Test failed', + }); } catch (error) { notifications.error({ message: 'Error', description: t('channel_test_unexpected'), }); } + setTestingState(false); }, + // eslint-disable-next-line react-hooks/exhaustive-deps [ prepareWebhookRequest, t, diff --git a/frontend/src/container/CreateAlertRule/SelectAlertType/index.tsx b/frontend/src/container/CreateAlertRule/SelectAlertType/index.tsx index cd837b666b..52f4d52215 100644 --- a/frontend/src/container/CreateAlertRule/SelectAlertType/index.tsx +++ b/frontend/src/container/CreateAlertRule/SelectAlertType/index.tsx @@ -1,4 +1,6 @@ import { Row, Typography } from 'antd'; +import logEvent from 'api/common/logEvent'; +import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts'; import { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { AlertTypes } from 'types/api/alerts/alertTypes'; @@ -34,6 +36,13 @@ function SelectAlertType({ onSelect }: SelectAlertTypeProps): JSX.Element { default: break; } + + logEvent('Alert: Sample alert link clicked', { + dataSource: ALERTS_DATA_SOURCE_MAP[option], + link: url, + page: 'New alert data source selection page', + }); + window.open(url, '_blank'); } const renderOptions = useMemo( diff --git a/frontend/src/container/CreateAlertRule/index.tsx b/frontend/src/container/CreateAlertRule/index.tsx index e5a4772f30..f7e491cd70 100644 --- a/frontend/src/container/CreateAlertRule/index.tsx +++ b/frontend/src/container/CreateAlertRule/index.tsx @@ -1,4 +1,5 @@ import { Form, Row } from 'antd'; +import logEvent from 'api/common/logEvent'; import { ENTITY_VERSION_V4 } from 'constants/app'; import { QueryParams } from 'constants/query'; import FormAlertRules from 'container/FormAlertRules'; @@ -68,6 +69,8 @@ function CreateRules(): JSX.Element { useEffect(() => { if (alertType) { onSelectType(alertType); + } else { + logEvent('Alert: New alert data source selection page visited', {}); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [alertType]); diff --git a/frontend/src/container/EditAlertChannels/index.tsx b/frontend/src/container/EditAlertChannels/index.tsx index 3c2e956f14..b4fe30d557 100644 --- a/frontend/src/container/EditAlertChannels/index.tsx +++ b/frontend/src/container/EditAlertChannels/index.tsx @@ -11,6 +11,7 @@ import testOpsgenie from 'api/channels/testOpsgenie'; import testPagerApi from 'api/channels/testPager'; import testSlackApi from 'api/channels/testSlack'; import testWebhookApi from 'api/channels/testWebhook'; +import logEvent from 'api/common/logEvent'; import ROUTES from 'constants/routes'; import { ChannelType, @@ -89,7 +90,7 @@ function EditAlertChannels({ description: t('webhook_url_required'), }); setSavingState(false); - return; + return { status: 'failed', statusMessage: t('webhook_url_required') }; } const response = await editSlackApi(prepareSlackRequest()); @@ -101,13 +102,17 @@ function EditAlertChannels({ }); history.replace(ROUTES.ALL_CHANNELS); - } else { - notifications.error({ - message: 'Error', - description: response.error || t('channel_edit_failed'), - }); + return { status: 'success', statusMessage: t('channel_edit_done') }; } + notifications.error({ + message: 'Error', + description: response.error || t('channel_edit_failed'), + }); setSavingState(false); + return { + status: 'failed', + statusMessage: response.error || t('channel_edit_failed'), + }; }, [prepareSlackRequest, t, notifications, selectedConfig]); const prepareWebhookRequest = useCallback(() => { @@ -136,13 +141,13 @@ function EditAlertChannels({ if (selectedConfig?.api_url === '') { showError(t('webhook_url_required')); setSavingState(false); - return; + return { status: 'failed', statusMessage: t('webhook_url_required') }; } if (username && (!password || password === '')) { showError(t('username_no_password')); setSavingState(false); - return; + return { status: 'failed', statusMessage: t('username_no_password') }; } const response = await editWebhookApi(prepareWebhookRequest()); @@ -154,10 +159,15 @@ function EditAlertChannels({ }); history.replace(ROUTES.ALL_CHANNELS); - } else { - showError(response.error || t('channel_edit_failed')); + return { status: 'success', statusMessage: t('channel_edit_done') }; } + showError(response.error || t('channel_edit_failed')); + setSavingState(false); + return { + status: 'failed', + statusMessage: response.error || t('channel_edit_failed'), + }; }, [prepareWebhookRequest, t, notifications, selectedConfig]); const prepareEmailRequest = useCallback( @@ -181,13 +191,18 @@ function EditAlertChannels({ description: t('channel_edit_done'), }); history.replace(ROUTES.ALL_CHANNELS); - } else { - notifications.error({ - message: 'Error', - description: response.error || t('channel_edit_failed'), - }); + return { status: 'success', statusMessage: t('channel_edit_done') }; } + notifications.error({ + message: 'Error', + description: response.error || t('channel_edit_failed'), + }); + setSavingState(false); + return { + status: 'failed', + statusMessage: response.error || t('channel_edit_failed'), + }; }, [prepareEmailRequest, t, notifications]); const preparePagerRequest = useCallback( @@ -218,7 +233,7 @@ function EditAlertChannels({ description: validationError, }); setSavingState(false); - return; + return { status: 'failed', statusMessage: validationError }; } const response = await editPagerApi(preparePagerRequest()); @@ -229,13 +244,18 @@ function EditAlertChannels({ }); history.replace(ROUTES.ALL_CHANNELS); - } else { - notifications.error({ - message: 'Error', - description: response.error || t('channel_edit_failed'), - }); + return { status: 'success', statusMessage: t('channel_edit_done') }; } + notifications.error({ + message: 'Error', + description: response.error || t('channel_edit_failed'), + }); + setSavingState(false); + return { + status: 'failed', + statusMessage: response.error || t('channel_edit_failed'), + }; }, [preparePagerRequest, notifications, selectedConfig, t]); const prepareOpsgenieRequest = useCallback( @@ -259,7 +279,7 @@ function EditAlertChannels({ description: t('api_key_required'), }); setSavingState(false); - return; + return { status: 'failed', statusMessage: t('api_key_required') }; } const response = await editOpsgenie(prepareOpsgenieRequest()); @@ -271,13 +291,18 @@ function EditAlertChannels({ }); history.replace(ROUTES.ALL_CHANNELS); - } else { - notifications.error({ - message: 'Error', - description: response.error || t('channel_edit_failed'), - }); + return { status: 'success', statusMessage: t('channel_edit_done') }; } + notifications.error({ + message: 'Error', + description: response.error || t('channel_edit_failed'), + }); + setSavingState(false); + return { + status: 'failed', + statusMessage: response.error || t('channel_edit_failed'), + }; }, [prepareOpsgenieRequest, t, notifications, selectedConfig]); const prepareMsTeamsRequest = useCallback( @@ -301,7 +326,7 @@ function EditAlertChannels({ description: t('webhook_url_required'), }); setSavingState(false); - return; + return { status: 'failed', statusMessage: t('webhook_url_required') }; } const response = await editMsTeamsApi(prepareMsTeamsRequest()); @@ -313,31 +338,46 @@ function EditAlertChannels({ }); history.replace(ROUTES.ALL_CHANNELS); - } else { - notifications.error({ - message: 'Error', - description: response.error || t('channel_edit_failed'), - }); + return { status: 'success', statusMessage: t('channel_edit_done') }; } + notifications.error({ + message: 'Error', + description: response.error || t('channel_edit_failed'), + }); + setSavingState(false); + return { + status: 'failed', + statusMessage: response.error || t('channel_edit_failed'), + }; }, [prepareMsTeamsRequest, t, notifications, selectedConfig]); const onSaveHandler = useCallback( - (value: ChannelType) => { + async (value: ChannelType) => { + let result; if (value === ChannelType.Slack) { - onSlackEditHandler(); + result = await onSlackEditHandler(); } else if (value === ChannelType.Webhook) { - onWebhookEditHandler(); + result = await onWebhookEditHandler(); } else if (value === ChannelType.Pagerduty) { - onPagerEditHandler(); + result = await onPagerEditHandler(); } else if (value === ChannelType.MsTeams) { - onMsTeamsEditHandler(); + result = await onMsTeamsEditHandler(); } else if (value === ChannelType.Opsgenie) { - onOpsgenieEditHandler(); + result = await onOpsgenieEditHandler(); } else if (value === ChannelType.Email) { - onEmailEditHandler(); + result = await onEmailEditHandler(); } + logEvent('Alert Channel: Save channel', { + type: value, + sendResolvedAlert: selectedConfig.send_resolved, + name: selectedConfig.name, + new: 'false', + status: result?.status, + statusMessage: result?.statusMessage, + }); }, + // eslint-disable-next-line react-hooks/exhaustive-deps [ onSlackEditHandler, onWebhookEditHandler, @@ -399,6 +439,14 @@ function EditAlertChannels({ description: t('channel_test_failed'), }); } + logEvent('Alert Channel: Test notification', { + type: channelType, + sendResolvedAlert: selectedConfig.send_resolved, + name: selectedConfig.name, + new: 'false', + status: + response && response.statusCode === 200 ? 'Test success' : 'Test failed', + }); } catch (error) { notifications.error({ message: 'Error', @@ -407,6 +455,7 @@ function EditAlertChannels({ } setTestingState(false); }, + // eslint-disable-next-line react-hooks/exhaustive-deps [ t, prepareWebhookRequest, diff --git a/frontend/src/container/FormAlertRules/BasicInfo.tsx b/frontend/src/container/FormAlertRules/BasicInfo.tsx index 5fae4a713d..40edb7977e 100644 --- a/frontend/src/container/FormAlertRules/BasicInfo.tsx +++ b/frontend/src/container/FormAlertRules/BasicInfo.tsx @@ -3,6 +3,8 @@ import './FormAlertRules.styles.scss'; import { PlusOutlined } from '@ant-design/icons'; import { Button, Form, Select, Switch, Tooltip } from 'antd'; import getChannels from 'api/channels/getAll'; +import logEvent from 'api/common/logEvent'; +import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts'; import ROUTES from 'constants/routes'; import useComponentPermission from 'hooks/useComponentPermission'; import useFetch from 'hooks/useFetch'; @@ -10,6 +12,7 @@ import { useCallback, useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useSelector } from 'react-redux'; import { AppState } from 'store/reducers'; +import { AlertTypes } from 'types/api/alerts/alertTypes'; import { AlertDef, Labels } from 'types/api/alerts/def'; import AppReducer from 'types/reducer/app'; import { requireErrorMessage } from 'utils/form/requireErrorMessage'; @@ -73,9 +76,24 @@ function BasicInfo({ const noChannels = channels.payload?.length === 0; const handleCreateNewChannels = useCallback(() => { + logEvent('Alert: Create notification channel button clicked', { + dataSource: ALERTS_DATA_SOURCE_MAP[alertDef?.alertType as AlertTypes], + ruleId: isNewRule ? 0 : alertDef?.id, + }); window.open(ROUTES.CHANNELS_NEW, '_blank'); + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); + useEffect(() => { + if (!channels.loading && isNewRule) { + logEvent('Alert: New alert creation page visited', { + dataSource: ALERTS_DATA_SOURCE_MAP[alertDef?.alertType as AlertTypes], + numberOfChannels: channels.payload?.length, + }); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [channels.payload, channels.loading]); + return ( <> {t('alert_form_step3')} diff --git a/frontend/src/container/FormAlertRules/QuerySection.tsx b/frontend/src/container/FormAlertRules/QuerySection.tsx index a567288585..aa56c84571 100644 --- a/frontend/src/container/FormAlertRules/QuerySection.tsx +++ b/frontend/src/container/FormAlertRules/QuerySection.tsx @@ -2,6 +2,7 @@ import './QuerySection.styles.scss'; import { Color } from '@signozhq/design-tokens'; import { Button, Tabs, Tooltip } from 'antd'; +import logEvent from 'api/common/logEvent'; import PromQLIcon from 'assets/Dashboard/PromQl'; import { ALERTS_DATA_SOURCE_MAP } from 'constants/alerts'; import { ENTITY_VERSION_V4 } from 'constants/app'; @@ -31,6 +32,7 @@ function QuerySection({ runQuery, alertDef, panelType, + ruleId, }: QuerySectionProps): JSX.Element { // init namespace for translations const { t } = useTranslation('alerts'); @@ -158,7 +160,15 @@ function QuerySection({