feat: create alerts is updated from trace explorer (#2995)

This commit is contained in:
Palash Gupta 2023-06-30 11:18:12 +05:30 committed by GitHub
parent 709bfda0cc
commit cda37b99b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 139 additions and 51 deletions

View File

@ -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'),
},
];

View File

@ -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) => (
<AlertTypeCard
key={o.selection}
title={o.title}
key={option.selection}
title={option.title}
onClick={(): void => {
onSelect(o.selection);
onSelect(option.selection);
}}
>
{o.description}
{option.description}
</AlertTypeCard>
))}
</>
);
};
),
[onSelect, optionList],
);
return (
<SelectTypeContainer>
<h3> {t('choose_alert_type')} </h3>
<Row>{renderOptions()}</Row>
<Row>{renderOptions}</Row>
</SelectTypeContainer>
);
}

View File

@ -0,0 +1,7 @@
import { AlertTypes } from 'types/api/alerts/alertTypes';
export interface OptionType {
title: string;
selection: AlertTypes;
description: string;
}

View File

@ -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,
};

View File

@ -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>(
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 (
<Row wrap={false}>

View File

@ -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<boolean>(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
>
<ExportPanelContainer isLoading={isLoading} onExport={onExport} />
<ExportPanelContainer
query={query}
isLoading={isLoading}
onExport={onExport}
/>
</Modal>
</>
);
@ -71,6 +95,7 @@ interface OnClickProps {
export interface ExportPanelProps {
isLoading?: boolean;
onExport: (dashboard: Dashboard | null) => void;
query: Query | null;
}
export default ExportPanel;

View File

@ -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]);

View File

@ -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),
)}`,
);
})

View File

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

View File

@ -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]);
};

View File

@ -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 {
<Container>
<ActionsWrapper>
<ExportPanel isLoading={isLoading} onExport={handleExport} />
<ExportPanel
query={stagedQuery}
isLoading={isLoading}
onExport={handleExport}
/>
</ActionsWrapper>
<Tabs

View File

@ -460,7 +460,10 @@ export function QueryBuilderProvider({
id: uuid(),
};
urlQuery.set(COMPOSITE_QUERY, JSON.stringify(currentGeneratedQuery));
urlQuery.set(
COMPOSITE_QUERY,
encodeURIComponent(JSON.stringify(currentGeneratedQuery)),
);
if (searchParams) {
Object.keys(searchParams).forEach((param) =>

View File

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