feat: Right side panel in create/edit alert UI (#1404)

* feat: metrics builder

* feat: tag key selection

* feat: metrics builder

* poc version

* added more changes to query builder

* added types for composite queries

* (feat): added edit rules and create rules forms

* added label key value input item

* (chore): added hidden labels for labelinput

* (chore): resolved some merge conflicts from develop

* (chore): added translations

* (chore): removed some old files in metric builder

* (chore): restored some of the files from develop branch

* (chore): restored env.ts

* (fix): solved empty builder queries errors

* (fix): changed queryIndex and formulaIndex type to string|number from number

* (feat): added chart preview for alert metric ui

* (feat): added threshold in chart, translations in alert form and a few fixes

* (fix): restoring env.ts

* (fix): placed threshold on horizontal line

* fix: resolved review comments

* fix: resolved label remove issue

* fix: removed console log

* fix: resolved issue with edit rule - old state values shown after update of threshold

* fix: resolved issue with match condition dropdown in alert ui

* fix: increased size of timeframe drop down

* fix: fixed label key value field and chart auto update when eval window changes

* feat: added a link for alert name in list alerts page and source for each rule update

* fix: resolved review coments in querysection of alerts ui

* feat: adding panel user guide in alerting form

* feat: added user guide panel in the alert form

* feat: added more help icon in user guide and fixed the sizing issue

Co-authored-by: Pranshu Chittora <pranshu@signoz.io>
This commit is contained in:
Amol Umbark 2022-07-15 17:48:16 +05:30 committed by GitHub
parent 10c6325e46
commit 7c14a75c68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 270 additions and 49 deletions

View File

@ -59,5 +59,27 @@
"option_critical": "Critical",
"option_error": "Error",
"option_warning": "Warning",
"option_info": "Info"
"option_info": "Info",
"user_guide_headline": "Steps to create an Alert",
"user_guide_qb_step1": "Step 1 - Define the metric",
"user_guide_qb_step1a": "Choose a metric which you want to create an alert on",
"user_guide_qb_step1b": "Filter it based on WHERE field or GROUPBY if needed",
"user_guide_qb_step1c": "Apply an aggregatiion function like COUNT, SUM, etc. or choose NOOP to plot the raw metric",
"user_guide_qb_step1d": "Create a formula based on Queries if needed",
"user_guide_qb_step2": "Step 2 - Define Alert Conditions",
"user_guide_qb_step2a": "Select the evaluation interval, threshold type and whether you want to alert above/below a value",
"user_guide_qb_step2b": "Enter the Alert threshold",
"user_guide_qb_step3": "Step 3 -Alert Configuration",
"user_guide_qb_step3a": "Set alert severity, name and descriptions",
"user_guide_qb_step3b": "Add tags to the alert in the Label field if needed",
"user_guide_pql_step1": "Step 1 - Define the metric",
"user_guide_pql_step1a": "Write a PromQL query for the metric",
"user_guide_pql_step1b": "Format the legends based on labels you want to highlight",
"user_guide_pql_step2": "Step 2 - Define Alert Conditions",
"user_guide_pql_step2a": "Select the threshold type and whether you want to alert above/below a value",
"user_guide_pql_step2b": "Enter the Alert threshold",
"user_guide_pql_step3": "Step 3 -Alert Configuration",
"user_guide_pql_step3a": "Set alert severity, name and descriptions",
"user_guide_pql_step3b": "Add tags to the alert in the Label field if needed",
"user_tooltip_more_help": "More details on how to create alerts"
}

View File

@ -59,5 +59,27 @@
"option_critical": "Critical",
"option_error": "Error",
"option_warning": "Warning",
"option_info": "Info"
"option_info": "Info",
"user_guide_headline": "Steps to create an Alert",
"user_guide_qb_step1": "Step 1 - Define the metric",
"user_guide_qb_step1a": "Choose a metric which you want to create an alert on",
"user_guide_qb_step1b": "Filter it based on WHERE field or GROUPBY if needed",
"user_guide_qb_step1c": "Apply an aggregatiion function like COUNT, SUM, etc. or choose NOOP to plot the raw metric",
"user_guide_qb_step1d": "Create a formula based on Queries if needed",
"user_guide_qb_step2": "Step 2 - Define Alert Conditions",
"user_guide_qb_step2a": "Select the evaluation interval, threshold type and whether you want to alert above/below a value",
"user_guide_qb_step2b": "Enter the Alert threshold",
"user_guide_qb_step3": "Step 3 -Alert Configuration",
"user_guide_qb_step3a": "Set alert severity, name and descriptions",
"user_guide_qb_step3b": "Add tags to the alert in the Label field if needed",
"user_guide_pql_step1": "Step 1 - Define the metric",
"user_guide_pql_step1a": "Write a PromQL query for the metric",
"user_guide_pql_step1b": "Format the legends based on labels you want to highlight",
"user_guide_pql_step2": "Step 2 - Define Alert Conditions",
"user_guide_pql_step2a": "Select the threshold type and whether you want to alert above/below a value",
"user_guide_pql_step2b": "Enter the Alert threshold",
"user_guide_pql_step3": "Step 3 -Alert Configuration",
"user_guide_pql_step3a": "Set alert severity, name and descriptions",
"user_guide_pql_step3b": "Add tags to the alert in the Label field if needed",
"user_tooltip_more_help": "More details on how to create alerts"
}

View File

@ -0,0 +1,132 @@
import { Col, Row, Typography } from 'antd';
import TextToolTip from 'components/TextToolTip';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { EQueryType } from 'types/common/dashboard';
import {
StyledList,
StyledListItem,
StyledMainContainer,
StyledTopic,
} from './styles';
function UserGuide({ queryType }: UserGuideProps): JSX.Element {
// init namespace for translations
const { t } = useTranslation('rules');
const renderStep1QB = (): JSX.Element => {
return (
<>
<StyledTopic>{t('user_guide_qb_step1')}</StyledTopic>
<StyledList>
<StyledListItem>{t('user_guide_qb_step1a')}</StyledListItem>
<StyledListItem>{t('user_guide_qb_step1b')}</StyledListItem>
<StyledListItem>{t('user_guide_qb_step1c')}</StyledListItem>
<StyledListItem>{t('user_guide_qb_step1d')}</StyledListItem>
</StyledList>
</>
);
};
const renderStep2QB = (): JSX.Element => {
return (
<>
<StyledTopic>{t('user_guide_qb_step2')}</StyledTopic>
<StyledList>
<StyledListItem>{t('user_guide_qb_step2a')}</StyledListItem>
<StyledListItem>{t('user_guide_qb_step2b')}</StyledListItem>
</StyledList>
</>
);
};
const renderStep3QB = (): JSX.Element => {
return (
<>
<StyledTopic>{t('user_guide_qb_step3')}</StyledTopic>
<StyledList>
<StyledListItem>{t('user_guide_qb_step3a')}</StyledListItem>
<StyledListItem>{t('user_guide_qb_step3b')}</StyledListItem>
</StyledList>
</>
);
};
const renderGuideForQB = (): JSX.Element => {
return (
<>
{renderStep1QB()}
{renderStep2QB()}
{renderStep3QB()}
</>
);
};
const renderStep1PQL = (): JSX.Element => {
return (
<>
<StyledTopic>{t('user_guide_pql_step1')}</StyledTopic>
<StyledList>
<StyledListItem>{t('user_guide_pql_step1a')}</StyledListItem>
<StyledListItem>{t('user_guide_pql_step1b')}</StyledListItem>
</StyledList>
</>
);
};
const renderStep2PQL = (): JSX.Element => {
return (
<>
<StyledTopic>{t('user_guide_pql_step2')}</StyledTopic>
<StyledList>
<StyledListItem>{t('user_guide_pql_step2a')}</StyledListItem>
<StyledListItem>{t('user_guide_pql_step2b')}</StyledListItem>
</StyledList>
</>
);
};
const renderStep3PQL = (): JSX.Element => {
return (
<>
<StyledTopic>{t('user_guide_pql_step3')}</StyledTopic>
<StyledList>
<StyledListItem>{t('user_guide_pql_step3a')}</StyledListItem>
<StyledListItem>{t('user_guide_pql_step3b')}</StyledListItem>
</StyledList>
</>
);
};
const renderGuideForPQL = (): JSX.Element => {
return (
<>
{renderStep1PQL()}
{renderStep2PQL()}
{renderStep3PQL()}
</>
);
};
return (
<StyledMainContainer>
<Row>
<Col flex="auto">
<Typography.Paragraph> {t('user_guide_headline')} </Typography.Paragraph>
</Col>
<Col flex="none">
<TextToolTip
text={t('user_tooltip_more_help')}
url="https://signoz.io/docs/userguide/alerts-management/#create-alert-rules"
/>
</Col>
</Row>
{queryType === EQueryType.QUERY_BUILDER && renderGuideForQB()}
{queryType === EQueryType.PROM && renderGuideForPQL()}
</StyledMainContainer>
);
}
interface UserGuideProps {
queryType: EQueryType;
}
export default UserGuide;

View File

@ -0,0 +1,17 @@
import { Card, Typography } from 'antd';
import styled from 'styled-components';
export const StyledMainContainer = styled(Card)``;
export const StyledTopic = styled(Typography.Paragraph)`
font-weight: 600;
`;
export const StyledList = styled.ul`
padding-left: 18px;
`;
export const StyledListItem = styled.li`
font-style: italic;
padding-bottom: 0.5rem;
`;

View File

@ -25,8 +25,16 @@ import BasicInfo from './BasicInfo';
import ChartPreview from './ChartPreview';
import QuerySection from './QuerySection';
import RuleOptions from './RuleOptions';
import { ActionButton, ButtonContainer, MainFormContainer } from './styles';
import {
ActionButton,
ButtonContainer,
MainFormContainer,
PanelContainer,
StyledLeftContainer,
StyledRightContainer,
} from './styles';
import useDebounce from './useDebounce';
import UserGuide from './UserGuide';
import {
prepareBuilderQueries,
prepareStagedQuery,
@ -309,50 +317,57 @@ function FormAlertRules({
return (
<>
{Element}
<MainFormContainer
initialValues={initialValue}
layout="vertical"
form={formInstance}
>
{queryCategory === EQueryType.QUERY_BUILDER && renderQBChartPreview()}
{queryCategory === EQueryType.PROM && renderPromChartPreview()}
<QuerySection
queryCategory={queryCategory}
setQueryCategory={onQueryCategoryChange}
metricQueries={metricQueries}
setMetricQueries={setMetricQueries}
formulaQueries={formulaQueries}
setFormulaQueries={setFormulaQueries}
promQueries={promQueries}
setPromQueries={setPromQueries}
/>
<RuleOptions
queryCategory={queryCategory}
alertDef={alertDef}
setAlertDef={setAlertDef}
/>
{renderBasicInfo()}
<ButtonContainer>
<ActionButton
loading={loading || false}
type="primary"
onClick={onSaveHandler}
icon={<SaveOutlined />}
<PanelContainer>
<StyledLeftContainer flex="5 1 600px">
<MainFormContainer
initialValues={initialValue}
layout="vertical"
form={formInstance}
>
{ruleId > 0 ? t('button_savechanges') : t('button_createrule')}
</ActionButton>
<ActionButton
disabled={loading || false}
type="default"
onClick={onCancelHandler}
>
{ruleId === 0 && t('button_cancelchanges')}
{ruleId > 0 && t('button_discard')}
</ActionButton>
</ButtonContainer>
</MainFormContainer>
{queryCategory === EQueryType.QUERY_BUILDER && renderQBChartPreview()}
{queryCategory === EQueryType.PROM && renderPromChartPreview()}
<QuerySection
queryCategory={queryCategory}
setQueryCategory={onQueryCategoryChange}
metricQueries={metricQueries}
setMetricQueries={setMetricQueries}
formulaQueries={formulaQueries}
setFormulaQueries={setFormulaQueries}
promQueries={promQueries}
setPromQueries={setPromQueries}
/>
<RuleOptions
queryCategory={queryCategory}
alertDef={alertDef}
setAlertDef={setAlertDef}
/>
{renderBasicInfo()}
<ButtonContainer>
<ActionButton
loading={loading || false}
type="primary"
onClick={onSaveHandler}
icon={<SaveOutlined />}
>
{ruleId > 0 ? t('button_savechanges') : t('button_createrule')}
</ActionButton>
<ActionButton
disabled={loading || false}
type="default"
onClick={onCancelHandler}
>
{ruleId === 0 && t('button_cancelchanges')}
{ruleId > 0 && t('button_discard')}
</ActionButton>
</ButtonContainer>
</MainFormContainer>
</StyledLeftContainer>
<StyledRightContainer flex="1 1 300px">
<UserGuide queryType={queryCategory} />
</StyledRightContainer>
</PanelContainer>
</>
);
}

View File

@ -1,11 +1,24 @@
import { Button, Card, Form, Input, InputNumber, Select } from 'antd';
import { Button, Card, Col, Form, Input, InputNumber, Row, Select } from 'antd';
import TextArea from 'antd/lib/input/TextArea';
import styled from 'styled-components';
export const MainFormContainer = styled(Form)`
max-width: 900px;
export const PanelContainer = styled(Row)`
flex-wrap: nowrap;
`;
export const StyledRightContainer = styled(Col)`
&&& {
}
`;
export const StyledLeftContainer = styled(Col)`
&&& {
margin-right: 1rem;
}
`;
export const MainFormContainer = styled(Form)``;
export const ButtonContainer = styled.div`
&&& {
display: flex;