mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Contact points v2 – part 1 (#70643)
This commit is contained in:
@@ -199,6 +199,7 @@ export const availableIconsIndex = {
|
|||||||
'square-shape': true,
|
'square-shape': true,
|
||||||
star: true,
|
star: true,
|
||||||
'step-backward': true,
|
'step-backward': true,
|
||||||
|
stopwatch: true,
|
||||||
'stopwatch-slash': true,
|
'stopwatch-slash': true,
|
||||||
sync: true,
|
sync: true,
|
||||||
'sync-slash': true,
|
'sync-slash': true,
|
||||||
|
|||||||
@@ -120,6 +120,7 @@
|
|||||||
"unicons/star",
|
"unicons/star",
|
||||||
"unicons/step-backward",
|
"unicons/step-backward",
|
||||||
"unicons/sync",
|
"unicons/sync",
|
||||||
|
"unicons/stopwatch",
|
||||||
"unicons/table",
|
"unicons/table",
|
||||||
"unicons/tag-alt",
|
"unicons/tag-alt",
|
||||||
"unicons/times",
|
"unicons/times",
|
||||||
|
|||||||
@@ -128,52 +128,53 @@ import u1117 from '../../../../../public/img/icons/unicons/square-shape.svg';
|
|||||||
import u1118 from '../../../../../public/img/icons/unicons/star.svg';
|
import u1118 from '../../../../../public/img/icons/unicons/star.svg';
|
||||||
import u1119 from '../../../../../public/img/icons/unicons/step-backward.svg';
|
import u1119 from '../../../../../public/img/icons/unicons/step-backward.svg';
|
||||||
import u1120 from '../../../../../public/img/icons/unicons/sync.svg';
|
import u1120 from '../../../../../public/img/icons/unicons/sync.svg';
|
||||||
import u1121 from '../../../../../public/img/icons/unicons/table.svg';
|
import u1121 from '../../../../../public/img/icons/unicons/stopwatch.svg';
|
||||||
import u1122 from '../../../../../public/img/icons/unicons/tag-alt.svg';
|
import u1122 from '../../../../../public/img/icons/unicons/table.svg';
|
||||||
import u1123 from '../../../../../public/img/icons/unicons/times.svg';
|
import u1123 from '../../../../../public/img/icons/unicons/tag-alt.svg';
|
||||||
import u1124 from '../../../../../public/img/icons/unicons/trash-alt.svg';
|
import u1124 from '../../../../../public/img/icons/unicons/times.svg';
|
||||||
import u1125 from '../../../../../public/img/icons/unicons/unlock.svg';
|
import u1125 from '../../../../../public/img/icons/unicons/trash-alt.svg';
|
||||||
import u1126 from '../../../../../public/img/icons/unicons/upload.svg';
|
import u1126 from '../../../../../public/img/icons/unicons/unlock.svg';
|
||||||
import u1127 from '../../../../../public/img/icons/unicons/user.svg';
|
import u1127 from '../../../../../public/img/icons/unicons/upload.svg';
|
||||||
import u1128 from '../../../../../public/img/icons/unicons/users-alt.svg';
|
import u1128 from '../../../../../public/img/icons/unicons/user.svg';
|
||||||
import u1129 from '../../../../../public/img/icons/unicons/wrap-text.svg';
|
import u1129 from '../../../../../public/img/icons/unicons/users-alt.svg';
|
||||||
import u1130 from '../../../../../public/img/icons/unicons/cloud-upload.svg';
|
import u1130 from '../../../../../public/img/icons/unicons/wrap-text.svg';
|
||||||
import u1131 from '../../../../../public/img/icons/unicons/credit-card.svg';
|
import u1131 from '../../../../../public/img/icons/unicons/cloud-upload.svg';
|
||||||
import u1132 from '../../../../../public/img/icons/unicons/file-copy-alt.svg';
|
import u1132 from '../../../../../public/img/icons/unicons/credit-card.svg';
|
||||||
import u1133 from '../../../../../public/img/icons/unicons/fire.svg';
|
import u1133 from '../../../../../public/img/icons/unicons/file-copy-alt.svg';
|
||||||
import u1134 from '../../../../../public/img/icons/unicons/hourglass.svg';
|
import u1134 from '../../../../../public/img/icons/unicons/fire.svg';
|
||||||
import u1135 from '../../../../../public/img/icons/unicons/layer-group.svg';
|
import u1135 from '../../../../../public/img/icons/unicons/hourglass.svg';
|
||||||
import u1136 from '../../../../../public/img/icons/unicons/layers-alt.svg';
|
import u1136 from '../../../../../public/img/icons/unicons/layer-group.svg';
|
||||||
import u1137 from '../../../../../public/img/icons/unicons/line-alt.svg';
|
import u1137 from '../../../../../public/img/icons/unicons/layers-alt.svg';
|
||||||
import u1138 from '../../../../../public/img/icons/unicons/list-ui-alt.svg';
|
import u1138 from '../../../../../public/img/icons/unicons/line-alt.svg';
|
||||||
import u1139 from '../../../../../public/img/icons/unicons/message.svg';
|
import u1139 from '../../../../../public/img/icons/unicons/list-ui-alt.svg';
|
||||||
import u1140 from '../../../../../public/img/icons/unicons/palette.svg';
|
import u1140 from '../../../../../public/img/icons/unicons/message.svg';
|
||||||
import u1141 from '../../../../../public/img/icons/unicons/percentage.svg';
|
import u1141 from '../../../../../public/img/icons/unicons/palette.svg';
|
||||||
import u1142 from '../../../../../public/img/icons/unicons/shield-exclamation.svg';
|
import u1142 from '../../../../../public/img/icons/unicons/percentage.svg';
|
||||||
import u1143 from '../../../../../public/img/icons/unicons/plus-square.svg';
|
import u1143 from '../../../../../public/img/icons/unicons/shield-exclamation.svg';
|
||||||
import u1144 from '../../../../../public/img/icons/unicons/x.svg';
|
import u1144 from '../../../../../public/img/icons/unicons/plus-square.svg';
|
||||||
import u1145 from '../../../../../public/img/icons/unicons/capture.svg';
|
import u1145 from '../../../../../public/img/icons/unicons/x.svg';
|
||||||
import u1146 from '../../../../../public/img/icons/custom/gf-grid.svg';
|
import u1146 from '../../../../../public/img/icons/unicons/capture.svg';
|
||||||
import u1147 from '../../../../../public/img/icons/custom/gf-landscape.svg';
|
import u1147 from '../../../../../public/img/icons/custom/gf-grid.svg';
|
||||||
import u1148 from '../../../../../public/img/icons/custom/gf-layout-simple.svg';
|
import u1148 from '../../../../../public/img/icons/custom/gf-landscape.svg';
|
||||||
import u1149 from '../../../../../public/img/icons/custom/gf-portrait.svg';
|
import u1149 from '../../../../../public/img/icons/custom/gf-layout-simple.svg';
|
||||||
import u1150 from '../../../../../public/img/icons/custom/gf-bar-alignment-after.svg';
|
import u1150 from '../../../../../public/img/icons/custom/gf-portrait.svg';
|
||||||
import u1151 from '../../../../../public/img/icons/custom/gf-bar-alignment-before.svg';
|
import u1151 from '../../../../../public/img/icons/custom/gf-bar-alignment-after.svg';
|
||||||
import u1152 from '../../../../../public/img/icons/custom/gf-bar-alignment-center.svg';
|
import u1152 from '../../../../../public/img/icons/custom/gf-bar-alignment-before.svg';
|
||||||
import u1153 from '../../../../../public/img/icons/custom/gf-interpolation-linear.svg';
|
import u1153 from '../../../../../public/img/icons/custom/gf-bar-alignment-center.svg';
|
||||||
import u1154 from '../../../../../public/img/icons/custom/gf-interpolation-smooth.svg';
|
import u1154 from '../../../../../public/img/icons/custom/gf-interpolation-linear.svg';
|
||||||
import u1155 from '../../../../../public/img/icons/custom/gf-interpolation-step-after.svg';
|
import u1155 from '../../../../../public/img/icons/custom/gf-interpolation-smooth.svg';
|
||||||
import u1156 from '../../../../../public/img/icons/custom/gf-interpolation-step-before.svg';
|
import u1156 from '../../../../../public/img/icons/custom/gf-interpolation-step-after.svg';
|
||||||
import u1157 from '../../../../../public/img/icons/custom/gf-logs.svg';
|
import u1157 from '../../../../../public/img/icons/custom/gf-interpolation-step-before.svg';
|
||||||
import u1158 from '../../../../../public/img/icons/custom/gf-movepane-left.svg';
|
import u1158 from '../../../../../public/img/icons/custom/gf-logs.svg';
|
||||||
import u1159 from '../../../../../public/img/icons/custom/gf-movepane-right.svg';
|
import u1159 from '../../../../../public/img/icons/custom/gf-movepane-left.svg';
|
||||||
import u1160 from '../../../../../public/img/icons/mono/favorite.svg';
|
import u1160 from '../../../../../public/img/icons/custom/gf-movepane-right.svg';
|
||||||
import u1161 from '../../../../../public/img/icons/mono/grafana.svg';
|
import u1161 from '../../../../../public/img/icons/mono/favorite.svg';
|
||||||
import u1162 from '../../../../../public/img/icons/mono/heart.svg';
|
import u1162 from '../../../../../public/img/icons/mono/grafana.svg';
|
||||||
import u1163 from '../../../../../public/img/icons/mono/heart-break.svg';
|
import u1163 from '../../../../../public/img/icons/mono/heart.svg';
|
||||||
import u1164 from '../../../../../public/img/icons/mono/panel-add.svg';
|
import u1164 from '../../../../../public/img/icons/mono/heart-break.svg';
|
||||||
import u1165 from '../../../../../public/img/icons/mono/library-panel.svg';
|
import u1165 from '../../../../../public/img/icons/mono/panel-add.svg';
|
||||||
import u1166 from '../../../../../public/img/icons/unicons/record-audio.svg';
|
import u1166 from '../../../../../public/img/icons/mono/library-panel.svg';
|
||||||
|
import u1167 from '../../../../../public/img/icons/unicons/record-audio.svg';
|
||||||
// do not edit this list directly
|
// do not edit this list directly
|
||||||
// the list of icons live here: @grafana/ui/components/Icon/cached.json
|
// the list of icons live here: @grafana/ui/components/Icon/cached.json
|
||||||
|
|
||||||
@@ -317,52 +318,53 @@ export function initIconCache() {
|
|||||||
cacheItem(u1118, 'unicons/star.svg');
|
cacheItem(u1118, 'unicons/star.svg');
|
||||||
cacheItem(u1119, 'unicons/step-backward.svg');
|
cacheItem(u1119, 'unicons/step-backward.svg');
|
||||||
cacheItem(u1120, 'unicons/sync.svg');
|
cacheItem(u1120, 'unicons/sync.svg');
|
||||||
cacheItem(u1121, 'unicons/table.svg');
|
cacheItem(u1121, 'unicons/stopwatch.svg');
|
||||||
cacheItem(u1122, 'unicons/tag-alt.svg');
|
cacheItem(u1122, 'unicons/table.svg');
|
||||||
cacheItem(u1123, 'unicons/times.svg');
|
cacheItem(u1123, 'unicons/tag-alt.svg');
|
||||||
cacheItem(u1124, 'unicons/trash-alt.svg');
|
cacheItem(u1124, 'unicons/times.svg');
|
||||||
cacheItem(u1125, 'unicons/unlock.svg');
|
cacheItem(u1125, 'unicons/trash-alt.svg');
|
||||||
cacheItem(u1126, 'unicons/upload.svg');
|
cacheItem(u1126, 'unicons/unlock.svg');
|
||||||
cacheItem(u1127, 'unicons/user.svg');
|
cacheItem(u1127, 'unicons/upload.svg');
|
||||||
cacheItem(u1128, 'unicons/users-alt.svg');
|
cacheItem(u1128, 'unicons/user.svg');
|
||||||
cacheItem(u1129, 'unicons/wrap-text.svg');
|
cacheItem(u1129, 'unicons/users-alt.svg');
|
||||||
cacheItem(u1130, 'unicons/cloud-upload.svg');
|
cacheItem(u1130, 'unicons/wrap-text.svg');
|
||||||
cacheItem(u1131, 'unicons/credit-card.svg');
|
cacheItem(u1131, 'unicons/cloud-upload.svg');
|
||||||
cacheItem(u1132, 'unicons/file-copy-alt.svg');
|
cacheItem(u1132, 'unicons/credit-card.svg');
|
||||||
cacheItem(u1133, 'unicons/fire.svg');
|
cacheItem(u1133, 'unicons/file-copy-alt.svg');
|
||||||
cacheItem(u1134, 'unicons/hourglass.svg');
|
cacheItem(u1134, 'unicons/fire.svg');
|
||||||
cacheItem(u1135, 'unicons/layer-group.svg');
|
cacheItem(u1135, 'unicons/hourglass.svg');
|
||||||
cacheItem(u1136, 'unicons/layers-alt.svg');
|
cacheItem(u1136, 'unicons/layer-group.svg');
|
||||||
cacheItem(u1137, 'unicons/line-alt.svg');
|
cacheItem(u1137, 'unicons/layers-alt.svg');
|
||||||
cacheItem(u1138, 'unicons/list-ui-alt.svg');
|
cacheItem(u1138, 'unicons/line-alt.svg');
|
||||||
cacheItem(u1139, 'unicons/message.svg');
|
cacheItem(u1139, 'unicons/list-ui-alt.svg');
|
||||||
cacheItem(u1140, 'unicons/palette.svg');
|
cacheItem(u1140, 'unicons/message.svg');
|
||||||
cacheItem(u1141, 'unicons/percentage.svg');
|
cacheItem(u1141, 'unicons/palette.svg');
|
||||||
cacheItem(u1142, 'unicons/shield-exclamation.svg');
|
cacheItem(u1142, 'unicons/percentage.svg');
|
||||||
cacheItem(u1143, 'unicons/plus-square.svg');
|
cacheItem(u1143, 'unicons/shield-exclamation.svg');
|
||||||
cacheItem(u1144, 'unicons/x.svg');
|
cacheItem(u1144, 'unicons/plus-square.svg');
|
||||||
cacheItem(u1145, 'unicons/capture.svg');
|
cacheItem(u1145, 'unicons/x.svg');
|
||||||
cacheItem(u1146, 'custom/gf-grid.svg');
|
cacheItem(u1146, 'unicons/capture.svg');
|
||||||
cacheItem(u1147, 'custom/gf-landscape.svg');
|
cacheItem(u1147, 'custom/gf-grid.svg');
|
||||||
cacheItem(u1148, 'custom/gf-layout-simple.svg');
|
cacheItem(u1148, 'custom/gf-landscape.svg');
|
||||||
cacheItem(u1149, 'custom/gf-portrait.svg');
|
cacheItem(u1149, 'custom/gf-layout-simple.svg');
|
||||||
cacheItem(u1150, 'custom/gf-bar-alignment-after.svg');
|
cacheItem(u1150, 'custom/gf-portrait.svg');
|
||||||
cacheItem(u1151, 'custom/gf-bar-alignment-before.svg');
|
cacheItem(u1151, 'custom/gf-bar-alignment-after.svg');
|
||||||
cacheItem(u1152, 'custom/gf-bar-alignment-center.svg');
|
cacheItem(u1152, 'custom/gf-bar-alignment-before.svg');
|
||||||
cacheItem(u1153, 'custom/gf-interpolation-linear.svg');
|
cacheItem(u1153, 'custom/gf-bar-alignment-center.svg');
|
||||||
cacheItem(u1154, 'custom/gf-interpolation-smooth.svg');
|
cacheItem(u1154, 'custom/gf-interpolation-linear.svg');
|
||||||
cacheItem(u1155, 'custom/gf-interpolation-step-after.svg');
|
cacheItem(u1155, 'custom/gf-interpolation-smooth.svg');
|
||||||
cacheItem(u1156, 'custom/gf-interpolation-step-before.svg');
|
cacheItem(u1156, 'custom/gf-interpolation-step-after.svg');
|
||||||
cacheItem(u1157, 'custom/gf-logs.svg');
|
cacheItem(u1157, 'custom/gf-interpolation-step-before.svg');
|
||||||
cacheItem(u1158, 'custom/gf-movepane-left.svg');
|
cacheItem(u1158, 'custom/gf-logs.svg');
|
||||||
cacheItem(u1159, 'custom/gf-movepane-right.svg');
|
cacheItem(u1159, 'custom/gf-movepane-left.svg');
|
||||||
cacheItem(u1160, 'mono/favorite.svg');
|
cacheItem(u1160, 'custom/gf-movepane-right.svg');
|
||||||
cacheItem(u1161, 'mono/grafana.svg');
|
cacheItem(u1161, 'mono/favorite.svg');
|
||||||
cacheItem(u1162, 'mono/heart.svg');
|
cacheItem(u1162, 'mono/grafana.svg');
|
||||||
cacheItem(u1163, 'mono/heart-break.svg');
|
cacheItem(u1163, 'mono/heart.svg');
|
||||||
cacheItem(u1164, 'mono/panel-add.svg');
|
cacheItem(u1164, 'mono/heart-break.svg');
|
||||||
cacheItem(u1165, 'mono/library-panel.svg');
|
cacheItem(u1165, 'mono/panel-add.svg');
|
||||||
cacheItem(u1166, 'unicons/record-audio.svg');
|
cacheItem(u1166, 'mono/library-panel.svg');
|
||||||
|
cacheItem(u1167, 'unicons/record-audio.svg');
|
||||||
// do not edit this list directly
|
// do not edit this list directly
|
||||||
// the list of icons live here: @grafana/ui/components/Icon/cached.json
|
// the list of icons live here: @grafana/ui/components/Icon/cached.json
|
||||||
}
|
}
|
||||||
|
|||||||
12
public/app/features/alerting/components/ConditionalWrap.tsx
Normal file
12
public/app/features/alerting/components/ConditionalWrap.tsx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface ConditionalWrapProps {
|
||||||
|
shouldWrap: boolean;
|
||||||
|
children: JSX.Element;
|
||||||
|
wrap: (children: JSX.Element) => JSX.Element;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ConditionalWrap = ({ shouldWrap, children, wrap }: ConditionalWrapProps): JSX.Element =>
|
||||||
|
shouldWrap ? React.cloneElement(wrap(children)) : children;
|
||||||
|
|
||||||
|
export default ConditionalWrap;
|
||||||
@@ -1,5 +1,267 @@
|
|||||||
|
import { css } from '@emotion/css';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const ContactPoints = () => <>Hello, contact points v2!</>;
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
|
import { Stack } from '@grafana/experimental';
|
||||||
|
import { Badge, Button, Dropdown, Icon, Menu, Tooltip, useStyles2 } from '@grafana/ui';
|
||||||
|
import { Span } from '@grafana/ui/src/unstable';
|
||||||
|
import ConditionalWrap from 'app/features/alerting/components/ConditionalWrap';
|
||||||
|
import { GrafanaNotifierType } from 'app/types/alerting';
|
||||||
|
|
||||||
|
import { INTEGRATION_ICONS } from '../../types/contact-points';
|
||||||
|
import { MetaText } from '../MetaText';
|
||||||
|
import { Spacer } from '../Spacer';
|
||||||
|
import { Strong } from '../Strong';
|
||||||
|
|
||||||
|
const ContactPoints = () => {
|
||||||
|
const styles = useStyles2(getStyles);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack direction="column">
|
||||||
|
<div className={styles.contactPointWrapper}>
|
||||||
|
<Stack direction="column" gap={0}>
|
||||||
|
<ContactPointHeader name={'grafana-default-email'} policies={['', '']} />
|
||||||
|
<div className={styles.receiversWrapper}>
|
||||||
|
<ContactPointReceiver type={'email'} description="gilles.demey@grafana.com" />
|
||||||
|
</div>
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.contactPointWrapper}>
|
||||||
|
<Stack direction="column" gap={0}>
|
||||||
|
<ContactPointHeader name={'New school'} provenance={'api'} />
|
||||||
|
<div className={styles.receiversWrapper}>
|
||||||
|
<Stack direction="column" gap={0}>
|
||||||
|
<ContactPointReceiver type={'slack'} description="#test-alerts" sendingResolved={false} />
|
||||||
|
<ContactPointReceiver type={'discord'} />
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.contactPointWrapper}>
|
||||||
|
<Stack direction="column" gap={0}>
|
||||||
|
<ContactPointHeader name={'Japan 🇯🇵'} />
|
||||||
|
<div className={styles.receiversWrapper}>
|
||||||
|
<ContactPointReceiver type={'line'} />
|
||||||
|
</div>
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.contactPointWrapper}>
|
||||||
|
<Stack direction="column" gap={0}>
|
||||||
|
<ContactPointHeader name={'Google Stuff'} />
|
||||||
|
<div className={styles.receiversWrapper}>
|
||||||
|
<ContactPointReceiver type={'googlechat'} />
|
||||||
|
</div>
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.contactPointWrapper}>
|
||||||
|
<Stack direction="column" gap={0}>
|
||||||
|
<ContactPointHeader name={'Chinese Contact Points'} />
|
||||||
|
<div className={styles.receiversWrapper}>
|
||||||
|
<Stack direction="column" gap={0}>
|
||||||
|
<ContactPointReceiver type={'dingding'} />
|
||||||
|
<ContactPointReceiver type={'wecom'} error="403 unauthorized" />
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.contactPointWrapper}>
|
||||||
|
<Stack direction="column" gap={0}>
|
||||||
|
<ContactPointHeader
|
||||||
|
name={
|
||||||
|
"This is a very long title to check if we are dealing with it appropriately, it shouldn't cause any layout issues"
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<div className={styles.receiversWrapper}>
|
||||||
|
<Stack direction="column" gap={0}>
|
||||||
|
<ContactPointReceiver type={'dingding'} />
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ContactPointHeaderProps {
|
||||||
|
name: string;
|
||||||
|
provenance?: string;
|
||||||
|
policies?: string[]; // some array of policies that refer to this contact point
|
||||||
|
}
|
||||||
|
|
||||||
|
const ContactPointHeader = (props: ContactPointHeaderProps) => {
|
||||||
|
const { name, provenance, policies = [] } = props;
|
||||||
|
|
||||||
|
const styles = useStyles2(getStyles);
|
||||||
|
const isProvisioned = Boolean(provenance);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.headerWrapper}>
|
||||||
|
<Stack direction="row" alignItems="center" gap={1}>
|
||||||
|
<Stack alignItems="center" gap={1}>
|
||||||
|
<Span variant="body">{name}</Span>
|
||||||
|
</Stack>
|
||||||
|
{policies.length > 0 ? (
|
||||||
|
<MetaText>
|
||||||
|
{/* TODO make this a link to the notification policies page with the filter applied */}
|
||||||
|
is used by <Strong>{policies.length}</Strong> notification policies
|
||||||
|
</MetaText>
|
||||||
|
) : (
|
||||||
|
<MetaText>is not used</MetaText>
|
||||||
|
)}
|
||||||
|
{isProvisioned && <Badge color="purple" text="Provisioned" />}
|
||||||
|
<Spacer />
|
||||||
|
<ConditionalWrap
|
||||||
|
shouldWrap={isProvisioned}
|
||||||
|
wrap={(children) => (
|
||||||
|
<Tooltip content="Provisioned items cannot be edited in the UI" placement="top">
|
||||||
|
{children}
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
size="sm"
|
||||||
|
icon="edit"
|
||||||
|
type="button"
|
||||||
|
disabled={isProvisioned}
|
||||||
|
aria-label="edit-action"
|
||||||
|
data-testid="edit-action"
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</Button>
|
||||||
|
</ConditionalWrap>
|
||||||
|
<Dropdown
|
||||||
|
overlay={
|
||||||
|
<Menu>
|
||||||
|
<Menu.Item label="Export" icon="download-alt" />
|
||||||
|
<Menu.Divider />
|
||||||
|
<Menu.Item label="Delete" icon="trash-alt" destructive disabled={isProvisioned} />
|
||||||
|
</Menu>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
variant="secondary"
|
||||||
|
size="sm"
|
||||||
|
icon="ellipsis-h"
|
||||||
|
type="button"
|
||||||
|
aria-label="more-actions"
|
||||||
|
data-testid="more-actions"
|
||||||
|
/>
|
||||||
|
</Dropdown>
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ContactPointReceiverProps {
|
||||||
|
type: GrafanaNotifierType | string;
|
||||||
|
description?: string;
|
||||||
|
error?: string;
|
||||||
|
sendingResolved?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ContactPointReceiver = (props: ContactPointReceiverProps) => {
|
||||||
|
const { type, description, error, sendingResolved = true } = props;
|
||||||
|
const styles = useStyles2(getStyles);
|
||||||
|
|
||||||
|
const iconName = INTEGRATION_ICONS[type];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.integrationWrapper}>
|
||||||
|
<Stack direction="column" gap={0}>
|
||||||
|
<div className={styles.receiverDescriptionRow}>
|
||||||
|
<Stack direction="row" alignItems="center" gap={1}>
|
||||||
|
<Stack direction="row" alignItems="center" gap={0.5}>
|
||||||
|
{iconName && <Icon name={iconName} />}
|
||||||
|
<Span variant="body" color="primary">
|
||||||
|
{type}
|
||||||
|
</Span>
|
||||||
|
</Stack>
|
||||||
|
{description && (
|
||||||
|
<Span variant="bodySmall" color="secondary">
|
||||||
|
{description}
|
||||||
|
</Span>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
<div className={styles.metadataRow}>
|
||||||
|
<Stack direction="row" gap={1}>
|
||||||
|
{error ? (
|
||||||
|
<>
|
||||||
|
{/* TODO we might need an error variant for MetaText, dito for success */}
|
||||||
|
{/* TODO show error details on hover or elsewhere */}
|
||||||
|
<Span color="error" variant="bodySmall" weight="bold">
|
||||||
|
<Stack direction="row" alignItems={'center'} gap={0.5}>
|
||||||
|
<Tooltip
|
||||||
|
content={
|
||||||
|
'failed to send notification to email addresses: gilles.demey@grafana.com: dial tcp 192.168.1.21:1025: connect: connection refused'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
<Icon name="exclamation-circle" /> Last delivery attempt failed
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
</Stack>
|
||||||
|
</Span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<MetaText icon="clock-nine">
|
||||||
|
Last delivery attempt <Strong>25 minutes ago</Strong>
|
||||||
|
</MetaText>
|
||||||
|
<MetaText icon="stopwatch">
|
||||||
|
took <Strong>2s</Strong>
|
||||||
|
</MetaText>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{!sendingResolved && (
|
||||||
|
<MetaText icon="info-circle">
|
||||||
|
Delivering <Strong>only firing</Strong> notifications
|
||||||
|
</MetaText>
|
||||||
|
)}
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
</Stack>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStyles = (theme: GrafanaTheme2) => ({
|
||||||
|
contactPointWrapper: css`
|
||||||
|
border-radius: ${theme.shape.borderRadius()};
|
||||||
|
border: solid 1px ${theme.colors.border.weak};
|
||||||
|
border-bottom: none;
|
||||||
|
`,
|
||||||
|
integrationWrapper: css`
|
||||||
|
position: relative;
|
||||||
|
background: ${theme.colors.background.primary};
|
||||||
|
|
||||||
|
border-bottom: solid 1px ${theme.colors.border.weak};
|
||||||
|
`,
|
||||||
|
headerWrapper: css`
|
||||||
|
padding: ${theme.spacing(1)} ${theme.spacing(1.5)};
|
||||||
|
|
||||||
|
background: ${theme.colors.background.secondary};
|
||||||
|
|
||||||
|
border-bottom: solid 1px ${theme.colors.border.weak};
|
||||||
|
border-top-left-radius: ${theme.shape.borderRadius()};
|
||||||
|
border-top-right-radius: ${theme.shape.borderRadius()};
|
||||||
|
`,
|
||||||
|
receiverDescriptionRow: css`
|
||||||
|
padding: ${theme.spacing(1)} ${theme.spacing(1.5)};
|
||||||
|
`,
|
||||||
|
metadataRow: css`
|
||||||
|
padding: 0 ${theme.spacing(1.5)} ${theme.spacing(1.5)} ${theme.spacing(1.5)};
|
||||||
|
|
||||||
|
border-bottom-left-radius: ${theme.shape.borderRadius()};
|
||||||
|
border-bottom-right-radius: ${theme.shape.borderRadius()};
|
||||||
|
`,
|
||||||
|
receiversWrapper: css``,
|
||||||
|
});
|
||||||
|
|
||||||
export default ContactPoints;
|
export default ContactPoints;
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* This hook will combine data from both the Alertmanager config
|
||||||
|
* and (if available) it will also fetch the status from the Grafana Managed status endpoint
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { NotifierType, NotifierStatus } from 'app/types';
|
||||||
|
|
||||||
|
// A Contact Point has 1 or more integrations
|
||||||
|
// each integration can have additional metadata assigned to it
|
||||||
|
export interface ContactPoint<T extends Notifier> {
|
||||||
|
notifiers: T[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Notifier {
|
||||||
|
type: NotifierType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grafana Managed contact points have receivers with additional diagnostics
|
||||||
|
export interface NotifierWithDiagnostics extends Notifier {
|
||||||
|
status: NotifierStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useContactPoints(AlertManagerSourceName: string) {}
|
||||||
@@ -4,7 +4,7 @@ import pluralize from 'pluralize';
|
|||||||
import React, { FC, Fragment, ReactNode } from 'react';
|
import React, { FC, Fragment, ReactNode } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import { GrafanaTheme2, IconName } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { Stack } from '@grafana/experimental';
|
import { Stack } from '@grafana/experimental';
|
||||||
import { Badge, Button, Dropdown, getTagColorsFromName, Icon, Menu, Tooltip, useStyles2 } from '@grafana/ui';
|
import { Badge, Button, Dropdown, getTagColorsFromName, Icon, Menu, Tooltip, useStyles2 } from '@grafana/ui';
|
||||||
import { Span } from '@grafana/ui/src/unstable';
|
import { Span } from '@grafana/ui/src/unstable';
|
||||||
@@ -12,6 +12,7 @@ import { contextSrv } from 'app/core/core';
|
|||||||
import { RouteWithID, Receiver, ObjectMatcher, AlertmanagerGroup } from 'app/plugins/datasource/alertmanager/types';
|
import { RouteWithID, Receiver, ObjectMatcher, AlertmanagerGroup } from 'app/plugins/datasource/alertmanager/types';
|
||||||
import { ReceiversState } from 'app/types';
|
import { ReceiversState } from 'app/types';
|
||||||
|
|
||||||
|
import { INTEGRATION_ICONS } from '../../types/contact-points';
|
||||||
import { getNotificationsPermissions } from '../../utils/access-control';
|
import { getNotificationsPermissions } from '../../utils/access-control';
|
||||||
import { normalizeMatchers } from '../../utils/matchers';
|
import { normalizeMatchers } from '../../utils/matchers';
|
||||||
import { createContactPointLink, createMuteTimingLink } from '../../utils/misc';
|
import { createContactPointLink, createMuteTimingLink } from '../../utils/misc';
|
||||||
@@ -130,7 +131,7 @@ const Policy: FC<PolicyComponentProps> = ({
|
|||||||
<div className={styles.policyItemWrapper}>
|
<div className={styles.policyItemWrapper}>
|
||||||
<Stack direction="column" gap={1}>
|
<Stack direction="column" gap={1}>
|
||||||
{/* Matchers and actions */}
|
{/* Matchers and actions */}
|
||||||
<div className={styles.matchersRow}>
|
<div>
|
||||||
<Stack direction="row" alignItems="center" gap={1}>
|
<Stack direction="row" alignItems="center" gap={1}>
|
||||||
{isDefaultPolicy ? (
|
{isDefaultPolicy ? (
|
||||||
<DefaultPolicyIndicator />
|
<DefaultPolicyIndicator />
|
||||||
@@ -429,18 +430,6 @@ interface ContactPointDetailsProps {
|
|||||||
receivers: Receiver[];
|
receivers: Receiver[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const INTEGRATION_ICONS: Record<string, IconName> = {
|
|
||||||
discord: 'discord',
|
|
||||||
email: 'envelope',
|
|
||||||
googlechat: 'google-hangouts-alt',
|
|
||||||
hipchat: 'hipchat',
|
|
||||||
line: 'line',
|
|
||||||
pagerduty: 'pagerduty',
|
|
||||||
slack: 'slack',
|
|
||||||
teams: 'microsoft',
|
|
||||||
telegram: 'telegram-alt',
|
|
||||||
};
|
|
||||||
|
|
||||||
// @TODO make this work for cloud AMs too
|
// @TODO make this work for cloud AMs too
|
||||||
const ContactPointsHoverDetails: FC<ContactPointDetailsProps> = ({
|
const ContactPointsHoverDetails: FC<ContactPointDetailsProps> = ({
|
||||||
alertManagerSourceName,
|
alertManagerSourceName,
|
||||||
@@ -601,10 +590,9 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
|||||||
metadataRow: css`
|
metadataRow: css`
|
||||||
background: ${theme.colors.background.secondary};
|
background: ${theme.colors.background.secondary};
|
||||||
|
|
||||||
border-bottom-left-radius: ${theme.shape.borderRadius(1)};
|
border-bottom-left-radius: ${theme.shape.borderRadius(2)};
|
||||||
border-bottom-right-radius: ${theme.shape.borderRadius(1)};
|
border-bottom-right-radius: ${theme.shape.borderRadius(2)};
|
||||||
`,
|
`,
|
||||||
matchersRow: css``,
|
|
||||||
policyWrapper: (hasFocus = false) => css`
|
policyWrapper: (hasFocus = false) => css`
|
||||||
flex: 1;
|
flex: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|||||||
13
public/app/features/alerting/unified/types/contact-points.ts
Normal file
13
public/app/features/alerting/unified/types/contact-points.ts
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import { IconName } from '@grafana/ui';
|
||||||
|
|
||||||
|
export const INTEGRATION_ICONS: Record<string, IconName> = {
|
||||||
|
discord: 'discord',
|
||||||
|
email: 'envelope',
|
||||||
|
googlechat: 'google-hangouts-alt',
|
||||||
|
hipchat: 'hipchat',
|
||||||
|
line: 'line',
|
||||||
|
pagerduty: 'pagerduty',
|
||||||
|
slack: 'slack',
|
||||||
|
teams: 'microsoft',
|
||||||
|
telegram: 'telegram-alt',
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user