diff --git a/pkg/services/user/model.go b/pkg/services/user/model.go
index b60bd4ac306..2d88ee79fa8 100644
--- a/pkg/services/user/model.go
+++ b/pkg/services/user/model.go
@@ -16,6 +16,8 @@ const (
HelpFlagGettingStartedPanelDismissed HelpFlags1 = 1 << iota
HelpFlagDashboardHelp1
HelpFlagEnterpriseAuth1
+ HelpFlagSyntheticMonitoring1
+ HelpFlagIRM1
)
type UpdateEmailActionType string
diff --git a/public/app/core/components/Branding/CloudBadge.tsx b/public/app/core/components/Branding/CloudBadge.tsx
new file mode 100644
index 00000000000..e98ac79b913
--- /dev/null
+++ b/public/app/core/components/Branding/CloudBadge.tsx
@@ -0,0 +1,7 @@
+import { t } from '@grafana/i18n';
+
+import { OrangeBadge } from './OrangeBadge';
+
+export function CloudBadge() {
+ return ;
+}
diff --git a/public/app/core/components/Branding/CloudEnterpriseBadge.tsx b/public/app/core/components/Branding/CloudEnterpriseBadge.tsx
index a904417053c..ce95d147581 100644
--- a/public/app/core/components/Branding/CloudEnterpriseBadge.tsx
+++ b/public/app/core/components/Branding/CloudEnterpriseBadge.tsx
@@ -1,32 +1,7 @@
-import { css } from '@emotion/css';
+import { t } from '@grafana/i18n';
-import { GrafanaTheme2 } from '@grafana/data';
-import { Trans } from '@grafana/i18n';
-import { Icon, useStyles2 } from '@grafana/ui';
+import { OrangeBadge } from './OrangeBadge';
export function CloudEnterpriseBadge() {
- const styles = useStyles2(getStyles);
- return (
-
-
- Cloud & Enterprise
-
- );
+ return ;
}
-
-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',
- }),
- };
-};
diff --git a/public/app/core/components/Branding/OrangeBadge.tsx b/public/app/core/components/Branding/OrangeBadge.tsx
new file mode 100644
index 00000000000..be9d080df79
--- /dev/null
+++ b/public/app/core/components/Branding/OrangeBadge.tsx
@@ -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 (
+
+
+ {text}
+
+ );
+}
+
+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',
+ }),
+ };
+};
diff --git a/public/app/features/alerting/unified/home/AdCard.tsx b/public/app/features/alerting/unified/home/AdCard.tsx
new file mode 100644
index 00000000000..01577b83150
--- /dev/null
+++ b/public/app/features/alerting/unified/home/AdCard.tsx
@@ -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(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 (
+
+
+
+
+
+
+
+
+
{title}
+
{description}
+
+
+
+
+ {items.map((item) => (
+
+
+ {item}
+
+ ))}
+
+
+
+
+ );
+}
+
+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',
+ }),
+});
diff --git a/public/app/features/alerting/unified/home/Home.tsx b/public/app/features/alerting/unified/home/Home.tsx
index d62f6735531..449f956255c 100644
--- a/public/app/features/alerting/unified/home/Home.tsx
+++ b/public/app/features/alerting/unified/home/Home.tsx
@@ -8,8 +8,10 @@ import { isLocalDevEnv } from '../utils/misc';
import { withPageErrorBoundary } from '../withPageErrorBoundary';
import GettingStarted, { WelcomeHeader } from './GettingStarted';
+import IRMCard from './IRMCard';
import { getInsightsScenes, insightsIsAvailable } from './Insights';
import { PluginIntegrations } from './PluginIntegrations';
+import SyntheticMonitoringCard from './SyntheticMonitoringCard';
function Home() {
const insightsEnabled = insightsIsAvailable() || isLocalDevEnv();
@@ -27,6 +29,12 @@ function Home() {
+
+
+
+
+
+
{insightsEnabled && (
diff --git a/public/app/features/alerting/unified/home/IRMCard.tsx b/public/app/features/alerting/unified/home/IRMCard.tsx
new file mode 100644
index 00000000000..ff22c94943d
--- /dev/null
+++ b/public/app/features/alerting/unified/home/IRMCard.tsx
@@ -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 (
+
+ );
+}
diff --git a/public/app/features/alerting/unified/home/SyntheticMonitoringCard.tsx b/public/app/features/alerting/unified/home/SyntheticMonitoringCard.tsx
new file mode 100644
index 00000000000..c98b7066c46
--- /dev/null
+++ b/public/app/features/alerting/unified/home/SyntheticMonitoringCard.tsx
@@ -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 (
+
+ );
+}
diff --git a/public/img/irm_logo.svg b/public/img/irm_logo.svg
new file mode 100644
index 00000000000..7c25966a158
--- /dev/null
+++ b/public/img/irm_logo.svg
@@ -0,0 +1,45 @@
+
diff --git a/public/img/synthetic_monitoring_logo.svg b/public/img/synthetic_monitoring_logo.svg
new file mode 100644
index 00000000000..3b5b9f49deb
--- /dev/null
+++ b/public/img/synthetic_monitoring_logo.svg
@@ -0,0 +1,10 @@
+
diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json
index 8c65d4ed09f..629a553e9da 100644
--- a/public/locales/en-US/grafana.json
+++ b/public/locales/en-US/grafana.json
@@ -352,6 +352,10 @@
"active-timing-fields": {
"am-active-timing-select-label-active-timings": "Active timings"
},
+ "ad": {
+ "close": "Close",
+ "learn-more": "Learn more"
+ },
"add-button": {
"add-more": "Add more"
},
@@ -1525,8 +1529,20 @@
}
},
"home": {
+ "irm-card-description": "Unify on-call, alerting, and incident response with Grafana Cloud IRM.",
+ "irm-card-item-1": "Manage on-call schedules with your calendar or Terraform.",
+ "irm-card-item-2": "Respond to incidents via web, app, Slack, or other channels.",
+ "irm-card-item-3": "Pinpoint root causes with AI-powered Grafana SIFT.",
+ "irm-card-item-4": "Analyze past incidents to improve response and resilience.",
+ "irm-card-title": "Incident response and management",
"label-get-started": "Get started",
"label-insights": "Insights",
+ "synthetic-monitoring-card-description": "Monitor critical user flows, websites, and APIs externally, from global locations.",
+ "synthetic-monitoring-card-item-1": "Simulate end-to-end user journeys with browser checks.",
+ "synthetic-monitoring-card-item-2": "Run ping, DNS, HTTP/S, and TCP checks at every network layer.",
+ "synthetic-monitoring-card-item-3": "Use 20+ global probes or private probes behind your firewall.",
+ "synthetic-monitoring-card-item-4": "Track SLOs with built-in Prometheus-style alerts — right from the UI.",
+ "synthetic-monitoring-card-title": "Synthetic Monitoring",
"title-alerting": "Alerting"
},
"import-to-gma": {
@@ -3894,7 +3910,8 @@
"close-button": {
"tooltip": "Close"
},
- "cloud-enterprise-feature-badge": "Cloud & Enterprise ",
+ "cloud-enterprise-feature-badge": "Cloud & Enterprise",
+ "cloud-feature-badge": "Cloud",
"combobox": {
"async": {
"error": "An error occurred while loading options."