diff --git a/pkg/api/index.go b/pkg/api/index.go index aaaaed3a1f6..bbc982a4a2e 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -196,6 +196,16 @@ func (hs *HTTPServer) getNavTree(c *models.ReqContext, hasEditPerm bool) ([]*dto }) } + if hs.Cfg.IsNgAlertEnabled() { + navTree = append(navTree, &dtos.NavLink{ + Text: "NgAlerting", + Id: "ngalerting", + SubTitle: "Next generation alerting", + Icon: "bell", + Url: setting.AppSubUrl + "/ngalerting", + }) + } + if c.IsSignedIn { navTree = append(navTree, getProfileNode(c)) } diff --git a/public/app/core/components/PageToolbar/PageToolbar.tsx b/public/app/core/components/PageToolbar/PageToolbar.tsx new file mode 100644 index 00000000000..8255d33f635 --- /dev/null +++ b/public/app/core/components/PageToolbar/PageToolbar.tsx @@ -0,0 +1,51 @@ +import React, { FC, ReactNode } from 'react'; +import { css } from 'emotion'; +import { GrafanaTheme } from '@grafana/data'; +import { HorizontalGroup, stylesFactory, useTheme } from '@grafana/ui'; + +interface Props { + title: string; + titlePrefix?: ReactNode; + actions: ReactNode[]; + titlePadding?: 'sm' | 'lg'; +} + +export const PageToolbar: FC = ({ actions, title, titlePrefix, titlePadding = 'lg' }) => { + const styles = getStyles(useTheme(), titlePadding); + return ( +
+ +
+ + {titlePrefix} + {title} + +
+ + {actions} + +
+
+ ); +}; + +const getStyles = stylesFactory((theme: GrafanaTheme, padding: string) => { + const titlePadding = padding === 'sm' ? theme.spacing.sm : theme.spacing.md; + + return { + toolbarWrapper: css` + display: flex; + padding: ${theme.spacing.sm}; + background: ${theme.colors.panelBg}; + justify-content: space-between; + border-bottom: 1px solid ${theme.colors.panelBorder}; + `, + toolbarLeft: css` + padding-left: ${theme.spacing.sm}; + `, + toolbarTitle: css` + font-size: ${theme.typography.size.lg}; + padding-left: ${titlePadding}; + `, + }; +}); diff --git a/public/app/features/alerting/EditNotificationChannelPage.tsx b/public/app/features/alerting/EditNotificationChannelPage.tsx index efa6b1ca4b9..57c4587a2da 100644 --- a/public/app/features/alerting/EditNotificationChannelPage.tsx +++ b/public/app/features/alerting/EditNotificationChannelPage.tsx @@ -91,7 +91,7 @@ export class EditNotificationChannelPage extends PureComponent { return ( { return ( { + state = { dataSources: [] }; + + componentDidMount() { + this.props.loadNotificationTypes(); + } + + onChangeAlertOption = (event: FormEvent) => { + this.props.updateAlertDefinitionOption({ [event.currentTarget.name]: event.currentTarget.value }); + }; + + onSaveAlert = () => { + const { createAlertDefinition } = this.props; + + createAlertDefinition(); + }; + + onDiscard = () => {}; + + onTest = () => {}; + + renderToolbarActions() { + return [ + , + , + , + ]; + } + + render() { + const { + alertDefinition, + notificationChannelTypes, + uiState, + updateAlertDefinitionUiState, + queryRunner, + } = this.props; + const styles = getStyles(config.theme); + + return ( +
+ } + actions={this.renderToolbarActions()} + titlePadding="sm" + /> + , + , + ]} + uiState={uiState} + updateUiState={updateAlertDefinitionUiState} + rightPaneComponents={ + + } + /> +
+ ); + } +} + +const mapStateToProps: MapStateToProps = state => { + return { + uiState: state.alertDefinition.uiState, + alertDefinition: state.alertDefinition.alertDefinition, + notificationChannelTypes: state.notificationChannel.notificationChannelTypes, + queryRunner: state.alertDefinition.queryRunner, + }; +}; + +const mapDispatchToProps: MapDispatchToProps = { + createAlertDefinition, + updateAlertDefinitionUiState, + updateAlertDefinitionOption, + loadNotificationTypes, +}; + +export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(NextGenAlertingPage)); + +const getStyles = stylesFactory((theme: GrafanaTheme) => { + return { + wrapper: css` + background-color: ${theme.colors.dashboardBg}; + `, + }; +}); diff --git a/public/app/features/alerting/components/AlertDefinitionOptions.tsx b/public/app/features/alerting/components/AlertDefinitionOptions.tsx new file mode 100644 index 00000000000..e70ffba47e1 --- /dev/null +++ b/public/app/features/alerting/components/AlertDefinitionOptions.tsx @@ -0,0 +1,55 @@ +import React, { FC, FormEvent } from 'react'; +import { css } from 'emotion'; +import { GrafanaTheme } from '@grafana/data'; +import { Field, Input, Select, TextArea, useStyles } from '@grafana/ui'; +import { AlertDefinition, NotificationChannelType } from 'app/types'; +import { mapChannelsToSelectableValue } from '../utils/notificationChannels'; + +interface Props { + alertDefinition: AlertDefinition; + notificationChannelTypes: NotificationChannelType[]; + onChange: (event: FormEvent) => void; +} + +export const AlertDefinitionOptions: FC = ({ alertDefinition, notificationChannelTypes, onChange }) => { + const styles = useStyles(getStyles); + + return ( +
+
+

Alert definition

+ + + + +