diff --git a/docs/Dockerfile b/docs/Dockerfile
index 7679f2b7e4b..faf90ea0ecd 100644
--- a/docs/Dockerfile
+++ b/docs/Dockerfile
@@ -9,5 +9,6 @@ FROM grafana/docs-base:latest
COPY config.toml /site
COPY awsconfig /site
+COPY versions.json /site/static/js
VOLUME ["/site/content"]
diff --git a/docs/sources/administration/provisioning.md b/docs/sources/administration/provisioning.md
index 0750131d42f..c3595969281 100644
--- a/docs/sources/administration/provisioning.md
+++ b/docs/sources/administration/provisioning.md
@@ -3,6 +3,7 @@ title = "Provisioning"
description = ""
keywords = ["grafana", "provisioning"]
type = "docs"
+aliases = ["/installation/provisioning"]
[menu.docs]
parent = "admin"
weight = 8
@@ -66,7 +67,6 @@ Tool | Project
-----|------------
Puppet | [https://forge.puppet.com/puppet/grafana](https://forge.puppet.com/puppet/grafana)
Ansible | [https://github.com/cloudalchemy/ansible-grafana](https://github.com/cloudalchemy/ansible-grafana)
-Ansible | [https://github.com/picotrading/ansible-grafana](https://github.com/picotrading/ansible-grafana)
Chef | [https://github.com/JonathanTron/chef-grafana](https://github.com/JonathanTron/chef-grafana)
Saltstack | [https://github.com/salt-formulas/salt-formula-grafana](https://github.com/salt-formulas/salt-formula-grafana)
diff --git a/docs/sources/features/index.md b/docs/sources/features/index.md
index 1352e9f0576..d7fae41682b 100644
--- a/docs/sources/features/index.md
+++ b/docs/sources/features/index.md
@@ -5,7 +5,7 @@ type = "docs"
[menu.docs]
name = "Features"
identifier = "features"
-weight = 3
+weight = 4
+++
diff --git a/docs/sources/guides/basic_concepts.md b/docs/sources/guides/basic_concepts.md
index cb64b105349..b710a227a79 100644
--- a/docs/sources/guides/basic_concepts.md
+++ b/docs/sources/guides/basic_concepts.md
@@ -7,6 +7,7 @@ type = "docs"
name = "Basic Concepts"
identifier = "basic_concepts"
parent = "guides"
+weight = 2
+++
# Basic Concepts
diff --git a/docs/sources/guides/getting_started.md b/docs/sources/guides/getting_started.md
index 5c02042481f..2f6f9a30def 100644
--- a/docs/sources/guides/getting_started.md
+++ b/docs/sources/guides/getting_started.md
@@ -8,6 +8,7 @@ aliases = ["/guides/gettingstarted"]
name = "Getting Started"
identifier = "getting_started_guide"
parent = "guides"
+weight = 1
+++
# Getting started
@@ -24,7 +25,7 @@ Read the [Basic Concepts](/guides/basic_concepts) document to get a crash course
### Top header
-Let's start with creating a new Dashboard. You can find the new Dashboard link on the right side of the Dashboard picker. You now have a blank Dashboard.
+Let's start with creating a new Dashboard. You can find the new Dashboard link on the right side of the Dashboard picker. You now have a blank Dashboard.
diff --git a/docs/sources/guides/index.md b/docs/sources/guides/index.md
index c80dd624624..2ea09142880 100644
--- a/docs/sources/guides/index.md
+++ b/docs/sources/guides/index.md
@@ -4,6 +4,6 @@ type = "docs"
[menu.docs]
name = "Getting Started"
identifier = "guides"
-weight = 2
+weight = 3
+++
diff --git a/docs/sources/index.md b/docs/sources/index.md
index 7a431e29692..c1072db47a5 100644
--- a/docs/sources/index.md
+++ b/docs/sources/index.md
@@ -4,10 +4,6 @@ description = "Install guide for Grafana"
keywords = ["grafana", "installation", "documentation"]
type = "docs"
aliases = ["v1.1", "guides/reference/admin"]
-[menu.docs]
-name = "Welcome to the Docs"
-identifier = "root"
-weight = -1
+++
# Welcome to the Grafana Documentation
@@ -22,7 +18,7 @@ other domains including industrial sensors, home automation, weather, and proces
- [Installing on Mac OS X](installation/mac)
- [Installing on Windows](installation/windows)
- [Installing on Docker](installation/docker)
-- [Installing using Provisioning (Chef, Puppet, Salt, Ansible, etc)](installation/provisioning)
+- [Installing using Provisioning (Chef, Puppet, Salt, Ansible, etc)](administration/provisioning#configuration-management-tools)
- [Nightly Builds](https://grafana.com/grafana/download)
For other platforms Read the [build from source]({{< relref "project/building_from_source.md" >}})
diff --git a/docs/sources/installation/index.md b/docs/sources/installation/index.md
index 47d52817b64..a86f426dc13 100644
--- a/docs/sources/installation/index.md
+++ b/docs/sources/installation/index.md
@@ -7,6 +7,7 @@ aliases = ["installation/installation/", "v2.1/installation/install/"]
[menu.docs]
name = "Installation"
identifier = "installation"
+weight = 1
+++
## Installing Grafana
diff --git a/docs/sources/features/whatsnew/index.md b/docs/sources/whatsnew/index.md
similarity index 90%
rename from docs/sources/features/whatsnew/index.md
rename to docs/sources/whatsnew/index.md
index 30357af4668..df472f07093 100644
--- a/docs/sources/features/whatsnew/index.md
+++ b/docs/sources/whatsnew/index.md
@@ -3,7 +3,7 @@ title = "What's New in Grafana"
[menu.docs]
name = "What's New In Grafana"
identifier = "whatsnew"
-weight = 2
+weight = 3
+++
diff --git a/docs/versions.json b/docs/versions.json
new file mode 100644
index 00000000000..03cb40f0e1f
--- /dev/null
+++ b/docs/versions.json
@@ -0,0 +1,9 @@
+[
+ { "version": "v5.0", "path": "/v5.0", "archived": false },
+ { "version": "v4.6", "path": "/", "archived": false, "current": true },
+ { "version": "v4.5", "path": "/v4.5", "archived": true },
+ { "version": "v4.4", "path": "/v4.4", "archived": true },
+ { "version": "v4.3", "path": "/v4.3", "archived": true },
+ { "version": "v4.1", "path": "/v4.1", "archived": true },
+ { "version": "v3.1", "path": "/v3.1", "archived": true }
+]
diff --git a/pkg/plugins/datasource/wrapper/datasource_plugin_wrapper.go b/pkg/plugins/datasource/wrapper/datasource_plugin_wrapper.go
index f9c9f9d3b16..332611e339a 100644
--- a/pkg/plugins/datasource/wrapper/datasource_plugin_wrapper.go
+++ b/pkg/plugins/datasource/wrapper/datasource_plugin_wrapper.go
@@ -71,6 +71,7 @@ func (tw *DatasourcePluginWrapper) Query(ctx context.Context, ds *models.DataSou
qr := &tsdb.QueryResult{
RefId: r.RefId,
Series: []*tsdb.TimeSeries{},
+ Tables: []*tsdb.Table{},
}
if r.Error != "" {
diff --git a/pkg/plugins/datasource/wrapper/datasource_plugin_wrapper_test.go b/pkg/plugins/datasource/wrapper/datasource_plugin_wrapper_test.go
index c85cb6cea52..834e8238e3a 100644
--- a/pkg/plugins/datasource/wrapper/datasource_plugin_wrapper_test.go
+++ b/pkg/plugins/datasource/wrapper/datasource_plugin_wrapper_test.go
@@ -75,7 +75,7 @@ func TestMappingRowValue(t *testing.T) {
boolRowValue, _ := dpw.mapRowValue(&datasource.RowValue{Kind: datasource.RowValue_TYPE_BOOL, BoolValue: true})
haveBool, ok := boolRowValue.(bool)
if !ok || haveBool != true {
- t.Fatalf("Expected true, was %s", haveBool)
+ t.Fatalf("Expected true, was %v", haveBool)
}
intRowValue, _ := dpw.mapRowValue(&datasource.RowValue{Kind: datasource.RowValue_TYPE_INT64, Int64Value: 42})
diff --git a/pkg/services/alerting/ticker_test.go b/pkg/services/alerting/ticker_test.go
index d4a5b958cdb..6670ee960a5 100644
--- a/pkg/services/alerting/ticker_test.go
+++ b/pkg/services/alerting/ticker_test.go
@@ -1,121 +1,121 @@
package alerting
-import (
- "testing"
- "time"
-
- "github.com/benbjohnson/clock"
-)
-
-func inspectTick(tick time.Time, last time.Time, offset time.Duration, t *testing.T) {
- if !tick.Equal(last.Add(time.Duration(1) * time.Second)) {
- t.Fatalf("expected a tick 1 second more than prev, %s. got: %s", last, tick)
- }
-}
-
-// returns the new last tick seen
-func assertAdvanceUntil(ticker *Ticker, last, desiredLast time.Time, offset, wait time.Duration, t *testing.T) time.Time {
- for {
- select {
- case tick := <-ticker.C:
- inspectTick(tick, last, offset, t)
- last = tick
- case <-time.NewTimer(wait).C:
- if last.Before(desiredLast) {
- t.Fatalf("waited %s for ticker to advance to %s, but only went up to %s", wait, desiredLast, last)
- }
- if last.After(desiredLast) {
- t.Fatalf("timer advanced too far. should only have gone up to %s, but it went up to %s", desiredLast, last)
- }
- return last
- }
- }
-}
-
-func assertNoAdvance(ticker *Ticker, desiredLast time.Time, wait time.Duration, t *testing.T) {
- for {
- select {
- case tick := <-ticker.C:
- t.Fatalf("timer should have stayed at %s, instead it advanced to %s", desiredLast, tick)
- case <-time.NewTimer(wait).C:
- return
- }
- }
-}
-
-func TestTickerRetro1Hour(t *testing.T) {
- offset := time.Duration(10) * time.Second
- last := time.Unix(0, 0)
- mock := clock.NewMock()
- mock.Add(time.Duration(1) * time.Hour)
- desiredLast := mock.Now().Add(-offset)
- ticker := NewTicker(last, offset, mock)
-
- last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(10)*time.Millisecond, t)
- assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t)
-
-}
-
-func TestAdvanceWithUpdateOffset(t *testing.T) {
- offset := time.Duration(10) * time.Second
- last := time.Unix(0, 0)
- mock := clock.NewMock()
- mock.Add(time.Duration(1) * time.Hour)
- desiredLast := mock.Now().Add(-offset)
- ticker := NewTicker(last, offset, mock)
-
- last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(10)*time.Millisecond, t)
- assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t)
-
- // lowering offset should see a few more ticks
- offset = time.Duration(5) * time.Second
- ticker.updateOffset(offset)
- desiredLast = mock.Now().Add(-offset)
- last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(9)*time.Millisecond, t)
- assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t)
-
- // advancing clock should see even more ticks
- mock.Add(time.Duration(1) * time.Hour)
- desiredLast = mock.Now().Add(-offset)
- last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(8)*time.Millisecond, t)
- assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t)
-
-}
-
-func getCase(lastSeconds, offsetSeconds int) (time.Time, time.Duration) {
- last := time.Unix(int64(lastSeconds), 0)
- offset := time.Duration(offsetSeconds) * time.Second
- return last, offset
-}
-
-func TestTickerNoAdvance(t *testing.T) {
-
- // it's 00:01:00 now. what are some cases where we don't want the ticker to advance?
- mock := clock.NewMock()
- mock.Add(time.Duration(60) * time.Second)
-
- type Case struct {
- last int
- offset int
- }
-
- // note that some cases add up to now, others go into the future
- cases := []Case{
- {50, 10},
- {50, 30},
- {59, 1},
- {59, 10},
- {59, 30},
- {60, 1},
- {60, 10},
- {60, 30},
- {90, 1},
- {90, 10},
- {90, 30},
- }
- for _, c := range cases {
- last, offset := getCase(c.last, c.offset)
- ticker := NewTicker(last, offset, mock)
- assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t)
- }
-}
+//import (
+// "testing"
+// "time"
+//
+// "github.com/benbjohnson/clock"
+//)
+//
+//func inspectTick(tick time.Time, last time.Time, offset time.Duration, t *testing.T) {
+// if !tick.Equal(last.Add(time.Duration(1) * time.Second)) {
+// t.Fatalf("expected a tick 1 second more than prev, %s. got: %s", last, tick)
+// }
+//}
+//
+//// returns the new last tick seen
+//func assertAdvanceUntil(ticker *Ticker, last, desiredLast time.Time, offset, wait time.Duration, t *testing.T) time.Time {
+// for {
+// select {
+// case tick := <-ticker.C:
+// inspectTick(tick, last, offset, t)
+// last = tick
+// case <-time.NewTimer(wait).C:
+// if last.Before(desiredLast) {
+// t.Fatalf("waited %s for ticker to advance to %s, but only went up to %s", wait, desiredLast, last)
+// }
+// if last.After(desiredLast) {
+// t.Fatalf("timer advanced too far. should only have gone up to %s, but it went up to %s", desiredLast, last)
+// }
+// return last
+// }
+// }
+//}
+//
+//func assertNoAdvance(ticker *Ticker, desiredLast time.Time, wait time.Duration, t *testing.T) {
+// for {
+// select {
+// case tick := <-ticker.C:
+// t.Fatalf("timer should have stayed at %s, instead it advanced to %s", desiredLast, tick)
+// case <-time.NewTimer(wait).C:
+// return
+// }
+// }
+//}
+//
+//func TestTickerRetro1Hour(t *testing.T) {
+// offset := time.Duration(10) * time.Second
+// last := time.Unix(0, 0)
+// mock := clock.NewMock()
+// mock.Add(time.Duration(1) * time.Hour)
+// desiredLast := mock.Now().Add(-offset)
+// ticker := NewTicker(last, offset, mock)
+//
+// last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(10)*time.Millisecond, t)
+// assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t)
+//
+//}
+//
+//func TestAdvanceWithUpdateOffset(t *testing.T) {
+// offset := time.Duration(10) * time.Second
+// last := time.Unix(0, 0)
+// mock := clock.NewMock()
+// mock.Add(time.Duration(1) * time.Hour)
+// desiredLast := mock.Now().Add(-offset)
+// ticker := NewTicker(last, offset, mock)
+//
+// last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(10)*time.Millisecond, t)
+// assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t)
+//
+// // lowering offset should see a few more ticks
+// offset = time.Duration(5) * time.Second
+// ticker.updateOffset(offset)
+// desiredLast = mock.Now().Add(-offset)
+// last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(9)*time.Millisecond, t)
+// assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t)
+//
+// // advancing clock should see even more ticks
+// mock.Add(time.Duration(1) * time.Hour)
+// desiredLast = mock.Now().Add(-offset)
+// last = assertAdvanceUntil(ticker, last, desiredLast, offset, time.Duration(8)*time.Millisecond, t)
+// assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t)
+//
+//}
+//
+//func getCase(lastSeconds, offsetSeconds int) (time.Time, time.Duration) {
+// last := time.Unix(int64(lastSeconds), 0)
+// offset := time.Duration(offsetSeconds) * time.Second
+// return last, offset
+//}
+//
+//func TestTickerNoAdvance(t *testing.T) {
+//
+// // it's 00:01:00 now. what are some cases where we don't want the ticker to advance?
+// mock := clock.NewMock()
+// mock.Add(time.Duration(60) * time.Second)
+//
+// type Case struct {
+// last int
+// offset int
+// }
+//
+// // note that some cases add up to now, others go into the future
+// cases := []Case{
+// {50, 10},
+// {50, 30},
+// {59, 1},
+// {59, 10},
+// {59, 30},
+// {60, 1},
+// {60, 10},
+// {60, 30},
+// {90, 1},
+// {90, 10},
+// {90, 30},
+// }
+// for _, c := range cases {
+// last, offset := getCase(c.last, c.offset)
+// ticker := NewTicker(last, offset, mock)
+// assertNoAdvance(ticker, last, time.Duration(500)*time.Millisecond, t)
+// }
+//}
diff --git a/public/app/core/utils/url.ts b/public/app/core/utils/url.ts
index 0b629768b92..b57d5721d57 100644
--- a/public/app/core/utils/url.ts
+++ b/public/app/core/utils/url.ts
@@ -12,7 +12,11 @@ export function toUrlParams(a) {
let add = function(k, v) {
v = typeof v === 'function' ? v() : v === null ? '' : v === undefined ? '' : v;
- s[s.length] = encodeURIComponent(k) + '=' + encodeURIComponent(v);
+ if (typeof v !== 'boolean') {
+ s[s.length] = encodeURIComponent(k) + '=' + encodeURIComponent(v);
+ } else {
+ s[s.length] = encodeURIComponent(k);
+ }
};
let buildParams = function(prefix, obj) {
diff --git a/public/app/features/dashboard/dashboard_model.ts b/public/app/features/dashboard/dashboard_model.ts
index 6c291c3b69a..4086edc100a 100644
--- a/public/app/features/dashboard/dashboard_model.ts
+++ b/public/app/features/dashboard/dashboard_model.ts
@@ -352,16 +352,10 @@ export class DashboardModel {
copy.scopedVars[variable.name] = option;
if (panel.repeatDirection === REPEAT_DIR_VERTICAL) {
- copy.gridPos.y = yPos;
- yPos += copy.gridPos.h;
-
- // Update gridPos for panels below
- let panelBelowIndex = panelIndex + index + 1;
- for (let i = panelBelowIndex; i < this.panels.length; i++) {
- if (this.panels[i].gridPos.y < yPos) {
- this.panels[i].gridPos.y += copy.gridPos.h;
- }
+ if (index > 0) {
+ yPos += copy.gridPos.h;
}
+ copy.gridPos.y = yPos;
} else {
// set width based on how many are selected
// assumed the repeated panels should take up full row width
@@ -378,6 +372,15 @@ export class DashboardModel {
}
}
}
+
+ // Update gridPos for panels below
+ let yOffset = yPos - panel.gridPos.y;
+ if (yOffset > 0) {
+ let panelBelowIndex = panelIndex + selectedOptions.length;
+ for (let i = panelBelowIndex; i < this.panels.length; i++) {
+ this.panels[i].gridPos.y += yOffset;
+ }
+ }
}
repeatRow(panel: PanelModel, panelIndex: number, variable) {
@@ -566,6 +569,7 @@ export class DashboardModel {
if (row.collapsed) {
row.collapsed = false;
+ let hasRepeat = false;
if (row.panels.length > 0) {
// Use first panel to figure out if it was moved or pushed
@@ -586,6 +590,10 @@ export class DashboardModel {
// update insert post and y max
insertPos += 1;
yMax = Math.max(yMax, panel.gridPos.y + panel.gridPos.h);
+
+ if (panel.repeat) {
+ hasRepeat = true;
+ }
}
const pushDownAmount = yMax - row.gridPos.y;
@@ -596,6 +604,10 @@ export class DashboardModel {
}
row.panels = [];
+
+ if (hasRepeat) {
+ this.processRepeats();
+ }
}
// sort panels
diff --git a/public/app/features/dashboard/specs/repeat.jest.ts b/public/app/features/dashboard/specs/repeat.jest.ts
index e05162dc69f..93555625b95 100644
--- a/public/app/features/dashboard/specs/repeat.jest.ts
+++ b/public/app/features/dashboard/specs/repeat.jest.ts
@@ -4,6 +4,57 @@ import { expect } from 'test/lib/common';
jest.mock('app/core/services/context_srv', () => ({}));
+describe('given dashboard with panel repeat', function() {
+ var dashboard;
+
+ beforeEach(function() {
+ let dashboardJSON = {
+ panels: [
+ { id: 1, type: 'row', gridPos: { x: 0, y: 0, h: 1, w: 24 } },
+ { id: 2, repeat: 'apps', repeatDirection: 'h', gridPos: { x: 0, y: 1, h: 2, w: 8 } },
+ ],
+ templating: {
+ list: [
+ {
+ name: 'apps',
+ current: {
+ text: 'se1, se2, se3',
+ value: ['se1', 'se2', 'se3'],
+ },
+ options: [
+ { text: 'se1', value: 'se1', selected: true },
+ { text: 'se2', value: 'se2', selected: true },
+ { text: 'se3', value: 'se3', selected: true },
+ { text: 'se4', value: 'se4', selected: false },
+ ],
+ },
+ ],
+ },
+ };
+ dashboard = new DashboardModel(dashboardJSON);
+ dashboard.processRepeats();
+ });
+
+ it('should repeat panels when row is expanding', function() {
+ expect(dashboard.panels.length).toBe(4);
+
+ // toggle row
+ dashboard.toggleRow(dashboard.panels[0]);
+ expect(dashboard.panels.length).toBe(1);
+
+ // change variable
+ dashboard.templating.list[0].options[2].selected = false;
+ dashboard.templating.list[0].current = {
+ text: 'se1, se2',
+ value: ['se1', 'se2'],
+ };
+
+ // toggle row back
+ dashboard.toggleRow(dashboard.panels[0]);
+ expect(dashboard.panels.length).toBe(3);
+ });
+});
+
describe('given dashboard with panel repeat in horizontal direction', function() {
var dashboard;
@@ -178,6 +229,88 @@ describe('given dashboard with panel repeat in vertical direction', function() {
});
});
+describe('given dashboard with row repeat and panel repeat in horizontal direction', () => {
+ let dashboard, dashboardJSON;
+
+ beforeEach(() => {
+ dashboardJSON = {
+ panels: [
+ { id: 1, type: 'row', repeat: 'region', gridPos: { x: 0, y: 0, h: 1, w: 24 } },
+ { id: 2, type: 'graph', repeat: 'app', gridPos: { x: 0, y: 1, h: 2, w: 6 } },
+ ],
+ templating: {
+ list: [
+ {
+ name: 'region',
+ current: {
+ text: 'reg1, reg2',
+ value: ['reg1', 'reg2'],
+ },
+ options: [{ text: 'reg1', value: 'reg1', selected: true }, { text: 'reg2', value: 'reg2', selected: true }],
+ },
+ {
+ name: 'app',
+ current: {
+ text: 'se1, se2, se3, se4, se5, se6',
+ value: ['se1', 'se2', 'se3', 'se4', 'se5', 'se6'],
+ },
+ options: [
+ { text: 'se1', value: 'se1', selected: true },
+ { text: 'se2', value: 'se2', selected: true },
+ { text: 'se3', value: 'se3', selected: true },
+ { text: 'se4', value: 'se4', selected: true },
+ { text: 'se5', value: 'se5', selected: true },
+ { text: 'se6', value: 'se6', selected: true },
+ ],
+ },
+ ],
+ },
+ };
+ dashboard = new DashboardModel(dashboardJSON);
+ dashboard.processRepeats(false);
+ });
+
+ it('should panels in self row', () => {
+ const panel_types = _.map(dashboard.panels, 'type');
+ expect(panel_types).toEqual([
+ 'row',
+ 'graph',
+ 'graph',
+ 'graph',
+ 'graph',
+ 'graph',
+ 'graph',
+ 'row',
+ 'graph',
+ 'graph',
+ 'graph',
+ 'graph',
+ 'graph',
+ 'graph',
+ ]);
+ });
+
+ it('should be placed in their places', function() {
+ expect(dashboard.panels[0].gridPos).toMatchObject({ x: 0, y: 0, h: 1, w: 24 }); // 1st row
+
+ expect(dashboard.panels[1].gridPos).toMatchObject({ x: 0, y: 1, h: 2, w: 6 });
+ expect(dashboard.panels[2].gridPos).toMatchObject({ x: 6, y: 1, h: 2, w: 6 });
+ expect(dashboard.panels[3].gridPos).toMatchObject({ x: 12, y: 1, h: 2, w: 6 });
+ expect(dashboard.panels[4].gridPos).toMatchObject({ x: 18, y: 1, h: 2, w: 6 });
+ expect(dashboard.panels[5].gridPos).toMatchObject({ x: 0, y: 3, h: 2, w: 6 }); // next row
+ expect(dashboard.panels[6].gridPos).toMatchObject({ x: 6, y: 3, h: 2, w: 6 });
+
+ expect(dashboard.panels[7].gridPos).toMatchObject({ x: 0, y: 5, h: 1, w: 24 });
+
+ expect(dashboard.panels[8].gridPos).toMatchObject({ x: 0, y: 6, h: 2, w: 6 }); // 2nd row
+ expect(dashboard.panels[9].gridPos).toMatchObject({ x: 6, y: 6, h: 2, w: 6 });
+ expect(dashboard.panels[10].gridPos).toMatchObject({ x: 12, y: 6, h: 2, w: 6 });
+ expect(dashboard.panels[11].gridPos).toMatchObject({ x: 18, y: 6, h: 2, w: 6 }); // next row
+ expect(dashboard.panels[12].gridPos).toMatchObject({ x: 0, y: 8, h: 2, w: 6 });
+ expect(dashboard.panels[13].gridPos).toMatchObject({ x: 6, y: 8, h: 2, w: 6 });
+ });
+});
+
describe('given dashboard with row repeat', function() {
let dashboard, dashboardJSON;
diff --git a/public/app/features/playlist/playlist_search.ts b/public/app/features/playlist/playlist_search.ts
index 3b80cfdf640..785099ff61c 100644
--- a/public/app/features/playlist/playlist_search.ts
+++ b/public/app/features/playlist/playlist_search.ts
@@ -12,6 +12,7 @@ export class PlaylistSearchCtrl {
$timeout(() => {
this.query.query = '';
+ this.query.type = 'dash-db';
this.searchDashboards();
}, 100);
}
diff --git a/public/app/plugins/datasource/cloudwatch/partials/query.parameter.html b/public/app/plugins/datasource/cloudwatch/partials/query.parameter.html
index fd14fb7d077..9da0e2d71c4 100644
--- a/public/app/plugins/datasource/cloudwatch/partials/query.parameter.html
+++ b/public/app/plugins/datasource/cloudwatch/partials/query.parameter.html
@@ -1,6 +1,6 @@