diff --git a/frontend/src/container/CreateAlertV2/CreateAlertHeader/__tests__/CreateAlertHeader.test.tsx b/frontend/src/container/CreateAlertV2/CreateAlertHeader/__tests__/CreateAlertHeader.test.tsx
index 5e831f857b..dbc11c03ac 100644
--- a/frontend/src/container/CreateAlertV2/CreateAlertHeader/__tests__/CreateAlertHeader.test.tsx
+++ b/frontend/src/container/CreateAlertV2/CreateAlertHeader/__tests__/CreateAlertHeader.test.tsx
@@ -1,7 +1,11 @@
/* eslint-disable react/jsx-props-no-spreading */
import { fireEvent, render, screen } from '@testing-library/react';
+import { QueryParams } from 'constants/query';
+import { initialQueriesMap } from 'constants/queryBuilder';
+import ROUTES from 'constants/routes';
import { defaultPostableAlertRuleV2 } from 'container/CreateAlertV2/constants';
import { getCreateAlertLocalStateFromAlertDef } from 'container/CreateAlertV2/utils';
+import * as useSafeNavigateHook from 'hooks/useSafeNavigate';
import { AlertTypes } from 'types/api/alerts/alertTypes';
import * as useCreateAlertRuleHook from '../../../../hooks/alerts/useCreateAlertRule';
@@ -10,6 +14,11 @@ import * as useUpdateAlertRuleHook from '../../../../hooks/alerts/useUpdateAlert
import { CreateAlertProvider } from '../../context';
import CreateAlertHeader from '../CreateAlertHeader';
+const mockSafeNavigate = jest.fn();
+jest.spyOn(useSafeNavigateHook, 'useSafeNavigate').mockReturnValue({
+ safeNavigate: mockSafeNavigate,
+});
+
jest.spyOn(useCreateAlertRuleHook, 'useCreateAlertRule').mockReturnValue({
mutate: jest.fn(),
isLoading: false,
@@ -100,4 +109,37 @@ describe('CreateAlertHeader', () => {
screen.getByPlaceholderText(ENTER_ALERT_RULE_NAME_PLACEHOLDER),
).toHaveValue('TEST_ALERT');
});
+
+ it('should navigate to classic experience when button is clicked', () => {
+ renderCreateAlertHeader();
+ const switchToClassicExperienceButton = screen.getByText(
+ 'Switch to Classic Experience',
+ );
+ expect(switchToClassicExperienceButton).toBeInTheDocument();
+ fireEvent.click(switchToClassicExperienceButton);
+
+ const params = new URLSearchParams();
+ params.set(QueryParams.showClassicCreateAlertsPage, 'true');
+ expect(mockSafeNavigate).toHaveBeenCalledWith(
+ `${ROUTES.ALERTS_NEW}?${params.toString()}`,
+ { replace: true },
+ );
+ });
+
+ it('should not render "switch to classic experience" button when isEditMode is true', () => {
+ render(
+
+
+ ,
+ );
+ expect(
+ screen.queryByText('Switch to Classic Experience'),
+ ).not.toBeInTheDocument();
+ });
});
diff --git a/frontend/src/container/CreateAlertV2/CreateAlertHeader/styles.scss b/frontend/src/container/CreateAlertV2/CreateAlertHeader/styles.scss
index 875ca32652..7dd4b25d63 100644
--- a/frontend/src/container/CreateAlertV2/CreateAlertHeader/styles.scss
+++ b/frontend/src/container/CreateAlertV2/CreateAlertHeader/styles.scss
@@ -3,6 +3,12 @@
font-family: inherit;
color: var(--text-vanilla-100);
+ &__tab-bar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ }
+
/* Tab block visuals */
&__tab {
display: flex;
diff --git a/frontend/src/container/CreateAlertV2/QuerySection/ChartPreview/ChartPreview.tsx b/frontend/src/container/CreateAlertV2/QuerySection/ChartPreview/ChartPreview.tsx
index 65144e8468..ac2cefc851 100644
--- a/frontend/src/container/CreateAlertV2/QuerySection/ChartPreview/ChartPreview.tsx
+++ b/frontend/src/container/CreateAlertV2/QuerySection/ChartPreview/ChartPreview.tsx
@@ -6,7 +6,7 @@ import ChartPreviewComponent from 'container/FormAlertRules/ChartPreview';
import PlotTag from 'container/NewWidget/LeftContainer/WidgetGraph/PlotTag';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import useGetYAxisUnit from 'hooks/useGetYAxisUnit';
-import { useEffect, useState } from 'react';
+import { useEffect, useMemo, useState } from 'react';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import { AlertTypes } from 'types/api/alerts/alertTypes';
@@ -16,9 +16,10 @@ import { GlobalReducer } from 'types/reducer/globalTime';
export interface ChartPreviewProps {
alertDef: AlertDef;
+ source?: YAxisSource;
}
-function ChartPreview({ alertDef }: ChartPreviewProps): JSX.Element {
+function ChartPreview({ alertDef, source }: ChartPreviewProps): JSX.Element {
const { currentQuery, panelType, stagedQuery } = useQueryBuilder();
const {
alertType,
@@ -35,8 +36,14 @@ function ChartPreview({ alertDef }: ChartPreviewProps): JSX.Element {
const yAxisUnit = alertState.yAxisUnit || '';
- const shouldUpdateYAxisUnit =
- !isEditMode && alertType === AlertTypes.METRICS_BASED_ALERT;
+ // Only update automatically when creating a new metrics-based alert rule
+ const shouldUpdateYAxisUnit = useMemo(() => {
+ // Do not update if we are coming to the page from dashboards (we still show warning)
+ if (source === YAxisSource.DASHBOARDS) {
+ return false;
+ }
+ return !isEditMode && alertType === AlertTypes.METRICS_BASED_ALERT;
+ }, [isEditMode, alertType, source]);
const selectedQueryName = thresholdState.selectedQuery;
const { yAxisUnit: initialYAxisUnit, isLoading } = useGetYAxisUnit(
diff --git a/frontend/src/container/CreateAlertV2/QuerySection/QuerySection.tsx b/frontend/src/container/CreateAlertV2/QuerySection/QuerySection.tsx
index e62f24641b..5e0d576982 100644
--- a/frontend/src/container/CreateAlertV2/QuerySection/QuerySection.tsx
+++ b/frontend/src/container/CreateAlertV2/QuerySection/QuerySection.tsx
@@ -2,10 +2,15 @@ import './styles.scss';
import { Button } from 'antd';
import classNames from 'classnames';
+import { YAxisSource } from 'components/YAxisUnitSelector/types';
+import { QueryParams } from 'constants/query';
import { PANEL_TYPES } from 'constants/queryBuilder';
import QuerySectionComponent from 'container/FormAlertRules/QuerySection';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
+import { getMetricNameFromQueryData } from 'hooks/useGetYAxisUnit';
+import useUrlQuery from 'hooks/useUrlQuery';
import { BarChart2, DraftingCompass, FileText, ScrollText } from 'lucide-react';
+import { useCallback, useMemo } from 'react';
import { AlertTypes } from 'types/api/alerts/alertTypes';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { EQueryType } from 'types/common/dashboard';
@@ -18,10 +23,12 @@ import { buildAlertDefForChartPreview } from './utils';
function QuerySection(): JSX.Element {
const {
currentQuery,
+ stagedQuery,
handleRunQuery,
redirectWithQueryBuilderData,
} = useQueryBuilder();
const { alertType, setAlertType, thresholdState } = useCreateAlertState();
+ const urlQuery = useUrlQuery();
const alertDef = buildAlertDefForChartPreview({ alertType, thresholdState });
@@ -30,6 +37,49 @@ function QuerySection(): JSX.Element {
redirectWithQueryBuilderData(query);
};
+ const source = useMemo(() => urlQuery.get(QueryParams.source) as YAxisSource, [
+ urlQuery,
+ ]);
+
+ const didQueryChange = useMemo(() => {
+ if (alertType !== AlertTypes.METRICS_BASED_ALERT) {
+ return false;
+ }
+
+ const selectedQueryName = thresholdState.selectedQuery;
+ const currentQueryData = currentQuery.builder.queryData.find(
+ (query) => query.queryName === selectedQueryName,
+ );
+ const stagedQueryData = stagedQuery?.builder.queryData.find(
+ (query) => query.queryName === selectedQueryName,
+ );
+ if (!currentQueryData || !stagedQueryData) {
+ return false;
+ }
+
+ const currentQueryKey = getMetricNameFromQueryData(currentQueryData);
+ const stagedQueryKey = getMetricNameFromQueryData(stagedQueryData);
+ return currentQueryKey !== stagedQueryKey;
+ }, [currentQuery, alertType, thresholdState, stagedQuery]);
+
+ const runQueryHandler = useCallback(() => {
+ // Reset the source param when the query is changed
+ // Then manually run the query
+ if (source === YAxisSource.DASHBOARDS && didQueryChange) {
+ redirectWithQueryBuilderData(currentQuery, {
+ [QueryParams.source]: null,
+ });
+ } else {
+ handleRunQuery();
+ }
+ }, [
+ currentQuery,
+ didQueryChange,
+ handleRunQuery,
+ redirectWithQueryBuilderData,
+ source,
+ ]);
+
const tabs = [
{
label: 'Metrics',
@@ -56,7 +106,7 @@ function QuerySection(): JSX.Element {
return (
-
+
{tabs.map((tab) => (
@@ -79,7 +129,7 @@ function QuerySection(): JSX.Element {
queryCategory={currentQuery.queryType}
setQueryCategory={onQueryCategoryChange}
alertType={alertType}
- runQuery={handleRunQuery}
+ runQuery={runQueryHandler}
alertDef={alertDef}
panelType={PANEL_TYPES.TIME_SERIES}
key={currentQuery.queryType}
diff --git a/frontend/src/container/CreateAlertV2/context/index.tsx b/frontend/src/container/CreateAlertV2/context/index.tsx
index 0da09dd04f..3bc6a8dc28 100644
--- a/frontend/src/container/CreateAlertV2/context/index.tsx
+++ b/frontend/src/container/CreateAlertV2/context/index.tsx
@@ -63,12 +63,13 @@ export function CreateAlertProvider(
initialAlertType,
} = props;
- const [alertState, setAlertState] = useReducer(
- alertCreationReducer,
- INITIAL_ALERT_STATE,
- );
-
const { currentQuery, redirectWithQueryBuilderData } = useQueryBuilder();
+
+ const [alertState, setAlertState] = useReducer(alertCreationReducer, {
+ ...INITIAL_ALERT_STATE,
+ yAxisUnit: currentQuery.unit,
+ });
+
const location = useLocation();
const queryParams = new URLSearchParams(location.search);
const thresholdsFromURL = queryParams.get(QueryParams.thresholds);
diff --git a/frontend/src/container/IngestionSettings/MultiIngestionSettings.tsx b/frontend/src/container/IngestionSettings/MultiIngestionSettings.tsx
index 8cc155dae6..8ab8f3cf9b 100644
--- a/frontend/src/container/IngestionSettings/MultiIngestionSettings.tsx
+++ b/frontend/src/container/IngestionSettings/MultiIngestionSettings.tsx
@@ -762,7 +762,7 @@ function MultiIngestionSettings(): JSX.Element {
const thresholds = cloneDeep(INITIAL_ALERT_THRESHOLD_STATE.thresholds);
thresholds[0].thresholdValue = threshold;
- const URL = `${ROUTES.ALERTS_NEW}?showNewCreateAlertsPage=true&${
+ const URL = `${ROUTES.ALERTS_NEW}?${
QueryParams.compositeQuery
}=${encodeURIComponent(stringifiedQuery)}&${
QueryParams.thresholds
diff --git a/frontend/src/container/IngestionSettings/__tests__/MultiIngestionSettings.test.tsx b/frontend/src/container/IngestionSettings/__tests__/MultiIngestionSettings.test.tsx
index 301feb0024..75a3034302 100644
--- a/frontend/src/container/IngestionSettings/__tests__/MultiIngestionSettings.test.tsx
+++ b/frontend/src/container/IngestionSettings/__tests__/MultiIngestionSettings.test.tsx
@@ -142,7 +142,6 @@ describe('MultiIngestionSettings Page', () => {
// Check URL contains alerts/new route
expect(navigationCall).toContain('/alerts/new');
- expect(navigationCall).toContain('showNewCreateAlertsPage=true');
// Parse query parameters
const urlParams = new URLSearchParams(navigationCall.split('?')[1]);
@@ -231,7 +230,6 @@ describe('MultiIngestionSettings Page', () => {
// Check URL contains alerts/new route
expect(navigationCall).toContain('/alerts/new');
- expect(navigationCall).toContain('showNewCreateAlertsPage=true');
// Parse query parameters
const urlParams = new URLSearchParams(navigationCall.split('?')[1]);
diff --git a/frontend/src/container/ListAlertRules/ListAlert.tsx b/frontend/src/container/ListAlertRules/ListAlert.tsx
index 075e200320..02d2a4773b 100644
--- a/frontend/src/container/ListAlertRules/ListAlert.tsx
+++ b/frontend/src/container/ListAlertRules/ListAlert.tsx
@@ -108,42 +108,15 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
});
}, [notificationsApi, t]);
- const onClickNewAlertV2Handler = useCallback(() => {
+ const onClickNewAlertHandler = useCallback(() => {
logEvent('Alert: New alert button clicked', {
number: allAlertRules?.length,
layout: 'new',
});
- params.set(QueryParams.showNewCreateAlertsPage, 'true');
- safeNavigate(`${ROUTES.ALERT_TYPE_SELECTION}?${params.toString()}`);
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
-
- const onClickNewClassicAlertHandler = useCallback(() => {
- logEvent('Alert: New alert button clicked', {
- number: allAlertRules?.length,
- layout: 'classic',
- });
safeNavigate(ROUTES.ALERT_TYPE_SELECTION);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
- const newAlertMenuItems: MenuProps['items'] = [
- {
- key: 'new',
- label: (
-
- Try the new experience Beta
-
- ),
- onClick: onClickNewAlertV2Handler,
- },
- {
- key: 'classic',
- label: 'Continue with the classic experience',
- onClick: onClickNewClassicAlertHandler,
- },
- ];
-
const onEditHandler = (record: GettableAlert, openInNewTab: boolean): void => {
const compositeQuery = sanitizeDefaultAlertQuery(
mapQueryDataFromApi(record.condition.compositeQuery),
@@ -414,11 +387,13 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
/>
{addNewAlert && (
-
- }>
- New Alert
-
-
+ }
+ >
+ New Alert
+
)}
{
expect(mockSafeNavigate).toHaveBeenCalled();
});
- it('should navigate to new create alerts page with correct params if showNewCreateAlertsPage is true', () => {
+ it('should navigate to classic create alerts page with correct params if showClassicCreateAlertsPage is true', () => {
useUrlQuerySpy.mockReturnValue(({
set: mockSetUrlQuery,
toString: mockToString,
- get: mockGetUrlQuery.mockReturnValue('true'),
+ get: mockGetUrlQuery.mockImplementation((key: string) => {
+ if (key === QueryParams.showClassicCreateAlertsPage) {
+ return 'true';
+ }
+ return null;
+ }),
} as Partial) as URLSearchParams);
render();
@@ -176,7 +181,7 @@ describe('AlertTypeSelection', () => {
AlertTypes.METRICS_BASED_ALERT,
);
expect(mockSetUrlQuery).toHaveBeenCalledWith(
- QueryParams.showNewCreateAlertsPage,
+ QueryParams.showClassicCreateAlertsPage,
'true',
);
expect(mockSafeNavigate).toHaveBeenCalled();