diff --git a/frontend/src/container/CreateAlertRule/SelectAlertType/config.ts b/frontend/src/container/CreateAlertRule/SelectAlertType/config.ts
new file mode 100644
index 0000000000..c973684e67
--- /dev/null
+++ b/frontend/src/container/CreateAlertRule/SelectAlertType/config.ts
@@ -0,0 +1,27 @@
+import { TFunction } from 'i18next';
+import { AlertTypes } from 'types/api/alerts/alertTypes';
+
+import { OptionType } from './types';
+
+export const getOptionList = (t: TFunction): OptionType[] => [
+ {
+ title: t('metric_based_alert'),
+ selection: AlertTypes.METRICS_BASED_ALERT,
+ description: t('metric_based_alert_desc'),
+ },
+ {
+ title: t('log_based_alert'),
+ selection: AlertTypes.LOGS_BASED_ALERT,
+ description: t('log_based_alert_desc'),
+ },
+ {
+ title: t('traces_based_alert'),
+ selection: AlertTypes.TRACES_BASED_ALERT,
+ description: t('traces_based_alert_desc'),
+ },
+ {
+ title: t('exceptions_based_alert'),
+ selection: AlertTypes.EXCEPTIONS_BASED_ALERT,
+ description: t('exceptions_based_alert_desc'),
+ },
+];
diff --git a/frontend/src/container/CreateAlertRule/SelectAlertType/index.tsx b/frontend/src/container/CreateAlertRule/SelectAlertType/index.tsx
index 8385c8462e..65a5914fca 100644
--- a/frontend/src/container/CreateAlertRule/SelectAlertType/index.tsx
+++ b/frontend/src/container/CreateAlertRule/SelectAlertType/index.tsx
@@ -1,61 +1,40 @@
import { Row } from 'antd';
+import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { AlertTypes } from 'types/api/alerts/alertTypes';
+import { getOptionList } from './config';
import { AlertTypeCard, SelectTypeContainer } from './styles';
-
-interface OptionType {
- title: string;
- selection: AlertTypes;
- description: string;
-}
+import { OptionType } from './types';
function SelectAlertType({ onSelect }: SelectAlertTypeProps): JSX.Element {
const { t } = useTranslation(['alerts']);
- const renderOptions = (): JSX.Element => {
- const optionList: OptionType[] = [
- {
- title: t('metric_based_alert'),
- selection: AlertTypes.METRICS_BASED_ALERT,
- description: t('metric_based_alert_desc'),
- },
- {
- title: t('log_based_alert'),
- selection: AlertTypes.LOGS_BASED_ALERT,
- description: t('log_based_alert_desc'),
- },
- {
- title: t('traces_based_alert'),
- selection: AlertTypes.TRACES_BASED_ALERT,
- description: t('traces_based_alert_desc'),
- },
- {
- title: t('exceptions_based_alert'),
- selection: AlertTypes.EXCEPTIONS_BASED_ALERT,
- description: t('exceptions_based_alert_desc'),
- },
- ];
- return (
+ const optionList = getOptionList(t);
+
+ const renderOptions = useMemo(
+ () => (
<>
- {optionList.map((o: OptionType) => (
+ {optionList.map((option: OptionType) => (
{
- onSelect(o.selection);
+ onSelect(option.selection);
}}
>
- {o.description}
+ {option.description}
))}
>
- );
- };
+ ),
+ [onSelect, optionList],
+ );
+
return (
{t('choose_alert_type')}
- {renderOptions()}
+ {renderOptions}
);
}
diff --git a/frontend/src/container/CreateAlertRule/SelectAlertType/types.ts b/frontend/src/container/CreateAlertRule/SelectAlertType/types.ts
new file mode 100644
index 0000000000..670f5a2708
--- /dev/null
+++ b/frontend/src/container/CreateAlertRule/SelectAlertType/types.ts
@@ -0,0 +1,7 @@
+import { AlertTypes } from 'types/api/alerts/alertTypes';
+
+export interface OptionType {
+ title: string;
+ selection: AlertTypes;
+ description: string;
+}
diff --git a/frontend/src/container/CreateAlertRule/config.ts b/frontend/src/container/CreateAlertRule/config.ts
new file mode 100644
index 0000000000..fe52bb12bf
--- /dev/null
+++ b/frontend/src/container/CreateAlertRule/config.ts
@@ -0,0 +1,8 @@
+import { AlertTypes } from 'types/api/alerts/alertTypes';
+import { DataSource } from 'types/common/queryBuilder';
+
+export const ALERT_TYPE_VS_SOURCE_MAPPING = {
+ [DataSource.LOGS]: AlertTypes.LOGS_BASED_ALERT,
+ [DataSource.METRICS]: AlertTypes.METRICS_BASED_ALERT,
+ [DataSource.TRACES]: AlertTypes.TRACES_BASED_ALERT,
+};
diff --git a/frontend/src/container/CreateAlertRule/index.tsx b/frontend/src/container/CreateAlertRule/index.tsx
index 40145d324e..9ce1634d13 100644
--- a/frontend/src/container/CreateAlertRule/index.tsx
+++ b/frontend/src/container/CreateAlertRule/index.tsx
@@ -1,9 +1,11 @@
import { Form, Row } from 'antd';
import FormAlertRules from 'container/FormAlertRules';
-import { useState } from 'react';
+import { useGetCompositeQueryParam } from 'hooks/queryBuilder/useGetCompositeQueryParam';
+import { useEffect, useState } from 'react';
import { AlertTypes } from 'types/api/alerts/alertTypes';
import { AlertDef } from 'types/api/alerts/def';
+import { ALERT_TYPE_VS_SOURCE_MAPPING } from './config';
import {
alertDefaults,
exceptionAlertDefaults,
@@ -17,6 +19,9 @@ function CreateRules(): JSX.Element {
const [alertType, setAlertType] = useState(
AlertTypes.METRICS_BASED_ALERT,
);
+
+ const compositeQuery = useGetCompositeQueryParam();
+
const [formInstance] = Form.useForm();
const onSelectType = (typ: AlertTypes): void => {
@@ -36,6 +41,19 @@ function CreateRules(): JSX.Element {
}
};
+ useEffect(() => {
+ if (!compositeQuery) {
+ return;
+ }
+ const dataSource = compositeQuery?.builder?.queryData[0]?.dataSource;
+
+ const alertType = ALERT_TYPE_VS_SOURCE_MAPPING[dataSource];
+
+ if (alertType) {
+ onSelectType(alertType);
+ }
+ }, [compositeQuery]);
+
if (!initValues) {
return (
diff --git a/frontend/src/container/ExportPanel/index.tsx b/frontend/src/container/ExportPanel/index.tsx
index 2a95bfd9ab..087b17fe72 100644
--- a/frontend/src/container/ExportPanel/index.tsx
+++ b/frontend/src/container/ExportPanel/index.tsx
@@ -1,24 +1,44 @@
import { Button, Dropdown, MenuProps, Modal } from 'antd';
+import { COMPOSITE_QUERY } from 'constants/queryBuilderQueryNames';
+import ROUTES from 'constants/routes';
+import history from 'lib/history';
import { useCallback, useMemo, useState } from 'react';
import { Dashboard } from 'types/api/dashboard/getAll';
+import { Query } from 'types/api/queryBuilder/queryBuilderData';
import { MENU_KEY, MENU_LABEL } from './config';
import ExportPanelContainer from './ExportPanel';
-function ExportPanel({ isLoading, onExport }: ExportPanelProps): JSX.Element {
+function ExportPanel({
+ isLoading,
+ onExport,
+ query,
+}: ExportPanelProps): JSX.Element {
const [isExport, setIsExport] = useState(false);
const onModalToggle = useCallback((value: boolean) => {
setIsExport(value);
}, []);
+ const onCreateAlertsHandler = useCallback(() => {
+ history.push(
+ `${ROUTES.ALERTS_NEW}?${COMPOSITE_QUERY}=${encodeURIComponent(
+ JSON.stringify(query),
+ )}`,
+ );
+ }, [query]);
+
const onMenuClickHandler: MenuProps['onClick'] = useCallback(
(e: OnClickProps) => {
if (e.key === MENU_KEY.EXPORT) {
onModalToggle(true);
}
+
+ if (e.key === MENU_KEY.CREATE_ALERTS) {
+ onCreateAlertsHandler();
+ }
},
- [onModalToggle],
+ [onModalToggle, onCreateAlertsHandler],
);
const menu: MenuProps = useMemo(
@@ -54,7 +74,11 @@ function ExportPanel({ isLoading, onExport }: ExportPanelProps): JSX.Element {
open={isExport}
centered
>
-
+
>
);
@@ -71,6 +95,7 @@ interface OnClickProps {
export interface ExportPanelProps {
isLoading?: boolean;
onExport: (dashboard: Dashboard | null) => void;
+ query: Query | null;
}
export default ExportPanel;
diff --git a/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx b/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx
index 30390c2824..a68d48ef8d 100644
--- a/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx
+++ b/frontend/src/container/GridGraphLayout/WidgetHeader/index.tsx
@@ -64,7 +64,7 @@ function WidgetHeader({
history.push(
`${window.location.pathname}/new?widgetId=${widgetId}&graphType=${
widget.panelTypes
- }&${COMPOSITE_QUERY}=${JSON.stringify(widget.query)}`,
+ }&${COMPOSITE_QUERY}=${encodeURIComponent(JSON.stringify(widget.query))}`,
);
}, [widget.id, widget.panelTypes, widget.query]);
diff --git a/frontend/src/container/ListAlertRules/ListAlert.tsx b/frontend/src/container/ListAlertRules/ListAlert.tsx
index c1204eb79b..76843be306 100644
--- a/frontend/src/container/ListAlertRules/ListAlert.tsx
+++ b/frontend/src/container/ListAlertRules/ListAlert.tsx
@@ -77,8 +77,8 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
history.push(
`${
ROUTES.EDIT_ALERTS
- }?ruleId=${record.id.toString()}&${COMPOSITE_QUERY}=${JSON.stringify(
- compositeQuery,
+ }?ruleId=${record.id.toString()}&${COMPOSITE_QUERY}=${encodeURIComponent(
+ JSON.stringify(compositeQuery),
)}`,
);
})
diff --git a/frontend/src/container/NewDashboard/ComponentsSlider/index.tsx b/frontend/src/container/NewDashboard/ComponentsSlider/index.tsx
index b20c4388f8..f490f1f23e 100644
--- a/frontend/src/container/NewDashboard/ComponentsSlider/index.tsx
+++ b/frontend/src/container/NewDashboard/ComponentsSlider/index.tsx
@@ -47,7 +47,9 @@ function DashboardGraphSlider({ toggleAddWidget }: Props): JSX.Element {
history.push(
`${history.location.pathname}/new?graphType=${name}&widgetId=${
emptyLayout.i
- }&${COMPOSITE_QUERY}=${JSON.stringify(initialQueriesMap.metrics)}`,
+ }&${COMPOSITE_QUERY}=${encodeURIComponent(
+ JSON.stringify(initialQueriesMap.metrics),
+ )}`,
);
} catch (error) {
notifications.error({
diff --git a/frontend/src/hooks/queryBuilder/useGetCompositeQueryParam.ts b/frontend/src/hooks/queryBuilder/useGetCompositeQueryParam.ts
index 4477a9fbf7..894167815b 100644
--- a/frontend/src/hooks/queryBuilder/useGetCompositeQueryParam.ts
+++ b/frontend/src/hooks/queryBuilder/useGetCompositeQueryParam.ts
@@ -8,7 +8,16 @@ export const useGetCompositeQueryParam = (): Query | null => {
return useMemo(() => {
const compositeQuery = urlQuery.get(COMPOSITE_QUERY);
+ let parsedCompositeQuery: Query | null = null;
- return compositeQuery ? JSON.parse(compositeQuery) : null;
+ try {
+ if (!compositeQuery) return null;
+
+ parsedCompositeQuery = JSON.parse(decodeURIComponent(compositeQuery));
+ } catch (e) {
+ parsedCompositeQuery = null;
+ }
+
+ return parsedCompositeQuery;
}, [urlQuery]);
};
diff --git a/frontend/src/pages/TracesExplorer/index.tsx b/frontend/src/pages/TracesExplorer/index.tsx
index f1215bc1ce..22f7a4f153 100644
--- a/frontend/src/pages/TracesExplorer/index.tsx
+++ b/frontend/src/pages/TracesExplorer/index.tsx
@@ -74,7 +74,9 @@ function TracesExplorer(): JSX.Element {
dashboardId: data?.payload?.uuid,
})}/new?${QueryParams.graphType}=graph&${
QueryParams.widgetId
- }=empty&${COMPOSITE_QUERY}=${JSON.stringify(exportDefaultQuery)}`;
+ }=empty&${COMPOSITE_QUERY}=${encodeURIComponent(
+ JSON.stringify(exportDefaultQuery),
+ )}`;
history.push(dashboardEditView);
},
@@ -118,7 +120,11 @@ function TracesExplorer(): JSX.Element {
-
+
diff --git a/frontend/src/store/actions/dashboard/saveDashboard.ts b/frontend/src/store/actions/dashboard/saveDashboard.ts
index 09007415ef..14e62fedac 100644
--- a/frontend/src/store/actions/dashboard/saveDashboard.ts
+++ b/frontend/src/store/actions/dashboard/saveDashboard.ts
@@ -91,7 +91,11 @@ export const SaveDashboard = ({
const compositeQuery = params.get(COMPOSITE_QUERY);
const { maxTime, minTime } = store.getState().globalTime;
const query = compositeQuery
- ? updateStepInterval(JSON.parse(compositeQuery), maxTime, minTime)
+ ? updateStepInterval(
+ JSON.parse(decodeURIComponent(compositeQuery)),
+ maxTime,
+ minTime,
+ )
: updateStepInterval(selectedWidget.query, maxTime, minTime);
const response = await updateDashboardApi({