add notification section to panel

This commit is contained in:
laurenashleigh
2026-01-12 11:41:24 +00:00
parent 563e437610
commit 8c0e09cc2d
3 changed files with 138 additions and 1 deletions
@@ -10,6 +10,7 @@ import { getDefaultFormValues } from '../rule-editor/formDefaults';
import { RuleFormType, RuleFormValues } from '../types/rule-form';
import { RuleConditionSection } from './RuleConditionSection';
import { RuleNotificationSection } from './RuleNotificationSection';
export interface AlertRuleDrawerFormProps {
isOpen: boolean;
@@ -35,6 +36,8 @@ export function AlertRuleDrawerForm({ isOpen, onClose, title }: AlertRuleDrawerF
<div className={styles.divider} aria-hidden="true" />
<RuleConditionSection type={RuleFormType.grafana} />
<div className={styles.divider} aria-hidden="true" />
<RuleNotificationSection />
<div className={styles.divider} aria-hidden="true" />
</FormProvider>
</Drawer>
);
@@ -0,0 +1,134 @@
import { css } from '@emotion/css';
import { useMemo, useState } from 'react';
import { notificationsAPIv0alpha1 } from '@grafana/alerting/unstable';
import type { GrafanaTheme2 } from '@grafana/data';
import { Trans, t } from '@grafana/i18n';
import { Button, Combobox, ComboboxOption, Field, Input, Stack, TextArea, useStyles2 } from '@grafana/ui';
import { LinkToContactPoints } from './rule-editor/alert-rule-form/simplifiedRouting/contactPoint/ContactPointSelector';
export function RuleNotificationSection() {
const styles = useStyles2(getStyles);
const [contactPoint, setContactPoint] = useState<ComboboxOption<string> | null>(null);
// Fetch contact points from Alerting API v0alpha1
const { currentData, status, refetch } = notificationsAPIv0alpha1.endpoints.listReceiver.useQuery({});
const options = useMemo<Array<ComboboxOption<string>>>(
() =>
(currentData?.items ?? []).map((item) => ({
value: item?.spec?.title ?? '',
label: item?.spec?.title ?? '',
})),
[currentData]
);
return (
<div className={styles.section}>
<div className={styles.sectionHeaderRow}>
<span className={styles.stepBadge}>
<Trans i18nKey="alerting.simplified.step-number-three">3</Trans>
</span>
<div className={styles.sectionHeader}>
<Trans i18nKey="alerting.simplified.notification.title">Notification</Trans>
</div>
</div>
<div className={styles.contentIndented}>
<Stack direction="column" gap={2}>
<Field
label={t('alerting.simplified.notification.contact-point', 'Contact point')}
description={t(
'alerting.simplified.notification.contact-point.description',
'Select who should receive a notification when the alert rule fires'
)}
noMargin
>
<Stack direction="row" gap={1} alignItems="center">
<Combobox<ComboboxOption<string>['value']>
options={options}
value={contactPoint}
onChange={(opt) => setContactPoint(opt)}
width={30}
placeholder={t('alerting.simplified.notification.select-contact-point', 'Select a contact point...')}
isClearable
data-testid="contact-point"
loading={status === 'pending'}
/>
<Button
icon="sync"
variant="secondary"
fill="text"
size="sm"
aria-label={t('alerting.common.refresh', 'Refresh')}
onClick={() => {
if (refetch) {
refetch();
}
}}
/>
<LinkToContactPoints />
</Stack>
</Field>
<Field label={t('alerting.simplified.notification.summary', 'Summary (optional)')} noMargin>
<TextArea
placeholder={t(
'alerting.simplified.notification.summary.placeholder',
'Enter a summary of what happened and why…'
)}
/>
</Field>
<Field label={t('alerting.simplified.notification.description', 'Description (optional)')} noMargin>
<TextArea
placeholder={t(
'alerting.simplified.notification.description.placeholder',
'Enter a description of what the alert rule does…'
)}
/>
</Field>
<Field label={t('alerting.simplified.notification.runbook-url', 'Runbook URL (optional)')} noMargin>
<Input
placeholder={t(
'alerting.simplified.notification.runbook-url.placeholder',
'Enter the webpage where you keep your runbook for the alert…'
)}
/>
</Field>
</Stack>
</div>
</div>
);
}
function getStyles(theme: GrafanaTheme2) {
return {
section: css({ width: '100%' }),
sectionHeaderRow: css({
display: 'flex',
alignItems: 'center',
gap: theme.spacing(1),
marginBottom: theme.spacing(1),
}),
sectionHeader: css({
fontWeight: 600,
fontSize: theme.typography.h4.fontSize,
lineHeight: theme.typography.h4.lineHeight,
}),
stepBadge: css({
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
height: 20,
width: 20,
borderRadius: theme.shape.radius.circle,
background: theme.colors.primary.main,
color: theme.colors.text.maxContrast,
fontSize: theme.typography.bodySmall.fontSize,
fontWeight: 600,
}),
contentIndented: css({ marginLeft: `calc(20px + ${theme.spacing(1)})` }),
};
}
@@ -97,7 +97,7 @@ export function ContactPointSelector({ alertManager }: ContactPointSelectorProps
</Stack>
);
}
function LinkToContactPoints() {
export function LinkToContactPoints() {
const hrefToContactPoints = '/alerting/notifications';
return (
<TextLink