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:
parent
3640bf77ba
commit
368afc211c
@ -199,6 +199,7 @@ export const availableIconsIndex = {
|
||||
'square-shape': true,
|
||||
star: true,
|
||||
'step-backward': true,
|
||||
stopwatch: true,
|
||||
'stopwatch-slash': true,
|
||||
sync: true,
|
||||
'sync-slash': true,
|
||||
|
@ -120,6 +120,7 @@
|
||||
"unicons/star",
|
||||
"unicons/step-backward",
|
||||
"unicons/sync",
|
||||
"unicons/stopwatch",
|
||||
"unicons/table",
|
||||
"unicons/tag-alt",
|
||||
"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 u1119 from '../../../../../public/img/icons/unicons/step-backward.svg';
|
||||
import u1120 from '../../../../../public/img/icons/unicons/sync.svg';
|
||||
import u1121 from '../../../../../public/img/icons/unicons/table.svg';
|
||||
import u1122 from '../../../../../public/img/icons/unicons/tag-alt.svg';
|
||||
import u1123 from '../../../../../public/img/icons/unicons/times.svg';
|
||||
import u1124 from '../../../../../public/img/icons/unicons/trash-alt.svg';
|
||||
import u1125 from '../../../../../public/img/icons/unicons/unlock.svg';
|
||||
import u1126 from '../../../../../public/img/icons/unicons/upload.svg';
|
||||
import u1127 from '../../../../../public/img/icons/unicons/user.svg';
|
||||
import u1128 from '../../../../../public/img/icons/unicons/users-alt.svg';
|
||||
import u1129 from '../../../../../public/img/icons/unicons/wrap-text.svg';
|
||||
import u1130 from '../../../../../public/img/icons/unicons/cloud-upload.svg';
|
||||
import u1131 from '../../../../../public/img/icons/unicons/credit-card.svg';
|
||||
import u1132 from '../../../../../public/img/icons/unicons/file-copy-alt.svg';
|
||||
import u1133 from '../../../../../public/img/icons/unicons/fire.svg';
|
||||
import u1134 from '../../../../../public/img/icons/unicons/hourglass.svg';
|
||||
import u1135 from '../../../../../public/img/icons/unicons/layer-group.svg';
|
||||
import u1136 from '../../../../../public/img/icons/unicons/layers-alt.svg';
|
||||
import u1137 from '../../../../../public/img/icons/unicons/line-alt.svg';
|
||||
import u1138 from '../../../../../public/img/icons/unicons/list-ui-alt.svg';
|
||||
import u1139 from '../../../../../public/img/icons/unicons/message.svg';
|
||||
import u1140 from '../../../../../public/img/icons/unicons/palette.svg';
|
||||
import u1141 from '../../../../../public/img/icons/unicons/percentage.svg';
|
||||
import u1142 from '../../../../../public/img/icons/unicons/shield-exclamation.svg';
|
||||
import u1143 from '../../../../../public/img/icons/unicons/plus-square.svg';
|
||||
import u1144 from '../../../../../public/img/icons/unicons/x.svg';
|
||||
import u1145 from '../../../../../public/img/icons/unicons/capture.svg';
|
||||
import u1146 from '../../../../../public/img/icons/custom/gf-grid.svg';
|
||||
import u1147 from '../../../../../public/img/icons/custom/gf-landscape.svg';
|
||||
import u1148 from '../../../../../public/img/icons/custom/gf-layout-simple.svg';
|
||||
import u1149 from '../../../../../public/img/icons/custom/gf-portrait.svg';
|
||||
import u1150 from '../../../../../public/img/icons/custom/gf-bar-alignment-after.svg';
|
||||
import u1151 from '../../../../../public/img/icons/custom/gf-bar-alignment-before.svg';
|
||||
import u1152 from '../../../../../public/img/icons/custom/gf-bar-alignment-center.svg';
|
||||
import u1153 from '../../../../../public/img/icons/custom/gf-interpolation-linear.svg';
|
||||
import u1154 from '../../../../../public/img/icons/custom/gf-interpolation-smooth.svg';
|
||||
import u1155 from '../../../../../public/img/icons/custom/gf-interpolation-step-after.svg';
|
||||
import u1156 from '../../../../../public/img/icons/custom/gf-interpolation-step-before.svg';
|
||||
import u1157 from '../../../../../public/img/icons/custom/gf-logs.svg';
|
||||
import u1158 from '../../../../../public/img/icons/custom/gf-movepane-left.svg';
|
||||
import u1159 from '../../../../../public/img/icons/custom/gf-movepane-right.svg';
|
||||
import u1160 from '../../../../../public/img/icons/mono/favorite.svg';
|
||||
import u1161 from '../../../../../public/img/icons/mono/grafana.svg';
|
||||
import u1162 from '../../../../../public/img/icons/mono/heart.svg';
|
||||
import u1163 from '../../../../../public/img/icons/mono/heart-break.svg';
|
||||
import u1164 from '../../../../../public/img/icons/mono/panel-add.svg';
|
||||
import u1165 from '../../../../../public/img/icons/mono/library-panel.svg';
|
||||
import u1166 from '../../../../../public/img/icons/unicons/record-audio.svg';
|
||||
import u1121 from '../../../../../public/img/icons/unicons/stopwatch.svg';
|
||||
import u1122 from '../../../../../public/img/icons/unicons/table.svg';
|
||||
import u1123 from '../../../../../public/img/icons/unicons/tag-alt.svg';
|
||||
import u1124 from '../../../../../public/img/icons/unicons/times.svg';
|
||||
import u1125 from '../../../../../public/img/icons/unicons/trash-alt.svg';
|
||||
import u1126 from '../../../../../public/img/icons/unicons/unlock.svg';
|
||||
import u1127 from '../../../../../public/img/icons/unicons/upload.svg';
|
||||
import u1128 from '../../../../../public/img/icons/unicons/user.svg';
|
||||
import u1129 from '../../../../../public/img/icons/unicons/users-alt.svg';
|
||||
import u1130 from '../../../../../public/img/icons/unicons/wrap-text.svg';
|
||||
import u1131 from '../../../../../public/img/icons/unicons/cloud-upload.svg';
|
||||
import u1132 from '../../../../../public/img/icons/unicons/credit-card.svg';
|
||||
import u1133 from '../../../../../public/img/icons/unicons/file-copy-alt.svg';
|
||||
import u1134 from '../../../../../public/img/icons/unicons/fire.svg';
|
||||
import u1135 from '../../../../../public/img/icons/unicons/hourglass.svg';
|
||||
import u1136 from '../../../../../public/img/icons/unicons/layer-group.svg';
|
||||
import u1137 from '../../../../../public/img/icons/unicons/layers-alt.svg';
|
||||
import u1138 from '../../../../../public/img/icons/unicons/line-alt.svg';
|
||||
import u1139 from '../../../../../public/img/icons/unicons/list-ui-alt.svg';
|
||||
import u1140 from '../../../../../public/img/icons/unicons/message.svg';
|
||||
import u1141 from '../../../../../public/img/icons/unicons/palette.svg';
|
||||
import u1142 from '../../../../../public/img/icons/unicons/percentage.svg';
|
||||
import u1143 from '../../../../../public/img/icons/unicons/shield-exclamation.svg';
|
||||
import u1144 from '../../../../../public/img/icons/unicons/plus-square.svg';
|
||||
import u1145 from '../../../../../public/img/icons/unicons/x.svg';
|
||||
import u1146 from '../../../../../public/img/icons/unicons/capture.svg';
|
||||
import u1147 from '../../../../../public/img/icons/custom/gf-grid.svg';
|
||||
import u1148 from '../../../../../public/img/icons/custom/gf-landscape.svg';
|
||||
import u1149 from '../../../../../public/img/icons/custom/gf-layout-simple.svg';
|
||||
import u1150 from '../../../../../public/img/icons/custom/gf-portrait.svg';
|
||||
import u1151 from '../../../../../public/img/icons/custom/gf-bar-alignment-after.svg';
|
||||
import u1152 from '../../../../../public/img/icons/custom/gf-bar-alignment-before.svg';
|
||||
import u1153 from '../../../../../public/img/icons/custom/gf-bar-alignment-center.svg';
|
||||
import u1154 from '../../../../../public/img/icons/custom/gf-interpolation-linear.svg';
|
||||
import u1155 from '../../../../../public/img/icons/custom/gf-interpolation-smooth.svg';
|
||||
import u1156 from '../../../../../public/img/icons/custom/gf-interpolation-step-after.svg';
|
||||
import u1157 from '../../../../../public/img/icons/custom/gf-interpolation-step-before.svg';
|
||||
import u1158 from '../../../../../public/img/icons/custom/gf-logs.svg';
|
||||
import u1159 from '../../../../../public/img/icons/custom/gf-movepane-left.svg';
|
||||
import u1160 from '../../../../../public/img/icons/custom/gf-movepane-right.svg';
|
||||
import u1161 from '../../../../../public/img/icons/mono/favorite.svg';
|
||||
import u1162 from '../../../../../public/img/icons/mono/grafana.svg';
|
||||
import u1163 from '../../../../../public/img/icons/mono/heart.svg';
|
||||
import u1164 from '../../../../../public/img/icons/mono/heart-break.svg';
|
||||
import u1165 from '../../../../../public/img/icons/mono/panel-add.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
|
||||
// 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(u1119, 'unicons/step-backward.svg');
|
||||
cacheItem(u1120, 'unicons/sync.svg');
|
||||
cacheItem(u1121, 'unicons/table.svg');
|
||||
cacheItem(u1122, 'unicons/tag-alt.svg');
|
||||
cacheItem(u1123, 'unicons/times.svg');
|
||||
cacheItem(u1124, 'unicons/trash-alt.svg');
|
||||
cacheItem(u1125, 'unicons/unlock.svg');
|
||||
cacheItem(u1126, 'unicons/upload.svg');
|
||||
cacheItem(u1127, 'unicons/user.svg');
|
||||
cacheItem(u1128, 'unicons/users-alt.svg');
|
||||
cacheItem(u1129, 'unicons/wrap-text.svg');
|
||||
cacheItem(u1130, 'unicons/cloud-upload.svg');
|
||||
cacheItem(u1131, 'unicons/credit-card.svg');
|
||||
cacheItem(u1132, 'unicons/file-copy-alt.svg');
|
||||
cacheItem(u1133, 'unicons/fire.svg');
|
||||
cacheItem(u1134, 'unicons/hourglass.svg');
|
||||
cacheItem(u1135, 'unicons/layer-group.svg');
|
||||
cacheItem(u1136, 'unicons/layers-alt.svg');
|
||||
cacheItem(u1137, 'unicons/line-alt.svg');
|
||||
cacheItem(u1138, 'unicons/list-ui-alt.svg');
|
||||
cacheItem(u1139, 'unicons/message.svg');
|
||||
cacheItem(u1140, 'unicons/palette.svg');
|
||||
cacheItem(u1141, 'unicons/percentage.svg');
|
||||
cacheItem(u1142, 'unicons/shield-exclamation.svg');
|
||||
cacheItem(u1143, 'unicons/plus-square.svg');
|
||||
cacheItem(u1144, 'unicons/x.svg');
|
||||
cacheItem(u1145, 'unicons/capture.svg');
|
||||
cacheItem(u1146, 'custom/gf-grid.svg');
|
||||
cacheItem(u1147, 'custom/gf-landscape.svg');
|
||||
cacheItem(u1148, 'custom/gf-layout-simple.svg');
|
||||
cacheItem(u1149, 'custom/gf-portrait.svg');
|
||||
cacheItem(u1150, 'custom/gf-bar-alignment-after.svg');
|
||||
cacheItem(u1151, 'custom/gf-bar-alignment-before.svg');
|
||||
cacheItem(u1152, 'custom/gf-bar-alignment-center.svg');
|
||||
cacheItem(u1153, 'custom/gf-interpolation-linear.svg');
|
||||
cacheItem(u1154, 'custom/gf-interpolation-smooth.svg');
|
||||
cacheItem(u1155, 'custom/gf-interpolation-step-after.svg');
|
||||
cacheItem(u1156, 'custom/gf-interpolation-step-before.svg');
|
||||
cacheItem(u1157, 'custom/gf-logs.svg');
|
||||
cacheItem(u1158, 'custom/gf-movepane-left.svg');
|
||||
cacheItem(u1159, 'custom/gf-movepane-right.svg');
|
||||
cacheItem(u1160, 'mono/favorite.svg');
|
||||
cacheItem(u1161, 'mono/grafana.svg');
|
||||
cacheItem(u1162, 'mono/heart.svg');
|
||||
cacheItem(u1163, 'mono/heart-break.svg');
|
||||
cacheItem(u1164, 'mono/panel-add.svg');
|
||||
cacheItem(u1165, 'mono/library-panel.svg');
|
||||
cacheItem(u1166, 'unicons/record-audio.svg');
|
||||
cacheItem(u1121, 'unicons/stopwatch.svg');
|
||||
cacheItem(u1122, 'unicons/table.svg');
|
||||
cacheItem(u1123, 'unicons/tag-alt.svg');
|
||||
cacheItem(u1124, 'unicons/times.svg');
|
||||
cacheItem(u1125, 'unicons/trash-alt.svg');
|
||||
cacheItem(u1126, 'unicons/unlock.svg');
|
||||
cacheItem(u1127, 'unicons/upload.svg');
|
||||
cacheItem(u1128, 'unicons/user.svg');
|
||||
cacheItem(u1129, 'unicons/users-alt.svg');
|
||||
cacheItem(u1130, 'unicons/wrap-text.svg');
|
||||
cacheItem(u1131, 'unicons/cloud-upload.svg');
|
||||
cacheItem(u1132, 'unicons/credit-card.svg');
|
||||
cacheItem(u1133, 'unicons/file-copy-alt.svg');
|
||||
cacheItem(u1134, 'unicons/fire.svg');
|
||||
cacheItem(u1135, 'unicons/hourglass.svg');
|
||||
cacheItem(u1136, 'unicons/layer-group.svg');
|
||||
cacheItem(u1137, 'unicons/layers-alt.svg');
|
||||
cacheItem(u1138, 'unicons/line-alt.svg');
|
||||
cacheItem(u1139, 'unicons/list-ui-alt.svg');
|
||||
cacheItem(u1140, 'unicons/message.svg');
|
||||
cacheItem(u1141, 'unicons/palette.svg');
|
||||
cacheItem(u1142, 'unicons/percentage.svg');
|
||||
cacheItem(u1143, 'unicons/shield-exclamation.svg');
|
||||
cacheItem(u1144, 'unicons/plus-square.svg');
|
||||
cacheItem(u1145, 'unicons/x.svg');
|
||||
cacheItem(u1146, 'unicons/capture.svg');
|
||||
cacheItem(u1147, 'custom/gf-grid.svg');
|
||||
cacheItem(u1148, 'custom/gf-landscape.svg');
|
||||
cacheItem(u1149, 'custom/gf-layout-simple.svg');
|
||||
cacheItem(u1150, 'custom/gf-portrait.svg');
|
||||
cacheItem(u1151, 'custom/gf-bar-alignment-after.svg');
|
||||
cacheItem(u1152, 'custom/gf-bar-alignment-before.svg');
|
||||
cacheItem(u1153, 'custom/gf-bar-alignment-center.svg');
|
||||
cacheItem(u1154, 'custom/gf-interpolation-linear.svg');
|
||||
cacheItem(u1155, 'custom/gf-interpolation-smooth.svg');
|
||||
cacheItem(u1156, 'custom/gf-interpolation-step-after.svg');
|
||||
cacheItem(u1157, 'custom/gf-interpolation-step-before.svg');
|
||||
cacheItem(u1158, 'custom/gf-logs.svg');
|
||||
cacheItem(u1159, 'custom/gf-movepane-left.svg');
|
||||
cacheItem(u1160, 'custom/gf-movepane-right.svg');
|
||||
cacheItem(u1161, 'mono/favorite.svg');
|
||||
cacheItem(u1162, 'mono/grafana.svg');
|
||||
cacheItem(u1163, 'mono/heart.svg');
|
||||
cacheItem(u1164, 'mono/heart-break.svg');
|
||||
cacheItem(u1165, 'mono/panel-add.svg');
|
||||
cacheItem(u1166, 'mono/library-panel.svg');
|
||||
cacheItem(u1167, 'unicons/record-audio.svg');
|
||||
// do not edit this list directly
|
||||
// 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';
|
||||
|
||||
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;
|
||||
|
@ -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 { Link } from 'react-router-dom';
|
||||
|
||||
import { GrafanaTheme2, IconName } from '@grafana/data';
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Stack } from '@grafana/experimental';
|
||||
import { Badge, Button, Dropdown, getTagColorsFromName, Icon, Menu, Tooltip, useStyles2 } from '@grafana/ui';
|
||||
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 { ReceiversState } from 'app/types';
|
||||
|
||||
import { INTEGRATION_ICONS } from '../../types/contact-points';
|
||||
import { getNotificationsPermissions } from '../../utils/access-control';
|
||||
import { normalizeMatchers } from '../../utils/matchers';
|
||||
import { createContactPointLink, createMuteTimingLink } from '../../utils/misc';
|
||||
@ -130,7 +131,7 @@ const Policy: FC<PolicyComponentProps> = ({
|
||||
<div className={styles.policyItemWrapper}>
|
||||
<Stack direction="column" gap={1}>
|
||||
{/* Matchers and actions */}
|
||||
<div className={styles.matchersRow}>
|
||||
<div>
|
||||
<Stack direction="row" alignItems="center" gap={1}>
|
||||
{isDefaultPolicy ? (
|
||||
<DefaultPolicyIndicator />
|
||||
@ -429,18 +430,6 @@ interface ContactPointDetailsProps {
|
||||
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
|
||||
const ContactPointsHoverDetails: FC<ContactPointDetailsProps> = ({
|
||||
alertManagerSourceName,
|
||||
@ -601,10 +590,9 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
||||
metadataRow: css`
|
||||
background: ${theme.colors.background.secondary};
|
||||
|
||||
border-bottom-left-radius: ${theme.shape.borderRadius(1)};
|
||||
border-bottom-right-radius: ${theme.shape.borderRadius(1)};
|
||||
border-bottom-left-radius: ${theme.shape.borderRadius(2)};
|
||||
border-bottom-right-radius: ${theme.shape.borderRadius(2)};
|
||||
`,
|
||||
matchersRow: css``,
|
||||
policyWrapper: (hasFocus = false) => css`
|
||||
flex: 1;
|
||||
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',
|
||||
};
|
Loading…
Reference in New Issue
Block a user