diff --git a/src/core_plugins/kibana/public/dashboard/components/__snapshots__/exit_full_screen_button.test.js.snap b/src/core_plugins/kibana/public/dashboard/components/__snapshots__/exit_full_screen_button.test.js.snap
new file mode 100644
index 000000000000..8f8032a483f4
--- /dev/null
+++ b/src/core_plugins/kibana/public/dashboard/components/__snapshots__/exit_full_screen_button.test.js.snap
@@ -0,0 +1,33 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`is rendered 1`] = `
+
+
+
+`;
diff --git a/src/core_plugins/kibana/public/dashboard/components/exit_full_screen_button.js b/src/core_plugins/kibana/public/dashboard/components/exit_full_screen_button.js
new file mode 100644
index 000000000000..02cfe1d3fe20
--- /dev/null
+++ b/src/core_plugins/kibana/public/dashboard/components/exit_full_screen_button.js
@@ -0,0 +1,56 @@
+import React, { PureComponent } from 'react';
+import PropTypes from 'prop-types';
+import chrome from 'ui/chrome';
+
+import {
+ KuiButton,
+} from 'ui_framework/components';
+
+import {
+ keyCodes,
+} from 'ui_framework/services';
+
+export class ExitFullScreenButton extends PureComponent {
+
+ onKeyDown = (e) => {
+ if (e.keyCode === keyCodes.ESCAPE) {
+ this.props.onExitFullScreenMode();
+ }
+ };
+
+ componentWillMount() {
+ document.addEventListener('keydown', this.onKeyDown, false);
+ chrome.setVisible(false);
+ }
+
+ componentWillUnmount() {
+ document.removeEventListener('keydown', this.onKeyDown, false);
+ chrome.setVisible(true);
+ }
+
+ render() {
+ return (
+
+
+
+
+ Exit full screen
+
+
+
+
+ );
+ }
+}
+
+ExitFullScreenButton.propTypes = {
+ onExitFullScreenMode: PropTypes.func.isRequired,
+};
+
diff --git a/src/core_plugins/kibana/public/dashboard/components/exit_full_screen_button.test.js b/src/core_plugins/kibana/public/dashboard/components/exit_full_screen_button.test.js
new file mode 100644
index 000000000000..77e2512c453f
--- /dev/null
+++ b/src/core_plugins/kibana/public/dashboard/components/exit_full_screen_button.test.js
@@ -0,0 +1,78 @@
+jest.mock('ui/chrome',
+ () => ({
+ getKibanaVersion: () => '6.0.0',
+ setVisible: () => {},
+ }), { virtual: true });
+
+import React from 'react';
+import { render, mount } from 'enzyme';
+import sinon from 'sinon';
+import chrome from 'ui/chrome';
+
+import {
+ ExitFullScreenButton,
+} from './exit_full_screen_button';
+
+import { keyCodes } from 'ui_framework/services';
+
+
+test('is rendered', () => {
+ const component = render(
+ {}}/>
+ );
+
+ expect(component)
+ .toMatchSnapshot();
+});
+
+describe('onExitFullScreenMode', () => {
+ test('is called when the button is pressed', () => {
+ const onExitHandler = sinon.stub();
+
+ const component = mount(
+
+ );
+
+ component.find('button').simulate('click');
+
+ sinon.assert.calledOnce(onExitHandler);
+ });
+
+ test('is called when the ESC key is pressed', () => {
+ const onExitHandler = sinon.stub();
+
+ mount();
+
+ const escapeKeyEvent = new KeyboardEvent('keydown', { keyCode: keyCodes.ESCAPE });
+ document.dispatchEvent(escapeKeyEvent);
+
+ sinon.assert.calledOnce(onExitHandler);
+ });
+});
+
+describe('chrome.setVisible', () => {
+ test('is called with false when the component is rendered', () => {
+ chrome.setVisible = sinon.stub();
+
+ const component = mount(
+ {}} />
+ );
+
+ component.find('button').simulate('click');
+
+ sinon.assert.calledOnce(chrome.setVisible);
+ sinon.assert.calledWith(chrome.setVisible, false);
+ });
+
+ test('is called with true the component is unmounted', () => {
+ const component = mount(
+ {}} />
+ );
+
+ chrome.setVisible = sinon.stub();
+ component.unmount();
+
+ sinon.assert.calledOnce(chrome.setVisible);
+ sinon.assert.calledWith(chrome.setVisible, true);
+ });
+});
diff --git a/src/core_plugins/kibana/public/dashboard/dashboard_app.html b/src/core_plugins/kibana/public/dashboard/dashboard_app.html
index 02f0c9cbf9aa..ac2057236a08 100644
--- a/src/core_plugins/kibana/public/dashboard/dashboard_app.html
+++ b/src/core_plugins/kibana/public/dashboard/dashboard_app.html
@@ -2,21 +2,6 @@
class="app-container dashboard-container"
ng-class="{'dashboard-container-with-margins': model.useMargins}"
>
-
-
-
-
- Exit full screen
-
-
-
-
diff --git a/src/core_plugins/kibana/public/dashboard/dashboard_app.js b/src/core_plugins/kibana/public/dashboard/dashboard_app.js
index ee91f54365a5..a8c4ceffc8f2 100644
--- a/src/core_plugins/kibana/public/dashboard/dashboard_app.js
+++ b/src/core_plugins/kibana/public/dashboard/dashboard_app.js
@@ -18,7 +18,6 @@ import { DashboardStateManager } from './dashboard_state_manager';
import { saveDashboard } from './lib';
import { showCloneModal } from './top_nav/show_clone_modal';
import { migrateLegacyQuery } from 'ui/utils/migrateLegacyQuery';
-import { keyCodes } from 'ui_framework/services';
import { DashboardContainerAPI } from './dashboard_container_api';
import * as filterActions from 'ui/doc_table/actions/filter';
import { FilterManagerProvider } from 'ui/filter_manager';
@@ -98,7 +97,6 @@ app.directive('dashboardApp', function ($injector) {
description: dashboardStateManager.getDescription(),
};
$scope.panels = dashboardStateManager.getPanels();
- $scope.fullScreenMode = dashboardStateManager.getFullScreenMode();
$scope.indexPatterns = dashboardStateManager.getPanelIndexPatterns();
};
@@ -268,50 +266,19 @@ app.directive('dashboardApp', function ($injector) {
}).catch(notify.error);
};
- $scope.showFilterBar = () => filterBar.getFilters().length > 0 || !$scope.fullScreenMode;
- let onRouteChange;
- const setFullScreenMode = (fullScreenMode) => {
- $scope.fullScreenMode = fullScreenMode;
- dashboardStateManager.setFullScreenMode(fullScreenMode);
- chrome.setVisible(!fullScreenMode);
- $scope.$broadcast('reLayout');
-
- // Make sure that if we exit the dashboard app, the chrome becomes visible again
- // (e.g. if the user clicks the back button).
- if (fullScreenMode) {
- onRouteChange = $scope.$on('$routeChangeStart', () => {
- chrome.setVisible(true);
- onRouteChange();
- });
- } else if (onRouteChange) {
- onRouteChange();
- }
- };
-
- $scope.$watch('fullScreenMode', () => setFullScreenMode(dashboardStateManager.getFullScreenMode()));
-
- $scope.exitFullScreenMode = () => setFullScreenMode(false);
-
- document.addEventListener('keydown', (e) => {
- if (e.keyCode === keyCodes.ESCAPE) {
- setFullScreenMode(false);
- }
- }, false);
+ $scope.showFilterBar = () => filterBar.getFilters().length > 0 || !dashboardStateManager.getFullScreenMode();
$scope.showAddPanel = () => {
- if ($scope.fullScreenMode) {
- $scope.exitFullScreenMode();
- }
+ dashboardStateManager.setFullScreenMode(false);
$scope.kbnTopNav.open('add');
};
$scope.enterEditMode = () => {
- if ($scope.fullScreenMode) {
- $scope.exitFullScreenMode();
- }
+ dashboardStateManager.setFullScreenMode(false);
$scope.kbnTopNav.click('edit');
};
const navActions = {};
- navActions[TopNavIds.FULL_SCREEN] = () => setFullScreenMode(true);
+ navActions[TopNavIds.FULL_SCREEN] = () =>
+ dashboardStateManager.setFullScreenMode(true);
navActions[TopNavIds.EXIT_EDIT_MODE] = () => onChangeViewMode(DashboardViewMode.VIEW);
navActions[TopNavIds.ENTER_EDIT_MODE] = () => onChangeViewMode(DashboardViewMode.EDIT);
navActions[TopNavIds.CLONE] = () => {
diff --git a/src/core_plugins/kibana/public/dashboard/dashboard_state_manager.js b/src/core_plugins/kibana/public/dashboard/dashboard_state_manager.js
index e795937a910b..669007e3615c 100644
--- a/src/core_plugins/kibana/public/dashboard/dashboard_state_manager.js
+++ b/src/core_plugins/kibana/public/dashboard/dashboard_state_manager.js
@@ -45,7 +45,7 @@ import {
* - maximizedPanelId
*
* State that is shared and needs to be synced:
- * - fullScreenMode - changes only propagate from AppState -> Store
+ * - fullScreenMode - changes propagate from AppState -> Store and from Store -> AppState.
* - viewMode - changes only propagate from AppState -> Store
* - panels - changes propagate from AppState -> Store and from Store -> AppState.
*
@@ -152,21 +152,22 @@ export class DashboardStateManager {
}
_handleStoreChanges() {
- if (this._areStoreAndAppStatePanelsEqual()) {
- return;
+ let dirty = false;
+ if (!this._areStoreAndAppStatePanelsEqual()) {
+ const panels = getPanels(store.getState());
+ this.appState.panels = [];
+ Object.values(panels).map(panel => {
+ this.appState.panels.push(panel);
+ });
+ dirty = true;
}
- const state = store.getState();
- // The only state that the store deals with that appState cares about is the panels array. Every other state change
- // (that appState cares about) is initiated from appState (e.g. view mode).
- this.appState.panels = [];
- _.map(getPanels(state), panel => {
- this.appState.panels.push(panel);
- });
+ const fullScreen = getFullScreenMode(store.getState());
+ if (fullScreen !== this.getFullScreenMode()) {
+ this.setFullScreenMode(fullScreen);
+ }
- this.changeListeners.forEach(function (listener) {
- return listener({ dirty: true, clean: false });
- });
+ this.changeListeners.forEach(listener => listener({ dirty }));
this.saveState();
}
diff --git a/src/core_plugins/kibana/public/dashboard/styles/index.less b/src/core_plugins/kibana/public/dashboard/styles/index.less
index 412095e3dc32..70e9813ed4d9 100644
--- a/src/core_plugins/kibana/public/dashboard/styles/index.less
+++ b/src/core_plugins/kibana/public/dashboard/styles/index.less
@@ -4,7 +4,7 @@
@import "~react-grid-layout/css/styles.css";
@import "~react-resizable/css/styles.css";
-.fullScreenModePlaceholder {
+.exitFullScreenButton {
text-align: center;
width: 100%;
height: 0;
diff --git a/src/core_plugins/kibana/public/dashboard/viewport/dashboard_viewport.js b/src/core_plugins/kibana/public/dashboard/viewport/dashboard_viewport.js
index 1105afdde8bf..af969bd0e23c 100644
--- a/src/core_plugins/kibana/public/dashboard/viewport/dashboard_viewport.js
+++ b/src/core_plugins/kibana/public/dashboard/viewport/dashboard_viewport.js
@@ -1,6 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { DashboardGrid } from '../grid';
+import { ExitFullScreenButton } from '../components/exit_full_screen_button';
export function DashboardViewport({
getContainerApi,
@@ -10,6 +11,8 @@ export function DashboardViewport({
title,
description,
useMargins,
+ isFullScreenMode,
+ onExitFullScreenMode,
}) {
return (
+ { isFullScreenMode && }
{
const maximizedPanelId = getMaximizedPanelId(dashboard);
@@ -10,10 +18,15 @@ const mapStateToProps = ({ dashboard }) => {
description: getDescription(dashboard),
title: getTitle(dashboard),
useMargins: getUseMargins(dashboard),
+ isFullScreenMode: getFullScreenMode(dashboard),
};
};
-export const DashboardViewportContainer = connect(
- mapStateToProps
-)(DashboardViewport);
+const mapDispatchToProps = (dispatch) => ({
+ onExitFullScreenMode: () => dispatch(updateIsFullScreenMode(false)),
+});
+export const DashboardViewportContainer = connect(
+ mapStateToProps,
+ mapDispatchToProps,
+)(DashboardViewport);