mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
ux: row collapse / expand starting to work
This commit is contained in:
@@ -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-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-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>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
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
public/app/headers/common.d.ts
vendored
5
public/app/headers/common.d.ts
vendored
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user