diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fafde3aebe..467d6c8276b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ **New features and improvements** - [Issue #117](https://github.com/grafana/grafana/issues/117). Graphite: Graphite query builder can now handle functions that multiple series as arguments! - [Issue #281](https://github.com/grafana/grafana/issues/281). Graphite: Metric node/segment selection is now a textbox with autocomplete dropdown, allow for custom glob expression for single node segment without entering text editor mode. +- [Issue #304](https://github.com/grafana/grafana/issues/304). Dashboard: View dashboard json, edit/update any panel using json editor, makes it possible to quickly copy a graph from one dashboard to another. - [Issue #578](https://github.com/grafana/grafana/issues/578). Dashboard: Row option to display row title even when the row is visible - [Issue #672](https://github.com/grafana/grafana/issues/672). Dashboard: panel fullscreen & edit state is present in url, can now link to graph in edit & fullscreen mode. - [Issue #709](https://github.com/grafana/grafana/issues/709). Dashboard: Small UI look polish to search results, made dashboard title link are larger diff --git a/src/app/controllers/all.js b/src/app/controllers/all.js index cf63f0940e0..4a4357ecee6 100644 --- a/src/app/controllers/all.js +++ b/src/app/controllers/all.js @@ -15,4 +15,5 @@ define([ './opentsdbTargetCtrl', './annotationsEditorCtrl', './templateEditorCtrl', + './jsonEditorCtrl', ], function () {}); diff --git a/src/app/controllers/dashboardCtrl.js b/src/app/controllers/dashboardCtrl.js index 346c25ec1a4..3def3fef30c 100644 --- a/src/app/controllers/dashboardCtrl.js +++ b/src/app/controllers/dashboardCtrl.js @@ -29,6 +29,7 @@ function (angular, $, config, _) { $scope.init = function() { $scope.availablePanels = config.panels; $scope.onAppEvent('setup-dashboard', $scope.setupDashboard); + $scope.onAppEvent('show-json-editor', $scope.showJsonEditor); $scope.reset_row(); $scope.registerWindowResizeEvent(); }; @@ -107,6 +108,13 @@ function (angular, $, config, _) { } }; + $scope.showJsonEditor = function(evt, options) { + var editScope = $rootScope.$new(); + editScope.object = options.object; + editScope.updateHandler = options.updateHandler; + $scope.emitAppEvent('show-dash-editor', { src: 'app/partials/edit_json.html', scope: editScope }); + }; + $scope.checkFeatureToggles = function() { $scope.submenuEnabled = $scope.dashboard.templating.enable || $scope.dashboard.annotations.enable; }; diff --git a/src/app/controllers/dashboardNavCtrl.js b/src/app/controllers/dashboardNavCtrl.js index 204b874db70..7f32fb685c2 100644 --- a/src/app/controllers/dashboardNavCtrl.js +++ b/src/app/controllers/dashboardNavCtrl.js @@ -140,9 +140,7 @@ function (angular, _, moment, config, store) { }; $scope.editJson = function() { - var editScope = $rootScope.$new(); - editScope.json = angular.toJson($scope.dashboard, true); - $scope.emitAppEvent('show-dash-editor', { src: 'app/partials/edit_json.html', scope: editScope }); + $scope.emitAppEvent('show-json-editor', { object: $scope.dashboard }); }; $scope.openSaveDropdown = function() { diff --git a/src/app/controllers/jsonEditorCtrl.js b/src/app/controllers/jsonEditorCtrl.js index 926e46e1694..60bda8514b7 100644 --- a/src/app/controllers/jsonEditorCtrl.js +++ b/src/app/controllers/jsonEditorCtrl.js @@ -7,7 +7,15 @@ function (angular) { var module = angular.module('grafana.controllers'); - module.controller('JsonEditorCtrl', function() { + module.controller('JsonEditorCtrl', function($scope) { + + $scope.json = angular.toJson($scope.object, true); + $scope.canUpdate = $scope.updateHandler !== void 0; + + $scope.update = function () { + var newObject = angular.fromJson($scope.json); + $scope.updateHandler(newObject, $scope.object); + }; }); diff --git a/src/app/controllers/row.js b/src/app/controllers/row.js index 314559405ea..621c3eddda5 100644 --- a/src/app/controllers/row.js +++ b/src/app/controllers/row.js @@ -13,7 +13,6 @@ function (angular, app, _) { title: "Row", height: "150px", collapse: false, - editable: true, panels: [], }; @@ -76,6 +75,19 @@ function (angular, app, _) { } }; + $scope.replacePanel = function(newPanel, oldPanel) { + var row = $scope.row; + var index = _.indexOf(row.panels, oldPanel); + row.panels.splice(index, 1); + + // adding it back needs to be done in next digest + $timeout(function() { + newPanel.id = oldPanel.id; + newPanel.span = oldPanel.span; + row.panels.splice(index, 0, newPanel); + }); + }; + $scope.duplicatePanel = function(panel, row) { $scope.dashboard.duplicatePanel(panel, row || $scope.row); }; diff --git a/src/app/dashboards/default.json b/src/app/dashboards/default.json index 15ec5cf1dd7..015ede1d7dc 100644 --- a/src/app/dashboards/default.json +++ b/src/app/dashboards/default.json @@ -8,9 +8,7 @@ { "title": "New row", "height": "150px", - "editable": true, "collapse": false, - "collapsable": true, "panels": [ { "error": false, @@ -22,15 +20,12 @@ "style": {}, "title": "Welcome to" } - ], - "notice": false + ] }, { "title": "Welcome to Grafana", "height": "210px", - "editable": true, "collapse": false, - "collapsable": true, "panels": [ { "error": false, @@ -53,15 +48,12 @@ "style": {}, "title": "Tips & Shortcuts" } - ], - "notice": false + ] }, { "title": "test", "height": "250px", - "editable": true, "collapse": false, - "collapsable": true, "panels": [ { "span": 12, @@ -132,27 +124,13 @@ "enable": false } } - ], - "notice": false - } - ], - "pulldowns": [ - { - "type": "filtering", - "collapse": false, - "notice": false, - "enable": false - }, - { - "type": "annotations", - "enable": false + ] } ], "nav": [ { "type": "timepicker", "collapse": false, - "notice": false, "enable": true, "status": "Stable", "time_options": [ @@ -188,5 +166,5 @@ "templating": { "list": [] }, - "version": 2 -} \ No newline at end of file + "version": 5 +} diff --git a/src/app/dashboards/empty.json b/src/app/dashboards/empty.json index fc97a61d125..d1f7ffcd548 100644 --- a/src/app/dashboards/empty.json +++ b/src/app/dashboards/empty.json @@ -17,22 +17,10 @@ } ], "editable": true, - "failover": false, - "panel_hints": true, "style": "dark", - "pulldowns": [ - { - "type": "filtering", - "collapse": false, - "notice": false, - "enable": false - } - ], "nav": [ { "type": "timepicker", - "collapse": false, - "notice": false, "enable": true, "status": "Stable", "time_options": [ diff --git a/src/app/partials/dashboard_topnav.html b/src/app/partials/dashboard_topnav.html index 70b3f9cd159..15ea694058c 100644 --- a/src/app/partials/dashboard_topnav.html +++ b/src/app/partials/dashboard_topnav.html @@ -47,7 +47,7 @@ Remove as favorite
  • - Edit Json + Dashboard JSON
  • Export dashboard diff --git a/src/app/partials/edit_json.html b/src/app/partials/edit_json.html index 98c546971df..c4fa5fd950f 100644 --- a/src/app/partials/edit_json.html +++ b/src/app/partials/edit_json.html @@ -1,9 +1,9 @@ -
    +
    - Edit / View JSON + JSON
    @@ -12,6 +12,7 @@
    diff --git a/src/app/services/panelSrv.js b/src/app/services/panelSrv.js index 43ce20bb28a..1864db59f02 100644 --- a/src/app/services/panelSrv.js +++ b/src/app/services/panelSrv.js @@ -52,6 +52,13 @@ function (angular, _) { ], condition: true }, + { + text: 'Advanced', + submenu: [ + { text: 'Panel JSON', click: 'editPanelJson()' }, + ], + condition: true + }, { text: 'Remove', click: 'remove_panel_from_row(row, panel)', @@ -62,6 +69,10 @@ function (angular, _) { $scope.inspector = {}; $scope.panelMeta.menu = _.where(menu, { condition: true }); + $scope.editPanelJson = function() { + $scope.emitAppEvent('show-json-editor', { object: $scope.panel, updateHandler: $scope.replacePanel }); + }; + $scope.updateColumnSpan = function(span) { $scope.panel.span = span;