mirror of https://github.com/grafana/grafana
Alerting: Add Synthetic and IRM link cards (#107538)
parent
15e1aa8855
commit
c7374b6910
@ -0,0 +1,7 @@ |
||||
import { t } from '@grafana/i18n'; |
||||
|
||||
import { OrangeBadge } from './OrangeBadge'; |
||||
|
||||
export function CloudBadge() { |
||||
return <OrangeBadge text={t('cloud-feature-badge', 'Cloud')} />; |
||||
} |
@ -0,0 +1,31 @@ |
||||
import { css } from '@emotion/css'; |
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data'; |
||||
import { Icon, useStyles2 } from '@grafana/ui'; |
||||
|
||||
export function OrangeBadge({ text }: { text: string }) { |
||||
const styles = useStyles2(getStyles); |
||||
return ( |
||||
<div className={styles.wrapper}> |
||||
<Icon name="cloud" size="sm" /> |
||||
{text} |
||||
</div> |
||||
); |
||||
} |
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => { |
||||
return { |
||||
wrapper: css({ |
||||
display: 'inline-flex', |
||||
padding: theme.spacing(0.5, 1), |
||||
borderRadius: theme.shape.radius.pill, |
||||
background: theme.colors.gradients.brandHorizontal, |
||||
color: theme.colors.primary.contrastText, |
||||
fontWeight: theme.typography.fontWeightMedium, |
||||
gap: theme.spacing(0.5), |
||||
fontSize: theme.typography.bodySmall.fontSize, |
||||
lineHeight: theme.typography.bodySmall.lineHeight, |
||||
alignItems: 'center', |
||||
}), |
||||
}; |
||||
}; |
@ -0,0 +1,146 @@ |
||||
import { css } from '@emotion/css'; |
||||
import { useState } from 'react'; |
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data'; |
||||
import { Trans, t } from '@grafana/i18n'; |
||||
import { Button, Divider, Icon, IconButton, useStyles2 } from '@grafana/ui'; |
||||
import { CloudBadge } from 'app/core/components/Branding/CloudBadge'; |
||||
import { backendSrv } from 'app/core/services/backend_srv'; |
||||
import { contextSrv } from 'app/core/services/context_srv'; |
||||
import { isOpenSourceBuildOrUnlicenced } from 'app/features/admin/EnterpriseAuthFeaturesCard'; |
||||
|
||||
type AdCardProps = { |
||||
title: string; |
||||
description: string; |
||||
href: string; |
||||
logoUrl: string; |
||||
items: string[]; |
||||
helpFlag: number; |
||||
}; |
||||
|
||||
export default function AdCard({ title, description, href, logoUrl, items, helpFlag }: AdCardProps) { |
||||
const styles = useStyles2(getAddCardStyles); |
||||
|
||||
const helpFlags = contextSrv.user.helpFlags1; |
||||
const [isDismissed, setDismissed] = useState<boolean>(Boolean(helpFlags & helpFlag)); |
||||
|
||||
const onDismiss = () => { |
||||
backendSrv.put(`/api/user/helpflags/${helpFlag}`, undefined, { showSuccessAlert: false }).then((res) => { |
||||
contextSrv.user.helpFlags1 = res.helpFlags1; |
||||
setDismissed(true); |
||||
}); |
||||
}; |
||||
|
||||
if (isDismissed || !isOpenSourceBuildOrUnlicenced()) { |
||||
return null; |
||||
} |
||||
|
||||
return ( |
||||
<div className={styles.cardBody} title={title}> |
||||
<div className={styles.preHeader}> |
||||
<CloudBadge /> |
||||
<IconButton name="times" size="sm" onClick={onDismiss} aria-label={t('alerting.ad.close', 'Close')} /> |
||||
</div> |
||||
<header className={styles.header}> |
||||
<img src={logoUrl} alt={title.concat(' logo')} className={styles.logo} /> |
||||
<div className={styles.contentColumn}> |
||||
<h3 className={styles.title}>{title}</h3> |
||||
<p className={styles.description}>{description}</p> |
||||
</div> |
||||
</header> |
||||
<Divider /> |
||||
<div className={styles.itemsList}> |
||||
{items.map((item) => ( |
||||
<div key={item} className={styles.listItem}> |
||||
<Icon className={styles.icon} name="check" /> |
||||
{item} |
||||
</div> |
||||
))} |
||||
</div> |
||||
<Divider /> |
||||
<Button fill="solid" variant="secondary" onClick={() => window.open(href, '_blank')} className={styles.button}> |
||||
<Trans i18nKey="alerting.ad.learn-more">Learn more</Trans> |
||||
<Icon name="external-link-alt" className={styles.buttonIcon} /> |
||||
</Button> |
||||
</div> |
||||
); |
||||
} |
||||
|
||||
const getAddCardStyles = (theme: GrafanaTheme2) => ({ |
||||
logo: css({ |
||||
objectFit: 'contain', |
||||
width: '47px', |
||||
height: '47px', |
||||
}), |
||||
|
||||
header: css({ |
||||
display: 'flex', |
||||
alignItems: 'flex-start', |
||||
gap: theme.spacing(2), |
||||
paddingTop: theme.spacing(2), |
||||
height: theme.spacing(8), |
||||
}), |
||||
|
||||
contentColumn: css({ |
||||
flex: 1, |
||||
}), |
||||
|
||||
title: css({ |
||||
marginBottom: theme.spacing(1), |
||||
fontSize: theme.typography.h4.fontSize, |
||||
fontWeight: theme.typography.h4.fontWeight, |
||||
color: theme.colors.text.primary, |
||||
}), |
||||
|
||||
description: css({ |
||||
fontSize: theme.typography.bodySmall.fontSize, |
||||
color: theme.colors.text.secondary, |
||||
lineHeight: theme.typography.bodySmall.lineHeight, |
||||
}), |
||||
|
||||
itemsList: css({ |
||||
display: 'grid', |
||||
gridTemplateColumns: '1fr', |
||||
gap: theme.spacing(0.5), |
||||
[theme.breakpoints.up('xl')]: { |
||||
gridTemplateColumns: '1fr 1fr', |
||||
gap: theme.spacing(1), |
||||
}, |
||||
}), |
||||
|
||||
listItem: css({ |
||||
display: 'flex', |
||||
alignItems: 'flex-start', |
||||
fontSize: theme.typography.bodySmall.fontSize, |
||||
color: theme.colors.text.secondary, |
||||
lineHeight: theme.typography.bodySmall.lineHeight, |
||||
marginBottom: theme.spacing(0.5), |
||||
}), |
||||
|
||||
icon: css({ |
||||
marginRight: theme.spacing(1), |
||||
color: theme.colors.success.main, |
||||
}), |
||||
|
||||
button: css({ |
||||
padding: `0 ${theme.spacing(2)}`, |
||||
}), |
||||
|
||||
buttonIcon: css({ |
||||
marginLeft: theme.spacing(1), |
||||
}), |
||||
|
||||
cardBody: css({ |
||||
padding: `${theme.spacing(3)} ${theme.spacing(4)} ${theme.spacing(2.25)} ${theme.spacing(4)}`, |
||||
backgroundColor: theme.colors.background.secondary, |
||||
borderRadius: theme.shape.radius.default, |
||||
border: `1px solid ${theme.colors.border.weak}`, |
||||
flex: 1, |
||||
}), |
||||
|
||||
preHeader: css({ |
||||
display: 'flex', |
||||
justifyContent: 'space-between', |
||||
alignItems: 'center', |
||||
}), |
||||
}); |
@ -0,0 +1,28 @@ |
||||
import { t } from '@grafana/i18n'; |
||||
import irmSvg from 'img/irm_logo.svg'; |
||||
|
||||
import AdCard from './AdCard'; |
||||
|
||||
const LINK = 'https://grafana.com/auth/sign-up/create-user?redirectPath=irm&src=oss-grafana&cnt=alerting-irm'; |
||||
const HELP_FLAG_IRM = 0x0010; |
||||
|
||||
export default function IRMCard() { |
||||
return ( |
||||
<AdCard |
||||
title={t('alerting.home.irm-card-title', 'Incident response and management')} |
||||
description={t( |
||||
'alerting.home.irm-card-description', |
||||
'Unify on-call, alerting, and incident response with Grafana Cloud IRM.' |
||||
)} |
||||
href={LINK} |
||||
logoUrl={irmSvg} |
||||
items={[ |
||||
t('alerting.home.irm-card-item-1', 'Manage on-call schedules with your calendar or Terraform.'), |
||||
t('alerting.home.irm-card-item-2', 'Respond to incidents via web, app, Slack, or other channels.'), |
||||
t('alerting.home.irm-card-item-3', 'Pinpoint root causes with AI-powered Grafana SIFT.'), |
||||
t('alerting.home.irm-card-item-4', 'Analyze past incidents to improve response and resilience.'), |
||||
]} |
||||
helpFlag={HELP_FLAG_IRM} |
||||
/> |
||||
); |
||||
} |
@ -0,0 +1,38 @@ |
||||
import { t } from '@grafana/i18n'; |
||||
import syntheticMonitoringSvg from 'img/synthetic_monitoring_logo.svg'; |
||||
|
||||
import AdCard from './AdCard'; |
||||
|
||||
const LINK = |
||||
'https://grafana.com/auth/sign-up/create-user?redirectPath=synthetic-monitoring&src=oss-grafana&cnt=alerting-synthetic-monitoring'; |
||||
const HELP_FLAG_SYNTHETIC_MONITORING = 0x0008; |
||||
|
||||
export default function SyntheticMonitoringCard() { |
||||
return ( |
||||
<AdCard |
||||
title={t('alerting.home.synthetic-monitoring-card-title', 'Synthetic Monitoring')} |
||||
description={t( |
||||
'alerting.home.synthetic-monitoring-card-description', |
||||
'Monitor critical user flows, websites, and APIs externally, from global locations.' |
||||
)} |
||||
href={LINK} |
||||
logoUrl={syntheticMonitoringSvg} |
||||
items={[ |
||||
t('alerting.home.synthetic-monitoring-card-item-1', 'Simulate end-to-end user journeys with browser checks.'), |
||||
t( |
||||
'alerting.home.synthetic-monitoring-card-item-2', |
||||
'Run ping, DNS, HTTP/S, and TCP checks at every network layer.' |
||||
), |
||||
t( |
||||
'alerting.home.synthetic-monitoring-card-item-3', |
||||
'Use 20+ global probes or private probes behind your firewall.' |
||||
), |
||||
t( |
||||
'alerting.home.synthetic-monitoring-card-item-4', |
||||
'Track SLOs with built-in Prometheus-style alerts — right from the UI.' |
||||
), |
||||
]} |
||||
helpFlag={HELP_FLAG_SYNTHETIC_MONITORING} |
||||
/> |
||||
); |
||||
} |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 3.6 KiB |
Loading…
Reference in new issue