Skip to content

Commit

Permalink
View edit mode
Browse files Browse the repository at this point in the history
clean up

show spy panel in embed mode

[webpack] fix loader query string usage (elastic#9497)

* [webpack] pin to fork with fixed loader aliases

* [optimizer] upgrade to postcss+autoprefixer

* [timelion] convert uiExports.modules -> webpackShims

* [uiExports] remove implementation-leaking and unused uiExport types

* [optimizer] remove unused imports

* [uiBundlerEnv] add a method for exporting global import aliases for special cases

[dev tools] Hide app link when there are no tools (elastic#9489)

* [dev tools] Hide app link when there are no tools

* [dev tools] Add tests for setting app as hidden

pie chart unhandled error fix (elastic#9422)

Add NoResults and Panel components. (elastic#9516)

* Add NoResults and Panel components.

* Lighten noResults text.

Update ToolBarFooter component to support content on the left side. (elastic#9514)

Fix bug with Button component appearance inside of a ToolBar. (elastic#9526)

Make basic Button hover state the same both in and out of ToolBar. (elastic#9528)

[grunt/eslint] fix precommit linting (elastic#9510)

* [grunt/eslint] fix precommit linting

 - remove use of `minimatch.makeRe()` because it does not support the entire glob syntax
 - log a warning whenever a js file is excluded by the `lintStagedFiles` task
 - eslint globs are relative to the project root, ensure that we check against relative version

* [grunt/eslint] only log warning wtr grunt paths

Add Tabs component. (elastic#9536)

- Fix bugs with Button and CheckBox focused states.
- Fix appearance of cell content in Table.

Disable linting for Tabs component example JS. (elastic#9538)

Set Button component to display: inline-block, to ensure it has the same height when applied to both button elements and anchor tags. (elastic#9541)

fixing metric vis to correctly show scrollbars when overflown (elastic#9481)

Adding Safari 7 support to autoprefixer (elastic#9534)

PhantomJS is using a rather outdated version of WebKit, which requires
various css-prefixes to render correctly. PhantomJS doesn't have a specific
user-agent, and Safari 7 is the closet version of WebKit.

use Stop Editing instead of Preview

Warn the user if they Stop Editing with unsaved changes

- Refresh the dashboard after stop editing so unsaved changes are lost
and no temporary edits will be shown in non-edit mode.

Don't watch the variable on scope, but the config attribute
  • Loading branch information
stacey-gammon committed Jan 19, 2017
1 parent 6b009a1 commit 506734c
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="panel panel-default" ng-switch on="panel.type" ng-if="savedObj || error">
<div class="panel panel-default" ng-class="{'panel--edit-mode': !isViewOnlyMode()}" ng-switch on="panel.type" ng-if="savedObj || error">
<div class="panel-heading">
<span class="panel-title" title="{{::savedObj.title}}">
{{::savedObj.title}}
Expand All @@ -7,13 +7,13 @@
<a aria-label="Expand" ng-click="toggleExpand()">
<span class="fa" ng-class="{'fa-expand': !isExpanded, 'fa-compress': isExpanded}"></span>
</a>
<a aria-label="Edit" ng-show="!isFullScreenMode && editUrl" ng-href="{{::editUrl}}">
<a aria-label="Edit" ng-show="!isViewOnlyMode() && editUrl" ng-href="{{::editUrl}}">
<i aria-hidden="true" class="fa fa-pencil"></i>
</a>
<a aria-label="Move" ng-show="!isExpanded && !isFullScreenMode" class="panel-move">
<a aria-label="Move" ng-show="!isViewOnlyMode()" class="panel-move">
<i aria-hidden="true" class="fa fa-arrows"></i>
</a>
<a aria-label="Remove" ng-show="!isExpanded && !isFullScreenMode" ng-click="remove()">
<a aria-label="Remove" ng-show="!isViewOnlyMode()" ng-click="remove()">
<i aria-hidden="true" class="fa fa-times"></i>
</a>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

import stateMonitorFactory from 'ui/state_management/state_monitor_factory';

export class DashboardAppStateManager {
constructor(stateDefaults, AppState) {
let temporaryStateMonitor;
let persistedStateMonitor;

let temporaryAppState;
let persistedAppState;

this.appState = new AppState(stateDefaults);
this.uiState = this.appState.makeStateful('uiState');
this.$appStatus = {};

// watch for state changes and update the appStatus.dirty value
this.stateMonitor = stateMonitorFactory.create($state, stateDefaults);
this.stateMonitor.onChange((status) => {
$appStatus.dirty = status.dirty;
});

this.viewMode = currentViewMode;
}

onViewModeChanged(newMode) {
this.viewMode = newMode;

}

destroy() {
this.stateMonitor.destroy();
}
}


function resetState(dashboardStateManager, newAppState) {
dashboardStateManager.appState = newAppState;
dashboardStateManager.uiState = newAppState.makeStateful('uiState');
}
13 changes: 13 additions & 0 deletions src/core_plugins/kibana/public/dashboard/dashboard_view_mode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* A dashboard mode.
* @typedef {string} DashboardMode
*/

/**
* Dashboard view modes.
* @type {{EDIT: DashboardMode, VIEW: DashboardMode}}
*/
export const DashboardViewMode = {
EDIT: 'edit',
VIEW: 'view'
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { loadPanelProvider } from 'plugins/kibana/dashboard/components/panel/lib
import FilterManagerProvider from 'ui/filter_manager';
import uiModules from 'ui/modules';
import panelTemplate from 'plugins/kibana/dashboard/components/panel/panel.html';
import { DashboardViewMode } from 'plugins/kibana/dashboard/dashboard_view_mode';

uiModules
.get('app/dashboard')
Expand Down Expand Up @@ -33,6 +34,11 @@ uiModules
restrict: 'E',
template: panelTemplate,
scope: {
/**
* What view mode the dashboard is currently in - edit or view only.
* @type {DashboardViewMode}
*/
dashboardViewMode: '=',
/**
* Whether or not the dashboard this panel is contained on is in 'full screen mode'.
* @type {boolean}
Expand Down Expand Up @@ -115,6 +121,14 @@ uiModules

$scope.editUrl = '#management/kibana/objects/' + service.name + '/' + id + '?notFound=' + e.savedObjectType;
});

/**
* Determines whether or not to show edit controls.
* @returns {boolean}
*/
$scope.isViewOnlyMode = () => {
return $scope.dashboardViewMode === DashboardViewMode.VIEW || $scope.isFullScreenMode;
};
}
};
});
17 changes: 16 additions & 1 deletion src/core_plugins/kibana/public/dashboard/directives/grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Binder from 'ui/binder';
import 'gridster';
import uiModules from 'ui/modules';
import { PanelUtils } from 'plugins/kibana/dashboard/components/panel/lib/panel_utils';
import { DashboardViewMode } from 'plugins/kibana/dashboard/dashboard_view_mode';

const app = uiModules.get('app/dashboard');

Expand Down Expand Up @@ -69,13 +70,26 @@ app.directive('dashboardGrid', function ($compile, Notifier) {
}
}).data('gridster');

function setResizeCapability() {
if ($scope.dashboardViewMode === DashboardViewMode.VIEW) {
gridster.disable_resize();
} else {
gridster.enable_resize();
}
}

// This is necessary to enable text selection within gridster elements
// http://stackoverflow.com/questions/21561027/text-not-selectable-from-editable-div-which-is-draggable
binder.jqOn($el, 'mousedown', function () {
gridster.disable().disable_resize();
});
binder.jqOn($el, 'mouseup', function enableResize() {
gridster.enable().enable_resize();
gridster.enable();
setResizeCapability();
});

$scope.$watch('dashboardViewMode', () => {
setResizeCapability();
});

$scope.$watchCollection('state.panels', function (panels) {
Expand Down Expand Up @@ -168,6 +182,7 @@ app.directive('dashboardGrid', function ($compile, Notifier) {
is-full-screen-mode="!chrome.getVisible()"
state="state"
is-expanded="false"
dashboard-view-mode="dashboardViewMode"
toggle-expand="toggleExpandPanel(${panel.panelIndex})"
parent-ui-state="uiState">
</li>`;
Expand Down
54 changes: 42 additions & 12 deletions src/core_plugins/kibana/public/dashboard/get_top_nav_config.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,52 @@
import { DashboardViewMode } from './dashboard_view_mode';

/**
* @param {DashboardMode} dashboardMode.
* @param kbnUrl - used to change the url.
* @return {Array<kbnTopNavConfig>} - Returns an array of objects for a top nav configuration.
* Note that order matters and the top nav will be displayed in the same order.
* @param {function} modeChange - a function to trigger a dashboard mode change.
* @return {Array<kbnTopNavConfig>} - Returns an array of objects for a top nav configuration, based on the
* mode.
*/
export function getTopNavConfig(kbnUrl) {
return [
getNewConfig(kbnUrl),
getAddConfig(),
getSaveConfig(),
getOpenConfig(),
getShareConfig(),
getOptionsConfig()];
export function getTopNavConfig(dashboardMode, kbnUrl, modeChange) {
switch (dashboardMode) {
case DashboardViewMode.VIEW:
return [getNewConfig(kbnUrl), getOpenConfig(), getShareConfig(), getEditConfig(modeChange)];
case DashboardViewMode.EDIT:
return [getNewConfig(kbnUrl), getOpenConfig(), getAddConfig(), getSaveConfig(), getOptionsConfig(), getViewConfig(modeChange)];
default:
return [];
}
}

/**
* @returns {kbnTopNavConfig}
*/
function getEditConfig(modeChange) {
return {
key: 'edit',
description: 'Switch to edit mode',
testId: 'dashboardEditMode',
run: () => {
modeChange(DashboardViewMode.EDIT);
}
};
}

/**
* @returns {kbnTopNavConfig}
*/
function getViewConfig(modeChange) {
return {
key: 'stop editing',
description: 'Stop editing and switch to view only mode',
testId: 'dashboardViewOnlyMode',
run: () => {
modeChange(DashboardViewMode.VIEW);
}
};
}

/**
*
* @param kbnUrl
* @returns {kbnTopNavConfig}
*/
function getNewConfig(kbnUrl) {
Expand Down
25 changes: 21 additions & 4 deletions src/core_plugins/kibana/public/dashboard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import uiRoutes from 'ui/routes';
import uiModules from 'ui/modules';
import indexTemplate from 'plugins/kibana/dashboard/index.html';
import { savedDashboardRegister } from 'plugins/kibana/dashboard/services/saved_dashboard_register';
import { DashboardViewMode } from './dashboard_view_mode';
import { getTopNavConfig } from './get_top_nav_config';
import { createPanelState } from 'plugins/kibana/dashboard/components/panel/lib/panel_state';
import { DashboardConstants } from './dashboard_constants';
Expand Down Expand Up @@ -56,7 +57,7 @@ uiRoutes
}
});

app.directive('dashboardApp', function (Notifier, courier, AppState, timefilter, kbnUrl) {
app.directive('dashboardApp', function (Notifier, courier, AppState, timefilter, kbnUrl, safeConfirm) {
return {
restrict: 'E',
controllerAs: 'dashboardApp',
Expand Down Expand Up @@ -107,7 +108,21 @@ app.directive('dashboardApp', function (Notifier, courier, AppState, timefilter,

$scope.$watch('state.options.darkTheme', setDarkTheme);

$scope.topNavMenu = getTopNavConfig(kbnUrl);
const changeViewMode = (newMode) => {
if ($appStatus.dirty && newMode === DashboardViewMode.VIEW) {
safeConfirm('You have unsaved changes to your dashboard that will be lost if you continue without saving.' +
'\n\nDo you wish to continue?')
.then(() => {
kbnUrl.change('/dashboard/{{id}}', { id: dash.id });
}).catch();
} else {
$scope.dashboardViewMode = newMode;
$scope.topNavMenu = getTopNavConfig(newMode, kbnUrl, changeViewMode);
}
};

// Brand new dashboards are defaulted to edit mode, existing ones default to view mode.
changeViewMode(dash.id ? DashboardViewMode.VIEW : DashboardViewMode.EDIT);

$scope.refresh = _.bindKey(courier, 'fetch');

Expand Down Expand Up @@ -202,7 +217,9 @@ app.directive('dashboardApp', function (Notifier, courier, AppState, timefilter,
$scope.$listen(queryFilter, 'fetch', $scope.refresh);

$scope.getDashTitle = function () {
return dash.lastSavedTitle || `${dash.title} (unsaved)`;
const displayTitle = dash.lastSavedTitle || `${dash.title} (unsaved)`;
const isEditMode = $scope.dashboardViewMode === DashboardViewMode.EDIT;
return isEditMode ? 'Editing ' + displayTitle : displayTitle;
};

$scope.newDashboard = function () {
Expand Down Expand Up @@ -292,7 +309,7 @@ app.directive('dashboardApp', function (Notifier, courier, AppState, timefilter,
init();

$scope.showEditHelpText = () => {
return !$scope.state.panels.length;
return !$scope.state.panels.length && $scope.dashboardViewMode === DashboardViewMode.EDIT;
};
}
};
Expand Down
9 changes: 7 additions & 2 deletions src/core_plugins/kibana/public/dashboard/styles/main.less
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,16 @@ dashboard-grid {
}

.gs-w {
border: 2px dashed transparent;

.panel {
border: 2px dashed transparent;
}

.panel .panel-heading .btn-group {
display: none;
}

&:hover {
border-color: @kibanaGray4;

dashboard-panel {
.visualize-show-spy {
Expand All @@ -50,6 +52,9 @@ dashboard-grid {
.panel .panel-heading .btn-group {
display: block !important;
}
.panel--edit-mode {
border-color: @kibanaGray4;
}
}

}
Expand Down
24 changes: 15 additions & 9 deletions src/ui/public/kbn_top_nav/kbn_top_nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,15 +101,21 @@ module.directive('kbnTopNav', function (Private) {

const extensions = getNavbarExtensions($attrs.name);

let controls = _.get($scope, $attrs.config, []);
if (controls instanceof KbnTopNavController) {
controls.addItems(extensions);
} else {
controls = controls.concat(extensions);
}

$scope.kbnTopNav = new KbnTopNavController(controls);
$scope.kbnTopNav._link($scope, $element);
let initialized = false;
$scope.$watch(() => _.get($scope, $attrs.config, []), function (newValue, oldValue) {
if (initialized && _.isEqual(oldValue, newValue)) return;

initialized = true;
let controls = newValue;
if (controls instanceof KbnTopNavController) {
controls.addItems(extensions);
} else {
controls = controls.concat(extensions);
}

$scope.kbnTopNav = new KbnTopNavController(controls);
$scope.kbnTopNav._link($scope, $element);
});

return $scope.kbnTopNav;
},
Expand Down

0 comments on commit 506734c

Please sign in to comment.