mirror of
https://github.com/grafana/grafana.git
synced 2025-09-20 17:15:59 +08:00
Alerting: Add plugins extension point to alerting home page (#85725)
* Add basic extension point to alerting home page * Remove home page scenes app. Improve plugins styles * Remove unused code * Fix home page rendering when no plugins registered * Add row-based integrations component * Add missing margins * Rollback the Box component changes * Remove unused import
This commit is contained in:
@ -116,6 +116,7 @@ export type PluginExtensionEventHelpers<Context extends object = object> = {
|
|||||||
// Extension Points available in core Grafana
|
// Extension Points available in core Grafana
|
||||||
export enum PluginExtensionPoints {
|
export enum PluginExtensionPoints {
|
||||||
AlertInstanceAction = 'grafana/alerting/instance/action',
|
AlertInstanceAction = 'grafana/alerting/instance/action',
|
||||||
|
AlertingHomePage = 'grafana/alerting/home',
|
||||||
CommandPalette = 'grafana/commandpalette/action',
|
CommandPalette = 'grafana/commandpalette/action',
|
||||||
DashboardPanelMenu = 'grafana/dashboard/panel/menu',
|
DashboardPanelMenu = 'grafana/dashboard/panel/menu',
|
||||||
DataSourceConfig = 'grafana/datasources/config',
|
DataSourceConfig = 'grafana/datasources/config',
|
||||||
|
@ -3,23 +3,8 @@ import React from 'react';
|
|||||||
import SVG from 'react-inlinesvg';
|
import SVG from 'react-inlinesvg';
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { EmbeddedScene, SceneFlexLayout, SceneFlexItem, SceneReactObject } from '@grafana/scenes';
|
|
||||||
import { useStyles2, useTheme2, Stack, Text, TextLink } from '@grafana/ui';
|
import { useStyles2, useTheme2, Stack, Text, TextLink } from '@grafana/ui';
|
||||||
|
|
||||||
export const getOverviewScene = () => {
|
|
||||||
return new EmbeddedScene({
|
|
||||||
body: new SceneFlexLayout({
|
|
||||||
children: [
|
|
||||||
new SceneFlexItem({
|
|
||||||
body: new SceneReactObject({
|
|
||||||
component: GettingStarted,
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function GettingStarted() {
|
export default function GettingStarted() {
|
||||||
const theme = useTheme2();
|
const theme = useTheme2();
|
||||||
const styles = useStyles2(getWelcomePageStyles);
|
const styles = useStyles2(getWelcomePageStyles);
|
||||||
@ -110,9 +95,7 @@ export function WelcomeHeader({ className }: { className?: string }) {
|
|||||||
const styles = useStyles2(getWelcomeHeaderStyles);
|
const styles = useStyles2(getWelcomeHeaderStyles);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.welcomeHeaderWrapper}>
|
<Stack gap={2} direction="column">
|
||||||
<div className={styles.subtitle}>Learn about problems in your systems moments after they occur</div>
|
|
||||||
|
|
||||||
<ContentBox className={cx(styles.ctaContainer, className)}>
|
<ContentBox className={cx(styles.ctaContainer, className)}>
|
||||||
<WelcomeCTABox
|
<WelcomeCTABox
|
||||||
title="Alert rules"
|
title="Alert rules"
|
||||||
@ -135,18 +118,11 @@ export function WelcomeHeader({ className }: { className?: string }) {
|
|||||||
hrefText="Manage notification policies"
|
hrefText="Manage notification policies"
|
||||||
/>
|
/>
|
||||||
</ContentBox>
|
</ContentBox>
|
||||||
</div>
|
</Stack>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getWelcomeHeaderStyles = (theme: GrafanaTheme2) => ({
|
const getWelcomeHeaderStyles = (theme: GrafanaTheme2) => ({
|
||||||
welcomeHeaderWrapper: css({
|
|
||||||
color: theme.colors.text.primary,
|
|
||||||
}),
|
|
||||||
subtitle: css({
|
|
||||||
color: theme.colors.text.secondary,
|
|
||||||
paddingBottom: theme.spacing(2),
|
|
||||||
}),
|
|
||||||
ctaContainer: css({
|
ctaContainer: css({
|
||||||
padding: theme.spacing(2),
|
padding: theme.spacing(2),
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
@ -195,6 +171,7 @@ function WelcomeCTABox({ title, description, href, hrefText }: WelcomeCTABoxProp
|
|||||||
|
|
||||||
const getWelcomeCTAButtonStyles = (theme: GrafanaTheme2) => ({
|
const getWelcomeCTAButtonStyles = (theme: GrafanaTheme2) => ({
|
||||||
container: css({
|
container: css({
|
||||||
|
color: theme.colors.text.primary,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
minWidth: '240px',
|
minWidth: '240px',
|
||||||
display: 'grid',
|
display: 'grid',
|
||||||
|
@ -1,74 +1,54 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
import { config } from '@grafana/runtime';
|
import { config } from '@grafana/runtime';
|
||||||
import { SceneApp, SceneAppPage } from '@grafana/scenes';
|
import { Box, Stack, Tab, TabContent, TabsBar } from '@grafana/ui';
|
||||||
import { usePageNav } from 'app/core/components/Page/usePageNav';
|
|
||||||
import { PluginPageContext, PluginPageContextType } from 'app/features/plugins/components/PluginPageContext';
|
|
||||||
|
|
||||||
|
import { AlertingPageWrapper } from '../components/AlertingPageWrapper';
|
||||||
import { isLocalDevEnv, isOpenSourceEdition } from '../utils/misc';
|
import { isLocalDevEnv, isOpenSourceEdition } from '../utils/misc';
|
||||||
|
|
||||||
import { getOverviewScene, WelcomeHeader } from './GettingStarted';
|
import GettingStarted, { WelcomeHeader } from './GettingStarted';
|
||||||
import { getInsightsScenes } from './Insights';
|
import { getInsightsScenes } from './Insights';
|
||||||
|
import { PluginIntegrations } from './PluginIntegrations';
|
||||||
let homeApp: SceneApp | undefined;
|
|
||||||
|
|
||||||
export function getHomeApp(insightsEnabled: boolean) {
|
|
||||||
if (homeApp) {
|
|
||||||
return homeApp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (insightsEnabled) {
|
|
||||||
homeApp = new SceneApp({
|
|
||||||
pages: [
|
|
||||||
new SceneAppPage({
|
|
||||||
title: 'Alerting',
|
|
||||||
subTitle: <WelcomeHeader />,
|
|
||||||
url: '/alerting',
|
|
||||||
hideFromBreadcrumbs: true,
|
|
||||||
tabs: [
|
|
||||||
new SceneAppPage({
|
|
||||||
title: 'Insights',
|
|
||||||
url: '/alerting/home/insights',
|
|
||||||
getScene: getInsightsScenes,
|
|
||||||
}),
|
|
||||||
new SceneAppPage({
|
|
||||||
title: 'Get started',
|
|
||||||
url: '/alerting/home/overview',
|
|
||||||
getScene: getOverviewScene,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
homeApp = new SceneApp({
|
|
||||||
pages: [
|
|
||||||
new SceneAppPage({
|
|
||||||
title: 'Alerting',
|
|
||||||
subTitle: <WelcomeHeader />,
|
|
||||||
url: '/alerting',
|
|
||||||
hideFromBreadcrumbs: true,
|
|
||||||
getScene: getOverviewScene,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return homeApp;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const insightsEnabled =
|
const insightsEnabled =
|
||||||
(!isOpenSourceEdition() || isLocalDevEnv()) && Boolean(config.featureToggles.alertingInsights);
|
(!isOpenSourceEdition() || isLocalDevEnv()) && Boolean(config.featureToggles.alertingInsights);
|
||||||
|
|
||||||
const appScene = getHomeApp(insightsEnabled);
|
const [activeTab, setActiveTab] = useState<'insights' | 'overview'>(insightsEnabled ? 'insights' : 'overview');
|
||||||
|
const insightsScene = getInsightsScenes();
|
||||||
const sectionNav = usePageNav('alerting')!;
|
|
||||||
const [pluginContext] = useState<PluginPageContextType>({ sectionNav });
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PluginPageContext.Provider value={pluginContext}>
|
<AlertingPageWrapper
|
||||||
<appScene.Component model={appScene} />
|
title="Alerting"
|
||||||
</PluginPageContext.Provider>
|
subTitle="Learn about problems in your systems moments after they occur"
|
||||||
|
navId="alerting"
|
||||||
|
>
|
||||||
|
<Stack gap={2} direction="column">
|
||||||
|
<WelcomeHeader />
|
||||||
|
<PluginIntegrations />
|
||||||
|
</Stack>
|
||||||
|
<Box marginTop={{ lg: 2, md: 0, xs: 0 }}>
|
||||||
|
<TabsBar>
|
||||||
|
{insightsEnabled && (
|
||||||
|
<Tab
|
||||||
|
key="insights"
|
||||||
|
label="Insights"
|
||||||
|
active={activeTab === 'insights'}
|
||||||
|
onChangeTab={() => setActiveTab('insights')}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Tab
|
||||||
|
key="overview"
|
||||||
|
label="Get started"
|
||||||
|
active={activeTab === 'overview'}
|
||||||
|
onChangeTab={() => setActiveTab('overview')}
|
||||||
|
/>
|
||||||
|
</TabsBar>
|
||||||
|
<TabContent>
|
||||||
|
{activeTab === 'insights' && <insightsScene.Component model={insightsScene} />}
|
||||||
|
{activeTab === 'overview' && <GettingStarted />}
|
||||||
|
</TabContent>
|
||||||
|
</Box>
|
||||||
|
</AlertingPageWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
import { css } from '@emotion/css';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { PluginExtensionPoints } from '@grafana/data';
|
||||||
|
import { GrafanaTheme2 } from '@grafana/data/';
|
||||||
|
import { getPluginComponentExtensions } from '@grafana/runtime';
|
||||||
|
import { Stack, Text } from '@grafana/ui';
|
||||||
|
import { useStyles2 } from '@grafana/ui/';
|
||||||
|
|
||||||
|
export function PluginIntegrations() {
|
||||||
|
const styles = useStyles2(getStyles);
|
||||||
|
|
||||||
|
const { extensions } = getPluginComponentExtensions({
|
||||||
|
extensionPointId: PluginExtensionPoints.AlertingHomePage,
|
||||||
|
limitPerPlugin: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (extensions.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Stack direction="column" gap={2}>
|
||||||
|
<Text element="h3" variant="h4">
|
||||||
|
Speed up your alerts creation now by using one of our tailored apps
|
||||||
|
</Text>
|
||||||
|
<Stack gap={2} wrap="wrap" direction="row">
|
||||||
|
{extensions.map((extension) => (
|
||||||
|
<div key={extension.id} className={styles.box}>
|
||||||
|
<extension.component />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</Stack>
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const getStyles = (theme: GrafanaTheme2) => ({
|
||||||
|
box: css({
|
||||||
|
padding: theme.spacing(2),
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: theme.colors.background.secondary,
|
||||||
|
maxWidth: '460px',
|
||||||
|
}),
|
||||||
|
});
|
Reference in New Issue
Block a user