Commit 15024e96 by Torkel Ödegaard

ux: row collapse / expand starting to work

parent 68562a20
......@@ -215,7 +215,7 @@ export class DashboardModel {
this.events.emit('panel-added', panel);
}
private sortPanelsByGridPos() {
sortPanelsByGridPos() {
this.panels.sort(function(panelA, panelB) {
if (panelA.gridPos.y === panelB.gridPos.y) {
return panelA.gridPos.x - panelB.gridPos.x;
......@@ -415,15 +415,28 @@ export class DashboardModel {
// Use first panel to figure out if it was moved or pushed
let firstPanel = row.panels[0];
let yDiff = firstPanel.gridPos.y - (row.gridPos.y + row.gridPos.h);
// start inserting after row
let insertPos = rowIndex+1;
// y max will represent the bottom y pos after all panels have been added
// needed to know home much panels below should be pushed down
let yMax = row.gridPos.y;
for (let panel of row.panels) {
// make sure y is adjusted (in case row moved while collapsed)
panel.gridPos.y -= yDiff;
// insert after row
this.panels.splice(insertPos, 0, new PanelModel(panel));
// update insert post and y max
insertPos += 1;
yMax = Math.max(yMax, panel.gridPos.y + panel.gridPos.h);
}
const pushDownAmount = yMax - row.gridPos.y;
// push panels below down
for (let panelIndex = insertPos; panelIndex < this.panels.length; panelIndex++) {
this.panels[panelIndex].gridPos.y += pushDownAmount;
}
row.panels = [];
......
......@@ -112,6 +112,8 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
for (const newPos of newLayout) {
this.panelMap[newPos.i].updateGridPos(newPos);
}
this.dashboard.sortPanelsByGridPos();
}
triggerForceUpdate() {
......
......@@ -23,32 +23,33 @@
</ul>
<ul class="nav dashnav-action-icons">
<!-- <li ng&#45;show="::ctrl.dashboard.meta.canShare" class="dropdown"> -->
<!-- <a class="pointer" ng&#45;click="ctrl.hideTooltip($event)" bs&#45;tooltip="'Share dashboard'" data&#45;placement="bottom" data&#45;toggle="dropdown"><i class="fa fa&#45;share&#45;square&#45;o"></i></a> -->
<!-- <ul class="dropdown&#45;menu"> -->
<!-- <li> -->
<!-- <a class="pointer" ng&#45;click="ctrl.shareDashboard(0)"> -->
<!-- <i class="fa fa&#45;link"></i> Link to Dashboard -->
<!-- <div class="dropdown&#45;desc">Share an internal link to the current dashboard. Some configuration options available.</div> -->
<!-- </a> -->
<!-- </li> -->
<!-- <li> -->
<!-- <a class="pointer" ng&#45;click="ctrl.shareDashboard(1)"> -->
<!-- <i class="icon&#45;gf icon&#45;gf&#45;snapshot"></i>Snapshot -->
<!-- <div class="dropdown&#45;desc">Interactive, publically accessible dashboard. Sensitive data is stripped out.</div> -->
<!-- </a> -->
<!-- </li> -->
<!-- <li> -->
<!-- <a class="pointer" ng&#45;click="ctrl.shareDashboard(2)"> -->
<!-- <i class="fa fa&#45;cloud&#45;upload"></i>Export -->
<!-- <div class="dropdown&#45;desc">Export the dashboard to a JSON file for others and to share on Grafana.com</div> -->
<!-- </a> -->
<!-- </li> -->
<!-- </ul> -->
<!-- </li> -->
<!-- <li ng&#45;show="::ctrl.dashboard.meta.canSave"> -->
<!-- <a ng&#45;click="ctrl.saveDashboard()" bs&#45;tooltip="'Save dashboard <br> CTRL+S'" data&#45;placement="bottom"><i class="fa fa&#45;save"></i></a> -->
<!-- </li> -->
<li ng-show="::ctrl.dashboard.meta.canShare" class="dropdown">
<a class="pointer" ng-click="ctrl.hideTooltip($event)" bs-tooltip="'Share dashboard'" data-placement="bottom" data-toggle="dropdown"><i class="fa fa-share-square-o"></i></a>
<ul class="dropdown-menu">
<li>
<a class="pointer" ng-click="ctrl.shareDashboard(0)">
<i class="fa fa-link"></i> Link to Dashboard
<div class="dropdown-desc">Share an internal link to the current dashboard. Some configuration options available.</div>
</a>
</li>
<li>
<a class="pointer" ng-click="ctrl.shareDashboard(1)">
<i class="icon-gf icon-gf-snapshot"></i>Snapshot
<div class="dropdown-desc">Interactive, publically accessible dashboard. Sensitive data is stripped out.</div>
</a>
</li>
<li>
<a class="pointer" ng-click="ctrl.shareDashboard(2)">
<i class="fa fa-cloud-upload"></i>Export
<div class="dropdown-desc">Export the dashboard to a JSON file for others and to share on Grafana.com</div>
</a>
</li>
</ul>
</li>
<li ng-show="::ctrl.dashboard.meta.canSave">
<a ng-click="ctrl.saveDashboard()" bs-tooltip="'Save dashboard <br> CTRL+S'" data-placement="bottom"><i class="fa fa-save"></i></a>
</li>
<li ng-if="::ctrl.dashboard.snapshot.originalUrl">
<a ng-href="{{ctrl.dashboard.snapshot.originalUrl}}" bs-tooltip="'Open original dashboard'" data-placement="bottom"><i class="fa fa-link"></i></a>
......
import {Emitter} from 'app/core/core';
import {Emitter} from 'app/core/utils/emitter';
import _ from 'lodash';
export interface GridPos {
......
......@@ -2,6 +2,10 @@ import _ from 'lodash';
import {DashboardModel} from '../dashboard_model';
import {PanelModel} from '../panel_model';
jest.mock('app/core/services/context_srv', () => ({
}));
describe('DashboardModel', function() {
describe('when creating new dashboard model defaults only', function() {
......@@ -69,7 +73,7 @@ describe('DashboardModel', function() {
dashboard.addPanel(panel);
dashboard.duplicatePanel(dashboard.panels[0]);
expect(dashboard.panels[1].gridPos).to.eql({x: 6, y: 0, h: 2, w: 6});
expect(dashboard.panels[1].gridPos).toMatchObject({x: 6, y: 0, h: 2, w: 6});
});
it('duplicate panel should remove repeat data', function() {
......@@ -414,7 +418,7 @@ describe('DashboardModel', function() {
});
});
describe('given dashboard with panel repeat in horizontal direction', function(ctx) {
describe('given dashboard with panel repeat in horizontal direction', function() {
var dashboard;
beforeEach(function() {
......@@ -455,9 +459,9 @@ describe('DashboardModel', function() {
});
it('should place on first row and adjust width so all fit', function() {
expect(dashboard.panels[0].gridPos).to.eql({x: 0, y: 0, h: 2, w: 8});
expect(dashboard.panels[1].gridPos).to.eql({x: 8, y: 0, h: 2, w: 8});
expect(dashboard.panels[2].gridPos).to.eql({x: 16, y: 0, h: 2, w: 8});
expect(dashboard.panels[0].gridPos).toMatchObject({x: 0, y: 0, h: 2, w: 8});
expect(dashboard.panels[1].gridPos).toMatchObject({x: 8, y: 0, h: 2, w: 8});
expect(dashboard.panels[2].gridPos).toMatchObject({x: 16, y: 0, h: 2, w: 8});
});
describe('After a second iteration', function() {
......@@ -526,7 +530,7 @@ describe('DashboardModel', function() {
});
describe('given dashboard with panel repeat in vertical direction', function(ctx) {
describe('given dashboard with panel repeat in vertical direction', function() {
var dashboard;
beforeEach(function() {
......@@ -552,13 +556,13 @@ describe('DashboardModel', function() {
});
it('should place on items on top of each other and keep witdh', function() {
expect(dashboard.panels[0].gridPos).to.eql({x: 5, y: 0, h: 2, w: 8});
expect(dashboard.panels[1].gridPos).to.eql({x: 5, y: 2, h: 2, w: 8});
expect(dashboard.panels[2].gridPos).to.eql({x: 5, y: 4, h: 2, w: 8});
expect(dashboard.panels[0].gridPos).toMatchObject({x: 5, y: 0, h: 2, w: 8});
expect(dashboard.panels[1].gridPos).toMatchObject({x: 5, y: 2, h: 2, w: 8});
expect(dashboard.panels[2].gridPos).toMatchObject({x: 5, y: 4, h: 2, w: 8});
});
});
describe('When collapsing row', function(ctx) {
describe('When collapsing row', function() {
var dashboard;
beforeEach(function() {
......@@ -575,13 +579,13 @@ describe('DashboardModel', function() {
});
it('should remove panels and put them inside collapsed row', function() {
expect(dashboard.panels.length).to.eql(3);
expect(dashboard.panels[1].panels.length).to.eql(2);
expect(dashboard.panels.length).toBe(3);
expect(dashboard.panels[1].panels.length).toBe(2);
});
});
describe('When expanding row', function(ctx) {
describe('When expanding row', function() {
var dashboard;
beforeEach(function() {
......@@ -598,24 +602,27 @@ describe('DashboardModel', function() {
{id: 4, type: 'graph', gridPos: {x: 12, y: 2, w: 12, h: 2}},
]
},
{id: 5, type: 'graph', gridPos: {x: 0, y: 6, w: 1, h: 1}},
],
});
dashboard.toggleRow(dashboard.panels[1]);
});
it('should add panels back', function() {
expect(dashboard.panels.length).to.eql(4);
expect(dashboard.panels.length).toBe(5);
});
it('should add them below row in array', function() {
expect(dashboard.panels[2].id).to.eql(3);
expect(dashboard.panels[3].id).to.eql(4);
expect(dashboard.panels[2].id).toBe(3);
expect(dashboard.panels[3].id).toBe(4);
});
it('should position them below row', function() {
expect(dashboard.panels[2].gridPos).to.eql({x: 0, y: 8, w: 12, h: 2});
expect(dashboard.panels[2].gridPos).toMatchObject({x: 0, y: 8, w: 12, h: 2});
});
it('should move panels below down', function() {
expect(dashboard.panels[4].gridPos).toMatchObject({x: 0, y: 10, w: 1, h: 1});
});
});
});
......@@ -5,11 +5,6 @@ declare module 'eventemitter3' {
export default config;
}
declare module 'gridstack' {
var gridstack: any;
export default gridstack;
}
declare module 'gemini-scrollbar' {
var d3: any;
export default d3;
......
......@@ -44,16 +44,16 @@
color: $text-muted;
visibility: hidden;
opacity: 0;
flex-grow: 1;
a {
color: $text-color-weak;
padding-left: $spacer;
&:hover {
color: $link-hover-color;
}
}
flex-grow: 1;
}
.dashboard-row__panel_count {
......
......@@ -111,7 +111,6 @@
padding: 3px 10px;
white-space: nowrap;
background-color: $tight-form-bg;
border: $input-btn-border-width solid $input-label-border-color;;
margin-bottom: 4px;
@include left-brand-border();
......
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