mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
save modal ux improvements (#11822)
changes to save modal when saving an updated dashboard Changed time range and variables are now not saved by default, you'll need to actively choose if you want to save updated time range and or variables.
This commit is contained in:
parent
938deae4b4
commit
37f9bdfc8c
@ -22,8 +22,10 @@ export class DashboardModel {
|
||||
editable: any;
|
||||
graphTooltip: any;
|
||||
time: any;
|
||||
originalTime: any;
|
||||
timepicker: any;
|
||||
templating: any;
|
||||
originalTemplating: any;
|
||||
annotations: any;
|
||||
refresh: any;
|
||||
snapshot: any;
|
||||
@ -68,8 +70,12 @@ export class DashboardModel {
|
||||
this.editable = data.editable !== false;
|
||||
this.graphTooltip = data.graphTooltip || 0;
|
||||
this.time = data.time || { from: 'now-6h', to: 'now' };
|
||||
this.originalTime = _.cloneDeep(this.time);
|
||||
this.timepicker = data.timepicker || {};
|
||||
this.templating = this.ensureListExist(data.templating);
|
||||
this.originalTemplating = _.map(this.templating.list, variable => {
|
||||
return { name: variable.name, current: _.clone(variable.current) };
|
||||
});
|
||||
this.annotations = this.ensureListExist(data.annotations);
|
||||
this.refresh = data.refresh;
|
||||
this.snapshot = data.snapshot;
|
||||
@ -130,7 +136,12 @@ export class DashboardModel {
|
||||
}
|
||||
|
||||
// cleans meta data and other non persistent state
|
||||
getSaveModelClone() {
|
||||
getSaveModelClone(options?) {
|
||||
let defaults = _.defaults(options || {}, {
|
||||
saveVariables: false,
|
||||
saveTimerange: false,
|
||||
});
|
||||
|
||||
// make clone
|
||||
var copy: any = {};
|
||||
for (var property in this) {
|
||||
@ -142,10 +153,23 @@ export class DashboardModel {
|
||||
}
|
||||
|
||||
// get variable save models
|
||||
//console.log(this.templating.list);
|
||||
copy.templating = {
|
||||
list: _.map(this.templating.list, variable => (variable.getSaveModel ? variable.getSaveModel() : variable)),
|
||||
};
|
||||
|
||||
if (!defaults.saveVariables && copy.templating.list.length === this.originalTemplating.length) {
|
||||
for (let i = 0; i < copy.templating.list.length; i++) {
|
||||
if (copy.templating.list[i].name === this.originalTemplating[i].name) {
|
||||
copy.templating.list[i].current = this.originalTemplating[i].current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!defaults.saveTimerange) {
|
||||
copy.time = this.originalTime;
|
||||
}
|
||||
|
||||
// get panel save models
|
||||
copy.panels = _.chain(this.panels)
|
||||
.filter(panel => panel.type !== 'add-panel')
|
||||
|
@ -1,4 +1,5 @@
|
||||
import coreModule from 'app/core/core_module';
|
||||
import _ from 'lodash';
|
||||
|
||||
const template = `
|
||||
<div class="modal-body">
|
||||
@ -14,19 +15,29 @@ const template = `
|
||||
</div>
|
||||
|
||||
<form name="ctrl.saveForm" ng-submit="ctrl.save()" class="modal-content" novalidate>
|
||||
<h6 class="text-center">Add a note to describe your changes</h6>
|
||||
<div class="p-t-2">
|
||||
<div class="p-t-1">
|
||||
<div class="gf-form-group" ng-if="ctrl.timeChange || ctrl.variableChange">
|
||||
<gf-form-switch class="gf-form"
|
||||
label="Save current time range" ng-if="ctrl.timeChange" label-class="width-12" switch-class="max-width-6"
|
||||
checked="ctrl.saveTimerange" on-change="buildUrl()">
|
||||
</gf-form-switch>
|
||||
<gf-form-switch class="gf-form"
|
||||
label="Save current variables" ng-if="ctrl.variableChange" label-class="width-12" switch-class="max-width-6"
|
||||
checked="ctrl.saveVariables" on-change="buildUrl()">
|
||||
</gf-form-switch>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-hint">
|
||||
<input
|
||||
type="text"
|
||||
name="message"
|
||||
class="gf-form-input"
|
||||
placeholder="Updates to …"
|
||||
placeholder="Add a note to describe your changes …"
|
||||
give-focus="true"
|
||||
ng-model="ctrl.message"
|
||||
ng-model-options="{allowInvalid: true}"
|
||||
ng-maxlength="this.max"
|
||||
maxlength="64"
|
||||
autocomplete="off" />
|
||||
<small class="gf-form-hint-text muted" ng-cloak>
|
||||
<span ng-class="{'text-error': ctrl.saveForm.message.$invalid && ctrl.saveForm.message.$dirty }">
|
||||
@ -40,7 +51,7 @@ const template = `
|
||||
|
||||
<div class="gf-form-button-row text-center">
|
||||
<button type="submit" class="btn btn-success" ng-disabled="ctrl.saveForm.$invalid">Save</button>
|
||||
<button class="btn btn-inverse" ng-click="ctrl.dismiss();">Cancel</button>
|
||||
<a class="btn btn-link" ng-click="ctrl.dismiss();">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -48,14 +59,51 @@ const template = `
|
||||
|
||||
export class SaveDashboardModalCtrl {
|
||||
message: string;
|
||||
saveVariables = false;
|
||||
saveTimerange = false;
|
||||
templating: any;
|
||||
time: any;
|
||||
originalTime: any;
|
||||
current = [];
|
||||
originalCurrent = [];
|
||||
max: number;
|
||||
saveForm: any;
|
||||
dismiss: () => void;
|
||||
timeChange = false;
|
||||
variableChange = false;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private dashboardSrv) {
|
||||
this.message = '';
|
||||
this.max = 64;
|
||||
this.templating = dashboardSrv.dash.templating.list;
|
||||
|
||||
this.compareTemplating();
|
||||
this.compareTime();
|
||||
}
|
||||
|
||||
compareTime() {
|
||||
if (_.isEqual(this.dashboardSrv.dash.time, this.dashboardSrv.dash.originalTime)) {
|
||||
this.timeChange = false;
|
||||
} else {
|
||||
this.timeChange = true;
|
||||
}
|
||||
}
|
||||
|
||||
compareTemplating() {
|
||||
if (this.dashboardSrv.dash.templating.list.length > 0) {
|
||||
for (let i = 0; i < this.dashboardSrv.dash.templating.list.length; i++) {
|
||||
if (
|
||||
this.dashboardSrv.dash.templating.list[i].current.text !==
|
||||
this.dashboardSrv.dash.originalTemplating[i].current.text
|
||||
) {
|
||||
return (this.variableChange = true);
|
||||
}
|
||||
}
|
||||
return (this.variableChange = false);
|
||||
} else {
|
||||
return (this.variableChange = false);
|
||||
}
|
||||
}
|
||||
|
||||
save() {
|
||||
@ -63,9 +111,14 @@ export class SaveDashboardModalCtrl {
|
||||
return;
|
||||
}
|
||||
|
||||
var options = {
|
||||
saveVariables: this.saveVariables,
|
||||
saveTimerange: this.saveTimerange,
|
||||
message: this.message,
|
||||
};
|
||||
|
||||
var dashboard = this.dashboardSrv.getCurrent();
|
||||
var saveModel = dashboard.getSaveModelClone();
|
||||
var options = { message: this.message };
|
||||
var saveModel = dashboard.getSaveModelClone(options);
|
||||
|
||||
return this.dashboardSrv.save(saveModel, options).then(this.dismiss);
|
||||
}
|
||||
|
@ -434,4 +434,63 @@ describe('DashboardModel', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('save variables and timeline', () => {
|
||||
let model;
|
||||
|
||||
beforeEach(() => {
|
||||
model = new DashboardModel({
|
||||
templating: {
|
||||
list: [
|
||||
{
|
||||
name: 'Server',
|
||||
current: {
|
||||
selected: true,
|
||||
text: 'server_001',
|
||||
value: 'server_001',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
time: {
|
||||
from: 'now-6h',
|
||||
to: 'now',
|
||||
},
|
||||
});
|
||||
model.templating.list[0] = {
|
||||
name: 'Server',
|
||||
current: {
|
||||
selected: true,
|
||||
text: 'server_002',
|
||||
value: 'server_002',
|
||||
},
|
||||
};
|
||||
model.time = {
|
||||
from: 'now-3h',
|
||||
to: 'now',
|
||||
};
|
||||
});
|
||||
|
||||
it('should not save variables and timeline', () => {
|
||||
let options = {
|
||||
saveVariables: false,
|
||||
saveTimerange: false,
|
||||
};
|
||||
let saveModel = model.getSaveModelClone(options);
|
||||
|
||||
expect(saveModel.templating.list[0].current.text).toBe('server_001');
|
||||
expect(saveModel.time.from).toBe('now-6h');
|
||||
});
|
||||
|
||||
it('should save variables and timeline', () => {
|
||||
let options = {
|
||||
saveVariables: true,
|
||||
saveTimerange: true,
|
||||
};
|
||||
let saveModel = model.getSaveModelClone(options);
|
||||
|
||||
expect(saveModel.templating.list[0].current.text).toBe('server_002');
|
||||
expect(saveModel.time.from).toBe('now-3h');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
90
public/app/features/dashboard/specs/save_modal.jest.ts
Normal file
90
public/app/features/dashboard/specs/save_modal.jest.ts
Normal file
@ -0,0 +1,90 @@
|
||||
import { SaveDashboardModalCtrl } from '../save_modal';
|
||||
|
||||
jest.mock('app/core/services/context_srv', () => ({}));
|
||||
|
||||
describe('SaveDashboardModal', () => {
|
||||
describe('save modal checkboxes', () => {
|
||||
it('should show checkboxes', () => {
|
||||
let fakeDashboardSrv = {
|
||||
dash: {
|
||||
templating: {
|
||||
list: [
|
||||
{
|
||||
current: {
|
||||
selected: true,
|
||||
tags: Array(0),
|
||||
text: 'server_001',
|
||||
value: 'server_001',
|
||||
},
|
||||
name: 'Server',
|
||||
},
|
||||
],
|
||||
},
|
||||
originalTemplating: [
|
||||
{
|
||||
current: {
|
||||
selected: true,
|
||||
text: 'server_002',
|
||||
value: 'server_002',
|
||||
},
|
||||
name: 'Server',
|
||||
},
|
||||
],
|
||||
time: {
|
||||
from: 'now-3h',
|
||||
to: 'now',
|
||||
},
|
||||
originalTime: {
|
||||
from: 'now-6h',
|
||||
to: 'now',
|
||||
},
|
||||
},
|
||||
};
|
||||
let modal = new SaveDashboardModalCtrl(fakeDashboardSrv);
|
||||
|
||||
expect(modal.timeChange).toBe(true);
|
||||
expect(modal.variableChange).toBe(true);
|
||||
});
|
||||
|
||||
it('should hide checkboxes', () => {
|
||||
let fakeDashboardSrv = {
|
||||
dash: {
|
||||
templating: {
|
||||
list: [
|
||||
{
|
||||
current: {
|
||||
selected: true,
|
||||
//tags: Array(0),
|
||||
text: 'server_002',
|
||||
value: 'server_002',
|
||||
},
|
||||
name: 'Server',
|
||||
},
|
||||
],
|
||||
},
|
||||
originalTemplating: [
|
||||
{
|
||||
current: {
|
||||
selected: true,
|
||||
text: 'server_002',
|
||||
value: 'server_002',
|
||||
},
|
||||
name: 'Server',
|
||||
},
|
||||
],
|
||||
time: {
|
||||
from: 'now-3h',
|
||||
to: 'now',
|
||||
},
|
||||
originalTime: {
|
||||
from: 'now-3h',
|
||||
to: 'now',
|
||||
},
|
||||
},
|
||||
};
|
||||
let modal = new SaveDashboardModalCtrl(fakeDashboardSrv);
|
||||
expect(modal.timeChange).toBe(false);
|
||||
expect(modal.variableChange).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user