Commit 01627b3a by Torkel Ödegaard

feat(ux): dashboard edit mode progress

parent 29e834e7
...@@ -26,7 +26,6 @@ export class DashboardCtrl { ...@@ -26,7 +26,6 @@ export class DashboardCtrl {
$timeout) { $timeout) {
$scope.editor = { index: 0 }; $scope.editor = { index: 0 };
$scope.panels = config.panels;
var resizeEventTimeout; var resizeEventTimeout;
...@@ -107,22 +106,12 @@ export class DashboardCtrl { ...@@ -107,22 +106,12 @@ export class DashboardCtrl {
$rootScope.$broadcast('refresh'); $rootScope.$broadcast('refresh');
}; };
$scope.addRow = function(dash, row) {
dash.rows.push(row);
};
$scope.addRowDefault = function() { $scope.addRowDefault = function() {
$scope.resetRow(); $scope.dashboard.rows.push({
$scope.row.title = 'New row'; title: 'New row',
$scope.addRow($scope.dashboard, $scope.row); panels: [],
};
$scope.resetRow = function() {
$scope.row = {
title: '',
height: '250px', height: '250px',
editable: true, });
};
}; };
$scope.showJsonEditor = function(evt, options) { $scope.showJsonEditor = function(evt, options) {
...@@ -132,24 +121,6 @@ export class DashboardCtrl { ...@@ -132,24 +121,6 @@ export class DashboardCtrl {
$scope.appEvent('show-dash-editor', { src: 'public/app/partials/edit_json.html', scope: editScope }); $scope.appEvent('show-dash-editor', { src: 'public/app/partials/edit_json.html', scope: editScope });
}; };
$scope.onDrop = function(panelId, row, dropTarget) {
var info = $scope.dashboard.getPanelInfoById(panelId);
if (dropTarget) {
var dropInfo = $scope.dashboard.getPanelInfoById(dropTarget.id);
dropInfo.row.panels[dropInfo.index] = info.panel;
info.row.panels[info.index] = dropTarget;
var dragSpan = info.panel.span;
info.panel.span = dropTarget.span;
dropTarget.span = dragSpan;
} else {
info.row.panels.splice(info.index, 1);
info.panel.span = 12 - $scope.dashboard.rowSpan(row);
row.panels.push(info.panel);
}
$rootScope.$broadcast('render');
};
$scope.registerWindowResizeEvent = function() { $scope.registerWindowResizeEvent = function() {
angular.element(window).bind('resize', function() { angular.element(window).bind('resize', function() {
$timeout.cancel(resizeEventTimeout); $timeout.cancel(resizeEventTimeout);
...@@ -166,7 +137,6 @@ export class DashboardCtrl { ...@@ -166,7 +137,6 @@ export class DashboardCtrl {
} }
init(dashboard) { init(dashboard) {
this.$scope.resetRow();
this.$scope.registerWindowResizeEvent(); this.$scope.registerWindowResizeEvent();
this.$scope.onAppEvent('show-json-editor', this.$scope.showJsonEditor); this.$scope.onAppEvent('show-json-editor', this.$scope.showJsonEditor);
this.$scope.onAppEvent('template-variable-value-updated', this.$scope.templateVariableUpdated); this.$scope.onAppEvent('template-variable-value-updated', this.$scope.templateVariableUpdated);
......
...@@ -11,18 +11,15 @@ ...@@ -11,18 +11,15 @@
<div class="dash-row-header pointer" ng-if="ctrl.dashboard.editMode"> <div class="dash-row-header pointer" ng-if="ctrl.dashboard.editMode">
<div class="dash-row-header-title" ng-bind="ctrl.row.title | interpolateTemplateVars:this"></div> <div class="dash-row-header-title" ng-bind="ctrl.row.title | interpolateTemplateVars:this"></div>
<div class="dash-row-header-settings dropdown"> <div class="dash-row-header-settings dropdown">
<!-- <a class="pointer dropdown&#45;toggle" data&#45;toggle="dropdown"> --> <a class="pointer dropdown-toggle" data-toggle="dropdown">
<!-- <i class="fa fa&#45;cog"></i> --> <i class="fa fa-plus-circle"></i>
<!-- </a> --> </a>
<ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="drop1"> <ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="drop1">
<li>
<a ng-click="toggleRow(row)">Collapse row</a>
</li>
<li class="dropdown-submenu"> <li class="dropdown-submenu">
<a href="javascript:void(0);">Add Panel</a> <a href="javascript:void(0);">Add Panel</a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li bindonce ng-repeat="(key, value) in panels"> <li bindonce ng-repeat="(key, value) in ctrl.panelPlugins">
<a ng-click="addPanelDefault(key)" bo-text="value.name"></a> <a ng-click="ctrl.addPanelDefault(key)" bo-text="value.name"></a>
</li> </li>
</ul> </ul>
</li> </li>
...@@ -42,20 +39,20 @@ ...@@ -42,20 +39,20 @@
<li><a ng-click="setHeight('700px')">700 px</a></li> <li><a ng-click="setHeight('700px')">700 px</a></li>
</ul> </ul>
</li> </li>
<li class="dropdown-submenu"> <!-- <li class="dropdown&#45;submenu"> -->
<a href="javascript:void(0);">Move</a> <!-- <a href="javascript:void(0);">Move</a> -->
<ul class="dropdown-menu"> <!-- <ul class="dropdown&#45;menu"> -->
<li><a ng-click="moveRow('up')">Up</a></li> <!-- <li><a ng&#45;click="moveRow('up')">Up</a></li> -->
<li><a ng-click="moveRow('down')">Down</a></li> <!-- <li><a ng&#45;click="moveRow('down')">Down</a></li> -->
<li><a ng-click="moveRow('top')">To top</a></li> <!-- <li><a ng&#45;click="moveRow('top')">To top</a></li> -->
<li><a ng-click="moveRow('bottom')">To Bottom</a></li> <!-- <li><a ng&#45;click="moveRow('bottom')">To Bottom</a></li> -->
</ul> <!-- </ul> -->
</li> <!-- </li> -->
<li> <li>
<a ng-click="editRow()">Row editor</a> <a ng-click="ctrl.editRow()">Row options</a>
</li> </li>
<li> <li>
<a ng-click="deleteRow()">Delete row</a> <a ng-click="ctrl.deleteRow()">Delete row</a>
</li> </li>
</ul> </ul>
</div> </div>
...@@ -68,12 +65,12 @@ ...@@ -68,12 +65,12 @@
</div> </div>
<div class="panels-wrapper" ng-if="!ctrl.row.collapse"> <div class="panels-wrapper" ng-if="!ctrl.row.collapse">
<div ng-repeat="panel in ctrl.row.panels track by panel.id" class="panel" ui-draggable="!ctrl.dashboard.meta.fullscreen" drag="panel.id" ui-on-drop="onDrop($data, row, panel)" drag-handle-class="drag-handle" panel-width> <div ng-repeat="panel in ctrl.row.panels track by panel.id" class="panel" ui-draggable="!ctrl.dashboard.meta.fullscreen" drag="panel.id" ui-on-drop="ctrl.onDrop($data, panel)" drag-handle-class="drag-handle" panel-width>
<plugin-component type="panel" class="panel-margin"> <plugin-component type="panel" class="panel-margin">
</plugin-component> </plugin-component>
</div> </div>
<div panel-drop-zone class="panel panel-drop-zone" ui-on-drop="onDrop($data, row)" data-drop="true"> <div panel-drop-zone class="panel panel-drop-zone" ui-on-drop="ctrl.onDrop($data)" data-drop="true">
<div class="panel-container" style="background: transparent"> <div class="panel-container" style="background: transparent">
<div style="text-align: center"> <div style="text-align: center">
<em>Drop here</em> <em>Drop here</em>
......
///<reference path="../../../headers/common.d.ts" /> ///<reference path="../../../headers/common.d.ts" />
import _ from 'lodash'; import _ from 'lodash';
import coreModule from 'app/core/core_module'; import config from 'app/core/config';
import {coreModule, appEvents} from 'app/core/core';
export class DashRowCtrl { export class DashRowCtrl {
showTitle: boolean; dashboard: any;
row: any;
panelPlugins;
/** @ngInject */ /** @ngInject */
constructor(private $scope, private $rootScope) { constructor(private $scope, private $rootScope) {
this.showTitle = true; this.panelPlugins = config.panels;
this.-
} }
} onDrop(panelId, dropTarget) {
var info = this.dashboard.getPanelInfoById(panelId);
if (dropTarget) {
var dropInfo = this.dashboard.getPanelInfoById(dropTarget.id);
dropInfo.row.panels[dropInfo.index] = info.panel;
info.row.panels[info.index] = dropTarget;
var dragSpan = info.panel.span;
info.panel.span = dropTarget.span;
dropTarget.span = dragSpan;
} else {
info.row.panels.splice(info.index, 1);
info.panel.span = 12 - this.dashboard.rowSpan(this.row);
this.row.panels.push(info.panel);
}
this.$rootScope.$broadcast('render');
}
addPanel(panel) {
this.dashboard.addPanel(panel, this.row);
}
editRow() {
// this.appEvent('show-dash-editor', {
// src: 'public/app/partials/roweditor.html',
// scope: this.$scope.$new()
// });
}
addPanelDefault(type) {
var defaultSpan = 12;
var _as = 12 - this.dashboard.rowSpan(this.row);
var panel = {
title: config.new_panel_title,
error: false,
span: _as < defaultSpan && _as > 0 ? _as : defaultSpan,
editable: true,
type: type,
isNew: true,
};
export function rowDirective() { this.addPanel(panel);
}
deleteRow() {
if (!this.row.panels.length) {
this.dashboard.rows = _.without(this.dashboard.rows, this.row);
return;
}
appEvents.emit('confirm-modal', {
title: 'Delete',
text: 'Are you sure you want to delete this row?',
icon: 'fa-trash',
yesText: 'Delete',
onConfirm: () => {
this.dashboard.rows = _.without(this.dashboard.rows, this.row);
}
});
}
}
export function rowDirective($rootScope) {
return { return {
restrict: 'E', restrict: 'E',
templateUrl: 'public/app/features/dashboard/row/row.html', templateUrl: 'public/app/features/dashboard/row/row.html',
...@@ -25,6 +87,22 @@ export function rowDirective() { ...@@ -25,6 +87,22 @@ export function rowDirective() {
scope: { scope: {
dashboard: "=", dashboard: "=",
row: "=", row: "=",
},
link: function(scope, element) {
scope.$watchGroup(['ctrl.row.collapse', 'ctrl.row.height'], function() {
element.css({minHeight: scope.ctrl.row.collapse ? '5px' : scope.ctrl.row.height});
});
$rootScope.onAppEvent('panel-fullscreen-enter', function(evt, info) {
var hasPanel = _.find(scope.ctrl.row.panels, {id: info.panelId});
if (!hasPanel) {
element.hide();
}
}, scope);
$rootScope.onAppEvent('panel-fullscreen-exit', function() {
element.show();
}, scope);
} }
}; };
} }
...@@ -63,7 +141,7 @@ coreModule.directive('panelWidth', function($rootScope) { ...@@ -63,7 +141,7 @@ coreModule.directive('panelWidth', function($rootScope) {
updateWidth(); updateWidth();
}, scope); }, scope);
scope.$watch('ctrl.panel.span', updateWidth); scope.$watch('panel.span', updateWidth);
if (fullscreen) { if (fullscreen) {
element.hide(); element.hide();
...@@ -71,3 +149,23 @@ coreModule.directive('panelWidth', function($rootScope) { ...@@ -71,3 +149,23 @@ coreModule.directive('panelWidth', function($rootScope) {
}; };
}); });
coreModule.directive('panelDropZone', function($timeout) {
return function(scope, element) {
scope.$on("ANGULAR_DRAG_START", function() {
$timeout(function() {
var dropZoneSpan = 12 - scope.ctrl.dashboard.rowSpan(scope.ctrl.row);
if (dropZoneSpan > 0) {
element.find('.panel-container').css('height', scope.ctrl.row.height);
element[0].style.width = ((dropZoneSpan / 1.2) * 10) + '%';
element.show();
}
});
});
scope.$on("ANGULAR_DRAG_END", function() {
element.hide();
});
};
});
define([ // define([
'angular', // 'angular',
'lodash', // 'lodash',
'app/core/config' // 'app/core/config'
], // ],
function (angular, _, config) { // function (angular, _, config) {
'use strict'; // 'use strict';
//
var module = angular.module('grafana.controllers'); // var module = angular.module('grafana.controllers');
//
module.controller('RowCtrl', function($scope, $rootScope, $timeout) { // module.controller('RowCtrl', function($scope, $rootScope, $timeout) {
var _d = { //
title: "Row", // $scope.moveRow = function(direction) {
height: "150px", // var rowsList = $scope.dashboard.rows;
collapse: false, // var rowIndex = _.indexOf(rowsList, $scope.row);
editable: true, // var newIndex = rowIndex;
panels: [], // switch(direction) {
}; // case 'up': {
// newIndex = rowIndex - 1;
_.defaults($scope.row,_d); // break;
// }
$scope.init = function() { // case 'down': {
$scope.editor = {index: 0}; // newIndex = rowIndex + 1;
}; // break;
// }
$scope.togglePanelMenu = function(posX) { // case 'top': {
$scope.showPanelMenu = !$scope.showPanelMenu; // newIndex = 0;
$scope.panelMenuPos = posX; // break;
}; // }
// case 'bottom': {
$scope.toggleRow = function(row) { // newIndex = rowsList.length - 1;
row.collapse = row.collapse ? false : true; // break;
}; // }
// default: {
$scope.settingsHover = function(row) { // newIndex = rowIndex;
// Shows/hides the settings button on hover // }
return row.hoverSettings = ! row.hoverSettings; // }
}; // if (newIndex >= 0 && newIndex <= (rowsList.length - 1)) {
// _.move(rowsList, rowIndex, newIndex);
$scope.addPanel = function(panel) { // }
$scope.dashboard.addPanel(panel, $scope.row); // };
}; //
// $scope.setHeight = function(height) {
$scope.deleteRow = function() { // $scope.row.height = height;
function delete_row() { // $scope.$broadcast('render');
$scope.dashboard.rows = _.without($scope.dashboard.rows, $scope.row); // };
} //
// $scope.init();
if (!$scope.row.panels.length) { // });
delete_row(); //
return; // });
}
$scope.appEvent('confirm-modal', {
title: 'Delete',
text: 'Are you sure you want to delete this row?',
icon: 'fa-trash',
yesText: 'Delete',
onConfirm: function() {
delete_row();
}
});
};
$scope.editRow = function() {
$scope.appEvent('show-dash-editor', {
src: 'public/app/partials/roweditor.html',
scope: $scope.$new()
});
};
$scope.moveRow = function(direction) {
var rowsList = $scope.dashboard.rows;
var rowIndex = _.indexOf(rowsList, $scope.row);
var newIndex = rowIndex;
switch(direction) {
case 'up': {
newIndex = rowIndex - 1;
break;
}
case 'down': {
newIndex = rowIndex + 1;
break;
}
case 'top': {
newIndex = 0;
break;
}
case 'bottom': {
newIndex = rowsList.length - 1;
break;
}
default: {
newIndex = rowIndex;
}
}
if (newIndex >= 0 && newIndex <= (rowsList.length - 1)) {
_.move(rowsList, rowIndex, newIndex);
}
};
$scope.addPanelDefault = function(type) {
var defaultSpan = 12;
var _as = 12 - $scope.dashboard.rowSpan($scope.row);
var panel = {
title: config.new_panel_title,
error: false,
span: _as < defaultSpan && _as > 0 ? _as : defaultSpan,
editable: true,
type: type,
isNew: true,
};
$scope.addPanel(panel);
$timeout(function() {
$scope.dashboardViewState.update({fullscreen: true, edit: true, panelId: panel.id });
});
};
$scope.setHeight = function(height) {
$scope.row.height = height;
$scope.$broadcast('render');
};
$scope.init();
});
module.directive('rowHeight', function() {
return function(scope, element) {
scope.$watchGroup(['row.collapse', 'row.height'], function() {
element.css({ minHeight: scope.row.collapse ? '5px' : scope.row.height });
});
scope.onAppEvent('panel-fullscreen-enter', function(evt, info) {
var hasPanel = _.find(scope.row.panels, {id: info.panelId});
if (!hasPanel) {
element.hide();
}
});
scope.onAppEvent('panel-fullscreen-exit', function() {
element.show();
});
};
});
module.directive('panelDropZone', function() {
return function(scope, element) {
scope.$on("ANGULAR_DRAG_START", function() {
var dropZoneSpan = 12 - scope.dashboard.rowSpan(scope.row);
if (dropZoneSpan > 0) {
element.find('.panel-container').css('height', scope.row.height);
element[0].style.width = ((dropZoneSpan / 1.2) * 10) + '%';
element.show();
}
});
scope.$on("ANGULAR_DRAG_END", function() {
element.hide();
});
};
});
});
...@@ -149,6 +149,7 @@ function (angular, _, $) { ...@@ -149,6 +149,7 @@ function (angular, _, $) {
ctrl.editMode = false; ctrl.editMode = false;
ctrl.fullscreen = false; ctrl.fullscreen = false;
ctrl.dashboard.editMode = this.oldDashboardEditMode;
this.$scope.appEvent('panel-fullscreen-exit', {panelId: ctrl.panel.id}); this.$scope.appEvent('panel-fullscreen-exit', {panelId: ctrl.panel.id});
...@@ -170,8 +171,10 @@ function (angular, _, $) { ...@@ -170,8 +171,10 @@ function (angular, _, $) {
ctrl.editMode = this.state.edit && this.dashboard.meta.canEdit; ctrl.editMode = this.state.edit && this.dashboard.meta.canEdit;
ctrl.fullscreen = true; ctrl.fullscreen = true;
this.oldDashboardEditMode = this.dashboard.editMode;
this.oldTimeRange = ctrl.range; this.oldTimeRange = ctrl.range;
this.fullscreenPanel = panelScope; this.fullscreenPanel = panelScope;
this.dashboard.editMode = false;
$(window).scrollTop(0); $(window).scrollTop(0);
......
...@@ -384,7 +384,6 @@ module.directive('grafanaGraph', function($rootScope, timeSrv) { ...@@ -384,7 +384,6 @@ module.directive('grafanaGraph', function($rootScope, timeSrv) {
if (!annotations || annotations.length === 0) { if (!annotations || annotations.length === 0) {
return; return;
} }
console.log(annotations);
var types = {}; var types = {};
types['$__alerting'] = { types['$__alerting'] = {
......
...@@ -80,7 +80,7 @@ $enable-flex: false; ...@@ -80,7 +80,7 @@ $enable-flex: false;
// Typography // Typography
// ------------------------- // -------------------------
$font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif; $font-family-sans-serif: "Open Sans", Helvetica, Arial, sans-serif;
$font-family-serif: Georgia, "Times New Roman", Times, serif; $font-family-serif: Georgia, "Times New Roman", Times, serif;
$font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace; $font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
$font-family-base: $font-family-sans-serif !default; $font-family-base: $font-family-sans-serif !default;
......
...@@ -211,7 +211,7 @@ div.flot-text { ...@@ -211,7 +211,7 @@ div.flot-text {
.dash-row-handle-column { .dash-row-handle-column {
width: 2rem; width: 2rem;
background: $page-bg; background: $input-label-bg;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
...@@ -235,7 +235,7 @@ div.flot-text { ...@@ -235,7 +235,7 @@ div.flot-text {
flex-direction: row; flex-direction: row;
text-align: left; text-align: left;
align-items: center; align-items: center;
background: $page-bg; background: $input-label-bg;
margin-right: $panel-margin; margin-right: $panel-margin;
} }
......
...@@ -290,12 +290,12 @@ ...@@ -290,12 +290,12 @@
sendData = angular.fromJson(sendData); sendData = angular.fromJson(sendData);
var dropOffset = calculateDropOffset(e); var dropOffset = calculateDropOffset(e);
var position = dropOffset ? { var position = dropOffset ? {
x: dropOffset.x - sendData.offset.x, x: dropOffset.x - sendData.offset.x,
y: dropOffset.y - sendData.offset.y y: dropOffset.y - sendData.offset.y
} : null; } : null;
determineEffectAllowed(e); determineEffectAllowed(e);
var uiOnDropFn = $parse(attr.uiOnDrop); var uiOnDropFn = $parse(attr.uiOnDrop);
...@@ -305,7 +305,7 @@ ...@@ -305,7 +305,7 @@
element.removeClass(dragEnterClass); element.removeClass(dragEnterClass);
dragging = 0; dragging = 0;
} }
function isDragChannelAccepted(dragChannel, dropChannel) { function isDragChannelAccepted(dragChannel, dropChannel) {
if (dropChannel === '*') { if (dropChannel === '*') {
return true; return true;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment