Skip to content

Commit

Permalink
EUIify dashboard options top nav (#21510) (#21751)
Browse files Browse the repository at this point in the history
* trying new EuiWrappingPopover

* allow button press to close popover

* fix button styling

* start options panel with darkTheme option

* add other options

* remove old options html

* get dashboar state functional test working
  • Loading branch information
nreese committed Aug 7, 2018
1 parent 4e437a1 commit 5661286
Show file tree
Hide file tree
Showing 9 changed files with 211 additions and 69 deletions.
34 changes: 21 additions & 13 deletions src/core_plugins/kibana/public/dashboard/dashboard_app.js
Expand Up @@ -42,6 +42,7 @@ import { saveDashboard } from './lib';
import { showCloneModal } from './top_nav/show_clone_modal';
import { showSaveModal } from './top_nav/show_save_modal';
import { showAddPanel } from './top_nav/show_add_panel';
import { showOptionsPopover } from './top_nav/show_options_popover';
import { migrateLegacyQuery } from 'ui/utils/migrateLegacyQuery';
import * as filterActions from 'ui/doc_table/actions/filter';
import { FilterManagerProvider } from 'ui/filter_manager';
Expand Down Expand Up @@ -116,9 +117,6 @@ app.directive('dashboardApp', function ($injector) {
// https://github.com/angular/angular.js/wiki/Understanding-Scopes
$scope.model = {
query: dashboardStateManager.getQuery(),
useMargins: dashboardStateManager.getUseMargins(),
hidePanelTitles: dashboardStateManager.getHidePanelTitles(),
darkTheme: dashboardStateManager.getDarkTheme(),
timeRestore: dashboardStateManager.getTimeRestore(),
title: dashboardStateManager.getTitle(),
description: dashboardStateManager.getDescription(),
Expand Down Expand Up @@ -201,16 +199,8 @@ app.directive('dashboardApp', function ($injector) {
$scope.refresh();
};

$scope.$watch('model.hidePanelTitles', () => {
dashboardStateManager.setHidePanelTitles($scope.model.hidePanelTitles);
});
$scope.$watch('model.useMargins', () => {
dashboardStateManager.setUseMargins($scope.model.useMargins);
});
$scope.$watch('model.darkTheme', () => {
dashboardStateManager.setDarkTheme($scope.model.darkTheme);
updateTheme();
});
updateTheme();

$scope.indexPatterns = [];

$scope.onPanelRemoved = (panelIndex) => {
Expand Down Expand Up @@ -391,6 +381,24 @@ app.directive('dashboardApp', function ($injector) {

showAddPanel(chrome.getSavedObjectsClient(), dashboardStateManager.addNewPanel, addNewVis, listingLimit, isLabsEnabled, visTypes);
};
navActions[TopNavIds.OPTIONS] = (menuItem, navController, anchorElement) => {
showOptionsPopover({
anchorElement,
darkTheme: dashboardStateManager.getDarkTheme(),
onDarkThemeChange: (isChecked) => {
dashboardStateManager.setDarkTheme(isChecked);
updateTheme();
},
useMargins: dashboardStateManager.getUseMargins(),
onUseMarginsChange: (isChecked) => {
dashboardStateManager.setUseMargins(isChecked);
},
hidePanelTitles: dashboardStateManager.getHidePanelTitles(),
onHidePanelTitlesChange: (isChecked) => {
dashboardStateManager.setHidePanelTitles(isChecked);
},
});
};
updateViewMode(dashboardStateManager.getViewMode());

// update root source when filters update
Expand Down
Expand Up @@ -48,7 +48,7 @@ export function getTopNavConfig(dashboardMode, actions, hideWriteControls) {
getSaveConfig(actions[TopNavIds.SAVE]),
getViewConfig(actions[TopNavIds.EXIT_EDIT_MODE]),
getAddConfig(actions[TopNavIds.ADD]),
getOptionsConfig(),
getOptionsConfig(actions[TopNavIds.OPTIONS]),
getShareConfig()];
default:
return [];
Expand Down Expand Up @@ -139,11 +139,11 @@ function getShareConfig() {
/**
* @returns {kbnTopNavConfig}
*/
function getOptionsConfig() {
function getOptionsConfig(action) {
return {
key: TopNavIds.OPTIONS,
description: 'Options',
testId: 'dashboardOptionsButton',
template: require('plugins/kibana/dashboard/top_nav/options.html')
run: action,
};
}
45 changes: 0 additions & 45 deletions src/core_plugins/kibana/public/dashboard/top_nav/options.html

This file was deleted.

100 changes: 100 additions & 0 deletions src/core_plugins/kibana/public/dashboard/top_nav/options.js
@@ -0,0 +1,100 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React, { Component } from 'react';
import PropTypes from 'prop-types';

import {
EuiForm,
EuiFormRow,
EuiSwitch,
} from '@elastic/eui';

export class OptionsMenu extends Component {

state = {
darkTheme: this.props.darkTheme,
useMargins: this.props.useMargins,
hidePanelTitles: this.props.hidePanelTitles,
}

handleDarkThemeChange = (evt) => {
const isChecked = evt.target.checked;
this.props.onDarkThemeChange(isChecked);
this.setState({ darkTheme: isChecked });
}

handleUseMarginsChange = (evt) => {
const isChecked = evt.target.checked;
this.props.onUseMarginsChange(isChecked);
this.setState({ useMargins: isChecked });
}

handleHidePanelTitlesChange = (evt) => {
const isChecked = evt.target.checked;
this.props.onHidePanelTitlesChange(isChecked);
this.setState({ hidePanelTitles: isChecked });
}

render() {
return (
<EuiForm
data-test-subj="dashboardOptionsMenu"
>

<EuiFormRow>
<EuiSwitch
label="Use dark theme"
checked={this.state.darkTheme}
onChange={this.handleDarkThemeChange}
data-test-subj="dashboardDarkThemeCheckbox"
/>
</EuiFormRow>

<EuiFormRow>
<EuiSwitch
label="Use margins between panels"
checked={this.state.useMargins}
onChange={this.handleUseMarginsChange}
data-test-subj="dashboardMarginsCheckbox"
/>
</EuiFormRow>

<EuiFormRow>
<EuiSwitch
label="Hide all panel titles"
checked={this.state.hidePanelTitles}
onChange={this.handleHidePanelTitlesChange}
data-test-subj="dashboardPanelTitlesCheckbox"
/>
</EuiFormRow>

</EuiForm>
);
}
}

OptionsMenu.propTypes = {
darkTheme: PropTypes.bool.isRequired,
onDarkThemeChange: PropTypes.func.isRequired,
useMargins: PropTypes.bool.isRequired,
onUseMarginsChange: PropTypes.func.isRequired,
hidePanelTitles: PropTypes.bool.isRequired,
onHidePanelTitlesChange: PropTypes.func.isRequired,
};
@@ -0,0 +1,7 @@
.dashOptionsPopover {
height: 100%;

.euiPopover__anchor {
height: 100%;
}
}
@@ -0,0 +1,75 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import './options_popover.less';
import React from 'react';
import ReactDOM from 'react-dom';

import { OptionsMenu } from './options';

import {
EuiWrappingPopover,
} from '@elastic/eui';

let isOpen = false;

const container = document.createElement('div');

const onClose = () => {
ReactDOM.unmountComponentAtNode(container);
isOpen = false;
};

export function showOptionsPopover({
anchorElement,
darkTheme,
onDarkThemeChange,
useMargins,
onUseMarginsChange,
hidePanelTitles,
onHidePanelTitlesChange,
}) {
if (isOpen) {
onClose();
return;
}

isOpen = true;

document.body.appendChild(container);
const element = (
<EuiWrappingPopover
className="dashOptionsPopover"
id="popover"
button={anchorElement}
isOpen={true}
closePopover={onClose}
>
<OptionsMenu
darkTheme={darkTheme}
onDarkThemeChange={onDarkThemeChange}
useMargins={useMargins}
onUseMarginsChange={onUseMarginsChange}
hidePanelTitles={hidePanelTitles}
onHidePanelTitlesChange={onHidePanelTitlesChange}
/>
</EuiWrappingPopover>
);
ReactDOM.render(element, container);
}
2 changes: 1 addition & 1 deletion src/ui/public/kbn_top_nav/kbn_top_nav.html
Expand Up @@ -22,7 +22,7 @@
aria-expanded="{{kbnTopNav.isCurrent(menuItem.key)}}"
aria-disabled="{{menuItem.disableButton()}}"
ng-class="{'kuiLocalMenuItem-isSelected': kbnTopNav.isCurrent(menuItem.key), 'kuiLocalMenuItem-isDisabled': menuItem.disableButton()}"
ng-click="kbnTopNav.handleClick(menuItem)"
ng-click="kbnTopNav.handleClick(menuItem, $event)"
ng-bind="menuItem.label"
tooltip="{{menuItem.tooltip()}}"
tooltip-placement="bottom"
Expand Down
4 changes: 2 additions & 2 deletions src/ui/public/kbn_top_nav/kbn_top_nav_controller.js
Expand Up @@ -79,11 +79,11 @@ export function KbnTopNavControllerProvider($compile) {
toggle = (key) => { this.setCurrent(this.isCurrent(key) ? null : key); };
click = (key) => { this.handleClick(this.getItem(key)); };
getItem = (key) => { return this.menuItems.find(i => i.key === key); };
handleClick = (menuItem) => {
handleClick = (menuItem, event) => {
if (menuItem.disableButton()) {
return false;
}
menuItem.run(menuItem, this);
menuItem.run(menuItem, this, event.target);
};
// apply the defaults to individual options
_applyOptDefault(opt = {}) {
Expand Down
7 changes: 2 additions & 5 deletions test/functional/page_objects/dashboard_page.js
Expand Up @@ -220,13 +220,9 @@ export function DashboardPageProvider({ getService, getPageObjects }) {
await testSubjects.click('deleteSelectedDashboards');
}

async clickOptions() {
await testSubjects.click('dashboardOptionsButton');
}

async isOptionsOpen() {
log.debug('isOptionsOpen');
return await testSubjects.exists('dashboardDarkThemeCheckbox');
return await testSubjects.exists('dashboardOptionsMenu');
}

async openOptions() {
Expand All @@ -253,6 +249,7 @@ export function DashboardPageProvider({ getService, getPageObjects }) {
}

async useDarkTheme(on) {
log.debug(`useDarkTheme: on ${on}`);
await this.openOptions();
const isDarkThemeOn = await this.isDarkThemeOn();
if (isDarkThemeOn !== on) {
Expand Down

0 comments on commit 5661286

Please sign in to comment.