diff --git a/CHANGELOG.md b/CHANGELOG.md
index 22a2af320d1..a53da5b0f68 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
## [`master`](https://github.com/elastic/eui/tree/master)
-No public interface changes since `16.0.1`.
+- Added `badge` prop and new styles `EuiHeaderAlert` ([#2506](https://github.com/elastic/eui/pull/2506))
## [`16.0.1`](https://github.com/elastic/eui/tree/v16.0.1)
diff --git a/src-docs/src/views/header/header_alert.js b/src-docs/src/views/header/header_alert.js
new file mode 100644
index 00000000000..6f7b739663e
--- /dev/null
+++ b/src-docs/src/views/header/header_alert.js
@@ -0,0 +1,412 @@
+import React, { Component, Fragment } from 'react';
+
+import {
+ EuiButton,
+ EuiFocusTrap,
+ EuiHorizontalRule,
+ EuiHeader,
+ EuiHeaderSection,
+ EuiHeaderSectionItem,
+ EuiHeaderSectionItemButton,
+ EuiHeaderLogo,
+ EuiHeaderLink,
+ EuiHeaderLinks,
+ EuiIcon,
+ EuiImage,
+ EuiNavDrawerGroup,
+ EuiNavDrawer,
+ EuiPage,
+ EuiPageBody,
+ EuiPageHeader,
+ EuiPageHeaderSection,
+ EuiPageContent,
+ EuiPageContentHeader,
+ EuiPageContentHeaderSection,
+ EuiPageContentBody,
+ EuiShowFor,
+ EuiTitle,
+} from '../../../../src/components';
+
+import { keyCodes } from '../../../../src/services';
+
+import HeaderUserMenu from './header_user_menu';
+import HeaderSpacesMenu from './header_spaces_menu';
+import HeaderUpdates from './header_updates';
+
+export default class extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ isFullScreen: false,
+ };
+
+ const faveExtraAction = {
+ color: 'subdued',
+ iconType: 'starEmpty',
+ iconSize: 's',
+ 'aria-label': 'Add to favorites',
+ };
+
+ const pinExtraAction = {
+ color: 'subdued',
+ iconType: 'pin',
+ iconSize: 's',
+ };
+
+ const pinExtraActionFn = val => {
+ pinExtraAction['aria-label'] = `Pin ${val} to top`;
+ return pinExtraAction;
+ };
+
+ this.topLinks = [
+ {
+ label: 'Recently viewed',
+ iconType: 'clock',
+ flyoutMenu: {
+ title: 'Recent items',
+ listItems: [
+ {
+ label: 'My dashboard',
+ href: '#/layout/nav-drawer',
+ iconType: 'dashboardApp',
+ extraAction: faveExtraAction,
+ },
+ {
+ label: 'Workpad with title that wraps',
+ href: '#/layout/nav-drawer',
+ iconType: 'canvasApp',
+ extraAction: faveExtraAction,
+ },
+ {
+ label: 'My logs',
+ href: '#/layout/nav-drawer',
+ iconType: 'logsApp',
+ 'aria-label': 'This is an alternate aria-label',
+ extraAction: faveExtraAction,
+ },
+ ],
+ },
+ },
+ {
+ label: 'Favorites',
+ iconType: 'starEmpty',
+ flyoutMenu: {
+ title: 'Favorite items',
+ listItems: [
+ {
+ label: 'My workpad',
+ href: '#/layout/nav-drawer',
+ iconType: 'canvasApp',
+ extraAction: {
+ color: 'subdued',
+ iconType: 'starFilled',
+ iconSize: 's',
+ 'aria-label': 'Remove from favorites',
+ alwaysShow: true,
+ },
+ },
+ {
+ label: 'My logs',
+ href: '#/layout/nav-drawer',
+ iconType: 'logsApp',
+ extraAction: {
+ color: 'subdued',
+ iconType: 'starFilled',
+ iconSize: 's',
+ 'aria-label': 'Remove from favorites',
+ alwaysShow: true,
+ },
+ },
+ ],
+ },
+ },
+ ];
+
+ this.exploreLinks = [
+ {
+ label: 'Canvas',
+ href: '#/layout/nav-drawer',
+ iconType: 'canvasApp',
+ isActive: true,
+ extraAction: {
+ ...pinExtraActionFn('Canvas'),
+ alwaysShow: true,
+ },
+ },
+ {
+ label: 'Discover',
+ href: '#/layout/nav-drawer',
+ iconType: 'discoverApp',
+ extraAction: { ...pinExtraActionFn('Discover') },
+ },
+ {
+ label: 'Visualize',
+ href: '#/layout/nav-drawer',
+ iconType: 'visualizeApp',
+ extraAction: { ...pinExtraActionFn('Visualize') },
+ },
+ {
+ label: 'Dashboard',
+ href: '#/layout/nav-drawer',
+ iconType: 'dashboardApp',
+ extraAction: { ...pinExtraActionFn('Dashboard') },
+ },
+ {
+ label: 'Machine learning',
+ href: '#/layout/nav-drawer',
+ iconType: 'machineLearningApp',
+ extraAction: { ...pinExtraActionFn('Machine learning') },
+ },
+ {
+ label: 'Custom Plugin (no icon)',
+ href: '#/layout/nav-drawer',
+ extraAction: { ...pinExtraActionFn('Custom Plugin') },
+ },
+ {
+ label: 'Nature Plugin (image as icon)',
+ href: '#/layout/nav-drawer',
+ extraAction: { ...pinExtraActionFn('Nature Plugin') },
+ icon: (
+
+ ),
+ },
+ ];
+
+ this.solutionsLinks = [
+ {
+ label: 'APM',
+ href: '#/layout/nav-drawer',
+ iconType: 'apmApp',
+ extraAction: { ...pinExtraActionFn('APM') },
+ },
+ {
+ label: 'Metrics',
+ href: '#/layout/nav-drawer',
+ iconType: 'metricsApp',
+ extraAction: { ...pinExtraActionFn('Infrastructure') },
+ },
+ {
+ label: 'Logs',
+ href: '#/layout/nav-drawer',
+ iconType: 'logsApp',
+ extraAction: { ...pinExtraActionFn('Log viewer') },
+ },
+ {
+ label: 'Uptime',
+ href: '#/layout/nav-drawer',
+ iconType: 'upgradeAssistantApp',
+ extraAction: { ...pinExtraActionFn('Uptime') },
+ },
+ {
+ label: 'Maps',
+ href: '#/layout/nav-drawer',
+ iconType: 'gisApp',
+ extraAction: { ...pinExtraActionFn('Maps') },
+ },
+ {
+ label: 'SIEM',
+ href: '#/layout/nav-drawer',
+ iconType: 'securityAnalyticsApp',
+ extraAction: { ...pinExtraActionFn('SIEM') },
+ },
+ ];
+
+ this.adminLinks = [
+ {
+ label: 'Admin',
+ iconType: 'managementApp',
+ flyoutMenu: {
+ title: 'Tools and settings',
+ listItems: [
+ {
+ label: 'Dev tools',
+ href: '#/layout/nav-drawer',
+ iconType: 'devToolsApp',
+ extraAction: {
+ color: 'subdued',
+ iconType: 'starEmpty',
+ iconSize: 's',
+ 'aria-label': 'Add to favorites',
+ },
+ },
+ {
+ label: 'Stack Monitoring',
+ href: '#/layout/nav-drawer',
+ iconType: 'monitoringApp',
+ extraAction: {
+ color: 'subdued',
+ iconType: 'starEmpty',
+ iconSize: 's',
+ 'aria-label': 'Add to favorites',
+ },
+ },
+ {
+ label: 'Stack Management',
+ href: '#/layout/nav-drawer',
+ iconType: 'managementApp',
+ extraAction: {
+ color: 'subdued',
+ iconType: 'starEmpty',
+ iconSize: 's',
+ 'aria-label': 'Add to favorites',
+ },
+ },
+ ],
+ },
+ },
+ ];
+ }
+
+ onKeyDown = event => {
+ if (event.keyCode === keyCodes.ESCAPE) {
+ event.preventDefault();
+ event.stopPropagation();
+ this.closeFullScreen();
+ }
+ };
+
+ toggleFullScreen = () => {
+ this.setState(prevState => ({
+ isFullScreen: !prevState.isFullScreen,
+ }));
+ };
+
+ closeFullScreen = () => {
+ this.setState({
+ isFullScreen: false,
+ });
+ };
+
+ renderLogo() {
+ return (
+
+ );
+ }
+
+ renderMenuTrigger() {
+ return (
+ this.navDrawerRef.toggleOpen()}>
+
+
+ );
+ }
+
+ setNavDrawerRef = ref => (this.navDrawerRef = ref);
+
+ render() {
+ let fullScreenDisplay;
+
+ if (this.state.isFullScreen) {
+ fullScreenDisplay = (
+
+
+
+
+
+
+ {this.renderMenuTrigger()}
+
+
+
+ {this.renderLogo()}
+
+
+
+
+
+
+
+ Home
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Kibana news feed demo
+
+
+
+
+
+
+
+ Click the button to
+ see ‘What’s new?’
+
+
+
+
+
+ Exit fullscreen demo
+
+
+
+
+
+
+
+ );
+ }
+ return (
+
+
+ Show fullscreen demo
+
+
+ {/*
+ If the below fullScreen code renders, it actually attaches to the body because of
+ EuiOverlayMask's React portal usage.
+ */}
+
+ {fullScreenDisplay}
+
+ );
+ }
+}
diff --git a/src-docs/src/views/header/header_example.js b/src-docs/src/views/header/header_example.js
index 565aed13fc8..32e8ad7eca8 100644
--- a/src-docs/src/views/header/header_example.js
+++ b/src-docs/src/views/header/header_example.js
@@ -6,6 +6,7 @@ import { GuideSectionTypes } from '../../components';
import {
EuiHeader,
+ EuiHeaderAlert,
EuiHeaderBreadcrumbs,
EuiHeaderSection,
EuiHeaderSectionItem,
@@ -20,6 +21,10 @@ import Header from './header';
const headerSource = require('!!raw-loader!./header');
const headerHtml = renderToHtml(Header);
+import HeaderAlert from './header_alert';
+const headerAlertSource = require('!!raw-loader!./header_alert');
+const headerAlertHtml = renderToHtml(HeaderAlert);
+
import HeaderLinks from './header_links';
const headerLinksSource = require('!!raw-loader!./header_links');
const headerLinksHtml = renderToHtml(HeaderLinks);
@@ -111,5 +116,33 @@ export const HeaderExample = {
snippet: headerLinksSnippet,
demo: ,
},
+ {
+ title: 'Display header alerts',
+ source: [
+ {
+ type: GuideSectionTypes.JS,
+ code: headerAlertSource,
+ },
+ {
+ type: GuideSectionTypes.HTML,
+ code: headerAlertHtml,
+ },
+ ],
+ text: (
+
+ Use an EuiHeaderSectionItemButton to display
+ additional information in an EuiPopover or{' '}
+ EuiFlyout, such as a user profile or news feed. In
+ the latter example, this additional content can be presented in a list
+ style format using EuiHeaderAlert components, as
+ shown below.
+
+ ),
+ props: {
+ EuiHeaderAlert,
+ },
+ snippet: headerLinksSnippet,
+ demo: ,
+ },
],
};
diff --git a/src-docs/src/views/header/header_updates.js b/src-docs/src/views/header/header_updates.js
new file mode 100755
index 00000000000..526a03c3a62
--- /dev/null
+++ b/src-docs/src/views/header/header_updates.js
@@ -0,0 +1,194 @@
+import React, { Component, Fragment } from 'react';
+
+import {
+ EuiIcon,
+ EuiHeaderAlert,
+ EuiHeaderSectionItemButton,
+ EuiFlyout,
+ EuiFlyoutBody,
+ EuiFlyoutHeader,
+ EuiTitle,
+ EuiNotificationBadge,
+ EuiLink,
+ EuiFlyoutFooter,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiButtonEmpty,
+ EuiText,
+ EuiBadge,
+} from '../../../../src/components';
+
+export default class extends Component {
+ constructor(props) {
+ super(props);
+
+ this.state = {
+ isFlyoutVisible: false,
+ showBadge: true,
+ };
+
+ this.alerts = [
+ {
+ title: 'Control access to features',
+ text: 'Show or hide applications and features per space in Kibana.',
+ action: Learn about feature controls,
+ date: '1 May 2019',
+ badge: 7.1,
+ },
+ {
+ title: 'Kibana 7.0 is turning heads',
+ text:
+ 'Simplified navigation, responsive dashboards, dark mode… pick your favorite.',
+ action: (
+
+ Read the blog
+
+ ),
+ date: '10 April 2019',
+ badge: 7.0,
+ },
+ {
+ title: 'Enter dark mode',
+ text:
+ 'Kibana now supports the easy-on-the-eyes theme across the entire UI.',
+ action: Go to Advanced Settings,
+ date: '10 April 2019',
+ badge: 7.0,
+ },
+ {
+ title: 'Pixel-perfect Canvas is production ready',
+ text: 'Your creative space for visualizing data awaits.',
+ action: (
+
+ Watch the webinar
+
+ ),
+ date: '26 March 2019',
+ badge: 6.7,
+ },
+ {
+ title: '6.7 release notes',
+ text: 'Stay up-to-date on the latest and greatest features.',
+ action: (
+
+ Check out the docs
+
+ ),
+ date: '26 March 2019',
+ badge: 6.7,
+ },
+ {
+ title: 'Rollups made simple in Kibana',
+ text:
+ 'Save space and preserve the integrity of your data directly in the UI.',
+ action: (
+
+ Read the blog
+
+ ),
+ date: '10 January 2019',
+ badge: 6.5,
+ },
+ ];
+ }
+
+ closeFlyout = () => {
+ this.setState({ isFlyoutVisible: false });
+ };
+
+ showFlyout = () => {
+ this.setState({ showBadge: false });
+ this.setState(prevState => ({
+ isFlyoutVisible: !prevState.isFlyoutVisible,
+ }));
+ };
+
+ render() {
+ const button = (
+
+
+
+ {this.state.showBadge ? (
+
+ ▪
+
+ ) : null}
+
+ );
+
+ let flyout;
+ const flyoutStyle = {
+ top: '49px',
+ height: 'calc(100vh - 49px)',
+ };
+ if (this.state.isFlyoutVisible) {
+ flyout = (
+
+ );
+ }
+
+ return (
+
+ {button}
+ {flyout}
+
+ );
+ }
+}
diff --git a/src-docs/src/views/header/header_user_menu.js b/src-docs/src/views/header/header_user_menu.js
index 66d3e5164df..c0ff4802d52 100644
--- a/src-docs/src/views/header/header_user_menu.js
+++ b/src-docs/src/views/header/header_user_menu.js
@@ -4,9 +4,7 @@ import {
EuiAvatar,
EuiFlexGroup,
EuiFlexItem,
- EuiHeaderAlert,
EuiHeaderSectionItemButton,
- EuiNotificationBadge,
EuiLink,
EuiText,
EuiSpacer,
@@ -43,10 +41,6 @@ export default class extends Component {
aria-label="Account menu"
onClick={this.onMenuButtonClick}>
-
-
- 3
-
);
@@ -90,26 +84,6 @@ export default class extends Component {
-
-
-
- Download your thing here}
- date="Nov. 14, 02:14PM."
- />
-
- Download your thing here}
- date="Nov. 14, 02:14PM."
- />
);
diff --git a/src/components/header/header_alert/__snapshots__/header_alert.test.tsx.snap b/src/components/header/header_alert/__snapshots__/header_alert.test.tsx.snap
index eaf93871bfd..dfeac591855 100644
--- a/src/components/header/header_alert/__snapshots__/header_alert.test.tsx.snap
+++ b/src/components/header/header_alert/__snapshots__/header_alert.test.tsx.snap
@@ -1,46 +1,17 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`EuiHeaderAlert is rendered 1`] = `
-