mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
DashboardModel: Tidy up some of the older code (#48355)
This commit is contained in:
parent
c41397a6e7
commit
713e624790
@ -1449,7 +1449,7 @@ describe('DashboardModel', () => {
|
||||
});
|
||||
|
||||
it('should ignore fieldConfig.defaults', () => {
|
||||
expect(model.panels[0].panels[0].fieldConfig.defaults).toEqual(undefined);
|
||||
expect(model.panels[0].panels?.[0].fieldConfig.defaults).toEqual(undefined);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1749,8 +1749,8 @@ describe('DashboardModel', () => {
|
||||
},
|
||||
],
|
||||
});
|
||||
panel1Targets = nestedModel.panels[0].panels[0].targets;
|
||||
panel2Targets = nestedModel.panels[0].panels[1].targets;
|
||||
panel1Targets = nestedModel.panels[0].panels?.[0].targets;
|
||||
panel2Targets = nestedModel.panels[0].panels?.[1].targets;
|
||||
});
|
||||
|
||||
it('multiple stats query should have been split into one query per stat', () => {
|
||||
@ -1851,7 +1851,7 @@ describe('DashboardModel', () => {
|
||||
});
|
||||
|
||||
it('should update datasources in panels collapsed rows', () => {
|
||||
expect(model.panels[3].panels[0].datasource).toEqual({ type: 'prometheus', uid: 'prom-uid' });
|
||||
expect(model.panels[3].panels?.[0].datasource).toEqual({ type: 'prometheus', uid: 'prom-uid' });
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -784,9 +784,10 @@ export class DashboardMigrator {
|
||||
for (j = 0; j < this.dashboard.panels.length; j++) {
|
||||
for (k = 0; k < panelUpgrades.length; k++) {
|
||||
this.dashboard.panels[j] = panelUpgrades[k].call(this, this.dashboard.panels[j]);
|
||||
if (this.dashboard.panels[j].panels) {
|
||||
for (n = 0; n < this.dashboard.panels[j].panels.length; n++) {
|
||||
this.dashboard.panels[j].panels[n] = panelUpgrades[k].call(this, this.dashboard.panels[j].panels[n]);
|
||||
const rowPanels = this.dashboard.panels[j].panels;
|
||||
if (rowPanels) {
|
||||
for (n = 0; n < rowPanels.length; n++) {
|
||||
rowPanels[n] = panelUpgrades[k].call(this, rowPanels[n]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -895,7 +896,7 @@ export class DashboardMigrator {
|
||||
delete panel.span;
|
||||
|
||||
if (rowPanelModel && rowPanel.collapsed) {
|
||||
rowPanelModel.panels.push(panel);
|
||||
rowPanelModel.panels?.push(panel);
|
||||
} else {
|
||||
this.dashboard.panels.push(new PanelModel(panel));
|
||||
}
|
||||
|
@ -370,7 +370,7 @@ describe('DashboardModel', () => {
|
||||
|
||||
it('should remove panels and put them inside collapsed row', () => {
|
||||
expect(dashboard.panels.length).toBe(3);
|
||||
expect(dashboard.panels[1].panels.length).toBe(2);
|
||||
expect(dashboard.panels[1].panels?.length).toBe(2);
|
||||
});
|
||||
|
||||
describe('and when removing row and its panels', () => {
|
||||
|
@ -1,17 +1,4 @@
|
||||
import {
|
||||
cloneDeep,
|
||||
defaults as _defaults,
|
||||
each,
|
||||
filter,
|
||||
find,
|
||||
findIndex,
|
||||
indexOf,
|
||||
isEqual,
|
||||
map,
|
||||
maxBy,
|
||||
pull,
|
||||
some,
|
||||
} from 'lodash';
|
||||
import { cloneDeep, defaults as _defaults, filter, indexOf, isEqual, map, maxBy, pull } from 'lodash';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
import {
|
||||
@ -194,14 +181,7 @@ export class DashboardModel implements TimeModel {
|
||||
}
|
||||
|
||||
addBuiltInAnnotationQuery() {
|
||||
let found = false;
|
||||
for (const item of this.annotations.list) {
|
||||
if (item.builtIn === 1) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const found = this.annotations.list.some((item) => item.builtIn === 1);
|
||||
if (found) {
|
||||
return;
|
||||
}
|
||||
@ -267,9 +247,7 @@ export class DashboardModel implements TimeModel {
|
||||
|
||||
// sort by keys
|
||||
copy = sortedDeepCloneWithoutNulls(copy);
|
||||
copy.getVariables = () => {
|
||||
return copy.templating.list;
|
||||
};
|
||||
copy.getVariables = () => copy.templating.list;
|
||||
|
||||
return copy;
|
||||
}
|
||||
@ -296,24 +274,11 @@ export class DashboardModel implements TimeModel {
|
||||
|
||||
private getPanelSaveModels() {
|
||||
return this.panels
|
||||
.filter((panel: PanelModel) => {
|
||||
if (this.isSnapshotTruthy()) {
|
||||
return true;
|
||||
}
|
||||
if (panel.type === 'add-panel') {
|
||||
return false;
|
||||
}
|
||||
// skip repeated panels in the saved model
|
||||
if (panel.repeatPanelId) {
|
||||
return false;
|
||||
}
|
||||
// skip repeated rows in the saved model
|
||||
if (panel.repeatedByRow) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map((panel: PanelModel) => {
|
||||
.filter(
|
||||
(panel) =>
|
||||
this.isSnapshotTruthy() || !(panel.type === 'add-panel' || panel.repeatPanelId || panel.repeatedByRow)
|
||||
)
|
||||
.map((panel) => {
|
||||
// If we save while editing we should include the panel in edit mode instead of the
|
||||
// unmodified source panel
|
||||
if (this.panelInEdit && this.panelInEdit.id === panel.id) {
|
||||
@ -358,18 +323,19 @@ export class DashboardModel implements TimeModel {
|
||||
};
|
||||
|
||||
if (!defaults.saveVariables) {
|
||||
for (let i = 0; i < copy.templating.list.length; i++) {
|
||||
const current = copy.templating.list[i];
|
||||
const original: any = find(originalVariables, { name: current.name, type: current.type });
|
||||
for (const current of copy.templating.list) {
|
||||
const original = originalVariables.find(
|
||||
({ name, type }: any) => name === current.name && type === current.type
|
||||
);
|
||||
|
||||
if (!original) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current.type === 'adhoc') {
|
||||
copy.templating.list[i].filters = original.filters;
|
||||
current.filters = original.filters;
|
||||
} else {
|
||||
copy.templating.list[i].current = original.current;
|
||||
current.current = original.current;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -384,18 +350,14 @@ export class DashboardModel implements TimeModel {
|
||||
this.events.publish(new RefreshEvent());
|
||||
this.lastRefresh = Date.now();
|
||||
|
||||
if (this.panelInEdit) {
|
||||
if (event.refreshAll || event.panelIds.includes(this.panelInEdit.id)) {
|
||||
this.panelInEdit.refresh();
|
||||
return;
|
||||
}
|
||||
if (this.panelInEdit && (event.refreshAll || event.panelIds.includes(this.panelInEdit.id))) {
|
||||
this.panelInEdit.refresh();
|
||||
return;
|
||||
}
|
||||
|
||||
for (const panel of this.panels) {
|
||||
if (!this.otherPanelInFullscreen(panel)) {
|
||||
if (event.refreshAll || event.panelIds.includes(panel.id)) {
|
||||
panel.refresh();
|
||||
}
|
||||
if (!this.otherPanelInFullscreen(panel) && (event.refreshAll || event.panelIds.includes(panel.id))) {
|
||||
panel.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -453,51 +415,40 @@ export class DashboardModel implements TimeModel {
|
||||
}
|
||||
|
||||
private ensurePanelsHaveIds() {
|
||||
for (const panel of this.panels) {
|
||||
if (!panel.id) {
|
||||
panel.id = this.getNextPanelId();
|
||||
}
|
||||
|
||||
if (panel.panels) {
|
||||
for (const rowPanel of panel.panels) {
|
||||
if (!rowPanel.id) {
|
||||
rowPanel.id = this.getNextPanelId();
|
||||
}
|
||||
}
|
||||
}
|
||||
let nextPanelId = this.getNextPanelId();
|
||||
for (const panel of this.panelIterator()) {
|
||||
panel.id ??= nextPanelId++;
|
||||
}
|
||||
}
|
||||
|
||||
private ensureListExist(data: any) {
|
||||
if (!data) {
|
||||
data = {};
|
||||
}
|
||||
if (!data.list) {
|
||||
data.list = [];
|
||||
}
|
||||
private ensureListExist(data: any = {}) {
|
||||
data.list ??= [];
|
||||
return data;
|
||||
}
|
||||
|
||||
getNextPanelId() {
|
||||
let max = 0;
|
||||
|
||||
for (const panel of this.panels) {
|
||||
for (const panel of this.panelIterator()) {
|
||||
if (panel.id > max) {
|
||||
max = panel.id;
|
||||
}
|
||||
|
||||
if (panel.collapsed) {
|
||||
for (const rowPanel of panel.panels) {
|
||||
if (rowPanel.id > max) {
|
||||
max = rowPanel.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return max + 1;
|
||||
}
|
||||
|
||||
*panelIterator() {
|
||||
for (const panel of this.panels) {
|
||||
yield panel;
|
||||
|
||||
const rowPanels = panel.panels ?? [];
|
||||
for (const rowPanel of rowPanels) {
|
||||
yield rowPanel as PanelModel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
forEachPanel(callback: (panel: PanelModel, index: number) => void) {
|
||||
for (let i = 0; i < this.panels.length; i++) {
|
||||
callback(this.panels[i], i);
|
||||
@ -509,13 +460,7 @@ export class DashboardModel implements TimeModel {
|
||||
return this.panelInEdit;
|
||||
}
|
||||
|
||||
for (const panel of this.panels) {
|
||||
if (panel.id === id) {
|
||||
return panel;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return this.panels.find((p) => p.id === id) ?? null;
|
||||
}
|
||||
|
||||
canEditPanel(panel?: PanelModel | null): boolean | undefined | null {
|
||||
@ -553,13 +498,12 @@ export class DashboardModel implements TimeModel {
|
||||
}
|
||||
|
||||
hasUnsavedChanges() {
|
||||
for (const panel of this.panels) {
|
||||
if (panel.hasChanged) {
|
||||
console.log('Panel has changed', panel);
|
||||
return true;
|
||||
}
|
||||
const changedPanel = this.panels.find((p) => p.hasChanged);
|
||||
if (changedPanel) {
|
||||
console.log('Panel has changed', changedPanel);
|
||||
}
|
||||
return false;
|
||||
|
||||
return Boolean(changedPanel);
|
||||
}
|
||||
|
||||
cleanUpRepeats() {
|
||||
@ -568,17 +512,12 @@ export class DashboardModel implements TimeModel {
|
||||
}
|
||||
|
||||
this.iteration = (this.iteration || new Date().getTime()) + 1;
|
||||
const panelsToRemove = [];
|
||||
|
||||
// cleanup scopedVars
|
||||
deleteScopeVars(this.panels);
|
||||
|
||||
for (let i = 0; i < this.panels.length; i++) {
|
||||
const panel = this.panels[i];
|
||||
if ((!panel.repeat || panel.repeatedByRow) && panel.repeatPanelId && panel.repeatIteration !== this.iteration) {
|
||||
panelsToRemove.push(panel);
|
||||
}
|
||||
}
|
||||
const panelsToRemove = this.panels.filter(
|
||||
(p) => (!p.repeat || p.repeatedByRow) && p.repeatPanelId && p.repeatIteration !== this.iteration
|
||||
);
|
||||
|
||||
// remove panels
|
||||
pull(this.panels, ...panelsToRemove);
|
||||
@ -607,13 +546,8 @@ export class DashboardModel implements TimeModel {
|
||||
}
|
||||
|
||||
cleanUpRowRepeats(rowPanels: PanelModel[]) {
|
||||
const panelsToRemove = [];
|
||||
for (let i = 0; i < rowPanels.length; i++) {
|
||||
const panel = rowPanels[i];
|
||||
if (!panel.repeat && panel.repeatPanelId) {
|
||||
panelsToRemove.push(panel);
|
||||
}
|
||||
}
|
||||
const panelsToRemove = rowPanels.filter((p) => !p.repeat && p.repeatPanelId);
|
||||
|
||||
pull(rowPanels, ...panelsToRemove);
|
||||
pull(this.panels, ...panelsToRemove);
|
||||
}
|
||||
@ -623,18 +557,17 @@ export class DashboardModel implements TimeModel {
|
||||
return;
|
||||
}
|
||||
|
||||
let rowPanels = row.panels;
|
||||
let rowPanels = row.panels ?? [];
|
||||
if (!row.collapsed) {
|
||||
const rowPanelIndex = findIndex(this.panels, (p: PanelModel) => p.id === row.id);
|
||||
const rowPanelIndex = this.panels.findIndex((p) => p.id === row.id);
|
||||
rowPanels = this.getRowPanels(rowPanelIndex);
|
||||
}
|
||||
|
||||
this.cleanUpRowRepeats(rowPanels);
|
||||
|
||||
for (let i = 0; i < rowPanels.length; i++) {
|
||||
const panel = rowPanels[i];
|
||||
for (const panel of rowPanels) {
|
||||
if (panel.repeat) {
|
||||
const panelIndex = findIndex(this.panels, (p: PanelModel) => p.id === panel.id);
|
||||
const panelIndex = this.panels.findIndex((p) => p.id === panel.id);
|
||||
this.repeatPanel(panel, panelIndex);
|
||||
}
|
||||
}
|
||||
@ -679,13 +612,13 @@ export class DashboardModel implements TimeModel {
|
||||
// for row clones we need to figure out panels under row to clone and where to insert clone
|
||||
let rowPanels: PanelModel[], insertPos: number;
|
||||
if (sourceRowPanel.collapsed) {
|
||||
rowPanels = cloneDeep(sourceRowPanel.panels);
|
||||
rowPanels = cloneDeep(sourceRowPanel.panels) ?? [];
|
||||
clone.panels = rowPanels;
|
||||
// insert copied row after preceding row
|
||||
insertPos = sourcePanelIndex + valueIndex;
|
||||
} else {
|
||||
rowPanels = this.getRowPanels(sourcePanelIndex);
|
||||
clone.panels = map(rowPanels, (panel: PanelModel) => panel.getSaveModel());
|
||||
clone.panels = rowPanels.map((panel) => panel.getSaveModel());
|
||||
// insert copied row after preceding row's panels
|
||||
insertPos = sourcePanelIndex + (rowPanels.length + 1) * valueIndex;
|
||||
}
|
||||
@ -696,7 +629,7 @@ export class DashboardModel implements TimeModel {
|
||||
}
|
||||
|
||||
repeatPanel(panel: PanelModel, panelIndex: number) {
|
||||
const variable: any = this.getPanelRepeatVariable(panel);
|
||||
const variable = this.getPanelRepeatVariable(panel);
|
||||
if (!variable) {
|
||||
return;
|
||||
}
|
||||
@ -717,7 +650,7 @@ export class DashboardModel implements TimeModel {
|
||||
let copy;
|
||||
|
||||
copy = this.getPanelRepeatClone(panel, index, panelIndex);
|
||||
copy.scopedVars = copy.scopedVars || {};
|
||||
copy.scopedVars ??= {};
|
||||
copy.scopedVars[variable.name] = option;
|
||||
|
||||
if (panel.repeatDirection === REPEAT_DIR_VERTICAL) {
|
||||
@ -746,12 +679,12 @@ export class DashboardModel implements TimeModel {
|
||||
const yOffset = yPos - panel.gridPos.y;
|
||||
if (yOffset > 0) {
|
||||
const panelBelowIndex = panelIndex + selectedOptions.length;
|
||||
for (let i = panelBelowIndex; i < this.panels.length; i++) {
|
||||
if (isOnTheSameGridRow(panel, this.panels[i])) {
|
||||
for (const curPanel of this.panels.slice(panelBelowIndex)) {
|
||||
if (isOnTheSameGridRow(panel, curPanel)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.panels[i].gridPos.y += yOffset;
|
||||
curPanel.gridPos.y += yOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -761,7 +694,7 @@ export class DashboardModel implements TimeModel {
|
||||
let yPos = panel.gridPos.y;
|
||||
|
||||
function setScopedVars(panel: PanelModel, variableOption: any) {
|
||||
panel.scopedVars = panel.scopedVars || {};
|
||||
panel.scopedVars ??= {};
|
||||
panel.scopedVars[variable.name] = variableOption;
|
||||
}
|
||||
|
||||
@ -776,19 +709,19 @@ export class DashboardModel implements TimeModel {
|
||||
|
||||
if (panel.collapsed) {
|
||||
// For collapsed row just copy its panels and set scoped vars and proper IDs
|
||||
each(rowPanels, (rowPanel: PanelModel, i: number) => {
|
||||
for (const rowPanel of rowPanels) {
|
||||
setScopedVars(rowPanel, option);
|
||||
if (optionIndex > 0) {
|
||||
this.updateRepeatedPanelIds(rowPanel, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
rowCopy.gridPos.y += optionIndex;
|
||||
yPos += optionIndex;
|
||||
panelBelowIndex = panelIndex + optionIndex + 1;
|
||||
} else {
|
||||
// insert after 'row' panel
|
||||
const insertPos = panelIndex + (rowPanels.length + 1) * optionIndex + 1;
|
||||
each(rowPanels, (rowPanel: PanelModel, i: number) => {
|
||||
rowPanels.forEach((rowPanel: PanelModel, i: number) => {
|
||||
setScopedVars(rowPanel, option);
|
||||
if (optionIndex > 0) {
|
||||
const cloneRowPanel = new PanelModel(rowPanel);
|
||||
@ -806,8 +739,8 @@ export class DashboardModel implements TimeModel {
|
||||
|
||||
// Update gridPos for panels below if we inserted more than 1 repeated row panel
|
||||
if (selectedOptions.length > 1) {
|
||||
for (let i = panelBelowIndex; i < this.panels.length; i++) {
|
||||
this.panels[i].gridPos.y += yPos;
|
||||
for (const panel of this.panels.slice(panelBelowIndex)) {
|
||||
panel.gridPos.y += yPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -839,11 +772,10 @@ export class DashboardModel implements TimeModel {
|
||||
if (!rowPanel.panels || rowPanel.panels.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const rowYPos = rowPanel.gridPos.y;
|
||||
const positions = map(rowPanel.panels, 'gridPos');
|
||||
const maxPos = maxBy(positions, (pos: GridPos) => {
|
||||
return pos.y + pos.h;
|
||||
});
|
||||
const maxPos = maxBy(positions, (pos: GridPos) => pos.y + pos.h);
|
||||
return maxPos!.y + maxPos!.h - rowYPos;
|
||||
}
|
||||
|
||||
@ -853,9 +785,9 @@ export class DashboardModel implements TimeModel {
|
||||
}
|
||||
|
||||
removeRow(row: PanelModel, removePanels: boolean) {
|
||||
const needToogle = (!removePanels && row.collapsed) || (removePanels && !row.collapsed);
|
||||
const needToggle = (!removePanels && row.collapsed) || (removePanels && !row.collapsed);
|
||||
|
||||
if (needToogle) {
|
||||
if (needToggle) {
|
||||
this.toggleRow(row);
|
||||
}
|
||||
|
||||
@ -863,60 +795,30 @@ export class DashboardModel implements TimeModel {
|
||||
}
|
||||
|
||||
expandRows() {
|
||||
for (let i = 0; i < this.panels.length; i++) {
|
||||
const panel = this.panels[i];
|
||||
|
||||
if (panel.type !== 'row') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (panel.collapsed) {
|
||||
this.toggleRow(panel);
|
||||
}
|
||||
const collapsedRows = this.panels.filter((p) => p.type === 'row' && p.collapsed);
|
||||
for (const row of collapsedRows) {
|
||||
this.toggleRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
collapseRows() {
|
||||
for (let i = 0; i < this.panels.length; i++) {
|
||||
const panel = this.panels[i];
|
||||
|
||||
if (panel.type !== 'row') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!panel.collapsed) {
|
||||
this.toggleRow(panel);
|
||||
}
|
||||
const collapsedRows = this.panels.filter((p) => p.type === 'row' && !p.collapsed);
|
||||
for (const row of collapsedRows) {
|
||||
this.toggleRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
isSubMenuVisible() {
|
||||
if (this.links.length > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.getVariables().find((variable) => variable.hide !== 2)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.annotations.list.find((annotation) => annotation.hide !== true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return (
|
||||
this.links.length > 0 ||
|
||||
this.getVariables().some((variable) => variable.hide !== 2) ||
|
||||
this.annotations.list.some((annotation) => !annotation.hide)
|
||||
);
|
||||
}
|
||||
|
||||
getPanelInfoById(panelId: number) {
|
||||
for (let i = 0; i < this.panels.length; i++) {
|
||||
if (this.panels[i].id === panelId) {
|
||||
return {
|
||||
panel: this.panels[i],
|
||||
index: i,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
const panelIndex = this.panels.findIndex((p) => p.id === panelId);
|
||||
return panelIndex >= 0 ? { panel: this.panels[panelIndex], index: panelIndex } : null;
|
||||
}
|
||||
|
||||
duplicatePanel(panel: PanelModel) {
|
||||
@ -962,64 +864,64 @@ export class DashboardModel implements TimeModel {
|
||||
toggleRow(row: PanelModel) {
|
||||
const rowIndex = indexOf(this.panels, row);
|
||||
|
||||
if (row.collapsed) {
|
||||
row.collapsed = false;
|
||||
const hasRepeat = some(row.panels as PanelModel[], (p: PanelModel) => p.repeat);
|
||||
if (!row.collapsed) {
|
||||
const rowPanels = this.getRowPanels(rowIndex);
|
||||
|
||||
if (row.panels.length > 0) {
|
||||
// Use first panel to figure out if it was moved or pushed
|
||||
// If the panel doesn't have gridPos.y, use the row gridPos.y instead.
|
||||
// This can happen for some generated dashboards.
|
||||
const firstPanelYPos = row.panels[0].gridPos.y ?? row.gridPos.y;
|
||||
const yDiff = firstPanelYPos - (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 (const panel of row.panels) {
|
||||
// set the y gridPos if it wasn't already set
|
||||
panel.gridPos.y ?? (panel.gridPos.y = row.gridPos.y); // (Safari 13.1 lacks ??= support)
|
||||
// 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 - 1;
|
||||
|
||||
// push panels below down
|
||||
for (let panelIndex = insertPos; panelIndex < this.panels.length; panelIndex++) {
|
||||
this.panels[panelIndex].gridPos.y += pushDownAmount;
|
||||
}
|
||||
|
||||
row.panels = [];
|
||||
|
||||
if (hasRepeat) {
|
||||
this.processRowRepeats(row);
|
||||
}
|
||||
}
|
||||
|
||||
// sort panels
|
||||
this.sortPanelsByGridPos();
|
||||
// remove panels
|
||||
pull(this.panels, ...rowPanels);
|
||||
// save panel models inside row panel
|
||||
row.panels = rowPanels.map((panel: PanelModel) => panel.getSaveModel());
|
||||
row.collapsed = true;
|
||||
|
||||
// emit change event
|
||||
this.events.publish(new DashboardPanelsChangedEvent());
|
||||
return;
|
||||
}
|
||||
|
||||
const rowPanels = this.getRowPanels(rowIndex);
|
||||
row.collapsed = false;
|
||||
const rowPanels = row.panels ?? [];
|
||||
const hasRepeat = rowPanels.some((p: PanelModel) => p.repeat);
|
||||
if (rowPanels.length > 0) {
|
||||
// Use first panel to figure out if it was moved or pushed
|
||||
// If the panel doesn't have gridPos.y, use the row gridPos.y instead.
|
||||
// This can happen for some generated dashboards.
|
||||
const firstPanelYPos = rowPanels[0].gridPos.y ?? row.gridPos.y;
|
||||
const yDiff = firstPanelYPos - (row.gridPos.y + row.gridPos.h);
|
||||
|
||||
// remove panels
|
||||
pull(this.panels, ...rowPanels);
|
||||
// save panel models inside row panel
|
||||
row.panels = map(rowPanels, (panel: PanelModel) => panel.getSaveModel());
|
||||
row.collapsed = true;
|
||||
// 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 (const panel of rowPanels) {
|
||||
// set the y gridPos if it wasn't already set
|
||||
panel.gridPos.y ?? (panel.gridPos.y = row.gridPos.y); // (Safari 13.1 lacks ??= support)
|
||||
// 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 - 1;
|
||||
|
||||
// push panels below down
|
||||
for (const panel of this.panels.slice(insertPos)) {
|
||||
panel.gridPos.y += pushDownAmount;
|
||||
}
|
||||
|
||||
row.panels = [];
|
||||
|
||||
if (hasRepeat) {
|
||||
this.processRowRepeats(row);
|
||||
}
|
||||
}
|
||||
|
||||
// sort panels
|
||||
this.sortPanelsByGridPos();
|
||||
|
||||
// emit change event
|
||||
this.events.publish(new DashboardPanelsChangedEvent());
|
||||
@ -1029,19 +931,11 @@ export class DashboardModel implements TimeModel {
|
||||
* Will return all panels after rowIndex until it encounters another row
|
||||
*/
|
||||
getRowPanels(rowIndex: number): PanelModel[] {
|
||||
const rowPanels = [];
|
||||
const panelsBelowRow = this.panels.slice(rowIndex + 1);
|
||||
const nextRowIndex = panelsBelowRow.findIndex((p) => p.type === 'row');
|
||||
|
||||
for (let index = rowIndex + 1; index < this.panels.length; index++) {
|
||||
const panel = this.panels[index];
|
||||
|
||||
// break when encountering another row
|
||||
if (panel.type === 'row') {
|
||||
break;
|
||||
}
|
||||
|
||||
// this panel must belong to row
|
||||
rowPanels.push(panel);
|
||||
}
|
||||
// Take all panels up to next row, or all panels if there are no other rows
|
||||
const rowPanels = panelsBelowRow.slice(0, nextRowIndex >= 0 ? nextRowIndex : this.panels.length);
|
||||
|
||||
return rowPanels;
|
||||
}
|
||||
@ -1095,14 +989,12 @@ export class DashboardModel implements TimeModel {
|
||||
|
||||
hasTimeChanged() {
|
||||
const { time, originalTime } = this;
|
||||
if (isEqual(time, originalTime)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compare momemt values vs strings values
|
||||
// Compare moment values vs strings values
|
||||
return !(
|
||||
isEqual(dateTime(time?.from), dateTime(originalTime?.from)) &&
|
||||
isEqual(dateTime(time?.to), dateTime(originalTime?.to))
|
||||
isEqual(time, originalTime) ||
|
||||
(isEqual(dateTime(time?.from), dateTime(originalTime?.from)) &&
|
||||
isEqual(dateTime(time?.to), dateTime(originalTime?.to)))
|
||||
);
|
||||
}
|
||||
|
||||
@ -1120,11 +1012,7 @@ export class DashboardModel implements TimeModel {
|
||||
}
|
||||
|
||||
autoFitPanels(viewHeight: number, kioskMode?: UrlQueryValue) {
|
||||
const currentGridHeight = Math.max(
|
||||
...this.panels.map((panel) => {
|
||||
return panel.gridPos.h + panel.gridPos.y;
|
||||
})
|
||||
);
|
||||
const currentGridHeight = Math.max(...this.panels.map((panel) => panel.gridPos.h + panel.gridPos.y));
|
||||
|
||||
const navbarHeight = 55;
|
||||
const margin = 20;
|
||||
@ -1145,10 +1033,10 @@ export class DashboardModel implements TimeModel {
|
||||
const visibleGridHeight = Math.floor(visibleHeight / (GRID_CELL_HEIGHT + GRID_CELL_VMARGIN));
|
||||
const scaleFactor = currentGridHeight / visibleGridHeight;
|
||||
|
||||
this.panels.forEach((panel, i) => {
|
||||
for (const panel of this.panels) {
|
||||
panel.gridPos.y = Math.round(panel.gridPos.y / scaleFactor) || 1;
|
||||
panel.gridPos.h = Math.round(panel.gridPos.h / scaleFactor) || 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
templateVariableValueUpdated() {
|
||||
@ -1160,39 +1048,32 @@ export class DashboardModel implements TimeModel {
|
||||
const panelId = parseInt(panelUrlId ?? '0', 10);
|
||||
|
||||
// First try to find it in a collapsed row and exand it
|
||||
for (const panel of this.panels) {
|
||||
if (panel.collapsed) {
|
||||
for (const rowPanel of panel.panels) {
|
||||
if (rowPanel.id === panelId) {
|
||||
this.toggleRow(panel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
const collapsedPanels = this.panels.filter((p) => p.collapsed);
|
||||
for (const panel of collapsedPanels) {
|
||||
const hasPanel = panel.panels?.some((rp: any) => rp.id === panelId);
|
||||
hasPanel && this.toggleRow(panel);
|
||||
}
|
||||
|
||||
return this.getPanelById(panelId);
|
||||
}
|
||||
|
||||
toggleLegendsForAll() {
|
||||
const panelsWithLegends = this.panels.filter((panel) => {
|
||||
return panel.legend !== undefined && panel.legend !== null;
|
||||
});
|
||||
const panelsWithLegends = this.panels.filter(isPanelWithLegend);
|
||||
|
||||
// determine if more panels are displaying legends or not
|
||||
const onCount = panelsWithLegends.filter((panel) => panel.legend!.show).length;
|
||||
const onCount = panelsWithLegends.filter((panel) => panel.legend.show).length;
|
||||
const offCount = panelsWithLegends.length - onCount;
|
||||
const panelLegendsOn = onCount >= offCount;
|
||||
|
||||
for (const panel of panelsWithLegends) {
|
||||
panel.legend!.show = !panelLegendsOn;
|
||||
panel.legend.show = !panelLegendsOn;
|
||||
panel.render();
|
||||
}
|
||||
}
|
||||
|
||||
getVariables = () => {
|
||||
getVariables() {
|
||||
return this.getVariablesFromState(this.uid);
|
||||
};
|
||||
}
|
||||
|
||||
canEditAnnotations(dashboardId: number) {
|
||||
let canEdit = true;
|
||||
@ -1209,13 +1090,8 @@ export class DashboardModel implements TimeModel {
|
||||
}
|
||||
|
||||
canAddAnnotations() {
|
||||
let canAdd = true;
|
||||
|
||||
// if RBAC is enabled there are additional conditions to check
|
||||
if (contextSrv.accessControlEnabled()) {
|
||||
canAdd = !!this.meta.annotationsPermissions?.dashboard.canAdd;
|
||||
}
|
||||
|
||||
// If RBAC is enabled there are additional conditions to check
|
||||
const canAdd = !contextSrv.accessControlEnabled() || this.meta.annotationsPermissions?.dashboard.canAdd;
|
||||
return this.canEditDashboard() && canAdd;
|
||||
}
|
||||
|
||||
@ -1247,27 +1123,23 @@ export class DashboardModel implements TimeModel {
|
||||
return false;
|
||||
}
|
||||
|
||||
const updated = map(currentVariables, (variable: any) => {
|
||||
return {
|
||||
name: variable.name,
|
||||
type: variable.type,
|
||||
current: cloneDeep(variable.current),
|
||||
filters: cloneDeep(variable.filters),
|
||||
};
|
||||
});
|
||||
const updated = currentVariables.map((variable: any) => ({
|
||||
name: variable.name,
|
||||
type: variable.type,
|
||||
current: cloneDeep(variable.current),
|
||||
filters: cloneDeep(variable.filters),
|
||||
}));
|
||||
|
||||
return !isEqual(updated, originalVariables);
|
||||
}
|
||||
|
||||
private cloneVariablesFrom(variables: any[]): any[] {
|
||||
return variables.map((variable) => {
|
||||
return {
|
||||
name: variable.name,
|
||||
type: variable.type,
|
||||
current: cloneDeep(variable.current),
|
||||
filters: cloneDeep(variable.filters),
|
||||
};
|
||||
});
|
||||
return variables.map((variable) => ({
|
||||
name: variable.name,
|
||||
type: variable.type,
|
||||
current: cloneDeep(variable.current),
|
||||
filters: cloneDeep(variable.filters),
|
||||
}));
|
||||
}
|
||||
|
||||
private variablesTimeRangeProcessDoneHandler(event: VariablesTimeRangeProcessDone) {
|
||||
@ -1299,3 +1171,7 @@ export class DashboardModel implements TimeModel {
|
||||
this.startRefresh(event.payload);
|
||||
}
|
||||
}
|
||||
|
||||
function isPanelWithLegend(panel: PanelModel): panel is PanelModel & Pick<Required<PanelModel>, 'legend'> {
|
||||
return Boolean(panel.legend);
|
||||
}
|
||||
|
@ -139,7 +139,7 @@ export class PanelModel implements DataConfigSource, IPanelModel {
|
||||
maxPerRow?: number;
|
||||
collapsed?: boolean;
|
||||
|
||||
panels?: any;
|
||||
panels?: PanelModel[];
|
||||
declare targets: DataQuery[];
|
||||
transformations?: DataTransformerConfig[];
|
||||
datasource: DataSourceRef | null = null;
|
||||
|
@ -50,14 +50,14 @@ describe('deleteScopeVars', () => {
|
||||
});
|
||||
|
||||
expect(panel1.scopedVars).toBeDefined();
|
||||
expect(panel1.panels[0].scopedVars).toBeDefined();
|
||||
expect(panel1.panels[1].scopedVars).toBeDefined();
|
||||
expect(panel1.panels?.[0].scopedVars).toBeDefined();
|
||||
expect(panel1.panels?.[1].scopedVars).toBeDefined();
|
||||
|
||||
deleteScopeVars([panel1]);
|
||||
|
||||
expect(panel1.scopedVars).toBeUndefined();
|
||||
expect(panel1.panels[0].scopedVars).toBeUndefined();
|
||||
expect(panel1.panels[1].scopedVars).toBeUndefined();
|
||||
expect(panel1.panels?.[0].scopedVars).toBeUndefined();
|
||||
expect(panel1.panels?.[1].scopedVars).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user