diff --git a/public/app/plugins/panel/graph/specs/graph_specs.ts b/public/app/plugins/panel/graph/specs/graph_specs.ts
index 1c240bb2967..11560e71c47 100644
--- a/public/app/plugins/panel/graph/specs/graph_specs.ts
+++ b/public/app/plugins/panel/graph/specs/graph_specs.ts
@@ -26,9 +26,9 @@ describe('grafanaGraph', function() {
beforeEach(angularMocks.inject(function($rootScope, $compile) {
var ctrl: any = {
- events: new Emitter(),
height: 200,
panel: {
+ events: new Emitter(),
legend: {},
grid: { },
yaxes: [
@@ -65,7 +65,7 @@ describe('grafanaGraph', function() {
var scope = $rootScope.$new();
scope.ctrl = ctrl;
-
+ scope.ctrl.events = ctrl.panel.events;
$rootScope.onAppEvent = sinon.spy();
diff --git a/public/dashboards/home.json b/public/dashboards/home.json
index d19ecfd6809..91f5abec5eb 100644
--- a/public/dashboards/home.json
+++ b/public/dashboards/home.json
@@ -13,7 +13,6 @@
{
"content": "
\n Home Dashboard\n
",
"editable": true,
- "height": 2,
"id": 1,
"links": [],
"mode": "html",
@@ -21,14 +20,16 @@
"title": "",
"transparent": true,
"type": "text",
- "width": 12,
- "x": 0,
- "y": 0
+ "gridPos": {
+ "w": 12,
+ "h": 2,
+ "x": 0,
+ "y": 0
+ }
},
{
"folderId": 0,
"headings": true,
- "height": 17,
"id": 3,
"limit": 4,
"links": [],
@@ -40,26 +41,31 @@
"title": "",
"transparent": false,
"type": "dashlist",
- "width": 7,
- "x": 0,
- "y": 6
+ "gridPos": {
+ "w": 7,
+ "h": 17,
+ "x": 0,
+ "y": 6
+ }
},
{
"editable": true,
"error": false,
- "height": 17,
"id": 4,
"links": [],
"title": "",
"transparent": false,
"type": "pluginlist",
- "width": 5,
- "x": 7,
- "y": 6
+ "gridPos": {
+ "w": 5,
+ "h": 17,
+ "x": 7,
+ "y": 6
+ }
}
],
"rows": [],
- "schemaVersion": 15,
+ "schemaVersion": 16,
"style": "dark",
"tags": [],
"templating": {
diff --git a/public/sass/_grafana.scss b/public/sass/_grafana.scss
index 7ccec0ae56a..a4e99987576 100644
--- a/public/sass/_grafana.scss
+++ b/public/sass/_grafana.scss
@@ -77,11 +77,12 @@
@import "components/tabbed_view";
@import "components/query_part";
@import "components/jsontree";
-@import "components/edit_sidemenu.scss";
+@import "components/edit_sidemenu";
@import "components/row.scss";
-@import "components/gridstack.scss";
-@import "components/json_explorer.scss";
-@import "components/code_editor.scss";
+@import "components/json_explorer";
+@import "components/code_editor";
+@import "components/dashboard_grid";
+
// PAGES
@import "pages/login";
diff --git a/public/sass/_variables.dark.scss b/public/sass/_variables.dark.scss
index 52761e4bfc6..7eea87b2009 100644
--- a/public/sass/_variables.dark.scss
+++ b/public/sass/_variables.dark.scss
@@ -105,9 +105,9 @@ $tight-form-bg: $dark-3;
$tight-form-func-bg: #333;
$tight-form-func-highlight-bg: #444;
-$modal-background: $black;
-$code-tag-bg: $gray-1;
-$code-tag-border: lighten($code-tag-bg, 2%);
+$modal-backdrop-bg: $dark-3;
+$code-tag-bg: $gray-1;
+$code-tag-border: lighten($code-tag-bg, 2%);
// Lists
diff --git a/public/sass/_variables.light.scss b/public/sass/_variables.light.scss
index 1e48d515c4d..1bb58532d67 100644
--- a/public/sass/_variables.light.scss
+++ b/public/sass/_variables.light.scss
@@ -112,9 +112,9 @@ $tight-form-bg: $gray-6;
$tight-form-func-bg: $gray-5;
$tight-form-func-highlight-bg: $gray-6;
-$modal-background: $body-bg;
-$code-tag-bg: $gray-6;
-$code-tag-border: darken($code-tag-bg, 3%);
+$modal-backdrop-bg: $body-bg;
+$code-tag-bg: $gray-6;
+$code-tag-border: darken($code-tag-bg, 3%);
// Lists
$grafanaListBackground: $gray-6;
diff --git a/public/sass/_variables.scss b/public/sass/_variables.scss
index d76111b080b..12692690772 100644
--- a/public/sass/_variables.scss
+++ b/public/sass/_variables.scss
@@ -222,8 +222,8 @@ $btn-border-radius: 3px;
$side-menu-width: 60px;
// dashboard
-$panel-margin: 0.4rem;
-$dashboard-padding: ($panel-margin * 2) $panel-margin $panel-margin $panel-margin;
+$panel-margin: 10px;
+$dashboard-padding: $panel-margin * 2;
// tabs
$tabs-padding-top: 0.6rem;
diff --git a/public/sass/components/_dashboard_grid.scss b/public/sass/components/_dashboard_grid.scss
new file mode 100644
index 00000000000..5a346d443a6
--- /dev/null
+++ b/public/sass/components/_dashboard_grid.scss
@@ -0,0 +1,24 @@
+@import "~react-grid-layout/css/styles.css";
+@import "~react-resizable/css/styles.css";
+
+.panel-in-fullscreen {
+
+ .react-grid-layout {
+ height: 100% !important;
+ }
+
+ .react-grid-item {
+ display: none;
+ transition-property: none !important;
+ }
+
+ .panel--fullscreen {
+ display: block !important;
+ position: unset !important;
+ width: 100% !important;
+ height: 100% !important;
+ transform: translate(0px, 0px) !important;
+ }
+}
+
+
diff --git a/public/sass/components/_gridstack.scss b/public/sass/components/_gridstack.scss
deleted file mode 100644
index a3d31e631c2..00000000000
--- a/public/sass/components/_gridstack.scss
+++ /dev/null
@@ -1,325 +0,0 @@
-.grid-stack-item > .ui-resizable-handle {
- filter: none;
-}
-
-.grid-stack {
- position: relative;
- min-height: 150px;
-}
-
-.grid-stack.grid-stack-rtl {
- direction: ltr;
-}
-
-.grid-stack.grid-stack-rtl > .grid-stack-item {
- direction: rtl;
-}
-
-.grid-stack .grid-stack-placeholder > .placeholder-content {
- background: $input-label-bg;
- box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 5px rgba(82,168,236,10.8);
- margin: 0;
- position: absolute;
- top: 0;
- left: 5px;
- right: 5px;
- bottom: 0;
- width: auto;
- text-align: center;
-}
-
-.grid-stack > .grid-stack-item {
- min-width: 8.3333333333%;
- position: absolute;
- padding: 0;
-}
-
-.grid-stack > .grid-stack-item > .grid-stack-item-content {
- margin: 0;
- position: absolute;
- top: 0;
- left: 7px;
- right: 7px;
- bottom: 0;
- width: auto;
-}
-
-.grid-stack > .grid-stack-item > .ui-resizable-handle {
- position: absolute;
- display: block;
- -ms-touch-action: none;
- touch-action: none;
- font-size: 10px;
- color: $text-color-weak;
-}
-
-.grid-stack > .grid-stack-item.ui-resizable-disabled > .ui-resizable-handle,
-.grid-stack > .grid-stack-item.ui-resizable-autohide > .ui-resizable-handle {
- display: none;
-}
-
-.grid-stack > .grid-stack-item.ui-draggable-dragging, .grid-stack > .grid-stack-item.ui-resizable-resizing {
- z-index: 100;
-}
-
-.grid-stack > .grid-stack-item.ui-draggable-dragging > .grid-stack-item-content,
-.grid-stack > .grid-stack-item.ui-draggable-dragging > .grid-stack-item-content, .grid-stack > .grid-stack-item.ui-resizable-resizing > .grid-stack-item-content,
-.grid-stack > .grid-stack-item.ui-resizable-resizing > .grid-stack-item-content {
- box-shadow: 1px 4px 6px rgba(0, 0, 0, 0.2);
- opacity: 0.8;
-}
-
-.grid-stack > .grid-stack-item > .ui-resizable-se,
-.grid-stack > .grid-stack-item > .ui-resizable-sw {
- font-family: 'grafana-icons' !important;
- speak: none;
- font-style: normal;
- font-weight: normal;
- font-variant: normal;
- text-transform: none;
- line-height: 1;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- &::before {
- content: "\e90b";
- }
-}
-.grid-stack > .grid-stack-item > .ui-resizable-se {
- cursor: se-resize;
- width: 16px;
- height: 16px;
- right: 6px;
- bottom: -2px;
-}
-
-.grid-stack > .grid-stack-item.ui-draggable-dragging > .ui-resizable-handle {
- display: none !important;
-}
-
-.grid-stack > .grid-stack-item[data-gs-width='1'] {
- width: 8.3333333333%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-x='1'] {
- left: 8.3333333333%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-min-width='1'] {
- min-width: 8.3333333333%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-max-width='1'] {
- max-width: 8.3333333333%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-width='2'] {
- width: 16.6666666667%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-x='2'] {
- left: 16.6666666667%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-min-width='2'] {
- min-width: 16.6666666667%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-max-width='2'] {
- max-width: 16.6666666667%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-width='3'] {
- width: 25%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-x='3'] {
- left: 25%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-min-width='3'] {
- min-width: 25%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-max-width='3'] {
- max-width: 25%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-width='4'] {
- width: 33.3333333333%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-x='4'] {
- left: 33.3333333333%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-min-width='4'] {
- min-width: 33.3333333333%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-max-width='4'] {
- max-width: 33.3333333333%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-width='5'] {
- width: 41.6666666667%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-x='5'] {
- left: 41.6666666667%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-min-width='5'] {
- min-width: 41.6666666667%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-max-width='5'] {
- max-width: 41.6666666667%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-width='6'] {
- width: 50%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-x='6'] {
- left: 50%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-min-width='6'] {
- min-width: 50%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-max-width='6'] {
- max-width: 50%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-width='7'] {
- width: 58.3333333333%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-x='7'] {
- left: 58.3333333333%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-min-width='7'] {
- min-width: 58.3333333333%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-max-width='7'] {
- max-width: 58.3333333333%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-width='8'] {
- width: 66.6666666667%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-x='8'] {
- left: 66.6666666667%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-min-width='8'] {
- min-width: 66.6666666667%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-max-width='8'] {
- max-width: 66.6666666667%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-width='9'] {
- width: 75%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-x='9'] {
- left: 75%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-min-width='9'] {
- min-width: 75%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-max-width='9'] {
- max-width: 75%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-width='10'] {
- width: 83.3333333333%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-x='10'] {
- left: 83.3333333333%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-min-width='10'] {
- min-width: 83.3333333333%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-max-width='10'] {
- max-width: 83.3333333333%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-width='11'] {
- width: 91.6666666667%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-x='11'] {
- left: 91.6666666667%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-min-width='11'] {
- min-width: 91.6666666667%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-max-width='11'] {
- max-width: 91.6666666667%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-width='12'] {
- width: 100%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-x='12'] {
- left: 100%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-min-width='12'] {
- min-width: 100%;
-}
-
-.grid-stack > .grid-stack-item[data-gs-max-width='12'] {
- max-width: 100%;
-}
-
-.grid-stack.grid-stack-animate,
-.grid-stack.grid-stack-animate .grid-stack-item {
- -webkit-transition: left 0.3s, top 0.3s, height 0.3s, width 0.3s;
- -moz-transition: left 0.3s, top 0.3s, height 0.3s, width 0.3s;
- -ms-transition: left 0.3s, top 0.3s, height 0.3s, width 0.3s;
- -o-transition: left 0.3s, top 0.3s, height 0.3s, width 0.3s;
- transition: left 0.3s, top 0.3s, height 0.3s, width 0.3s;
-}
-
-.grid-stack.grid-stack-animate .grid-stack-item.ui-draggable-dragging,
-.grid-stack.grid-stack-animate .grid-stack-item.ui-resizable-resizing,
-.grid-stack.grid-stack-animate .grid-stack-item.grid-stack-placeholder {
- -webkit-transition: left 0s, top 0s, height 0s, width 0s;
- -moz-transition: left 0s, top 0s, height 0s, width 0s;
- -ms-transition: left 0s, top 0s, height 0s, width 0s;
- -o-transition: left 0s, top 0s, height 0s, width 0s;
- transition: left 0s, top 0s, height 0s, width 0s;
-}
-
-.grid-stack.grid-stack-one-column-mode {
- height: auto !important;
-}
-
-.grid-stack.grid-stack-one-column-mode > .grid-stack-item {
- position: relative !important;
- width: auto !important;
- left: 0 !important;
- top: auto !important;
- margin-bottom: 20px;
- max-width: none !important;
-}
-
-.grid-stack.grid-stack-one-column-mode > .grid-stack-item > .ui-resizable-handle {
- display: none;
-}
diff --git a/public/sass/components/_modals.scss b/public/sass/components/_modals.scss
index 2525f104aa7..14713fbda74 100644
--- a/public/sass/components/_modals.scss
+++ b/public/sass/components/_modals.scss
@@ -10,7 +10,7 @@
bottom: 0;
left: 0;
z-index: $zindex-modal-backdrop;
- background-color: $black;
+ background-color: $modal-backdrop-bg;
}
.modal-backdrop,
diff --git a/public/sass/components/_navbar.scss b/public/sass/components/_navbar.scss
index 4ccabb5f19a..8456af7b152 100644
--- a/public/sass/components/_navbar.scss
+++ b/public/sass/components/_navbar.scss
@@ -17,7 +17,7 @@
.sidemenu-open {
.navbar {
- padding-left: 0;
+ padding-left: $panel-margin;
}
}
diff --git a/public/sass/components/_submenu.scss b/public/sass/components/_submenu.scss
index 878058bd1c4..8211fffa9ee 100644
--- a/public/sass/components/_submenu.scss
+++ b/public/sass/components/_submenu.scss
@@ -5,7 +5,7 @@
align-content: flex-start;
align-items: flex-start;
- margin: 0 $panel-margin ($panel-margin*2) $panel-margin;
+ margin: 0 0 $panel-margin 0;
}
.annotation-disabled, .annotation-disabled a {
diff --git a/public/sass/pages/_dashboard.scss b/public/sass/pages/_dashboard.scss
index 53adcf6d825..0559f75fd91 100644
--- a/public/sass/pages/_dashboard.scss
+++ b/public/sass/pages/_dashboard.scss
@@ -25,6 +25,7 @@ div.flot-text {
background-color: $panel-bg;
border: $panel-border;
position: relative;
+ height: 100%;
&.panel-transparent {
background-color: transparent;
@@ -34,6 +35,7 @@ div.flot-text {
.panel-content {
padding: 0px 10px 5px 10px;
+ height: 100%;
}
.panel-title-container {
diff --git a/public/test/specs/helpers.d.ts b/public/test/specs/helpers.d.ts
deleted file mode 100644
index 4b64bd79031..00000000000
--- a/public/test/specs/helpers.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-declare let helpers: any;
-export default helpers;
-
-
diff --git a/public/test/specs/helpers.js b/public/test/specs/helpers.js
deleted file mode 100644
index 40c4a75423c..00000000000
--- a/public/test/specs/helpers.js
+++ /dev/null
@@ -1,180 +0,0 @@
-define([
- 'lodash',
- 'app/core/config',
- 'app/core/utils/datemath',
-], function(_, config, dateMath) {
- 'use strict';
-
- function ControllerTestContext() {
- var self = this;
-
- this.datasource = {};
- this.$element = {};
- this.annotationsSrv = {};
- this.timeSrv = new TimeSrvStub();
- this.templateSrv = new TemplateSrvStub();
- this.datasourceSrv = {
- getMetricSources: function() {},
- get: function() {
- return {
- then: function(callback) {
- callback(self.datasource);
- }
- };
- }
- };
-
- this.providePhase = function(mocks) {
- return window.module(function($provide) {
- $provide.value('datasourceSrv', self.datasourceSrv);
- $provide.value('annotationsSrv', self.annotationsSrv);
- $provide.value('timeSrv', self.timeSrv);
- $provide.value('templateSrv', self.templateSrv);
- $provide.value('$element', self.$element);
- _.each(mocks, function(value, key) {
- $provide.value(key, value);
- });
- });
- };
-
- this.createPanelController = function(Ctrl) {
- return window.inject(function($controller, $rootScope, $q, $location, $browser) {
- self.scope = $rootScope.$new();
- self.$location = $location;
- self.$browser = $browser;
- self.$q = $q;
- self.panel = {type: 'test'};
- self.dashboard = {meta: {}};
-
- $rootScope.appEvent = sinon.spy();
- $rootScope.onAppEvent = sinon.spy();
- $rootScope.colors = [];
-
- for (var i = 0; i < 50; i++) { $rootScope.colors.push('#' + i); }
-
- config.panels['test'] = {info: {}};
- self.ctrl = $controller(Ctrl, {$scope: self.scope}, {
- panel: self.panel, dashboard: self.dashboard, row: {}
- });
- });
- };
-
- this.createControllerPhase = function(controllerName) {
- return window.inject(function($controller, $rootScope, $q, $location, $browser) {
- self.scope = $rootScope.$new();
- self.$location = $location;
- self.$browser = $browser;
- self.scope.contextSrv = {};
- self.scope.panel = {};
- self.scope.row = { panels:[] };
- self.scope.dashboard = {meta: {}};
- self.scope.dashboardMeta = {};
- self.scope.dashboardViewState = new DashboardViewStateStub();
- self.scope.appEvent = sinon.spy();
- self.scope.onAppEvent = sinon.spy();
-
- $rootScope.colors = [];
- for (var i = 0; i < 50; i++) { $rootScope.colors.push('#' + i); }
-
- self.$q = $q;
- self.scope.skipDataOnInit = true;
- self.scope.skipAutoInit = true;
- self.controller = $controller(controllerName, {
- $scope: self.scope
- });
- });
- };
- }
-
- function ServiceTestContext() {
- var self = this;
- self.templateSrv = new TemplateSrvStub();
- self.timeSrv = new TimeSrvStub();
- self.datasourceSrv = {};
- self.backendSrv = {};
- self.$routeParams = {};
-
- this.providePhase = function(mocks) {
- return window.module(function($provide) {
- _.each(mocks, function(key) {
- $provide.value(key, self[key]);
- });
- });
- };
-
- this.createService = function(name) {
- return window.inject(function($q, $rootScope, $httpBackend, $injector, $location, $timeout) {
- self.$q = $q;
- self.$rootScope = $rootScope;
- self.$httpBackend = $httpBackend;
- self.$location = $location;
-
- self.$rootScope.onAppEvent = function() {};
- self.$rootScope.appEvent = function() {};
- self.$timeout = $timeout;
-
- self.service = $injector.get(name);
- });
- };
- }
-
- function DashboardViewStateStub() {
- this.registerPanel = function() {
- };
- }
-
- function TimeSrvStub() {
- this.init = sinon.spy();
- this.time = { from:'now-1h', to: 'now'};
- this.timeRange = function(parse) {
- if (parse === false) {
- return this.time;
- }
- return {
- from : dateMath.parse(this.time.from, false),
- to : dateMath.parse(this.time.to, true)
- };
- };
-
- this.replace = function(target) {
- return target;
- };
-
- this.setTime = function(time) {
- this.time = time;
- };
- }
-
- function ContextSrvStub() {
- this.hasRole = function() {
- return true;
- };
- }
-
- function TemplateSrvStub() {
- this.variables = [];
- this.templateSettings = { interpolate : /\[\[([\s\S]+?)\]\]/g };
- this.data = {};
- this.replace = function(text) {
- return _.template(text, this.templateSettings)(this.data);
- };
- this.init = function() {};
- this.getAdhocFilters = function() { return []; };
- this.fillVariableValuesForUrl = function() {};
- this.updateTemplateData = function() { };
- this.variableExists = function() { return false; };
- this.variableInitialized = function() { };
- this.highlightVariablesAsHtml = function(str) { return str; };
- this.setGrafanaVariable = function(name, value) {
- this.data[name] = value;
- };
- }
-
- return {
- ControllerTestContext: ControllerTestContext,
- TimeSrvStub: TimeSrvStub,
- ContextSrvStub: ContextSrvStub,
- ServiceTestContext: ServiceTestContext
- };
-
-});
diff --git a/public/test/specs/helpers.ts b/public/test/specs/helpers.ts
new file mode 100644
index 00000000000..709617a9465
--- /dev/null
+++ b/public/test/specs/helpers.ts
@@ -0,0 +1,195 @@
+import _ from 'lodash';
+import config from 'app/core/config';
+import * as dateMath from 'app/core/utils/datemath';
+import {angularMocks, sinon} from '../lib/common';
+import {PanelModel} from 'app/features/dashboard/PanelModel';
+
+export function ControllerTestContext() {
+ var self = this;
+
+ this.datasource = {};
+ this.$element = {};
+ this.annotationsSrv = {};
+ this.timeSrv = new TimeSrvStub();
+ this.templateSrv = new TemplateSrvStub();
+ this.datasourceSrv = {
+ getMetricSources: function() {},
+ get: function() {
+ return {
+ then: function(callback) {
+ callback(self.datasource);
+ },
+ };
+ },
+ };
+
+ this.providePhase = function(mocks) {
+ return angularMocks.module(function($provide) {
+ $provide.value('datasourceSrv', self.datasourceSrv);
+ $provide.value('annotationsSrv', self.annotationsSrv);
+ $provide.value('timeSrv', self.timeSrv);
+ $provide.value('templateSrv', self.templateSrv);
+ $provide.value('$element', self.$element);
+ _.each(mocks, function(value, key) {
+ $provide.value(key, value);
+ });
+ });
+ };
+
+ this.createPanelController = function(Ctrl) {
+ return angularMocks.inject(function($controller, $rootScope, $q, $location, $browser) {
+ self.scope = $rootScope.$new();
+ self.$location = $location;
+ self.$browser = $browser;
+ self.$q = $q;
+ self.panel = new PanelModel({type: 'test'});
+ self.dashboard = {meta: {}};
+
+ $rootScope.appEvent = sinon.spy();
+ $rootScope.onAppEvent = sinon.spy();
+ $rootScope.colors = [];
+
+ for (var i = 0; i < 50; i++) {
+ $rootScope.colors.push('#' + i);
+ }
+
+ config.panels['test'] = {info: {}};
+ self.ctrl = $controller(
+ Ctrl,
+ {$scope: self.scope},
+ {
+ panel: self.panel,
+ dashboard: self.dashboard,
+ },
+ );
+ });
+ };
+
+ this.createControllerPhase = function(controllerName) {
+ return angularMocks.inject(function($controller, $rootScope, $q, $location, $browser) {
+ self.scope = $rootScope.$new();
+ self.$location = $location;
+ self.$browser = $browser;
+ self.scope.contextSrv = {};
+ self.scope.panel = {};
+ self.scope.dashboard = {meta: {}};
+ self.scope.dashboardMeta = {};
+ self.scope.dashboardViewState = new DashboardViewStateStub();
+ self.scope.appEvent = sinon.spy();
+ self.scope.onAppEvent = sinon.spy();
+
+ $rootScope.colors = [];
+ for (var i = 0; i < 50; i++) {
+ $rootScope.colors.push('#' + i);
+ }
+
+ self.$q = $q;
+ self.scope.skipDataOnInit = true;
+ self.scope.skipAutoInit = true;
+ self.controller = $controller(controllerName, {
+ $scope: self.scope,
+ });
+ });
+ };
+}
+
+export function ServiceTestContext() {
+ var self = this;
+ self.templateSrv = new TemplateSrvStub();
+ self.timeSrv = new TimeSrvStub();
+ self.datasourceSrv = {};
+ self.backendSrv = {};
+ self.$routeParams = {};
+
+ this.providePhase = function(mocks) {
+ return angularMocks.module(function($provide) {
+ _.each(mocks, function(key) {
+ $provide.value(key, self[key]);
+ });
+ });
+ };
+
+ this.createService = function(name) {
+ return angularMocks.inject(function($q, $rootScope, $httpBackend, $injector, $location, $timeout) {
+ self.$q = $q;
+ self.$rootScope = $rootScope;
+ self.$httpBackend = $httpBackend;
+ self.$location = $location;
+
+ self.$rootScope.onAppEvent = function() {};
+ self.$rootScope.appEvent = function() {};
+ self.$timeout = $timeout;
+
+ self.service = $injector.get(name);
+ });
+ };
+}
+
+export function DashboardViewStateStub() {
+ this.registerPanel = function() {};
+}
+
+export function TimeSrvStub() {
+ this.init = sinon.spy();
+ this.time = {from: 'now-1h', to: 'now'};
+ this.timeRange = function(parse) {
+ if (parse === false) {
+ return this.time;
+ }
+ return {
+ from: dateMath.parse(this.time.from, false),
+ to: dateMath.parse(this.time.to, true),
+ };
+ };
+
+ this.replace = function(target) {
+ return target;
+ };
+
+ this.setTime = function(time) {
+ this.time = time;
+ };
+}
+
+export function ContextSrvStub() {
+ this.hasRole = function() {
+ return true;
+ };
+}
+
+export function TemplateSrvStub() {
+ this.variables = [];
+ this.templateSettings = {interpolate: /\[\[([\s\S]+?)\]\]/g};
+ this.data = {};
+ this.replace = function(text) {
+ return _.template(text, this.templateSettings)(this.data);
+ };
+ this.init = function() {};
+ this.getAdhocFilters = function() {
+ return [];
+ };
+ this.fillVariableValuesForUrl = function() {};
+ this.updateTemplateData = function() {};
+ this.variableExists = function() {
+ return false;
+ };
+ this.variableInitialized = function() {};
+ this.highlightVariablesAsHtml = function(str) {
+ return str;
+ };
+ this.setGrafanaVariable = function(name, value) {
+ this.data[name] = value;
+ };
+}
+
+var allDeps = {
+ ContextSrvStub: ContextSrvStub,
+ TemplateSrvStub: TemplateSrvStub,
+ TimeSrvStub: TimeSrvStub,
+ ControllerTestContext: ControllerTestContext,
+ ServiceTestContext: ServiceTestContext,
+ DashboardViewStateStub: DashboardViewStateStub
+};
+
+// for legacy
+export default allDeps;
diff --git a/public/test/test-main.js b/public/test/test-main.js
deleted file mode 100644
index 1347c421a64..00000000000
--- a/public/test/test-main.js
+++ /dev/null
@@ -1,130 +0,0 @@
-(function() {
- "use strict";
-
- // Tun on full stack traces in errors to help debugging
- Error.stackTraceLimit=Infinity;
-
- window.__karma__.loaded = function() {};
-
- System.config({
- baseURL: '/base/',
- defaultJSExtensions: true,
- paths: {
- 'mousetrap': 'vendor/npm/mousetrap/mousetrap.js',
- 'eventemitter3': 'vendor/npm/eventemitter3/index.js',
- 'remarkable': 'vendor/npm/remarkable/dist/remarkable.js',
- 'tether': 'vendor/npm/tether/dist/js/tether.js',
- 'tether-drop': 'vendor/npm/tether-drop/dist/js/drop.js',
- 'moment': 'vendor/moment.js',
- "jquery": "vendor/jquery/dist/jquery.js",
- 'lodash-src': 'vendor/lodash/dist/lodash.js',
- "lodash": 'app/core/lodash_extended.js',
- "angular": 'vendor/angular/angular.js',
- 'angular-mocks': 'vendor/angular-mocks/angular-mocks.js',
- "bootstrap": "vendor/bootstrap/bootstrap.js",
- 'angular-route': 'vendor/angular-route/angular-route.js',
- 'angular-sanitize': 'vendor/angular-sanitize/angular-sanitize.js',
- "angular-ui": "vendor/angular-ui/ui-bootstrap-tpls.js",
- "angular-strap": "vendor/angular-other/angular-strap.js",
- "angular-dragdrop": "vendor/angular-native-dragdrop/draganddrop.js",
- "angular-bindonce": "vendor/angular-bindonce/bindonce.js",
- "spectrum": "vendor/spectrum.js",
- "bootstrap-tagsinput": "vendor/tagsinput/bootstrap-tagsinput.js",
- "jquery.flot": "vendor/flot/jquery.flot",
- "jquery.flot.pie": "vendor/flot/jquery.flot.pie",
- "jquery.flot.selection": "vendor/flot/jquery.flot.selection",
- "jquery.flot.stack": "vendor/flot/jquery.flot.stack",
- "jquery.flot.stackpercent": "vendor/flot/jquery.flot.stackpercent",
- "jquery.flot.time": "vendor/flot/jquery.flot.time",
- "jquery.flot.crosshair": "vendor/flot/jquery.flot.crosshair",
- "jquery.flot.fillbelow": "vendor/flot/jquery.flot.fillbelow",
- "jquery.flot.gauge": "vendor/flot/jquery.flot.gauge",
- "d3": "vendor/d3/d3.js",
- "jquery.flot.dashes": "vendor/flot/jquery.flot.dashes",
- "twemoji": "vendor/npm/twemoji/2/twemoji.amd.js",
- "ace": "vendor/npm/ace-builds/src-noconflict/ace",
- },
-
- packages: {
- app: {
- defaultExtension: 'js',
- },
- vendor: {
- defaultExtension: 'js',
- },
- },
-
- map: {
- },
-
- meta: {
- 'vendor/angular/angular.js': {
- format: 'global',
- deps: ['jquery'],
- exports: 'angular',
- },
- 'vendor/angular-mocks/angular-mocks.js': {
- format: 'global',
- deps: ['angular'],
- },
- 'vendor/npm/eventemitter3/index.js': {
- format: 'cjs',
- exports: 'EventEmitter'
- },
- 'vendor/npm/mousetrap/mousetrap.js': {
- format: 'global',
- exports: 'Mousetrap'
- },
- 'vendor/npm/ace-builds/src-noconflict/ace.js': {
- format: 'global',
- exports: 'ace'
- },
- }
- });
-
- function file2moduleName(filePath) {
- return filePath.replace(/\\/g, '/')
- .replace(/^\/base\//, '')
- .replace(/\.\w*$/, '');
- }
-
- function onlySpecFiles(path) {
- return /specs.*/.test(path);
- }
-
- window.grafanaBootData = {settings: {}};
-
- var modules = ['angular', 'angular-mocks', 'app/app'];
- var promises = modules.map(function(name) {
- return System.import(name);
- });
-
- Promise.all(promises).then(function(deps) {
- var angular = deps[0];
-
- angular.module('grafana', ['ngRoute']);
- angular.module('grafana.services', ['ngRoute', '$strap.directives']);
- angular.module('grafana.panels', []);
- angular.module('grafana.controllers', []);
- angular.module('grafana.directives', []);
- angular.module('grafana.filters', []);
- angular.module('grafana.routes', ['ngRoute']);
-
- // load specs
- return Promise.all(
- Object.keys(window.__karma__.files) // All files served by Karma.
- .filter(onlySpecFiles)
- .map(file2moduleName)
- .map(function(path) {
- // console.log(path);
- return System.import(path);
- }));
- }).then(function() {
- window.__karma__.start();
- }, function(error) {
- window.__karma__.error(error.stack || error);
- }).catch(function(error) {
- window.__karma__.error(error.stack || error);
- });
-
-})();
diff --git a/scripts/webpack/webpack.dev.js b/scripts/webpack/webpack.dev.js
index 037212c26de..1ed9a412fdf 100644
--- a/scripts/webpack/webpack.dev.js
+++ b/scripts/webpack/webpack.dev.js
@@ -10,7 +10,7 @@ const WebpackCleanupPlugin = require('webpack-cleanup-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = merge(common, {
- devtool: "eval-source-map",
+ devtool: "cheap-module-source-map",
entry: {
dark: './public/sass/grafana.dark.scss',
diff --git a/yarn.lock b/yarn.lock
index 2b5ccda06b1..326d2176eb5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1072,6 +1072,10 @@ base@^0.11.1:
mixin-deep "^1.2.0"
pascalcase "^0.1.1"
+batch-processor@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/batch-processor/-/batch-processor-1.0.0.tgz#75c95c32b748e0850d10c2b168f6bdbe9891ace8"
+
bcrypt-pbkdf@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d"
@@ -1509,6 +1513,10 @@ class-utils@^0.3.5:
lazy-cache "^2.0.2"
static-extend "^0.1.1"
+classnames@2.x, classnames@^2.2.5:
+ version "2.2.5"
+ resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d"
+
clean-css@3.4.x, clean-css@~3.4.2:
version "3.4.28"
resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff"
@@ -2411,6 +2419,12 @@ elegant-spinner@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e"
+element-resize-detector@^1.1.12:
+ version "1.1.12"
+ resolved "https://registry.yarnpkg.com/element-resize-detector/-/element-resize-detector-1.1.12.tgz#8b3fd6eedda17f9c00b360a0ea2df9927ae80ba2"
+ dependencies:
+ batch-processor "^1.0.0"
+
elliptic@^6.0.0:
version "6.4.0"
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df"
@@ -3445,14 +3459,6 @@ graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6,
version "1.0.1"
resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
-"gridstack@https://github.com/grafana/gridstack.js#grafana":
- version "1.0.0-dev"
- resolved "https://github.com/grafana/gridstack.js#bd40b3fe4dafc99350145c7b4761d8693593f6fe"
- dependencies:
- jquery "^3.1.0"
- jquery-ui "^1.12.0"
- lodash "^4.14.2"
-
growl@1.10.3:
version "1.10.3"
resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.3.tgz#1926ba90cf3edfe2adb4927f5880bc22c66c790f"
@@ -4434,11 +4440,7 @@ jest-validate@^21.1.0:
leven "^2.1.0"
pretty-format "^21.2.1"
-jquery-ui@^1.12.0:
- version "1.12.1"
- resolved "https://registry.yarnpkg.com/jquery-ui/-/jquery-ui-1.12.1.tgz#bcb4045c8dd0539c134bc1488cdd3e768a7a9e51"
-
-jquery@^3.1.0, jquery@^3.2.1:
+jquery@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.2.1.tgz#5c4d9de652af6cd0a770154a631bba12b015c787"
@@ -4975,6 +4977,10 @@ lodash.flattendeep@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
+lodash.isequal@^4.0.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
+
lodash.kebabcase@^4.0.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36"
@@ -5011,7 +5017,7 @@ lodash@^3.10.1, lodash@^3.5.0, lodash@^3.6.0, lodash@^3.7.0, lodash@^3.8.0, loda
version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
-lodash@^4.0.0, lodash@^4.0.1, lodash@^4.14.0, lodash@^4.14.2, lodash@^4.15.0, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.7.0, lodash@^4.8.0, lodash@~4.17.4:
+lodash@^4.0.0, lodash@^4.0.1, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.7.0, lodash@^4.8.0, lodash@~4.17.4:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
@@ -6719,7 +6725,7 @@ promzard@^0.3.0:
dependencies:
read "1"
-prop-types@^15.5.10, prop-types@^15.6.0:
+prop-types@15.x, prop-types@^15.5.10, prop-types@^15.6.0:
version "15.6.0"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856"
dependencies:
@@ -6877,6 +6883,38 @@ react-dom@^16.0.0:
object-assign "^4.1.1"
prop-types "^15.6.0"
+"react-draggable@^2.2.6 || ^3.0.3", react-draggable@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-3.0.3.tgz#a6f9b3a7171981b76dadecf238316925cb9eacf4"
+ dependencies:
+ classnames "^2.2.5"
+ prop-types "^15.5.10"
+
+react-grid-layout@^0.16.0:
+ version "0.16.0"
+ resolved "https://registry.yarnpkg.com/react-grid-layout/-/react-grid-layout-0.16.0.tgz#f74363cd134b2f8a763224d7b6287cbb68e6de05"
+ dependencies:
+ classnames "2.x"
+ lodash.isequal "^4.0.0"
+ prop-types "15.x"
+ react-draggable "^3.0.3"
+ react-resizable "^1.7.5"
+
+react-resizable@^1.7.5:
+ version "1.7.5"
+ resolved "https://registry.yarnpkg.com/react-resizable/-/react-resizable-1.7.5.tgz#83eb75bb3684da6989bbbf4f826e1470f0af902e"
+ dependencies:
+ prop-types "15.x"
+ react-draggable "^2.2.6 || ^3.0.3"
+
+react-sizeme@^2.3.6:
+ version "2.3.6"
+ resolved "https://registry.yarnpkg.com/react-sizeme/-/react-sizeme-2.3.6.tgz#d60ea2634acc3fd827a3c7738d41eea0992fa678"
+ dependencies:
+ element-resize-detector "^1.1.12"
+ invariant "^2.2.2"
+ lodash "^4.17.4"
+
react-test-renderer@^16.0.0:
version "16.0.0"
resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.0.0.tgz#9fe7b8308f2f71f29fc356d4102086f131c9cb15"