Skip to content

Commit

Permalink
Jinja2 based routes (#1319)
Browse files Browse the repository at this point in the history
# What this PR does

This PR adds the new way to set up routes using jinja2 templating
language

<img width="1174" alt="Screenshot 2023-03-06 at 22 11 13"
src="https://user-images.githubusercontent.com/2262529/223134053-69d43c47-bb2a-4790-a16d-767425017a76.png">
<img width="1175" alt="Screenshot 2023-03-06 at 22 11 34"
src="https://user-images.githubusercontent.com/2262529/223134070-1e5ef82f-021c-4d5d-b255-b19bb3445641.png">


## Which issue(s) this PR fixes

## Checklist

- [ ] Tests updated
- [ ] Documentation added
- [ ] `CHANGELOG.md` updated
  • Loading branch information
iskhakov authored Mar 8, 2023
1 parent ca67dab commit d21f66d
Show file tree
Hide file tree
Showing 14 changed files with 261 additions and 108 deletions.
1 change: 0 additions & 1 deletion README.md

This file was deleted.

2 changes: 1 addition & 1 deletion integration-tests/utils/integrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const createIntegrationAndSendDemoAlert = async (
await goToOnCallPageByClickingOnTab(page, 'Integrations');

// open the create integration modal
(await page.waitForSelector('text=New integration for receiving alerts')).click();
(await page.waitForSelector('text=New integration to receive alerts')).click();

// create a webhook integration
(await page.waitForSelector('div[data-testid="create-integration-modal"] >> text=Webhook')).click();
Expand Down
37 changes: 22 additions & 15 deletions src/containers/AlertReceiveChannelCard/AlertReceiveChannelCard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';

import { Tooltip, HorizontalGroup, VerticalGroup } from '@grafana/ui';
import { Tooltip, HorizontalGroup, VerticalGroup, Badge } from '@grafana/ui';
import cn from 'classnames/bind';
import { observer } from 'mobx-react';
import Emoji from 'react-emoji-render';
Expand Down Expand Up @@ -58,30 +58,37 @@ const AlertReceiveChannelCard = observer((props: AlertReceiveChannelCardProps) =
)}
</div>
<VerticalGroup spacing="xs">
<Text type="primary" size="medium">
<Emoji className={cx('title')} text={alertReceiveChannel.verbal_name} />
</Text>

<HorizontalGroup>
<IntegrationLogo scale={0.08} integration={integration} />
<Text type="secondary" size="small">
{integration?.display_name}
</Text>
<Text type="secondary" size="small">
|
<Text type="primary" size="medium">
<Emoji className={cx('title')} text={alertReceiveChannel.verbal_name} />
</Text>
{alertReceiveChannelCounter && (
<PluginLink
query={{ page: 'incidents', integration: alertReceiveChannel.id }}
className={cx('alertsInfoText')}
>
<b>{alertReceiveChannelCounter?.alerts_count}</b> alert
{alertReceiveChannelCounter?.alerts_count === 1 ? '' : 's'} in{' '}
<b>{alertReceiveChannelCounter?.alert_groups_count}</b> Alert Group
{alertReceiveChannelCounter?.alert_groups_count === 1 ? '' : 's'}
<Badge
text={alertReceiveChannelCounter?.alerts_count + '/' + alertReceiveChannelCounter?.alert_groups_count}
color={'blue'}
tooltip={
alertReceiveChannelCounter?.alerts_count +
' alert' +
(alertReceiveChannelCounter?.alerts_count === 1 ? '' : 's') +
' in ' +
alertReceiveChannelCounter?.alert_groups_count +
' alert group' +
(alertReceiveChannelCounter?.alert_groups_count === 1 ? '' : 's')
}
/>
</PluginLink>
)}
</HorizontalGroup>
<HorizontalGroup>
<IntegrationLogo scale={0.08} integration={integration} />
<Text type="secondary" size="small">
{integration?.display_name}
</Text>
</HorizontalGroup>
</VerticalGroup>
</HorizontalGroup>
</div>
Expand Down
23 changes: 14 additions & 9 deletions src/containers/AlertRules/AlertRules.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,18 @@

.channel-filter-header {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 8px;
flex-wrap: wrap-reverse;
}

.channel-filter-header-left,
.channel-filter-header-right {
flex-grow: 1;
margin-bottom: 16px;
}

.channel-filter-header-right {
display: flex;
justify-content: flex-end;
}

.channel-filter-header-title {
Expand Down Expand Up @@ -120,16 +128,13 @@

.integration__heading-container {
display: flex;
flex-wrap: wrap;
}

.integration__heading-container-left {
margin-bottom: 12px;
flex-wrap: wrap-reverse;
}

.integration__heading-container-left,
.integration__heading-container-right {
flex-grow: 1;
margin-bottom: 12px;
}

.integration__heading-container-right {
Expand Down
128 changes: 95 additions & 33 deletions src/containers/AlertRules/AlertRules.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import {
ConfirmModal,
Field,
HorizontalGroup,
Icon,
IconButton,
Input,
LoadingPlaceholder,
Modal,
Tooltip,
VerticalGroup,
} from '@grafana/ui';
import cn from 'classnames/bind';
import { observer } from 'mobx-react';
Expand All @@ -19,6 +21,7 @@ import Emoji from 'react-emoji-render';
import Collapse from 'components/Collapse/Collapse';
import Block from 'components/GBlock/Block';
import PluginLink from 'components/PluginLink/PluginLink';
import SourceCode from 'components/SourceCode/SourceCode';
import Text from 'components/Text/Text';
import WithConfirm from 'components/WithConfirm/WithConfirm';
import { parseEmojis } from 'containers/AlertRules/AlertRules.helpers';
Expand Down Expand Up @@ -261,7 +264,7 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {
onDismiss={() => this.setState({ editIntegrationName: undefined })}
>
<div className={cx('root')} data-testid="edit-integration-name-modal">
<Field invalid={isIntegrationNameempty} label="Integration name">
<Field invalid={isIntegrationNameempty}>
<Input
autoFocus
value={editIntegrationName}
Expand Down Expand Up @@ -694,40 +697,99 @@ class AlertRules extends React.Component<AlertRulesProps, AlertRulesState> {

const index = channelFilterIds.indexOf(channelFilterId);
return (
<div className={cx('channel-filter-header')}>
<div className={cx('channel-filter-header-title')}>
{channelFilter.is_default ? (
<Text type="success">{channelFilterIds.length > 1 ? 'ELSE ' : ''}</Text>
) : (
<>
<Text type="success">{index === 0 ? 'IF ' : 'ELSE IF '}</Text>alert payload matches regex
<Text
keyboard
//@ts-ignore
onClick={this.getEditChannelFilterClickHandler(channelFilter)}
>
{channelFilter.filtering_term}
</Text>
</>
)}
escalate to{' '}
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<div onClick={(e) => e.stopPropagation()}>
<GSelect
showSearch
modelName="escalationChainStore"
displayField="name"
placeholder="Select Escalation Chain"
className={cx('select', 'control', 'no-trigger-collapse-please')}
value={channelFilter.escalation_chain}
onChange={this.getEscalationChainChangeHandler(channelFilterId)}
showWarningIfEmptyValue={true}
/>
<>
<div className={cx('channel-filter-header')}>
<div className={cx('channel-filter-header-left')}>
<div className={cx('channel-filter-header-title')}>
{channelFilter.is_default ? (
<>
{channelFilterIds.length > 1 && <Text keyboard>ELSE</Text>}
<Text>route to escalation chain:</Text>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<div onClick={(e) => e.stopPropagation()}>
<GSelect
showSearch
modelName="escalationChainStore"
displayField="name"
placeholder="Select Escalation Chain"
className={cx('select', 'control', 'no-trigger-collapse-please')}
value={channelFilter.escalation_chain}
onChange={this.getEscalationChainChangeHandler(channelFilterId)}
showWarningIfEmptyValue={true}
width={'auto'}
icon={'list-ul'}
/>
</div>
</WithPermissionControlTooltip>
</>
) : (
<>
<Text keyboard>{index === 0 ? 'IF' : 'ELSE IF'}</Text>
{channelFilter.filtering_term_type === 0 ? (
<>
<Tooltip content={'Recommend you to switch from regular expressions to jinja2 templates'}>
<Text>regular expression</Text>
</Tooltip>
<Tooltip content={'We recommend to switch to jinja2 based routes'}>
<Icon
name="exclamation-circle"
style={{
color: '#FF5286',
}}
/>
</Tooltip>
</>
) : (
<Text>jinja2 expression</Text>
)}
<Text>is</Text>
<Text keyboard>{'True'}</Text>
<Text>{'for new Alert Group:'}</Text>
</>
)}
</div>
</WithPermissionControlTooltip>
</div>
<div className={cx('channel-filter-header-right')}>
<div onClick={(e) => e.stopPropagation()}>{this.renderChannelFilterButtons(channelFilterId, index)}</div>
</div>
</div>
<div onClick={(e) => e.stopPropagation()}>{this.renderChannelFilterButtons(channelFilterId, index)}</div>
</div>
{!channelFilter.is_default && (
<VerticalGroup>
<HorizontalGroup>
{!channelFilter.is_default && (
<>
{channelFilter.filtering_term_type === 0 ? (
<SourceCode showCopyToClipboard={false}>
{'payload =~ "' + channelFilter.filtering_term + '"'}
</SourceCode>
) : (
<SourceCode showCopyToClipboard={false}>{channelFilter.filtering_term}</SourceCode>
)}
</>
)}
</HorizontalGroup>
<HorizontalGroup>
<Text>{'route to escalation chain: '}</Text>
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
<div onClick={(e) => e.stopPropagation()}>
<GSelect
showSearch
modelName="escalationChainStore"
displayField="name"
placeholder="Select Escalation Chain"
className={cx('select', 'control', 'no-trigger-collapse-please')}
value={channelFilter.escalation_chain}
onChange={this.getEscalationChainChangeHandler(channelFilterId)}
showWarningIfEmptyValue={true}
width={'auto'}
icon={'list-ul'}
/>
</div>
</WithPermissionControlTooltip>
</HorizontalGroup>
</VerticalGroup>
)}
</>
);
};

Expand Down
Loading

0 comments on commit d21f66d

Please sign in to comment.