From a8814979081a3a7fa94d349116f96e0d4ffe59c0 Mon Sep 17 00:00:00 2001 From: Pierre GIRAUD Date: Mon, 20 Aug 2018 15:33:49 +0200 Subject: [PATCH 1/3] Max number of repeated panels per row Instead of min width --- docs/sources/reference/dashboard.md | 2 +- docs/sources/reference/templating.md | 6 ++++-- pkg/models/dashboards.go | 2 +- .../features/dashboard/dashboard_migration.ts | 11 +++++++++- .../app/features/dashboard/dashboard_model.ts | 4 ++-- public/app/features/dashboard/panel_model.ts | 2 +- .../specs/dashboard_migration.test.ts | 20 ++++++++++--------- .../features/panel/partials/general_tab.html | 4 ++-- public/dashboards/home.json | 2 +- 9 files changed, 33 insertions(+), 20 deletions(-) diff --git a/docs/sources/reference/dashboard.md b/docs/sources/reference/dashboard.md index 6be12600da5..3d96923bc72 100644 --- a/docs/sources/reference/dashboard.md +++ b/docs/sources/reference/dashboard.md @@ -51,7 +51,7 @@ When a user creates a new dashboard, a new dashboard JSON object is initialized "list": [] }, "refresh": "5s", - "schemaVersion": 16, + "schemaVersion": 17, "version": 0, "links": [] } diff --git a/docs/sources/reference/templating.md b/docs/sources/reference/templating.md index f20cc0ccfc9..71ce6bdd2ae 100644 --- a/docs/sources/reference/templating.md +++ b/docs/sources/reference/templating.md @@ -292,9 +292,11 @@ The `direction` controls how the panels will be arranged. By choosing `horizontal` the panels will be arranged side-by-side. Grafana will automatically adjust the width of each repeated panel so that the whole row is filled. Currently, you cannot mix other panels on a row with a repeated -panel. Each panel will never be smaller that the provided `Min width` if you have many selected values. +panel. -By choosing `vertical` the panels will be arranged from top to bottom in a column. The `Min width` doesn't have any effect in this case. The width of the repeated panels will be the same as of the first panel (the original template) being repeated. +Set `Max per row` to tell grafana how many panels per row you want at most. It defaults to *4* if you don't set anything. + +By choosing `vertical` the panels will be arranged from top to bottom in a column. The width of the repeated panels will be the same as of the first panel (the original template) being repeated. Only make changes to the first panel (the original template). To have the changes take effect on all panels you need to trigger a dynamic dashboard re-build. You can do this by either changing the variable value (that is the basis for the repeat) or reload the dashboard. diff --git a/pkg/models/dashboards.go b/pkg/models/dashboards.go index 3a8010e797b..0f3f56175fe 100644 --- a/pkg/models/dashboards.go +++ b/pkg/models/dashboards.go @@ -112,7 +112,7 @@ func NewDashboard(title string) *Dashboard { func NewDashboardFolder(title string) *Dashboard { folder := NewDashboard(title) folder.IsFolder = true - folder.Data.Set("schemaVersion", 16) + folder.Data.Set("schemaVersion", 17) folder.Data.Set("version", 0) folder.IsFolder = true return folder diff --git a/public/app/features/dashboard/dashboard_migration.ts b/public/app/features/dashboard/dashboard_migration.ts index abd12ab4b13..4196456907f 100644 --- a/public/app/features/dashboard/dashboard_migration.ts +++ b/public/app/features/dashboard/dashboard_migration.ts @@ -21,7 +21,7 @@ export class DashboardMigrator { let i, j, k, n; const oldVersion = this.dashboard.schemaVersion; const panelUpgrades = []; - this.dashboard.schemaVersion = 16; + this.dashboard.schemaVersion = 17; if (oldVersion === this.dashboard.schemaVersion) { return; @@ -368,6 +368,15 @@ export class DashboardMigrator { this.upgradeToGridLayout(old); } + if (oldVersion < 17) { + panelUpgrades.push(panel => { + if (panel.minSpan) { + panel.maxPerRow = GRID_COLUMN_COUNT / panel.minSpan; + } + delete panel.minSpan; + }); + } + if (panelUpgrades.length === 0) { return; } diff --git a/public/app/features/dashboard/dashboard_model.ts b/public/app/features/dashboard/dashboard_model.ts index 6f98bc5a17a..33529abdd15 100644 --- a/public/app/features/dashboard/dashboard_model.ts +++ b/public/app/features/dashboard/dashboard_model.ts @@ -442,7 +442,7 @@ export class DashboardModel { } const selectedOptions = this.getSelectedVariableOptions(variable); - const minWidth = panel.minSpan || 6; + const maxPerRow = panel.maxPerRow || 4; let xPos = 0; let yPos = panel.gridPos.y; @@ -462,7 +462,7 @@ export class DashboardModel { } else { // set width based on how many are selected // assumed the repeated panels should take up full row width - copy.gridPos.w = Math.max(GRID_COLUMN_COUNT / selectedOptions.length, minWidth); + copy.gridPos.w = Math.max(GRID_COLUMN_COUNT / selectedOptions.length, GRID_COLUMN_COUNT / maxPerRow); copy.gridPos.x = xPos; copy.gridPos.y = yPos; diff --git a/public/app/features/dashboard/panel_model.ts b/public/app/features/dashboard/panel_model.ts index 2d5a70b47dd..2fec8e379dd 100644 --- a/public/app/features/dashboard/panel_model.ts +++ b/public/app/features/dashboard/panel_model.ts @@ -77,7 +77,7 @@ export class PanelModel { repeatPanelId?: number; repeatDirection?: string; repeatedByRow?: boolean; - minSpan?: number; + maxPerRow?: number; collapsed?: boolean; panels?: any; soloMode?: boolean; diff --git a/public/app/features/dashboard/specs/dashboard_migration.test.ts b/public/app/features/dashboard/specs/dashboard_migration.test.ts index 5f693c9f6d9..e15bd65d5a5 100644 --- a/public/app/features/dashboard/specs/dashboard_migration.test.ts +++ b/public/app/features/dashboard/specs/dashboard_migration.test.ts @@ -127,7 +127,7 @@ describe('DashboardModel', () => { }); it('dashboard schema version should be set to latest', () => { - expect(model.schemaVersion).toBe(16); + expect(model.schemaVersion).toBe(17); }); it('graph thresholds should be migrated', () => { @@ -364,14 +364,6 @@ describe('DashboardModel', () => { expect(dashboard.panels.length).toBe(2); }); - it('minSpan should be twice', () => { - model.rows = [createRow({ height: 8 }, [[6]])]; - model.rows[0].panels[0] = { minSpan: 12 }; - - const dashboard = new DashboardModel(model); - expect(dashboard.panels[0].minSpan).toBe(24); - }); - it('should assign id', () => { model.rows = [createRow({ collapse: true, height: 8 }, [[6], [6]])]; model.rows[0].panels[0] = {}; @@ -380,6 +372,16 @@ describe('DashboardModel', () => { expect(dashboard.panels[0].id).toBe(1); }); }); + + describe('when migrating from minSpan to maxPerRow', () => { + it('maxPerRow should be correct', () => { + const model = { + panels: [{ minSpan: 8 }], + }; + const dashboard = new DashboardModel(model); + expect(dashboard.panels[0].maxPerRow).toBe(3); + }); + }); }); function createRow(options, panelDescriptions: any[]) { diff --git a/public/app/features/panel/partials/general_tab.html b/public/app/features/panel/partials/general_tab.html index d6c2d4804a0..76c38f73912 100644 --- a/public/app/features/panel/partials/general_tab.html +++ b/public/app/features/panel/partials/general_tab.html @@ -32,8 +32,8 @@
- Min width -
diff --git a/public/dashboards/home.json b/public/dashboards/home.json index 55cf7242aa6..f2c441053bb 100644 --- a/public/dashboards/home.json +++ b/public/dashboards/home.json @@ -65,7 +65,7 @@ } ], "rows": [], - "schemaVersion": 16, + "schemaVersion": 17, "style": "dark", "tags": [], "templating": { From 97b087f5a561019392bb21053a64e07c91bbbba2 Mon Sep 17 00:00:00 2001 From: Pierre GIRAUD Date: Tue, 21 Aug 2018 09:22:41 +0200 Subject: [PATCH 2/3] Use factors for max repeated panels per row --- public/app/core/specs/factors.test.ts | 8 ++++++++ public/app/core/utils/factors.ts | 5 +++++ public/app/features/dashboard/dashboard_migration.ts | 12 +++++++++++- public/app/features/panel/panel_ctrl.ts | 5 ++++- 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 public/app/core/specs/factors.test.ts create mode 100644 public/app/core/utils/factors.ts diff --git a/public/app/core/specs/factors.test.ts b/public/app/core/specs/factors.test.ts new file mode 100644 index 00000000000..aed59b5be8b --- /dev/null +++ b/public/app/core/specs/factors.test.ts @@ -0,0 +1,8 @@ +import getFactors from 'app/core/utils/factors'; + +describe('factors', () => { + it('should return factors for 12', () => { + const factors = getFactors(12); + expect(factors).toEqual([1, 2, 3, 4, 6, 12]); + }); +}); diff --git a/public/app/core/utils/factors.ts b/public/app/core/utils/factors.ts new file mode 100644 index 00000000000..e9ce327a631 --- /dev/null +++ b/public/app/core/utils/factors.ts @@ -0,0 +1,5 @@ +// Returns the factors of a number +// Example getFactors(12) -> [1, 2, 3, 4, 6, 12] +export default function getFactors(num: number): number[] { + return Array.from(new Array(num + 1), (_, i) => i).filter(i => num % i === 0); +} diff --git a/public/app/features/dashboard/dashboard_migration.ts b/public/app/features/dashboard/dashboard_migration.ts index 4196456907f..2dbeb6c6e80 100644 --- a/public/app/features/dashboard/dashboard_migration.ts +++ b/public/app/features/dashboard/dashboard_migration.ts @@ -9,6 +9,7 @@ import { } from 'app/core/constants'; import { PanelModel } from './panel_model'; import { DashboardModel } from './dashboard_model'; +import getFactors from 'app/core/utils/factors'; export class DashboardMigrator { dashboard: DashboardModel; @@ -371,7 +372,16 @@ export class DashboardMigrator { if (oldVersion < 17) { panelUpgrades.push(panel => { if (panel.minSpan) { - panel.maxPerRow = GRID_COLUMN_COUNT / panel.minSpan; + const max = GRID_COLUMN_COUNT / panel.minSpan; + const factors = getFactors(GRID_COLUMN_COUNT); + // find the best match compared to factors + // (ie. [1,2,3,4,6,12,24] for 24 columns) + panel.maxPerRow = + factors[ + _.findIndex(factors, o => { + return o > max; + }) - 1 + ]; } delete panel.minSpan; }); diff --git a/public/app/features/panel/panel_ctrl.ts b/public/app/features/panel/panel_ctrl.ts index 432d22fecdf..f68423315d7 100644 --- a/public/app/features/panel/panel_ctrl.ts +++ b/public/app/features/panel/panel_ctrl.ts @@ -5,6 +5,7 @@ import Remarkable from 'remarkable'; import config from 'app/core/config'; import { profiler } from 'app/core/core'; import { Emitter } from 'app/core/core'; +import getFactors from 'app/core/utils/factors'; import { duplicatePanel, copyPanel as copyPanelUtil, @@ -12,7 +13,7 @@ import { sharePanel as sharePanelUtil, } from 'app/features/dashboard/utils/panel'; -import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, PANEL_HEADER_HEIGHT, PANEL_BORDER } from 'app/core/constants'; +import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT, PANEL_HEADER_HEIGHT, PANEL_BORDER } from 'app/core/constants'; export class PanelCtrl { panel: any; @@ -32,6 +33,7 @@ export class PanelCtrl { events: Emitter; timing: any; loading: boolean; + maxPanelsPerRowOptions: number[]; constructor($scope, $injector) { this.$injector = $injector; @@ -92,6 +94,7 @@ export class PanelCtrl { if (!this.editModeInitiated) { this.editModeInitiated = true; this.events.emit('init-edit-mode', null); + this.maxPanelsPerRowOptions = getFactors(GRID_COLUMN_COUNT); } } From f374da032e5cc9a12646c596298a1d8d38200206 Mon Sep 17 00:00:00 2001 From: Pierre GIRAUD Date: Wed, 9 Jan 2019 11:34:13 +0100 Subject: [PATCH 3/3] Hint for user on when the repeat is applied --- public/app/features/panel/partials/general_tab.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/public/app/features/panel/partials/general_tab.html b/public/app/features/panel/partials/general_tab.html index 76c38f73912..8881d2c28a4 100644 --- a/public/app/features/panel/partials/general_tab.html +++ b/public/app/features/panel/partials/general_tab.html @@ -37,7 +37,12 @@ +
+
+ Note: You may need to change the variable selection to see this in action. +
+