Templates&grouping changes (#2291)
# What this PR does - Fixed newlines in cheatsheat display - Reference templates by keys instead of display names - UI esthetic changes asked by Raphael (borders, sizing, spacing etc) - Increased Demo Alert Modal height - Moved MoveUp/MoveDown on routes to ellipsis on the right - Hide Heartbeat Settings if there's none to display - Removed Telegram request as now the data is available in response
This commit is contained in:
parent
e4788d5732
commit
bc32726fbb
26 changed files with 420 additions and 292 deletions
|
|
@ -1,5 +1,4 @@
|
|||
import { TemplateForEdit, commonTemplateForEdit } from './CommonAlertTemplatesForm.config';
|
||||
|
||||
export interface Template {
|
||||
name: string;
|
||||
group: string;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { TemplateOptions } from 'pages/integration_2/Integration2.config';
|
||||
|
||||
export interface Template {
|
||||
name: string;
|
||||
group: string;
|
||||
|
|
@ -9,6 +11,7 @@ export interface TemplateForEdit {
|
|||
description?: string;
|
||||
additionalData?: {
|
||||
chatOpsName?: string;
|
||||
chatOpsDisplayName?: string;
|
||||
data?: string;
|
||||
additionalDescription?: string;
|
||||
};
|
||||
|
|
@ -18,17 +21,17 @@ export interface TemplateForEdit {
|
|||
export const commonTemplateForEdit: { [id: string]: TemplateForEdit } = {
|
||||
web_title_template: {
|
||||
displayName: 'Web title',
|
||||
name: 'web_title_template',
|
||||
name: TemplateOptions.WebTitle.key,
|
||||
description: '',
|
||||
},
|
||||
web_message_template: {
|
||||
displayName: 'Web message',
|
||||
name: 'web_message_template',
|
||||
name: TemplateOptions.WebMessage.key,
|
||||
description: '',
|
||||
},
|
||||
slack_title_template: {
|
||||
name: 'slack_title_template',
|
||||
displayName: 'Slack title',
|
||||
displayName: TemplateOptions.SlackTitle.key,
|
||||
description: '',
|
||||
additionalData: {
|
||||
chatOpsName: 'slack',
|
||||
|
|
@ -36,22 +39,22 @@ export const commonTemplateForEdit: { [id: string]: TemplateForEdit } = {
|
|||
},
|
||||
},
|
||||
sms_title_template: {
|
||||
name: 'sms_title_template',
|
||||
name: TemplateOptions.SMS.key,
|
||||
displayName: 'Sms title',
|
||||
description: '',
|
||||
},
|
||||
phone_call_title_template: {
|
||||
name: 'phone_call_title_template',
|
||||
name: TemplateOptions.Phone.key,
|
||||
displayName: 'Phone call title',
|
||||
description: '',
|
||||
},
|
||||
email_title_template: {
|
||||
name: 'email_title_template',
|
||||
name: TemplateOptions.EmailTitle.key,
|
||||
displayName: 'Email title',
|
||||
description: '',
|
||||
},
|
||||
telegram_title_template: {
|
||||
name: 'telegram_title_template',
|
||||
name: TemplateOptions.TelegramTitle.key,
|
||||
displayName: 'Telegram title',
|
||||
description: '',
|
||||
additionalData: {
|
||||
|
|
@ -59,7 +62,7 @@ export const commonTemplateForEdit: { [id: string]: TemplateForEdit } = {
|
|||
},
|
||||
},
|
||||
slack_message_template: {
|
||||
name: 'slack_message_template',
|
||||
name: TemplateOptions.SlackMessage.key,
|
||||
displayName: 'Slack message',
|
||||
description: '',
|
||||
additionalData: {
|
||||
|
|
@ -68,12 +71,12 @@ export const commonTemplateForEdit: { [id: string]: TemplateForEdit } = {
|
|||
},
|
||||
},
|
||||
email_message_template: {
|
||||
name: 'email_message_template',
|
||||
name: TemplateOptions.EmailMessage.key,
|
||||
displayName: 'Email message',
|
||||
description: '',
|
||||
},
|
||||
telegram_message_template: {
|
||||
name: 'telegram_message_template',
|
||||
name: TemplateOptions.TelegramMessage.key,
|
||||
displayName: 'Telegram message',
|
||||
description: '',
|
||||
additionalData: {
|
||||
|
|
@ -81,7 +84,7 @@ export const commonTemplateForEdit: { [id: string]: TemplateForEdit } = {
|
|||
},
|
||||
},
|
||||
slack_image_url_template: {
|
||||
name: 'slack_image_url_template',
|
||||
name: TemplateOptions.SlackImage.key,
|
||||
displayName: 'Slack image url',
|
||||
description: '',
|
||||
additionalData: {
|
||||
|
|
@ -90,12 +93,12 @@ export const commonTemplateForEdit: { [id: string]: TemplateForEdit } = {
|
|||
},
|
||||
},
|
||||
web_image_url_template: {
|
||||
name: 'web_image_url_template',
|
||||
name: TemplateOptions.WebImage.key,
|
||||
displayName: 'Web image url',
|
||||
description: '',
|
||||
},
|
||||
telegram_image_url_template: {
|
||||
name: 'telegram_image_url_template',
|
||||
name: TemplateOptions.TelegramImage.key,
|
||||
displayName: 'Telegram image url',
|
||||
description: '',
|
||||
additionalData: {
|
||||
|
|
@ -103,32 +106,29 @@ export const commonTemplateForEdit: { [id: string]: TemplateForEdit } = {
|
|||
},
|
||||
},
|
||||
grouping_id_template: {
|
||||
name: 'grouping_id_template',
|
||||
name: TemplateOptions.Grouping.key,
|
||||
displayName: 'Grouping',
|
||||
description:
|
||||
'Reduce noise, minimize duplication with Alert Grouping, based on time, alert content, and even multiple features at the same time. Check the cheasheet to customize your template.',
|
||||
additionalData: {
|
||||
additionalDescription: 'Alerts with this Grouping ID are grouped together',
|
||||
},
|
||||
},
|
||||
acknowledge_condition_template: {
|
||||
name: 'acknowledge_condition_template',
|
||||
name: TemplateOptions.Autoacknowledge.key,
|
||||
displayName: 'Acknowledge condition',
|
||||
description: '',
|
||||
},
|
||||
resolve_condition_template: {
|
||||
name: 'resolve_condition_template',
|
||||
name: TemplateOptions.Resolve.key,
|
||||
displayName: 'Resolve condition',
|
||||
description:
|
||||
'When monitoring systems return to normal, they can send "resolve" alerts. If Autoresolution Template is True, the alert will resolve its group as "resolved by source". If the group is already resolved, the alert will be added to that group',
|
||||
'When monitoring systems return to normal, they can send "resolve" alerts. OnCall can use these signals to resolve alert groups accordingly.',
|
||||
},
|
||||
source_link_template: {
|
||||
name: 'source_link_template',
|
||||
name: TemplateOptions.SourceLink.key,
|
||||
displayName: 'Source link',
|
||||
description: '',
|
||||
},
|
||||
route_template: {
|
||||
name: 'route_template',
|
||||
name: TemplateOptions.Routing.key,
|
||||
displayName: 'Routing',
|
||||
description:
|
||||
'Routes direct alerts to different escalation chains based on the content, such as severity or region.',
|
||||
|
|
|
|||
|
|
@ -47,7 +47,12 @@ export const genericTemplateCheatSheet: CheatSheetInterface = {
|
|||
{
|
||||
name: 'Markdown refresher',
|
||||
listItems: [
|
||||
{ codeExample: '**bold**, _italic_, >quote, `code`, ```multiline code```, [``](url), - bullet list' },
|
||||
{
|
||||
codeExample: `**bold**, _italic_, >quote, \`code\`,
|
||||
\`\`\`multiline code\`\`\`
|
||||
<slug|url>
|
||||
- bullet list`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
@ -56,10 +61,17 @@ export const genericTemplateCheatSheet: CheatSheetInterface = {
|
|||
{ listItemName: ' {{ payload.labels.foo }} - extract field value' },
|
||||
{
|
||||
listItemName: 'Conditions',
|
||||
codeExample: '{%- if "status" in payload %} \n {{ payload.status }} \n {% endif -%}',
|
||||
codeExample: `{%- if "status" in payload %}
|
||||
{{ payload.status }}
|
||||
{% endif -%}`,
|
||||
},
|
||||
{ listItemName: 'Booleans', codeExample: '{{ payload.status == "resolved" }}' },
|
||||
{
|
||||
listItemName: 'Loops',
|
||||
codeExample: `{% for label in labels %}
|
||||
{{ label.title }}
|
||||
{% endfor %}`,
|
||||
},
|
||||
{ listItemName: 'Booleans', codeExample: '{{ payload.status == “resolved” }}' },
|
||||
{ listItemName: 'Loops', codeExample: '{% for label in labels %} \n {{ label.title }} \n {% endfor %}' },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
@ -132,11 +144,17 @@ export const slackMessageTemplateCheatSheet: CheatSheetInterface = {
|
|||
listItems: [
|
||||
{
|
||||
listItemName: 'Examples Convert Web template in Classic Markdown to Slack markdown',
|
||||
codeExample: '{{ web_message \n| replace("**", "*") \n| regex_replace("/((.*))[(.*)]/", "<$2|$1>") }}',
|
||||
codeExample: `{{
|
||||
web_message
|
||||
| replace("**", "*")
|
||||
| regex_replace("/((.*))[(.*)]/", "<$2|$1>")
|
||||
}}`,
|
||||
},
|
||||
{
|
||||
listItemName: 'Show status if exists',
|
||||
codeExample: '{%- if "status" in payload %} \n **Status**: {{ payload.status }} \n {% endif -%}',
|
||||
codeExample: `{%- if "status" in payload %}
|
||||
**Status**: {{ payload.status }}
|
||||
{% endif -%}`,
|
||||
},
|
||||
{
|
||||
listItemName: 'Show field value or “N/A” is not exist',
|
||||
|
|
@ -144,8 +162,10 @@ export const slackMessageTemplateCheatSheet: CheatSheetInterface = {
|
|||
},
|
||||
{
|
||||
listItemName: 'Iterate over labels dictionary',
|
||||
codeExample:
|
||||
'**Labels:** \n {% for k, v in payload["labels"].items() %} \n *{{ k }}*: {{ v }} \n {% endfor %} ',
|
||||
codeExample: `**Labels:**
|
||||
{% for k, v in payload["labels"].items() %}
|
||||
*{{ k }}*: {{ v }}
|
||||
{% endfor %}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,16 +2,23 @@
|
|||
width: 40%;
|
||||
height: 100%;
|
||||
padding: 16px;
|
||||
padding-right: 0;
|
||||
border: var(--border-weak);
|
||||
min-width: min-content;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.cheatsheet-container > div {
|
||||
|
||||
.cheatsheet-innerContainer {
|
||||
padding-right: 16px;
|
||||
overflow-y: scroll;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
|
||||
> div {
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.cheatsheet-item {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
|
@ -20,3 +27,7 @@
|
|||
margin-bottom: 16px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.code {
|
||||
white-space: pre;
|
||||
}
|
||||
|
|
@ -9,8 +9,7 @@ import Text from 'components/Text/Text';
|
|||
import { openNotification } from 'utils';
|
||||
|
||||
import { CheatSheetInterface, CheatSheetItem } from './CheatSheet.config';
|
||||
|
||||
import styles from './CheatSheet.module.css';
|
||||
import styles from './CheatSheet.module.scss';
|
||||
|
||||
interface CheatSheetProps {
|
||||
cheatSheetName: string;
|
||||
|
|
@ -24,22 +23,24 @@ const CheatSheet = (props: CheatSheetProps) => {
|
|||
const { cheatSheetName, cheatSheetData, onClose } = props;
|
||||
return (
|
||||
<div className={cx('cheatsheet-container')}>
|
||||
<VerticalGroup>
|
||||
<HorizontalGroup justify="space-between">
|
||||
<Text strong>{cheatSheetName} cheatsheet</Text>
|
||||
<IconButton name="times" onClick={onClose} />
|
||||
</HorizontalGroup>
|
||||
<Text type="secondary">{cheatSheetData.description}</Text>
|
||||
<div style={{ width: '100%' }}>
|
||||
{cheatSheetData.fields?.map((field: CheatSheetItem) => {
|
||||
return (
|
||||
<div key={field.name} className={cx('cheatsheet-item')}>
|
||||
<CheatSheetListItem field={field} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</VerticalGroup>
|
||||
<div className={cx('cheatsheet-innerContainer')}>
|
||||
<VerticalGroup>
|
||||
<HorizontalGroup justify="space-between">
|
||||
<Text strong>{cheatSheetName} cheatsheet</Text>
|
||||
<IconButton name="times" onClick={onClose} />
|
||||
</HorizontalGroup>
|
||||
<Text type="secondary">{cheatSheetData.description}</Text>
|
||||
<div className={cx('u-width-100')}>
|
||||
{cheatSheetData.fields?.map((field: CheatSheetItem) => {
|
||||
return (
|
||||
<div key={field.name} className={cx('cheatsheet-item')}>
|
||||
<CheatSheetListItem field={field} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</VerticalGroup>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
@ -65,7 +66,9 @@ const CheatSheetListItem = (props: CheatSheetListItemProps) => {
|
|||
<div className={cx('cheatsheet-item-small')}>
|
||||
<Block bordered fullWidth withBackground>
|
||||
<HorizontalGroup justify="space-between">
|
||||
<Text type="link">{item.codeExample}</Text>
|
||||
<Text type="link" className={cx('code')}>
|
||||
{item.codeExample}
|
||||
</Text>
|
||||
<CopyToClipboard text={item.codeExample} onCopy={() => openNotification('Example copied')}>
|
||||
<IconButton name="copy" />
|
||||
</CopyToClipboard>
|
||||
|
|
|
|||
|
|
@ -5,17 +5,24 @@
|
|||
|
||||
.integrationBlock__heading {
|
||||
background-color: var(--background-secondary);
|
||||
border: none;
|
||||
border: var(--border-medium) !important;
|
||||
border-radius: 0 !important;
|
||||
border-top-left-radius: 4px !important;
|
||||
border-top-right-radius: 4px !important;
|
||||
}
|
||||
|
||||
.integrationBlock__content {
|
||||
background: var(--background-primary);
|
||||
border: var(--border-weak);
|
||||
border: var(--border-medium) !important;
|
||||
|
||||
border-top: none !important;
|
||||
padding-bottom: 0;
|
||||
border-bottom-left-radius: 4px !important;
|
||||
border-bottom-right-radius: 4px !important;
|
||||
|
||||
&--collapsedBorder {
|
||||
border-left: none;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
flex-direction: row;
|
||||
margin-bottom: 4px;
|
||||
max-width: 100%;
|
||||
margin-left: 16px;
|
||||
|
||||
&__content {
|
||||
width: 100%;
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ const IntegrationTemplateBlock: React.FC<IntegrationTemplateBlockProps> = ({
|
|||
</Tooltip>
|
||||
</WithPermissionControlTooltip>
|
||||
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
|
||||
<Tooltip content={'Reset Template to default'}>
|
||||
<Tooltip content={'Reset template to default'}>
|
||||
<Button variant={'secondary'} icon={'times'} size={'md'} onClick={onRemove} />
|
||||
</Tooltip>
|
||||
</WithPermissionControlTooltip>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
display: flex;
|
||||
white-space: nowrap;
|
||||
flex-direction: row;
|
||||
gap: 8px;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
&__item--large {
|
||||
|
|
@ -32,3 +32,21 @@
|
|||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.collapsedRoute {
|
||||
&__container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
&__item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { useState } from 'react';
|
||||
|
||||
import { ConfirmModal, HorizontalGroup, Icon, VerticalGroup } from '@grafana/ui';
|
||||
import { ConfirmModal, HorizontalGroup, Icon } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
|
|
@ -63,6 +63,7 @@ const CollapsedIntegrationRouteDisplay: React.FC<CollapsedIntegrationRouteDispla
|
|||
alertReceiveChannelStore.channelFilterIds[alertReceiveChannelId],
|
||||
routeIndex
|
||||
)}
|
||||
className={cx('u-margin-right-xs')}
|
||||
tooltipContent={undefined}
|
||||
/>
|
||||
{routeWording === 'Default' && <Text type="secondary">Unmatched alerts routed to default route</Text>}
|
||||
|
|
@ -95,29 +96,31 @@ const CollapsedIntegrationRouteDisplay: React.FC<CollapsedIntegrationRouteDispla
|
|||
}
|
||||
content={
|
||||
<div className={cx('spacing')}>
|
||||
<VerticalGroup>
|
||||
<div className={cx('collapsedRoute__container')}>
|
||||
{chatOpsAvailableChannels.length > 0 && (
|
||||
<HorizontalGroup spacing="xs">
|
||||
<Text type="secondary">Publish to ChatOps</Text>
|
||||
<div className={cx('collapsedRoute__item')}>
|
||||
<HorizontalGroup spacing="xs">
|
||||
<Text type="secondary">Publish to ChatOps</Text>
|
||||
|
||||
{chatOpsAvailableChannels
|
||||
.filter((it) => it)
|
||||
.map((chatOpsChannel) => (
|
||||
<>
|
||||
<Icon name={chatOpsChannel.icon} />
|
||||
<Text type="primary" strong>
|
||||
{chatOpsChannel.name}
|
||||
</Text>
|
||||
</>
|
||||
))}
|
||||
</HorizontalGroup>
|
||||
{chatOpsAvailableChannels
|
||||
.filter((it) => it)
|
||||
.map((chatOpsChannel) => (
|
||||
<>
|
||||
<Icon name={chatOpsChannel.icon} className={cx('icon')} />
|
||||
<Text type="primary">{chatOpsChannel.name}</Text>
|
||||
</>
|
||||
))}
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<HorizontalGroup>
|
||||
<HorizontalGroup spacing={'xs'}>
|
||||
<div className={cx('collapsedRoute__item')}>
|
||||
<div className={cx('u-flex', 'u-align-items-center', 'u-flex-xs')}>
|
||||
<Icon name="list-ui-alt" />
|
||||
<Text type="secondary">Trigger escalation chain</Text>
|
||||
</HorizontalGroup>
|
||||
<Text type="secondary" className={cx('u-margin-right-xs')}>
|
||||
Trigger escalation chain
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
{escalationChain?.name && (
|
||||
<PluginLink
|
||||
|
|
@ -130,15 +133,15 @@ const CollapsedIntegrationRouteDisplay: React.FC<CollapsedIntegrationRouteDispla
|
|||
)}
|
||||
|
||||
{!escalationChain?.name && (
|
||||
<HorizontalGroup spacing={'xs'}>
|
||||
<div className={cx('u-flex', 'u-align-items-center', 'u-flex-xs')}>
|
||||
<div className={cx('icon-exclamation')}>
|
||||
<Icon name="exclamation-triangle" />
|
||||
</div>
|
||||
<Text type="primary">Not selected</Text>
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
)}
|
||||
</HorizontalGroup>
|
||||
</VerticalGroup>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ import { AlertReceiveChannel } from 'models/alert_receive_channel/alert_receive_
|
|||
import { AlertTemplatesDTO } from 'models/alert_templates';
|
||||
import { ChannelFilter } from 'models/channel_filter/channel_filter.types';
|
||||
import CommonIntegrationHelper from 'pages/integration_2/CommonIntegration2.helper';
|
||||
import { MONACO_INPUT_HEIGHT_SMALL, MONACO_OPTIONS } from 'pages/integration_2/Integration2.config';
|
||||
import IntegrationHelper from 'pages/integration_2/Integration2.helper';
|
||||
import { MONACO_INPUT_HEIGHT_SMALL, MONACO_OPTIONS } from 'pages/integration_2/Integration2Common.config';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { openNotification } from 'utils';
|
||||
import { UserActions } from 'utils/authorization';
|
||||
|
|
@ -121,6 +121,7 @@ const ExpandedIntegrationRouteDisplay: React.FC<ExpandedIntegrationRouteDisplayP
|
|||
text={CommonIntegrationHelper.getRouteConditionWording(channelFilterIds, routeIndex)}
|
||||
tooltipTitle={CommonIntegrationHelper.getRouteConditionTooltipWording(channelFilterIds, routeIndex)}
|
||||
tooltipContent={undefined}
|
||||
className={cx('u-margin-right-xs')}
|
||||
/>
|
||||
</HorizontalGroup>
|
||||
<HorizontalGroup spacing={'xs'}>
|
||||
|
|
@ -323,26 +324,36 @@ export const RouteButtonsDisplay: React.FC<RouteButtonsDisplayProps> = ({
|
|||
|
||||
return (
|
||||
<HorizontalGroup spacing={'xs'}>
|
||||
{routeIndex > 0 && !channelFilter.is_default && (
|
||||
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
|
||||
<Tooltip placement="top" content={'Move Up'}>
|
||||
<Button variant={'secondary'} onClick={onRouteMoveUp} icon={'arrow-up'} size={'sm'} />
|
||||
</Tooltip>
|
||||
</WithPermissionControlTooltip>
|
||||
)}
|
||||
|
||||
{routeIndex < channelFilterIds.length - 2 && !channelFilter.is_default && (
|
||||
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
|
||||
<Tooltip placement="top" content={'Move Down'}>
|
||||
<Button variant={'secondary'} onClick={onRouteMoveDown} icon={'arrow-down'} size={'sm'} />
|
||||
</Tooltip>
|
||||
</WithPermissionControlTooltip>
|
||||
)}
|
||||
|
||||
{!channelFilter.is_default && (
|
||||
<WithContextMenu
|
||||
renderMenuItems={() => (
|
||||
<div className={cx('integrations-actionsList')}>
|
||||
{routeIndex > 0 && !channelFilter.is_default && (
|
||||
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
|
||||
<div className={cx('integrations-actionItem')}>
|
||||
<HorizontalGroup spacing="xs">
|
||||
<Icon name="arrow-up" />
|
||||
<Text type="primary" onClick={onRouteMoveUp}>
|
||||
Move Up
|
||||
</Text>
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
</WithPermissionControlTooltip>
|
||||
)}
|
||||
|
||||
{routeIndex < channelFilterIds.length - 2 && !channelFilter.is_default && (
|
||||
<WithPermissionControlTooltip userAction={UserActions.IntegrationsWrite}>
|
||||
<div className={cx('integrations-actionItem')}>
|
||||
<HorizontalGroup spacing="xs">
|
||||
<Icon name={'arrow-down'} />
|
||||
<Text type="primary" onClick={onRouteMoveDown}>
|
||||
Move Down
|
||||
</Text>
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
</WithPermissionControlTooltip>
|
||||
)}
|
||||
|
||||
<CopyToClipboard text={channelFilter.id} onCopy={() => openNotification('Route ID is copied')}>
|
||||
<div className={cx('integrations-actionItem')}>
|
||||
<HorizontalGroup spacing={'xs'}>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { MONACO_INPUT_HEIGHT_SMALL, MONACO_INPUT_HEIGHT_TALL } from 'pages/integration_2/Integration2.config';
|
||||
import { MONACO_INPUT_HEIGHT_SMALL, MONACO_INPUT_HEIGHT_TALL } from 'pages/integration_2/Integration2Common.config';
|
||||
|
||||
interface TemplateToRender {
|
||||
name: string;
|
||||
|
|
|
|||
|
|
@ -10,9 +10,9 @@ import Text from 'components/Text/Text';
|
|||
import { templatesToRender } from 'containers/IntegrationContainers/IntegrationTemplatesList.config';
|
||||
import { AlertReceiveChannel } from 'models/alert_receive_channel/alert_receive_channel.types';
|
||||
import { AlertTemplatesDTO } from 'models/alert_templates';
|
||||
import { MONACO_INPUT_HEIGHT_TALL, MONACO_OPTIONS } from 'pages/integration_2/Integration2.config';
|
||||
import IntegrationHelper from 'pages/integration_2/Integration2.helper';
|
||||
import styles from 'pages/integration_2/Integration2.module.scss';
|
||||
import { MONACO_INPUT_HEIGHT_TALL, MONACO_OPTIONS } from 'pages/integration_2/Integration2Common.config';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { openErrorNotification, openNotification } from 'utils';
|
||||
|
||||
|
|
@ -90,11 +90,15 @@ const IntegrationTemplateList: React.FC<IntegrationTemplateListProps> = ({
|
|||
<>
|
||||
{isResolveConditionTemplate(contents.name) && (
|
||||
<Tooltip content={'Edit'}>
|
||||
<InlineSwitch value={autoresolveValue} onChange={handleSaveClick} />
|
||||
<InlineSwitch
|
||||
value={autoresolveValue}
|
||||
onChange={handleSaveClick}
|
||||
className={cx('inline-switch')}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
{isResolveConditionTemplateEditable(contents.name) && (
|
||||
<div className={cx('input')}>
|
||||
<div className={cx('input', { 'input-with-toggle': isResolveConditionTemplate(contents.name) })}>
|
||||
<MonacoEditor
|
||||
value={IntegrationHelper.getFilteredTemplate(
|
||||
templates[contents.name] || '',
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
max-height: 100%;
|
||||
width: 100%;
|
||||
border: var(--border-strong);
|
||||
padding-left: 16px;
|
||||
}
|
||||
|
||||
.template-block-title {
|
||||
|
|
@ -53,7 +54,9 @@
|
|||
.template-block-result {
|
||||
width: 30%;
|
||||
overflow-y: scroll !important;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
.result {
|
||||
padding: 0 16px;
|
||||
padding-bottom: 60px;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { AlertReceiveChannel } from 'models/alert_receive_channel/alert_receive_
|
|||
import { AlertTemplatesDTO } from 'models/alert_templates';
|
||||
import { Alert } from 'models/alertgroup/alertgroup.types';
|
||||
import { ChannelFilter } from 'models/channel_filter/channel_filter.types';
|
||||
import { TemplateOptions } from 'pages/integration_2/Integration2.config';
|
||||
import { waitForElement } from 'utils/DOM';
|
||||
import LocationHelper from 'utils/LocationHelper';
|
||||
import { UserActions } from 'utils/authorization';
|
||||
|
|
@ -124,27 +125,27 @@ const IntegrationTemplate = observer((props: IntegrationTemplateProps) => {
|
|||
}
|
||||
}, [onUpdateTemplates, changedTemplateBody]);
|
||||
|
||||
const getCheatSheet = (templateName) => {
|
||||
switch (templateName) {
|
||||
case 'Grouping':
|
||||
case 'Autoresolve':
|
||||
const getCheatSheet = (templateKey: string) => {
|
||||
switch (templateKey) {
|
||||
case TemplateOptions.Grouping.key:
|
||||
case TemplateOptions.Resolve.key:
|
||||
return groupingTemplateCheatSheet;
|
||||
case 'Web title':
|
||||
case 'Web message':
|
||||
case 'Web image':
|
||||
case TemplateOptions.WebTitle.key:
|
||||
case TemplateOptions.WebMessage.key:
|
||||
case TemplateOptions.WebImage.key:
|
||||
return genericTemplateCheatSheet;
|
||||
case 'Auto acknowledge':
|
||||
case 'Source link':
|
||||
case 'Phone call':
|
||||
case 'SMS':
|
||||
case 'Slack title':
|
||||
case 'Slack message':
|
||||
case 'Slack image':
|
||||
case 'Telegram title':
|
||||
case 'Telegram message':
|
||||
case 'Telegram image':
|
||||
case 'Email title':
|
||||
case 'Email message':
|
||||
case TemplateOptions.Autoacknowledge.key:
|
||||
case TemplateOptions.SourceLink.key:
|
||||
case TemplateOptions.Phone.key:
|
||||
case TemplateOptions.SMS.key:
|
||||
case TemplateOptions.SlackTitle.key:
|
||||
case TemplateOptions.SlackMessage.key:
|
||||
case TemplateOptions.SlackImage.key:
|
||||
case TemplateOptions.TelegramTitle.key:
|
||||
case TemplateOptions.TelegramMessage.key:
|
||||
case TemplateOptions.TelegramImage.key:
|
||||
case TemplateOptions.EmailTitle.key:
|
||||
case TemplateOptions.EmailMessage.key:
|
||||
return slackMessageTemplateCheatSheet;
|
||||
default:
|
||||
return genericTemplateCheatSheet;
|
||||
|
|
@ -190,7 +191,7 @@ const IntegrationTemplate = observer((props: IntegrationTemplateProps) => {
|
|||
{isCheatSheetVisible ? (
|
||||
<CheatSheet
|
||||
cheatSheetName={template.displayName}
|
||||
cheatSheetData={getCheatSheet(template.displayName)}
|
||||
cheatSheetData={getCheatSheet(template.name)}
|
||||
onClose={onCloseCheatSheet}
|
||||
/>
|
||||
) : (
|
||||
|
|
@ -201,7 +202,7 @@ const IntegrationTemplate = observer((props: IntegrationTemplateProps) => {
|
|||
<Text>Template editor</Text>
|
||||
|
||||
<Button variant="secondary" fill="outline" onClick={onShowCheatSheet} icon="book" size="sm">
|
||||
Cheatsheat
|
||||
Cheatsheet
|
||||
</Button>
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
|
|
@ -249,9 +250,6 @@ const Result = (props: ResultProps) => {
|
|||
const { alertReceiveChannelId, template, templateBody, chatOpsPermalink, payload, error, onSaveAndFollowLink } =
|
||||
props;
|
||||
|
||||
const getCapitalizedChatopsName = (name: string) => {
|
||||
return name.charAt(0).toUpperCase() + name.slice(1);
|
||||
};
|
||||
return (
|
||||
<div className={cx('template-block-result')}>
|
||||
<div className={cx('template-block-title')}>
|
||||
|
|
@ -286,7 +284,7 @@ const Result = (props: ResultProps) => {
|
|||
<VerticalGroup>
|
||||
<Button onClick={() => onSaveAndFollowLink(chatOpsPermalink)}>
|
||||
<HorizontalGroup spacing="xs" align="center">
|
||||
Save and open Alert Group in {getCapitalizedChatopsName(template.additionalData.chatOpsName)}{' '}
|
||||
Save and open Alert Group in {template.additionalData.chatOpsDisplayName}{' '}
|
||||
<Icon name="external-link-alt" />
|
||||
</HorizontalGroup>
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import TooltipBadge from 'components/TooltipBadge/TooltipBadge';
|
|||
import { AlertReceiveChannel } from 'models/alert_receive_channel/alert_receive_channel.types';
|
||||
import { AlertTemplatesDTO } from 'models/alert_templates';
|
||||
import { Alert } from 'models/alertgroup/alertgroup.types';
|
||||
import { MONACO_PAYLOAD_OPTIONS } from 'pages/integration_2/Integration2.config';
|
||||
import { MONACO_OPTIONS, MONACO_PAYLOAD_OPTIONS } from 'pages/integration_2/Integration2Common.config';
|
||||
import { useStore } from 'state/useStore';
|
||||
|
||||
import styles from './TemplatesAlertGroupsList.module.css';
|
||||
|
|
@ -129,6 +129,7 @@ const TemplatesAlertGroupsList = (props: TemplatesAlertGroupsListProps) => {
|
|||
className={cx('alert-groups-last-payload-badge')}
|
||||
/>
|
||||
<div className={cx('alert-groups-editor-withBadge')}>
|
||||
{/* Editor used for Editing Given Payload */}
|
||||
<MonacoEditor
|
||||
value={JSON.stringify(selectedAlertPayload, null, 4)}
|
||||
data={undefined}
|
||||
|
|
@ -167,8 +168,10 @@ const TemplatesAlertGroupsList = (props: TemplatesAlertGroupsListProps) => {
|
|||
useAutoCompleteList={false}
|
||||
language={MONACO_LANGUAGE.json}
|
||||
data={templates}
|
||||
monacoOptions={MONACO_PAYLOAD_OPTIONS}
|
||||
showLineNumbers
|
||||
monacoOptions={{
|
||||
...MONACO_OPTIONS,
|
||||
readOnly: false,
|
||||
}}
|
||||
height={getCodeEditorHeight()}
|
||||
onChange={getChangeHandler()}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { AlertReceiveChannel } from 'models/alert_receive_channel/alert_receive_channel.types';
|
||||
import { EscalationChain } from 'models/escalation_chain/escalation_chain.types';
|
||||
import { SlackChannel } from 'models/slack_channel/slack_channel.types';
|
||||
import { TelegramChannel } from 'models/telegram_channel/telegram_channel.types';
|
||||
import { TelegramChannel, TelegramChannelDetails } from 'models/telegram_channel/telegram_channel.types';
|
||||
|
||||
export enum FilteringTermType {
|
||||
regex,
|
||||
|
|
@ -15,6 +15,7 @@ export interface ChannelFilter {
|
|||
slack_channel_id?: SlackChannel['id'];
|
||||
slack_channel?: SlackChannel;
|
||||
telegram_channel?: TelegramChannel['id'];
|
||||
telegram_channel_details?: TelegramChannelDetails;
|
||||
created_at: string;
|
||||
filtering_term: string;
|
||||
filtering_term_as_jinja2: string;
|
||||
|
|
|
|||
|
|
@ -6,3 +6,8 @@ export interface TelegramChannel {
|
|||
discussion_group_name: string;
|
||||
is_default_channel: false;
|
||||
}
|
||||
|
||||
export interface TelegramChannelDetails {
|
||||
display_name: string;
|
||||
id: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,125 +3,12 @@
|
|||
Any change to this file needs to be done in the oncall-private also
|
||||
*/
|
||||
|
||||
import { KeyValuePair } from 'utils';
|
||||
import { BASE_INTEGRATION_TEMPLATES_LIST, BaseTemplateOptions } from './Integration2Common.config';
|
||||
|
||||
export const TEXTAREA_ROWS_COUNT = 4;
|
||||
export const MAX_CHARACTERS_COUNT = 50;
|
||||
|
||||
export const MONACO_OPTIONS = {
|
||||
renderLineHighlight: false,
|
||||
readOnly: true,
|
||||
scrollbar: {
|
||||
vertical: 'hidden',
|
||||
horizontal: 'hidden',
|
||||
verticalScrollbarSize: 0,
|
||||
handleMouseWheel: false,
|
||||
},
|
||||
hideCursorInOverviewRuler: true,
|
||||
minimap: { enabled: false },
|
||||
cursorStyle: {
|
||||
display: 'none',
|
||||
},
|
||||
export const TemplateOptions = {
|
||||
...BaseTemplateOptions,
|
||||
};
|
||||
|
||||
export const MONACO_PAYLOAD_OPTIONS = {
|
||||
renderLineHighlight: false,
|
||||
readOnly: false,
|
||||
hideCursorInOverviewRuler: true,
|
||||
minimap: { enabled: false },
|
||||
cursorStyle: {
|
||||
display: 'none',
|
||||
},
|
||||
export const INTEGRATION_TEMPLATES_LIST = {
|
||||
...BASE_INTEGRATION_TEMPLATES_LIST,
|
||||
};
|
||||
|
||||
export const MONACO_INPUT_HEIGHT_SMALL = '32px';
|
||||
export const MONACO_INPUT_HEIGHT_TALL = '120px';
|
||||
|
||||
const TemplateOptions = {
|
||||
SourceLink: new KeyValuePair('source_link_template', 'Source Link'),
|
||||
Autoacknowledge: new KeyValuePair('acknowledge_condition_template', 'Autoacknowledge'),
|
||||
Phone: new KeyValuePair('phone_call_title_template', 'Phone'),
|
||||
SMS: new KeyValuePair('sms_title_template', 'SMS'),
|
||||
SlackTitle: new KeyValuePair('slack_title_template', 'Title'),
|
||||
SlackMessage: new KeyValuePair('slack_message_template', 'Message'),
|
||||
SlackImage: new KeyValuePair('slack_image_url_template', 'Image'),
|
||||
EmailTitle: new KeyValuePair('email_title_template', 'Title'),
|
||||
EmailMessage: new KeyValuePair('email_message_template', 'Message'),
|
||||
TelegramTitle: new KeyValuePair('telegram_title_template', 'Title'),
|
||||
TelegramMessage: new KeyValuePair('telegram_message_template', 'Message'),
|
||||
TelegramImage: new KeyValuePair('telegram_image_url_template', 'Image'),
|
||||
|
||||
Email: new KeyValuePair('Email', 'Email'),
|
||||
Slack: new KeyValuePair('Slack', 'Slack'),
|
||||
MSTeams: new KeyValuePair('Microsoft Teams', 'Microsoft Teams'),
|
||||
Telegram: new KeyValuePair('Telegram', 'Telegram'),
|
||||
};
|
||||
|
||||
export const INTEGRATION_TEMPLATES_LIST = [
|
||||
{
|
||||
label: TemplateOptions.SourceLink.value,
|
||||
value: TemplateOptions.SourceLink.key,
|
||||
},
|
||||
{
|
||||
label: TemplateOptions.Autoacknowledge.value,
|
||||
value: TemplateOptions.Autoacknowledge.key,
|
||||
},
|
||||
{
|
||||
label: TemplateOptions.Phone.value,
|
||||
value: TemplateOptions.Phone.key,
|
||||
},
|
||||
{
|
||||
label: TemplateOptions.SMS.value,
|
||||
value: TemplateOptions.SMS.key,
|
||||
},
|
||||
{
|
||||
label: TemplateOptions.Email.value,
|
||||
value: TemplateOptions.Email.key,
|
||||
children: [
|
||||
{
|
||||
label: TemplateOptions.EmailTitle.value,
|
||||
value: TemplateOptions.EmailTitle.key,
|
||||
},
|
||||
{
|
||||
label: TemplateOptions.EmailMessage.value,
|
||||
value: TemplateOptions.EmailMessage.key,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: TemplateOptions.Slack.value,
|
||||
value: TemplateOptions.Slack.key,
|
||||
children: [
|
||||
{
|
||||
label: TemplateOptions.SlackTitle.value,
|
||||
value: TemplateOptions.SlackTitle.key,
|
||||
},
|
||||
{
|
||||
label: TemplateOptions.SlackMessage.value,
|
||||
value: TemplateOptions.SlackMessage.key,
|
||||
},
|
||||
{
|
||||
label: TemplateOptions.SlackImage.value,
|
||||
value: TemplateOptions.SlackImage.key,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: TemplateOptions.Telegram.value,
|
||||
value: TemplateOptions.Telegram.key,
|
||||
children: [
|
||||
{
|
||||
label: TemplateOptions.TelegramTitle.value,
|
||||
value: TemplateOptions.TelegramTitle.key,
|
||||
},
|
||||
{
|
||||
label: TemplateOptions.TelegramMessage.value,
|
||||
value: TemplateOptions.TelegramMessage.key,
|
||||
},
|
||||
{
|
||||
label: TemplateOptions.TelegramImage.value,
|
||||
value: TemplateOptions.TelegramImage.key,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { ChannelFilter } from 'models/channel_filter/channel_filter.types';
|
|||
import { RootStore } from 'state';
|
||||
import { AppFeature } from 'state/features';
|
||||
|
||||
import { MAX_CHARACTERS_COUNT, TEXTAREA_ROWS_COUNT } from './Integration2.config';
|
||||
import { MAX_CHARACTERS_COUNT, TEXTAREA_ROWS_COUNT } from './Integration2Common.config';
|
||||
|
||||
const IntegrationHelper = {
|
||||
getFilteredTemplate: (template: string, isTextArea: boolean): string => {
|
||||
|
|
@ -63,7 +63,6 @@ const IntegrationHelper = {
|
|||
|
||||
getChatOpsChannels(channelFilter: ChannelFilter, store: RootStore): Array<{ name: string; icon: IconName }> {
|
||||
const channels: Array<{ name: string; icon: IconName }> = [];
|
||||
const telegram = Object.keys(store.telegramChannelStore.items).map((k) => store.telegramChannelStore.items[k]);
|
||||
|
||||
if (store.hasFeature(AppFeature.Slack) && channelFilter.notify_in_slack) {
|
||||
const matchingSlackChannel = store.teamStore.currentTeam?.slack_channel?.id
|
||||
|
|
@ -77,15 +76,12 @@ const IntegrationHelper = {
|
|||
}
|
||||
}
|
||||
|
||||
const matchingTelegram = telegram.find((t) => t.id === channelFilter.telegram_channel);
|
||||
|
||||
if (
|
||||
store.hasFeature(AppFeature.Telegram) &&
|
||||
channelFilter.telegram_channel &&
|
||||
channelFilter.notify_in_telegram &&
|
||||
matchingTelegram?.channel_name
|
||||
channelFilter.telegram_channel_details &&
|
||||
channelFilter.notify_in_telegram
|
||||
) {
|
||||
channels.push({ name: matchingTelegram.channel_name, icon: 'telegram-alt' });
|
||||
channels.push({ name: channelFilter.telegram_channel_details.display_name, icon: 'telegram-alt' });
|
||||
}
|
||||
|
||||
return channels;
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ $LARGE-MARGIN: 24px;
|
|||
|
||||
&__description {
|
||||
display: block;
|
||||
margin-bottom: $LARGE-MARGIN;
|
||||
margin-bottom: 32px;;
|
||||
}
|
||||
|
||||
&__counter {
|
||||
|
|
@ -118,6 +118,9 @@ $LARGE-MARGIN: 24px;
|
|||
flex-grow: 1;
|
||||
max-width: calc(100% - 80px);
|
||||
}
|
||||
.input-with-toggler {
|
||||
max-width: calc(100% - 134px);
|
||||
}
|
||||
|
||||
.how-to-connect__container {
|
||||
display: flex;
|
||||
|
|
@ -205,3 +208,11 @@ $LARGE-MARGIN: 24px;
|
|||
gap: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.radius {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.inline-switch {
|
||||
height: 34px;
|
||||
}
|
||||
|
|
@ -58,10 +58,9 @@ import {
|
|||
import { AlertTemplatesDTO } from 'models/alert_templates';
|
||||
import { ChannelFilter } from 'models/channel_filter';
|
||||
import { MaintenanceType } from 'models/maintenance/maintenance.types';
|
||||
import { INTEGRATION_TEMPLATES_LIST, MONACO_PAYLOAD_OPTIONS } from 'pages/integration_2/Integration2.config';
|
||||
import { INTEGRATION_TEMPLATES_LIST } from 'pages/integration_2/Integration2.config';
|
||||
import IntegrationHelper from 'pages/integration_2/Integration2.helper';
|
||||
import styles from 'pages/integration_2/Integration2.module.scss';
|
||||
import { AppFeature } from 'state/features';
|
||||
import { PageProps, SelectOption, WithStoreProps } from 'state/types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { withMobXProviderContext } from 'state/withStore';
|
||||
|
|
@ -72,6 +71,8 @@ import { UserActions } from 'utils/authorization';
|
|||
import { PLUGIN_ROOT } from 'utils/consts';
|
||||
import sanitize from 'utils/sanitize';
|
||||
|
||||
import { MONACO_PAYLOAD_OPTIONS } from './Integration2Common.config';
|
||||
|
||||
const cx = cn.bind(styles);
|
||||
|
||||
interface Integration2Props extends WithStoreProps, PageProps, RouteComponentProps<{ id: string }> {}
|
||||
|
|
@ -118,15 +119,9 @@ class Integration2 extends React.Component<Integration2Props, Integration2State>
|
|||
} = this.props;
|
||||
|
||||
const {
|
||||
store,
|
||||
store: { alertReceiveChannelStore, telegramChannelStore },
|
||||
store: { alertReceiveChannelStore },
|
||||
} = this.props;
|
||||
|
||||
if (store.hasFeature(AppFeature.Telegram)) {
|
||||
// workaround until we get the whole telegram data in response
|
||||
telegramChannelStore.updateItems();
|
||||
}
|
||||
|
||||
if (query?.template) {
|
||||
this.openEditTemplateModal(query.template, query.routeId && query.routeId);
|
||||
}
|
||||
|
|
@ -311,7 +306,7 @@ class Integration2 extends React.Component<Integration2Props, Integration2State>
|
|||
border={getVar('--border-weak')}
|
||||
className={cx('tag')}
|
||||
>
|
||||
<Text type="primary" size="small">
|
||||
<Text type="primary" size="small" className={cx('radius')}>
|
||||
Templates
|
||||
</Text>
|
||||
</Tag>
|
||||
|
|
@ -677,7 +672,7 @@ const IntegrationSendDemoPayloadModal: React.FC<IntegrationSendDemoPayloadModalP
|
|||
<MonacoEditor
|
||||
value={initialDemoJSON}
|
||||
disabled={true}
|
||||
height={`200px`}
|
||||
height={`60vh`}
|
||||
useAutoCompleteList={false}
|
||||
language={MONACO_LANGUAGE.json}
|
||||
data={undefined}
|
||||
|
|
@ -736,7 +731,7 @@ const IntegrationActions: React.FC<IntegrationActionsProps> = ({
|
|||
alertReceiveChannel,
|
||||
changeIsTemplateSettingsOpen,
|
||||
}) => {
|
||||
const { maintenanceStore, alertReceiveChannelStore } = useStore();
|
||||
const { maintenanceStore, alertReceiveChannelStore, heartbeatStore } = useStore();
|
||||
|
||||
const history = useHistory();
|
||||
|
||||
|
|
@ -830,11 +825,13 @@ const IntegrationActions: React.FC<IntegrationActionsProps> = ({
|
|||
<Text type="primary">Integration Settings</Text>
|
||||
</div>
|
||||
|
||||
<WithPermissionControlTooltip key="ok" userAction={UserActions.IntegrationsWrite}>
|
||||
<div className={cx('integration__actionItem')} onClick={() => setIsHearbeatFormOpen(true)}>
|
||||
Hearbeat Settings
|
||||
</div>
|
||||
</WithPermissionControlTooltip>
|
||||
{showHeartbeatSettings() && (
|
||||
<WithPermissionControlTooltip key="ok" userAction={UserActions.IntegrationsWrite}>
|
||||
<div className={cx('integration__actionItem')} onClick={() => setIsHearbeatFormOpen(true)}>
|
||||
Heartbeat Settings
|
||||
</div>
|
||||
</WithPermissionControlTooltip>
|
||||
)}
|
||||
|
||||
{!alertReceiveChannel.maintenance_till && (
|
||||
<WithPermissionControlTooltip userAction={UserActions.MaintenanceWrite}>
|
||||
|
|
@ -935,6 +932,12 @@ const IntegrationActions: React.FC<IntegrationActionsProps> = ({
|
|||
</>
|
||||
);
|
||||
|
||||
function showHeartbeatSettings() {
|
||||
const heartbeatId = alertReceiveChannelStore.alertReceiveChannelToHeartbeat[alertReceiveChannel.id];
|
||||
const heartbeat = heartbeatStore.items[heartbeatId];
|
||||
return !!heartbeat?.last_heartbeat_time_verbal;
|
||||
}
|
||||
|
||||
function deleteIntegration() {
|
||||
alertReceiveChannelStore
|
||||
.deleteAlertReceiveChannel(alertReceiveChannel.id)
|
||||
|
|
@ -976,7 +979,7 @@ const HowToConnectComponent: React.FC<{ id: AlertReceiveChannel['id'] }> = ({ id
|
|||
border={getVar('--border-weak')}
|
||||
className={cx('how-to-connect__tag')}
|
||||
>
|
||||
<Text type="primary" size="small">
|
||||
<Text type="primary" size="small" className={cx('radius')}>
|
||||
HTTP Endpoint
|
||||
</Text>
|
||||
</Tag>
|
||||
|
|
@ -1082,20 +1085,22 @@ const IntegrationHeader: React.FC<IntegrationHeaderProps> = ({
|
|||
|
||||
{renderHearbeat(alertReceiveChannel)}
|
||||
|
||||
<div className={cx('headerTop__item')}>
|
||||
<Text type="secondary">Type:</Text>
|
||||
<HorizontalGroup spacing="xs">
|
||||
<IntegrationLogo scale={0.08} integration={integration} />
|
||||
<Text type="primary">{integration?.display_name}</Text>
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
<div className={cx('headerTop__item')}>
|
||||
<Text type="secondary">Team:</Text>
|
||||
<TeamName team={grafanaTeamStore.items[alertReceiveChannel.team]} />
|
||||
</div>
|
||||
<div className={cx('headerTop__item')}>
|
||||
<Text type="secondary">Created by:</Text>
|
||||
<UserDisplayWithAvatar id={alertReceiveChannel.author as any}></UserDisplayWithAvatar>
|
||||
<div style={{ display: 'flex', flexDirection: 'row', gap: '16px', marginLeft: '8px' }}>
|
||||
<div className={cx('headerTop__item')}>
|
||||
<Text type="secondary">Type:</Text>
|
||||
<HorizontalGroup spacing="xs">
|
||||
<IntegrationLogo scale={0.08} integration={integration} />
|
||||
<Text type="primary">{integration?.display_name}</Text>
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
<div className={cx('headerTop__item')}>
|
||||
<Text type="secondary">Team:</Text>
|
||||
<TeamName team={grafanaTeamStore.items[alertReceiveChannel.team]} />
|
||||
</div>
|
||||
<div className={cx('headerTop__item')}>
|
||||
<Text type="secondary">Created by:</Text>
|
||||
<UserDisplayWithAvatar id={alertReceiveChannel.author as any}></UserDisplayWithAvatar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,129 @@
|
|||
import { KeyValuePair } from 'utils';
|
||||
|
||||
export const TEXTAREA_ROWS_COUNT = 4;
|
||||
export const MAX_CHARACTERS_COUNT = 50;
|
||||
|
||||
export const MONACO_OPTIONS = {
|
||||
renderLineHighlight: false,
|
||||
readOnly: true,
|
||||
scrollbar: {
|
||||
vertical: 'hidden',
|
||||
horizontal: 'hidden',
|
||||
verticalScrollbarSize: 0,
|
||||
handleMouseWheel: false,
|
||||
},
|
||||
hideCursorInOverviewRuler: true,
|
||||
minimap: { enabled: false },
|
||||
cursorStyle: {
|
||||
display: 'none',
|
||||
},
|
||||
};
|
||||
|
||||
export const MONACO_PAYLOAD_OPTIONS = {
|
||||
renderLineHighlight: false,
|
||||
readOnly: false,
|
||||
hideCursorInOverviewRuler: true,
|
||||
minimap: { enabled: false },
|
||||
cursorStyle: {
|
||||
display: 'none',
|
||||
},
|
||||
};
|
||||
|
||||
export const MONACO_INPUT_HEIGHT_SMALL = '32px';
|
||||
export const MONACO_INPUT_HEIGHT_TALL = '120px';
|
||||
|
||||
export const BaseTemplateOptions = {
|
||||
WebTitle: new KeyValuePair('web_title_template', 'Web Title'),
|
||||
WebMessage: new KeyValuePair('web_message_template', 'Web Message'),
|
||||
WebImage: new KeyValuePair('web_image_url_template', 'Web Image'),
|
||||
Grouping: new KeyValuePair('grouping_id_template', 'Grouping'),
|
||||
Resolve: new KeyValuePair('resolve_condition_template', 'Resolve condition'),
|
||||
Routing: new KeyValuePair('route_template', 'Routing'),
|
||||
|
||||
SourceLink: new KeyValuePair('source_link_template', 'Source Link'),
|
||||
Autoacknowledge: new KeyValuePair('acknowledge_condition_template', 'Autoacknowledge'),
|
||||
Phone: new KeyValuePair('phone_call_title_template', 'Phone'),
|
||||
SMS: new KeyValuePair('sms_title_template', 'SMS'),
|
||||
SlackTitle: new KeyValuePair('slack_title_template', 'Title'),
|
||||
SlackMessage: new KeyValuePair('slack_message_template', 'Message'),
|
||||
SlackImage: new KeyValuePair('slack_image_url_template', 'Image'),
|
||||
EmailTitle: new KeyValuePair('email_title_template', 'Title'),
|
||||
EmailMessage: new KeyValuePair('email_message_template', 'Message'),
|
||||
TelegramTitle: new KeyValuePair('telegram_title_template', 'Title'),
|
||||
TelegramMessage: new KeyValuePair('telegram_message_template', 'Message'),
|
||||
TelegramImage: new KeyValuePair('telegram_image_url_template', 'Image'),
|
||||
|
||||
Email: new KeyValuePair('Email', 'Email'),
|
||||
Slack: new KeyValuePair('Slack', 'Slack'),
|
||||
MSTeams: new KeyValuePair('Microsoft Teams', 'Microsoft Teams'),
|
||||
Telegram: new KeyValuePair('Telegram', 'Telegram'),
|
||||
};
|
||||
|
||||
export const BASE_INTEGRATION_TEMPLATES_LIST = [
|
||||
{
|
||||
label: BaseTemplateOptions.SourceLink.value,
|
||||
value: BaseTemplateOptions.SourceLink.key,
|
||||
},
|
||||
{
|
||||
label: BaseTemplateOptions.Autoacknowledge.value,
|
||||
value: BaseTemplateOptions.Autoacknowledge.key,
|
||||
},
|
||||
{
|
||||
label: BaseTemplateOptions.Phone.value,
|
||||
value: BaseTemplateOptions.Phone.key,
|
||||
},
|
||||
{
|
||||
label: BaseTemplateOptions.SMS.value,
|
||||
value: BaseTemplateOptions.SMS.key,
|
||||
},
|
||||
{
|
||||
label: BaseTemplateOptions.Email.value,
|
||||
value: BaseTemplateOptions.Email.key,
|
||||
children: [
|
||||
{
|
||||
label: BaseTemplateOptions.EmailTitle.value,
|
||||
value: BaseTemplateOptions.EmailTitle.key,
|
||||
},
|
||||
{
|
||||
label: BaseTemplateOptions.EmailMessage.value,
|
||||
value: BaseTemplateOptions.EmailMessage.key,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: BaseTemplateOptions.Slack.value,
|
||||
value: BaseTemplateOptions.Slack.key,
|
||||
children: [
|
||||
{
|
||||
label: BaseTemplateOptions.SlackTitle.value,
|
||||
value: BaseTemplateOptions.SlackTitle.key,
|
||||
},
|
||||
{
|
||||
label: BaseTemplateOptions.SlackMessage.value,
|
||||
value: BaseTemplateOptions.SlackMessage.key,
|
||||
},
|
||||
{
|
||||
label: BaseTemplateOptions.SlackImage.value,
|
||||
value: BaseTemplateOptions.SlackImage.key,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: BaseTemplateOptions.Telegram.value,
|
||||
value: BaseTemplateOptions.Telegram.key,
|
||||
children: [
|
||||
{
|
||||
label: BaseTemplateOptions.TelegramTitle.value,
|
||||
value: BaseTemplateOptions.TelegramTitle.key,
|
||||
},
|
||||
{
|
||||
label: BaseTemplateOptions.TelegramMessage.value,
|
||||
value: BaseTemplateOptions.TelegramMessage.key,
|
||||
},
|
||||
{
|
||||
label: BaseTemplateOptions.TelegramImage.value,
|
||||
value: BaseTemplateOptions.TelegramImage.key,
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
@ -44,4 +44,4 @@
|
|||
&:hover {
|
||||
background: var(--gray-9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ class Integrations extends React.Component<IntegrationsProps, IntegrationsState>
|
|||
const {
|
||||
query: { p },
|
||||
} = this.props;
|
||||
|
||||
this.setState({ page: p ? Number(p) : 1 }, this.update);
|
||||
|
||||
this.parseQueryParams();
|
||||
|
|
|
|||
|
|
@ -68,3 +68,15 @@
|
|||
margin-top: 8px;
|
||||
opacity: 15%;
|
||||
}
|
||||
|
||||
.u-flex-xs {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.u-margin-right-xs {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.u-margin-right-md {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue