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({