Merge branch 'master' into react-panels

This commit is contained in:
Torkel Ödegaard
2018-09-10 15:42:36 +02:00
597 changed files with 13109 additions and 9258 deletions

View File

@@ -30,7 +30,7 @@ export class AdHocFiltersCtrl {
if (this.variable.value && !_.isArray(this.variable.value)) {
}
for (let tag of this.variable.filters) {
for (const tag of this.variable.filters) {
if (this.segments.length > 0) {
this.segments.push(this.uiSegmentSrv.newCondition('AND'));
}
@@ -55,8 +55,8 @@ export class AdHocFiltersCtrl {
}
return this.datasourceSrv.get(this.variable.datasource).then(ds => {
var options: any = {};
var promise = null;
const options: any = {};
let promise = null;
if (segment.type !== 'value') {
promise = ds.getTagKeys();
@@ -113,9 +113,9 @@ export class AdHocFiltersCtrl {
}
updateVariableModel() {
var filters = [];
var filterIndex = -1;
var hasFakes = false;
const filters = [];
let filterIndex = -1;
let hasFakes = false;
this.segments.forEach(segment => {
if (segment.type === 'value' && segment.fake) {
@@ -153,7 +153,7 @@ export class AdHocFiltersCtrl {
}
}
var template = `
const template = `
<div class="gf-form-inline">
<div class="gf-form" ng-repeat="segment in ctrl.segments">
<metric-segment segment="segment" get-options="ctrl.getOptions(segment, $index)"

View File

@@ -26,15 +26,15 @@ import './dashgrid/RowOptions';
import './folder_picker/folder_picker';
import './move_to_folder_modal/move_to_folder';
import './settings/settings';
import './panellinks/module';
import './dashlinks/module';
import coreModule from 'app/core/core_module';
import { DashboardListCtrl } from './dashboard_list_ctrl';
import { FolderDashboardsCtrl } from './folder_dashboards_ctrl';
import { FolderSettingsCtrl } from './folder_settings_ctrl';
import { DashboardImportCtrl } from './dashboard_import_ctrl';
import { CreateFolderCtrl } from './create_folder_ctrl';
coreModule.controller('DashboardListCtrl', DashboardListCtrl);
coreModule.controller('FolderDashboardsCtrl', FolderDashboardsCtrl);
coreModule.controller('FolderSettingsCtrl', FolderSettingsCtrl);
coreModule.controller('DashboardImportCtrl', DashboardImportCtrl);

View File

@@ -87,20 +87,20 @@ export class ChangeTracker {
return true;
}
var meta = this.current.meta;
const meta = this.current.meta;
return !meta.canSave || meta.fromScript || meta.fromFile;
}
// remove stuff that should not count in diff
cleanDashboardFromIgnoredChanges(dashData) {
// need to new up the domain model class to get access to expand / collapse row logic
let model = new DashboardModel(dashData);
const model = new DashboardModel(dashData);
// Expand all rows before making comparison. This is required because row expand / collapse
// change order of panel array and panel positions.
model.expandRows();
let dash = model.getSaveModelClone();
const dash = model.getSaveModelClone();
// ignore time and refresh
dash.time = 0;
@@ -128,7 +128,7 @@ export class ChangeTracker {
});
// ignore template variable values
_.each(dash.templating.list, function(value) {
_.each(dash.templating.list, value => {
value.current = null;
value.options = null;
value.filters = null;
@@ -138,18 +138,18 @@ export class ChangeTracker {
}
hasChanges() {
let current = this.cleanDashboardFromIgnoredChanges(this.current.getSaveModelClone());
let original = this.cleanDashboardFromIgnoredChanges(this.original);
const current = this.cleanDashboardFromIgnoredChanges(this.current.getSaveModelClone());
const original = this.cleanDashboardFromIgnoredChanges(this.original);
var currentTimepicker = _.find(current.nav, { type: 'timepicker' });
var originalTimepicker = _.find(original.nav, { type: 'timepicker' });
const currentTimepicker = _.find(current.nav, { type: 'timepicker' });
const originalTimepicker = _.find(original.nav, { type: 'timepicker' });
if (currentTimepicker && originalTimepicker) {
currentTimepicker.now = originalTimepicker.now;
}
var currentJson = angular.toJson(current, true);
var originalJson = angular.toJson(original, true);
const currentJson = angular.toJson(current, true);
const originalJson = angular.toJson(original, true);
return currentJson !== originalJson;
}
@@ -167,8 +167,8 @@ export class ChangeTracker {
}
saveChanges() {
var self = this;
var cancel = this.$rootScope.$on('dashboard-saved', () => {
const self = this;
const cancel = this.$rootScope.$on('dashboard-saved', () => {
cancel();
this.$timeout(() => {
self.gotoNext();
@@ -179,8 +179,8 @@ export class ChangeTracker {
}
gotoNext() {
var baseLen = this.$location.absUrl().length - this.$location.url().length;
var nextUrl = this.next.substring(baseLen);
const baseLen = this.$location.absUrl().length - this.$location.url().length;
const nextUrl = this.next.substring(baseLen);
this.$location.url(nextUrl);
}
}

View File

@@ -8,7 +8,7 @@ export class CreateFolderCtrl {
hasValidationError: boolean;
validationError: any;
/** @ngInject **/
/** @ngInject */
constructor(private backendSrv, private $location, private validationSrv, navModelSrv) {
this.navModel = navModelSrv.getNav('dashboards', 'manage-dashboards', 0);
}

View File

@@ -100,11 +100,11 @@ export class DashboardCtrl {
}
setWindowTitleAndTheme() {
window.document.title = config.window_title_prefix + this.dashboard.title;
window.document.title = config.windowTitlePrefix + this.dashboard.title;
}
showJsonEditor(evt, options) {
var editScope = this.$rootScope.$new();
const editScope = this.$rootScope.$new();
editScope.object = options.object;
editScope.updateHandler = options.updateHandler;
this.$scope.appEvent('show-dash-editor', {
@@ -131,14 +131,14 @@ export class DashboardCtrl {
return;
}
var panelInfo = this.dashboard.getPanelInfoById(options.panelId);
const panelInfo = this.dashboard.getPanelInfoById(options.panelId);
this.removePanel(panelInfo.panel, true);
}
removePanel(panel: PanelModel, ask: boolean) {
// confirm deletion
if (ask !== false) {
var text2, confirmText;
let text2, confirmText;
if (panel.alert) {
text2 = 'Panel includes an alert rule, removing panel will also remove alert rule';

View File

@@ -1,5 +1,6 @@
import _ from 'lodash';
import config from 'app/core/config';
import locationUtil from 'app/core/utils/location_util';
export class DashboardImportCtrl {
navModel: any;
@@ -51,8 +52,8 @@ export class DashboardImportCtrl {
this.inputs = [];
if (this.dash.__inputs) {
for (let input of this.dash.__inputs) {
var inputModel = {
for (const input of this.dash.__inputs) {
const inputModel = {
name: input.name,
label: input.label,
info: input.description,
@@ -78,7 +79,7 @@ export class DashboardImportCtrl {
}
setDatasourceOptions(input, inputModel) {
var sources = _.filter(config.datasources, val => {
const sources = _.filter(config.datasources, val => {
return val.type === input.pluginId;
});
@@ -95,7 +96,7 @@ export class DashboardImportCtrl {
inputValueChanged() {
this.inputsValid = true;
for (let input of this.inputs) {
for (const input of this.inputs) {
if (!input.value) {
this.inputsValid = false;
}
@@ -162,7 +163,7 @@ export class DashboardImportCtrl {
}
saveDashboard() {
var inputs = this.inputs.map(input => {
const inputs = this.inputs.map(input => {
return {
name: input.name,
type: input.type,
@@ -179,14 +180,15 @@ export class DashboardImportCtrl {
folderId: this.folderId,
})
.then(res => {
this.$location.url(res.importedUrl);
const dashUrl = locationUtil.stripBaseFromUrl(res.importedUrl);
this.$location.url(dashUrl);
});
}
loadJsonText() {
try {
this.parseError = '';
var dash = JSON.parse(this.jsonText);
const dash = JSON.parse(this.jsonText);
this.onUpload(dash);
} catch (err) {
console.log(err);
@@ -198,8 +200,8 @@ export class DashboardImportCtrl {
checkGnetDashboard() {
this.gnetError = '';
var match = /(^\d+$)|dashboards\/(\d+)/.exec(this.gnetUrl);
var dashboardId;
const match = /(^\d+$)|dashboards\/(\d+)/.exec(this.gnetUrl);
let dashboardId;
if (match && match[1]) {
dashboardId = match[1];

View File

@@ -1,8 +0,0 @@
export class DashboardListCtrl {
navModel: any;
/** @ngInject */
constructor(navModelSrv) {
this.navModel = navModelSrv.getNav('dashboards', 'manage-dashboards', 0);
}
}

View File

@@ -36,7 +36,7 @@ export class DashboardLoaderSrv {
}
loadDashboard(type, slug, uid) {
var promise;
let promise;
if (type === 'script') {
promise = this._loadScriptedDashboard(slug);
@@ -59,7 +59,7 @@ export class DashboardLoaderSrv {
});
}
promise.then(function(result) {
promise.then(result => {
if (result.meta.dashboardNotFound !== true) {
impressionSrv.addDashboardImpression(result.dashboard.id);
}
@@ -71,7 +71,7 @@ export class DashboardLoaderSrv {
}
_loadScriptedDashboard(file) {
var url = 'public/dashboards/' + file.replace(/\.(?!js)/, '/') + '?' + new Date().getTime();
const url = 'public/dashboards/' + file.replace(/\.(?!js)/, '/') + '?' + new Date().getTime();
return this.$http({ url: url, method: 'GET' })
.then(this._executeScript.bind(this))
@@ -99,14 +99,14 @@ export class DashboardLoaderSrv {
}
_executeScript(result) {
var services = {
const services = {
dashboardSrv: this.dashboardSrv,
datasourceSrv: this.datasourceSrv,
$q: this.$q,
};
/*jshint -W054 */
var script_func = new Function(
const scriptFunc = new Function(
'ARGS',
'kbn',
'dateMath',
@@ -119,12 +119,12 @@ export class DashboardLoaderSrv {
'services',
result.data
);
var script_result = script_func(this.$routeParams, kbn, dateMath, _, moment, window, document, $, $, services);
const scriptResult = scriptFunc(this.$routeParams, kbn, dateMath, _, moment, window, document, $, $, services);
// Handle async dashboard scripts
if (_.isFunction(script_result)) {
var deferred = this.$q.defer();
script_result(dashboard => {
if (_.isFunction(scriptResult)) {
const deferred = this.$q.defer();
scriptResult(dashboard => {
this.$timeout(() => {
deferred.resolve({ data: dashboard });
});
@@ -132,7 +132,7 @@ export class DashboardLoaderSrv {
return deferred.promise;
}
return { data: script_result };
return { data: scriptResult };
}
}

View File

@@ -18,9 +18,9 @@ export class DashboardMigrator {
}
updateSchema(old) {
var i, j, k, n;
var oldVersion = this.dashboard.schemaVersion;
var panelUpgrades = [];
let i, j, k, n;
const oldVersion = this.dashboard.schemaVersion;
const panelUpgrades = [];
this.dashboard.schemaVersion = 16;
if (oldVersion === this.dashboard.schemaVersion) {
@@ -36,7 +36,7 @@ export class DashboardMigrator {
}
}
panelUpgrades.push(function(panel) {
panelUpgrades.push(panel => {
// rename panel type
if (panel.type === 'graphite') {
panel.type = 'graph';
@@ -83,8 +83,8 @@ export class DashboardMigrator {
// schema version 3 changes
if (oldVersion < 3) {
// ensure panel ids
var maxId = this.dashboard.getNextPanelId();
panelUpgrades.push(function(panel) {
let maxId = this.dashboard.getNextPanelId();
panelUpgrades.push(panel => {
if (!panel.id) {
panel.id = maxId;
maxId += 1;
@@ -95,11 +95,11 @@ export class DashboardMigrator {
// schema version 4 changes
if (oldVersion < 4) {
// move aliasYAxis changes
panelUpgrades.push(function(panel) {
panelUpgrades.push(panel => {
if (panel.type !== 'graph') {
return;
}
_.each(panel.aliasYAxis, function(value, key) {
_.each(panel.aliasYAxis, (value, key) => {
panel.seriesOverrides = [{ alias: key, yaxis: value }];
});
delete panel.aliasYAxis;
@@ -108,7 +108,7 @@ export class DashboardMigrator {
if (oldVersion < 6) {
// move pulldowns to new schema
var annotations = _.find(old.pulldowns, { type: 'annotations' });
const annotations = _.find(old.pulldowns, { type: 'annotations' });
if (annotations) {
this.dashboard.annotations = {
@@ -118,7 +118,7 @@ export class DashboardMigrator {
// update template variables
for (i = 0; i < this.dashboard.templating.list.length; i++) {
var variable = this.dashboard.templating.list[i];
const variable = this.dashboard.templating.list[i];
if (variable.datasource === void 0) {
variable.datasource = null;
}
@@ -140,29 +140,26 @@ export class DashboardMigrator {
}
// ensure query refIds
panelUpgrades.push(function(panel) {
_.each(
panel.targets,
function(target) {
if (!target.refId) {
target.refId = this.dashboard.getNextQueryLetter(panel);
}
}.bind(this)
);
panelUpgrades.push(panel => {
_.each(panel.targets, target => {
if (!target.refId) {
target.refId = this.dashboard.getNextQueryLetter(panel);
}
});
});
}
if (oldVersion < 8) {
panelUpgrades.push(function(panel) {
_.each(panel.targets, function(target) {
panelUpgrades.push(panel => {
_.each(panel.targets, target => {
// update old influxdb query schema
if (target.fields && target.tags && target.groupBy) {
if (target.rawQuery) {
delete target.fields;
delete target.fill;
} else {
target.select = _.map(target.fields, function(field) {
var parts = [];
target.select = _.map(target.fields, field => {
const parts = [];
parts.push({ type: 'field', params: [field.name] });
parts.push({ type: field.func, params: [] });
if (field.mathExpr) {
@@ -174,7 +171,7 @@ export class DashboardMigrator {
return parts;
});
delete target.fields;
_.each(target.groupBy, function(part) {
_.each(target.groupBy, part => {
if (part.type === 'time' && part.interval) {
part.params = [part.interval];
delete part.interval;
@@ -198,13 +195,13 @@ export class DashboardMigrator {
// schema version 9 changes
if (oldVersion < 9) {
// move aliasYAxis changes
panelUpgrades.push(function(panel) {
panelUpgrades.push(panel => {
if (panel.type !== 'singlestat' && panel.thresholds !== '') {
return;
}
if (panel.thresholds) {
var k = panel.thresholds.split(',');
const k = panel.thresholds.split(',');
if (k.length >= 3) {
k.shift();
@@ -217,14 +214,14 @@ export class DashboardMigrator {
// schema version 10 changes
if (oldVersion < 10) {
// move aliasYAxis changes
panelUpgrades.push(function(panel) {
panelUpgrades.push(panel => {
if (panel.type !== 'table') {
return;
}
_.each(panel.styles, function(style) {
_.each(panel.styles, style => {
if (style.thresholds && style.thresholds.length >= 3) {
var k = style.thresholds;
const k = style.thresholds;
k.shift();
style.thresholds = k;
}
@@ -234,7 +231,7 @@ export class DashboardMigrator {
if (oldVersion < 12) {
// update template variables
_.each(this.dashboard.templating.list, function(templateVariable) {
_.each(this.dashboard.templating.list, templateVariable => {
if (templateVariable.refresh) {
templateVariable.refresh = 1;
}
@@ -251,7 +248,7 @@ export class DashboardMigrator {
if (oldVersion < 12) {
// update graph yaxes changes
panelUpgrades.push(function(panel) {
panelUpgrades.push(panel => {
if (panel.type !== 'graph') {
return;
}
@@ -300,7 +297,7 @@ export class DashboardMigrator {
if (oldVersion < 13) {
// update graph yaxes changes
panelUpgrades.push(function(panel) {
panelUpgrades.push(panel => {
if (panel.type !== 'graph') {
return;
}
@@ -309,7 +306,7 @@ export class DashboardMigrator {
}
panel.thresholds = [];
var t1: any = {},
const t1: any = {},
t2: any = {};
if (panel.grid.threshold1 !== null) {
@@ -389,7 +386,7 @@ export class DashboardMigrator {
upgradeToGridLayout(old) {
let yPos = 0;
let widthFactor = GRID_COLUMN_COUNT / 12;
const widthFactor = GRID_COLUMN_COUNT / 12;
const maxPanelId = _.max(
_.flattenDeep(
@@ -407,15 +404,15 @@ export class DashboardMigrator {
// Add special "row" panels if even one row is collapsed, repeated or has visible title
const showRows = _.some(old.rows, row => row.collapse || row.showTitle || row.repeat);
for (let row of old.rows) {
for (const row of old.rows) {
if (row.repeatIteration) {
continue;
}
let height: any = row.height || DEFAULT_ROW_HEIGHT;
const height: any = row.height || DEFAULT_ROW_HEIGHT;
const rowGridHeight = getGridHeight(height);
let rowPanel: any = {};
const rowPanel: any = {};
let rowPanelModel: PanelModel;
if (showRows) {
// add special row panel
@@ -436,9 +433,9 @@ export class DashboardMigrator {
yPos++;
}
let rowArea = new RowArea(rowGridHeight, GRID_COLUMN_COUNT, yPos);
const rowArea = new RowArea(rowGridHeight, GRID_COLUMN_COUNT, yPos);
for (let panel of row.panels) {
for (const panel of row.panels) {
panel.span = panel.span || DEFAULT_PANEL_SPAN;
if (panel.minSpan) {
panel.minSpan = Math.min(GRID_COLUMN_COUNT, GRID_COLUMN_COUNT / 12 * panel.minSpan);
@@ -446,7 +443,7 @@ export class DashboardMigrator {
const panelWidth = Math.floor(panel.span) * widthFactor;
const panelHeight = panel.height ? getGridHeight(panel.height) : rowGridHeight;
let panelPos = rowArea.getPanelPosition(panelHeight, panelWidth);
const panelPos = rowArea.getPanelPosition(panelHeight, panelWidth);
yPos = rowArea.yPos;
panel.gridPos = {
x: panelPos.x,

View File

@@ -95,7 +95,7 @@ export class DashboardModel {
addBuiltInAnnotationQuery() {
let found = false;
for (let item of this.annotations.list) {
for (const item of this.annotations.list) {
if (item.builtIn === 1) {
found = true;
break;
@@ -138,14 +138,14 @@ export class DashboardModel {
// cleans meta data and other non persistent state
getSaveModelClone(options?) {
let defaults = _.defaults(options || {}, {
const defaults = _.defaults(options || {}, {
saveVariables: true,
saveTimerange: true,
});
// make clone
var copy: any = {};
for (var property in this) {
let copy: any = {};
for (const property in this) {
if (DashboardModel.nonPersistedProperties[property] || !this.hasOwnProperty(property)) {
continue;
}
@@ -160,8 +160,8 @@ export class DashboardModel {
if (!defaults.saveVariables) {
for (let i = 0; i < copy.templating.list.length; i++) {
let current = copy.templating.list[i];
let original = _.find(this.originalTemplating, { name: current.name, type: current.type });
const current = copy.templating.list[i];
const original = _.find(this.originalTemplating, { name: current.name, type: current.type });
if (!original) {
continue;
@@ -246,13 +246,13 @@ export class DashboardModel {
getNextPanelId() {
let max = 0;
for (let panel of this.panels) {
for (const panel of this.panels) {
if (panel.id > max) {
max = panel.id;
}
if (panel.collapsed) {
for (let rowPanel of panel.panels) {
for (const rowPanel of panel.panels) {
if (rowPanel.id > max) {
max = rowPanel.id;
}
@@ -270,7 +270,7 @@ export class DashboardModel {
}
getPanelById(id) {
for (let panel of this.panels) {
for (const panel of this.panels) {
if (panel.id === id) {
return panel;
}
@@ -281,7 +281,7 @@ export class DashboardModel {
addPanel(panelData) {
panelData.id = this.getNextPanelId();
let panel = new PanelModel(panelData);
const panel = new PanelModel(panelData);
this.panels.unshift(panel);
@@ -291,7 +291,7 @@ export class DashboardModel {
}
sortPanelsByGridPos() {
this.panels.sort(function(panelA, panelB) {
this.panels.sort((panelA, panelB) => {
if (panelA.gridPos.y === panelB.gridPos.y) {
return panelA.gridPos.x - panelB.gridPos.x;
} else {
@@ -306,15 +306,15 @@ export class DashboardModel {
}
this.iteration = (this.iteration || new Date().getTime()) + 1;
let panelsToRemove = [];
const panelsToRemove = [];
// cleanup scopedVars
for (let panel of this.panels) {
for (const panel of this.panels) {
delete panel.scopedVars;
}
for (let i = 0; i < this.panels.length; i++) {
let panel = this.panels[i];
const panel = this.panels[i];
if ((!panel.repeat || panel.repeatedByRow) && panel.repeatPanelId && panel.repeatIteration !== this.iteration) {
panelsToRemove.push(panel);
}
@@ -337,7 +337,7 @@ export class DashboardModel {
this.iteration = (this.iteration || new Date().getTime()) + 1;
for (let i = 0; i < this.panels.length; i++) {
let panel = this.panels[i];
const panel = this.panels[i];
if (panel.repeat) {
this.repeatPanel(panel, i);
}
@@ -348,9 +348,9 @@ export class DashboardModel {
}
cleanUpRowRepeats(rowPanels) {
let panelsToRemove = [];
const panelsToRemove = [];
for (let i = 0; i < rowPanels.length; i++) {
let panel = rowPanels[i];
const panel = rowPanels[i];
if (!panel.repeat && panel.repeatPanelId) {
panelsToRemove.push(panel);
}
@@ -366,16 +366,16 @@ export class DashboardModel {
let rowPanels = row.panels;
if (!row.collapsed) {
let rowPanelIndex = _.findIndex(this.panels, p => p.id === row.id);
const rowPanelIndex = _.findIndex(this.panels, p => p.id === row.id);
rowPanels = this.getRowPanels(rowPanelIndex);
}
this.cleanUpRowRepeats(rowPanels);
for (let i = 0; i < rowPanels.length; i++) {
let panel = rowPanels[i];
const panel = rowPanels[i];
if (panel.repeat) {
let panelIndex = _.findIndex(this.panels, p => p.id === panel.id);
const panelIndex = _.findIndex(this.panels, p => p.id === panel.id);
this.repeatPanel(panel, panelIndex);
}
}
@@ -387,7 +387,7 @@ export class DashboardModel {
return sourcePanel;
}
let clone = new PanelModel(sourcePanel.getSaveModel());
const clone = new PanelModel(sourcePanel.getSaveModel());
clone.id = this.getNextPanelId();
// insert after source panel + value index
@@ -403,13 +403,13 @@ export class DashboardModel {
// if first clone return source
if (valueIndex === 0) {
if (!sourceRowPanel.collapsed) {
let rowPanels = this.getRowPanels(sourcePanelIndex);
const rowPanels = this.getRowPanels(sourcePanelIndex);
sourceRowPanel.panels = rowPanels;
}
return sourceRowPanel;
}
let clone = new PanelModel(sourceRowPanel.getSaveModel());
const clone = new PanelModel(sourceRowPanel.getSaveModel());
// for row clones we need to figure out panels under row to clone and where to insert clone
let rowPanels, insertPos;
if (sourceRowPanel.collapsed) {
@@ -430,7 +430,7 @@ export class DashboardModel {
}
repeatPanel(panel: PanelModel, panelIndex: number) {
let variable = _.find(this.templating.list, { name: panel.repeat });
const variable = _.find(this.templating.list, { name: panel.repeat });
if (!variable) {
return;
}
@@ -440,13 +440,13 @@ export class DashboardModel {
return;
}
let selectedOptions = this.getSelectedVariableOptions(variable);
let minWidth = panel.minSpan || 6;
const selectedOptions = this.getSelectedVariableOptions(variable);
const minWidth = panel.minSpan || 6;
let xPos = 0;
let yPos = panel.gridPos.y;
for (let index = 0; index < selectedOptions.length; index++) {
let option = selectedOptions[index];
const option = selectedOptions[index];
let copy;
copy = this.getPanelRepeatClone(panel, index, panelIndex);
@@ -476,9 +476,9 @@ export class DashboardModel {
}
// Update gridPos for panels below
let yOffset = yPos - panel.gridPos.y;
const yOffset = yPos - panel.gridPos.y;
if (yOffset > 0) {
let panelBelowIndex = panelIndex + selectedOptions.length;
const panelBelowIndex = panelIndex + selectedOptions.length;
for (let i = panelBelowIndex; i < this.panels.length; i++) {
this.panels[i].gridPos.y += yOffset;
}
@@ -486,7 +486,7 @@ export class DashboardModel {
}
repeatRow(panel: PanelModel, panelIndex: number, variable) {
let selectedOptions = this.getSelectedVariableOptions(variable);
const selectedOptions = this.getSelectedVariableOptions(variable);
let yPos = panel.gridPos.y;
function setScopedVars(panel, variableOption) {
@@ -495,12 +495,12 @@ export class DashboardModel {
}
for (let optionIndex = 0; optionIndex < selectedOptions.length; optionIndex++) {
let option = selectedOptions[optionIndex];
let rowCopy = this.getRowRepeatClone(panel, optionIndex, panelIndex);
const option = selectedOptions[optionIndex];
const rowCopy = this.getRowRepeatClone(panel, optionIndex, panelIndex);
setScopedVars(rowCopy, option);
let rowHeight = this.getRowHeight(rowCopy);
let rowPanels = rowCopy.panels || [];
const rowHeight = this.getRowHeight(rowCopy);
const rowPanels = rowCopy.panels || [];
let panelBelowIndex;
if (panel.collapsed) {
@@ -516,11 +516,11 @@ export class DashboardModel {
panelBelowIndex = panelIndex + optionIndex + 1;
} else {
// insert after 'row' panel
let insertPos = panelIndex + (rowPanels.length + 1) * optionIndex + 1;
const insertPos = panelIndex + (rowPanels.length + 1) * optionIndex + 1;
_.each(rowPanels, (rowPanel, i) => {
setScopedVars(rowPanel, option);
if (optionIndex > 0) {
let cloneRowPanel = new PanelModel(rowPanel);
const cloneRowPanel = new PanelModel(rowPanel);
this.updateRepeatedPanelIds(cloneRowPanel, true);
// For exposed row additionally set proper Y grid position and add it to dashboard panels
cloneRowPanel.gridPos.y += rowHeight * optionIndex;
@@ -575,7 +575,7 @@ export class DashboardModel {
}
removePanel(panel: PanelModel) {
var index = _.indexOf(this.panels, panel);
const index = _.indexOf(this.panels, panel);
this.panels.splice(index, 1);
this.events.emit('panel-removed', panel);
}
@@ -592,7 +592,7 @@ export class DashboardModel {
expandRows() {
for (let i = 0; i < this.panels.length; i++) {
var panel = this.panels[i];
const panel = this.panels[i];
if (panel.type !== 'row') {
continue;
@@ -606,7 +606,7 @@ export class DashboardModel {
collapseRows() {
for (let i = 0; i < this.panels.length; i++) {
var panel = this.panels[i];
const panel = this.panels[i];
if (panel.type !== 'row') {
continue;
@@ -628,12 +628,12 @@ export class DashboardModel {
return true;
}
var visibleVars = _.filter(this.templating.list, variable => variable.hide !== 2);
const visibleVars = _.filter(this.templating.list, variable => variable.hide !== 2);
if (visibleVars.length > 0) {
return true;
}
var visibleAnnotations = _.filter(this.annotations.list, annotation => annotation.hide !== true);
const visibleAnnotations = _.filter(this.annotations.list, annotation => annotation.hide !== true);
if (visibleAnnotations.length > 0) {
return true;
}
@@ -683,29 +683,29 @@ export class DashboardModel {
formatDate(date, format?) {
date = moment.isMoment(date) ? date : moment(date);
format = format || 'YYYY-MM-DD HH:mm:ss';
let timezone = this.getTimezone();
const timezone = this.getTimezone();
return timezone === 'browser' ? moment(date).format(format) : moment.utc(date).format(format);
}
destroy() {
this.events.removeAllListeners();
for (let panel of this.panels) {
for (const panel of this.panels) {
panel.destroy();
}
}
toggleRow(row: PanelModel) {
let rowIndex = _.indexOf(this.panels, row);
const rowIndex = _.indexOf(this.panels, row);
if (row.collapsed) {
row.collapsed = false;
let hasRepeat = _.some(row.panels, p => p.repeat);
const hasRepeat = _.some(row.panels, p => p.repeat);
if (row.panels.length > 0) {
// 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);
const firstPanel = row.panels[0];
const yDiff = firstPanel.gridPos.y - (row.gridPos.y + row.gridPos.h);
// start inserting after row
let insertPos = rowIndex + 1;
@@ -713,7 +713,7 @@ export class DashboardModel {
// needed to know home much panels below should be pushed down
let yMax = row.gridPos.y;
for (let panel of row.panels) {
for (const panel of row.panels) {
// make sure y is adjusted (in case row moved while collapsed)
// console.log('yDiff', yDiff);
panel.gridPos.y -= yDiff;
@@ -746,7 +746,7 @@ export class DashboardModel {
return;
}
let rowPanels = this.getRowPanels(rowIndex);
const rowPanels = this.getRowPanels(rowIndex);
// remove panels
_.pull(this.panels, ...rowPanels);
@@ -762,10 +762,10 @@ export class DashboardModel {
* Will return all panels after rowIndex until it encounters another row
*/
getRowPanels(rowIndex: number): PanelModel[] {
let rowPanels = [];
const rowPanels = [];
for (let index = rowIndex + 1; index < this.panels.length; index++) {
let panel = this.panels[index];
const panel = this.panels[index];
// break when encountering another row
if (panel.type === 'row') {
@@ -806,10 +806,10 @@ export class DashboardModel {
}
getNextQueryLetter(panel) {
var letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
return _.find(letters, function(refId) {
return _.every(panel.targets, function(other) {
return _.find(letters, refId => {
return _.every(panel.targets, other => {
return other.refId !== refId;
});
});
@@ -824,7 +824,7 @@ export class DashboardModel {
}
private updateSchema(old) {
let migrator = new DashboardMigrator(this);
const migrator = new DashboardMigrator(this);
migrator.updateSchema(old);
}
@@ -875,12 +875,20 @@ export class DashboardModel {
})
);
// Consider navbar and submenu controls, padding and margin
let visibleHeight = window.innerHeight - 55 - 20;
const navbarHeight = 55;
const margin = 20;
const submenuHeight = 50;
// Remove submenu if visible
if (this.meta.submenuEnabled) {
visibleHeight -= 50;
let visibleHeight = viewHeight - navbarHeight - margin;
// Remove submenu height if visible
if (this.meta.submenuEnabled && !this.meta.kiosk) {
visibleHeight -= submenuHeight;
}
// add back navbar height
if (this.meta.kiosk === 'b') {
visibleHeight += 55;
}
const visibleGridHeight = Math.floor(visibleHeight / (GRID_CELL_HEIGHT + GRID_CELL_VMARGIN));

View File

@@ -68,18 +68,18 @@ export class AddPanelPanel extends React.Component<AddPanelPanelProps, AddPanelP
}
getCopiedPanelPlugins(filter) {
let panels = _.chain(config.panels)
const panels = _.chain(config.panels)
.filter({ hideFromList: false })
.map(item => item)
.value();
let copiedPanels = [];
let copiedPanelJson = store.get(LS_PANEL_COPY_KEY);
const copiedPanelJson = store.get(LS_PANEL_COPY_KEY);
if (copiedPanelJson) {
let copiedPanel = JSON.parse(copiedPanelJson);
let pluginInfo = _.find(panels, { id: copiedPanel.type });
const copiedPanel = JSON.parse(copiedPanelJson);
const pluginInfo = _.find(panels, { id: copiedPanel.type });
if (pluginInfo) {
let pluginCopy = _.cloneDeep(pluginInfo);
const pluginCopy = _.cloneDeep(pluginInfo);
pluginCopy.name = copiedPanel.title;
pluginCopy.sort = -1;
pluginCopy.defaults = copiedPanel;
@@ -96,7 +96,7 @@ export class AddPanelPanel extends React.Component<AddPanelPanelProps, AddPanelP
const dashboard = this.props.dashboard;
const { gridPos } = this.props.panel;
var newPanel: any = {
const newPanel: any = {
type: panelPluginInfo.id,
title: 'Panel Title',
gridPos: { x: gridPos.x, y: gridPos.y, w: gridPos.w, h: gridPos.h },
@@ -126,7 +126,7 @@ export class AddPanelPanel extends React.Component<AddPanelPanelProps, AddPanelP
}
renderText(text: string) {
let searchWords = this.state.filter.split('');
const searchWords = this.state.filter.split('');
return <Highlighter highlightClassName="highlight-search-match" textToHighlight={text} searchWords={searchWords} />;
}
@@ -153,7 +153,7 @@ export class AddPanelPanel extends React.Component<AddPanelPanelProps, AddPanelP
filterKeyPress(evt) {
if (evt.key === 'Enter') {
let panel = _.head(this.state.panelPlugins);
const panel = _.head(this.state.panelPlugins);
if (panel) {
this.onAddPanel(panel);
}
@@ -161,7 +161,7 @@ export class AddPanelPanel extends React.Component<AddPanelPanelProps, AddPanelP
}
filterPanels(panels, filter) {
let regex = new RegExp(filter, 'i');
const regex = new RegExp(filter, 'i');
return panels.filter(panel => {
return regex.test(panel.name);
});
@@ -186,12 +186,12 @@ export class AddPanelPanel extends React.Component<AddPanelPanelProps, AddPanelP
}
render() {
let addClass = classNames({
const addClass = classNames({
'active active--panel': this.state.tab === 'Add',
'': this.state.tab === 'Copy',
});
let copyClass = classNames({
const copyClass = classNames({
'': this.state.tab === 'Add',
'active active--panel': this.state.tab === 'Copy',
});

View File

@@ -77,7 +77,7 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
this.state = { animated: false };
// subscribe to dashboard events
let dashboard = this.props.dashboard;
const dashboard = this.props.dashboard;
dashboard.on('panel-added', this.triggerForceUpdate.bind(this));
dashboard.on('panel-removed', this.triggerForceUpdate.bind(this));
dashboard.on('repeats-processed', this.triggerForceUpdate.bind(this));
@@ -91,8 +91,8 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
const layout = [];
this.panelMap = {};
for (let panel of this.props.dashboard.panels) {
let stringId = panel.id.toString();
for (const panel of this.props.dashboard.panels) {
const stringId = panel.id.toString();
this.panelMap[stringId] = panel;
if (!panel.gridPos) {
@@ -100,7 +100,7 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
continue;
}
let panelPos: any = {
const panelPos: any = {
i: stringId,
x: panel.gridPos.x,
y: panel.gridPos.y,
@@ -174,10 +174,10 @@ export class DashboardGrid extends React.Component<DashboardGridProps, any> {
const panelElements = [];
console.log('render panels');
for (let panel of this.props.dashboard.panels) {
for (const panel of this.props.dashboard.panels) {
const panelClasses = classNames({ panel: true, 'panel--fullscreen': panel.fullscreen });
panelElements.push(
<div key={panel.id.toString()} className={panelClasses}>
<div key={panel.id.toString()} className={panelClasses} id={`panel-${panel.id}`}>
<DashboardPanel panel={panel} dashboard={this.props.dashboard} panelType={panel.type} />
</div>
);

View File

@@ -94,9 +94,9 @@ export class DashboardPanel extends React.Component<Props, State> {
return;
}
let loader = getAngularLoader();
var template = '<plugin-component type="panel" class="panel-height-helper"></plugin-component>';
let scopeProps = { panel: this.props.panel, dashboard: this.props.dashboard };
const loader = getAngularLoader();
const template = '<plugin-component type="panel" class="panel-height-helper"></plugin-component>';
const scopeProps = { panel: this.props.panel, dashboard: this.props.dashboard };
this.angularPanel = loader.load(this.element, scopeProps, template);
}

View File

@@ -10,8 +10,7 @@ export interface PanelProps extends OuterProps {
data: any[];
}
export interface DataPanel extends ComponentClass<OuterProps> {
}
export interface DataPanel extends ComponentClass<OuterProps> {}
interface State {
isLoading: boolean;
@@ -20,7 +19,7 @@ interface State {
export const DataPanelWrapper = (ComposedComponent: ComponentClass<PanelProps>) => {
class Wrapper extends Component<OuterProps, State> {
public static defaultProps = {
static defaultProps = {
isVisible: true,
};
@@ -33,12 +32,12 @@ export const DataPanelWrapper = (ComposedComponent: ComponentClass<PanelProps>)
};
}
public componentDidMount() {
componentDidMount() {
console.log('data panel mount');
this.issueQueries();
}
public issueQueries = async () => {
issueQueries = async () => {
const { isVisible } = this.props;
if (!isVisible) {
@@ -49,14 +48,12 @@ export const DataPanelWrapper = (ComposedComponent: ComponentClass<PanelProps>)
await new Promise(resolve => {
setTimeout(() => {
this.setState({ isLoading: false, data: [{value: 10}] });
this.setState({ isLoading: false, data: [{ value: 10 }] });
}, 500);
});
};
public render() {
render() {
const { data, isLoading } = this.state;
console.log('data panel render');
@@ -82,4 +79,3 @@ export const DataPanelWrapper = (ComposedComponent: ComponentClass<PanelProps>)
return Wrapper;
};

View File

@@ -33,9 +33,9 @@ export class PanelHeader extends React.Component<PanelHeaderProps, any> {
};
render() {
let isFullscreen = false;
let isLoading = false;
let panelHeaderClass = classNames({ 'panel-header': true, 'grid-drag-handle': !isFullscreen });
const isFullscreen = false;
const isLoading = false;
const panelHeaderClass = classNames({ 'panel-header': true, 'grid-drag-handle': !isFullscreen });
return (
<div className={panelHeaderClass}>

View File

@@ -0,0 +1,31 @@
import angular from 'angular';
import coreModule from 'app/core/core_module';
export interface AttachedPanel {
destroy();
}
export class PanelLoader {
/** @ngInject */
constructor(private $compile, private $rootScope) {}
load(elem, panel, dashboard): AttachedPanel {
const template = '<plugin-component type="panel" class="panel-height-helper"></plugin-component>';
const panelScope = this.$rootScope.$new();
panelScope.panel = panel;
panelScope.dashboard = dashboard;
const compiledElem = this.$compile(template)(panelScope);
const rootNode = angular.element(elem);
rootNode.append(compiledElem);
return {
destroy: () => {
panelScope.$destroy();
compiledElem.remove();
},
};
}
}
coreModule.service('panelLoader', PanelLoader);

View File

@@ -21,9 +21,9 @@ export class QueriesTab extends React.Component<Props, any> {
return;
}
let loader = getAngularLoader();
var template = '<metrics-tab />';
let scopeProps = {
const loader = getAngularLoader();
const template = '<metrics-tab />';
const scopeProps = {
ctrl: {
panel: this.props.panel,
dashboard: this.props.dashboard,

View File

@@ -23,7 +23,7 @@ export class VizTypePicker extends PureComponent<Props, State> {
}
getPanelPlugins(filter) {
let panels = _.chain(config.panels)
const panels = _.chain(config.panels)
.filter({ hideFromList: false })
.map(item => item)
.value();

View File

@@ -0,0 +1,135 @@
<h3 class="dashboard-settings__header">
<a ng-click="ctrl.backToList()">Dashboard Links</a>
<span ng-show="ctrl.mode === 'new'">&gt; New</span>
<span ng-show="ctrl.mode === 'edit'">&gt; Edit</span>
</h3>
<div ng-if="ctrl.mode == 'list'">
<div ng-if="ctrl.dashboard.links.length === 0">
<div class="empty-list-cta">
<div class="empty-list-cta__title">
There are no dashboard links added yet
</div>
<a ng-click="ctrl.setupNew()" class="empty-list-cta__button btn btn-xlarge btn-success">
<i class="gicon gicon-add-link"></i>
Add Dashboard Link
</a>
<div class="grafana-info-box">
<h5>What are Dashboard Links?</h5>
<p>
Dashboard Links allow you to place links to other dashboards and web sites directly in below the dashboard header.
</p>
</div>
</div>
</div>
<div ng-if="ctrl.dashboard.links.length > 0">
<div class="page-action-bar">
<div class="page-action-bar__spacer"></div>
<a type="button" class="btn btn-success" ng-click="ctrl.setupNew()">
<i class="fa fa-plus"></i> New</a>
</div>
<table class="filter-table filter-table--hover">
<thead>
<tr>
<th>Type</th>
<th>Info</th>
<th colspan="3"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="link in ctrl.dashboard.links">
<td class="pointer" ng-click="ctrl.editLink(link)">
<i class="fa fa-fw fa-external-link"></i>
{{link.type}}
</td>
<td>
<div ng-if="link.title">
{{link.title}}
</div>
<div ng-if="!link.title && link.url">
{{link.url}}
</div>
<span ng-if="!link.title && link.tags" ng-repeat="tag in link.tags" tag-color-from-name="tag" class="label label-tag" style="margin-right: 6px">
{{tag}}
</span>
</td>
<td style="width: 1%">
<i ng-click="ctrl.moveLink($index, -1)" ng-hide="$first" class="pointer fa fa-arrow-up"></i>
</td>
<td style="width: 1%">
<i ng-click="ctrl.moveLink($index, 1)" ng-hide="$last" class="pointer fa fa-arrow-down"></i>
</td>
<td style="width: 1%">
<a ng-click="ctrl.deleteLink($index)" class="btn btn-danger btn-mini" ng-hide="annotation.builtIn">
<i class="fa fa-remove"></i>
</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div ng-if="ctrl.mode == 'edit' || ctrl.mode == 'new'">
<div class="gf-form-group">
<div class="gf-form-group">
<div class="gf-form">
<span class="gf-form-label width-8">Type</span>
<div class="gf-form-select-wrapper width-10">
<select class="gf-form-input" ng-model="ctrl.link.type" ng-options="f for f in ['dashboards','link']"></select>
</div>
</div>
<div class="gf-form" ng-show="ctrl.link.type === 'dashboards'">
<span class="gf-form-label width-8">With tags</span>
<bootstrap-tagsinput ng-model="ctrl.link.tags" tagclass="label label-tag" placeholder="add tags" style="margin-right: .25rem"></bootstrap-tagsinput>
</div>
<gf-form-switch ng-show="ctrl.link.type === 'dashboards'" class="gf-form" label="As dropdown" checked="ctrl.link.asDropdown"
switch-class="max-width-4" label-class="width-8"></gf-form-switch>
<div class="gf-form" ng-show="ctrl.link.type === 'dashboards' && ctrl.link.asDropdown">
<span class="gf-form-label width-8">Title</span>
<input type="text" ng-model="ctrl.link.title" class="gf-form-input max-width-10" ng-model-onblur>
</div>
<div ng-show="ctrl.link.type === 'link'">
<div class="gf-form">
<li class="gf-form-label width-8">Url</li>
<input type="text" ng-model="ctrl.link.url" class="gf-form-input width-20" ng-model-onblur>
</div>
<div class="gf-form">
<span class="gf-form-label width-8">Title</span>
<input type="text" ng-model="ctrl.link.title" class="gf-form-input width-20" ng-model-onblur>
</div>
<div class="gf-form">
<span class="gf-form-label width-8">Tooltip</span>
<input type="text" ng-model="ctrl.link.tooltip" class="gf-form-input width-20" placeholder="Open dashboard" ng-model-onblur>
</div>
<div class="gf-form">
<span class="gf-form-label width-8">Icon</span>
<div class="gf-form-select-wrapper width-20">
<select class="gf-form-input" ng-model="ctrl.link.icon" ng-options="k as k for (k, v) in ctrl.iconMap"></select>
</div>
</div>
</div>
</div>
<div class="gf-form-group">
<h5 class="section-heading">Include</h5>
<div>
<gf-form-switch class="gf-form" label="Time range" checked="ctrl.link.keepTime" switch-class="max-width-6" label-class="width-9"></gf-form-switch>
<gf-form-switch class="gf-form" label="Variable values" checked="ctrl.link.includeVars" switch-class="max-width-6" label-class="width-9"></gf-form-switch>
<gf-form-switch class="gf-form" label="Open in new tab" checked="ctrl.link.targetBlank" switch-class="max-width-6" label-class="width-9"></gf-form-switch>
</div>
</div>
</div>
<button class="btn btn-success" ng-if="ctrl.mode == 'new'" ng-click="ctrl.addLink()">
Add
</button>
<button class="btn btn-success" ng-if="ctrl.mode == 'edit'" ng-click="ctrl.saveLink()">
Update
</button>
</div>

View File

@@ -0,0 +1,78 @@
import angular from 'angular';
import _ from 'lodash';
export let iconMap = {
'external link': 'fa-external-link',
dashboard: 'fa-th-large',
question: 'fa-question',
info: 'fa-info',
bolt: 'fa-bolt',
doc: 'fa-file-text-o',
cloud: 'fa-cloud',
};
export class DashLinkEditorCtrl {
dashboard: any;
iconMap: any;
mode: any;
link: any;
/** @ngInject */
constructor($scope, $rootScope) {
this.iconMap = iconMap;
this.dashboard.links = this.dashboard.links || [];
this.mode = 'list';
$scope.$on('$destroy', () => {
$rootScope.appEvent('dash-links-updated');
});
}
backToList() {
this.mode = 'list';
}
setupNew() {
this.mode = 'new';
this.link = { type: 'dashboards', icon: 'external link' };
}
addLink() {
this.dashboard.links.push(this.link);
this.mode = 'list';
}
editLink(link) {
this.link = link;
this.mode = 'edit';
console.log(this.link);
}
saveLink() {
this.backToList();
}
moveLink(index, dir) {
_.move(this.dashboard.links, index, index + dir);
}
deleteLink(index) {
this.dashboard.links.splice(index, 1);
this.dashboard.updateSubmenuVisibility();
}
}
function dashLinksEditor() {
return {
restrict: 'E',
controller: DashLinkEditorCtrl,
templateUrl: 'public/app/features/dashboard/dashlinks/editor.html',
bindToController: true,
controllerAs: 'ctrl',
scope: {
dashboard: '=',
},
};
}
angular.module('grafana.directives').directive('dashLinksEditor', dashLinksEditor);

View File

@@ -0,0 +1,177 @@
import angular from 'angular';
import _ from 'lodash';
import { iconMap } from './editor';
function dashLinksContainer() {
return {
scope: {
links: '=',
},
restrict: 'E',
controller: 'DashLinksContainerCtrl',
template: '<dash-link ng-repeat="link in generatedLinks" link="link"></dash-link>',
link: () => {},
};
}
/** @ngInject */
function dashLink($compile, $sanitize, linkSrv) {
return {
restrict: 'E',
link: (scope, elem) => {
const link = scope.link;
let template =
'<div class="gf-form">' +
'<a class="pointer gf-form-label" data-placement="bottom"' +
(link.asDropdown ? ' ng-click="fillDropdown(link)" data-toggle="dropdown"' : '') +
'>' +
'<i></i> <span></span></a>';
if (link.asDropdown) {
template +=
'<ul class="dropdown-menu" role="menu">' +
'<li ng-repeat="dash in link.searchHits">' +
'<a href="{{dash.url}}" target="{{dash.target}}">{{dash.title}}</a>' +
'</li>' +
'</ul>';
}
template += '</div>';
elem.html(template);
$compile(elem.contents())(scope);
function update() {
const linkInfo = linkSrv.getAnchorInfo(link);
const anchor = elem.find('a');
const span = elem.find('span');
span.text(linkInfo.title);
if (!link.asDropdown) {
anchor.attr('href', linkInfo.href);
sanitizeAnchor();
}
anchor.attr('data-placement', 'bottom');
// tooltip
anchor.tooltip({
title: $sanitize(scope.link.tooltip),
html: true,
container: 'body',
});
}
function sanitizeAnchor() {
const anchor = elem.find('a');
const anchorSanitized = $sanitize(anchor.parent().html());
anchor.parent().html(anchorSanitized);
}
elem.find('i').attr('class', 'fa fa-fw ' + scope.link.icon);
elem.find('a').attr('target', scope.link.target);
// fix for menus on the far right
if (link.asDropdown && scope.$last) {
elem.find('.dropdown-menu').addClass('pull-right');
}
update();
scope.$on('refresh', update);
},
};
}
export class DashLinksContainerCtrl {
/** @ngInject */
constructor($scope, $rootScope, $q, backendSrv, dashboardSrv, linkSrv) {
const currentDashId = dashboardSrv.getCurrent().id;
function buildLinks(linkDef) {
if (linkDef.type === 'dashboards') {
if (!linkDef.tags) {
console.log('Dashboard link missing tag');
return $q.when([]);
}
if (linkDef.asDropdown) {
return $q.when([
{
title: linkDef.title,
tags: linkDef.tags,
keepTime: linkDef.keepTime,
includeVars: linkDef.includeVars,
target: linkDef.targetBlank ? '_blank' : '_self',
icon: 'fa fa-bars',
asDropdown: true,
},
]);
}
return $scope.searchDashboards(linkDef, 7);
}
if (linkDef.type === 'link') {
return $q.when([
{
url: linkDef.url,
title: linkDef.title,
icon: iconMap[linkDef.icon],
tooltip: linkDef.tooltip,
target: linkDef.targetBlank ? '_blank' : '_self',
keepTime: linkDef.keepTime,
includeVars: linkDef.includeVars,
},
]);
}
return $q.when([]);
}
function updateDashLinks() {
const promises = _.map($scope.links, buildLinks);
$q.all(promises).then(results => {
$scope.generatedLinks = _.flatten(results);
});
}
$scope.searchDashboards = (link, limit) => {
return backendSrv.search({ tag: link.tags, limit: limit }).then(results => {
return _.reduce(
results,
(memo, dash) => {
// do not add current dashboard
if (dash.id !== currentDashId) {
memo.push({
title: dash.title,
url: dash.url,
target: link.target === '_self' ? '' : link.target,
icon: 'fa fa-th-large',
keepTime: link.keepTime,
includeVars: link.includeVars,
});
}
return memo;
},
[]
);
});
};
$scope.fillDropdown = link => {
$scope.searchDashboards(link, 100).then(results => {
_.each(results, hit => {
hit.url = linkSrv.getLinkUrl(hit);
});
link.searchHits = results;
});
};
updateDashLinks();
$rootScope.onAppEvent('dash-links-updated', updateDashLinks, $scope);
}
}
angular.module('grafana.directives').directive('dashLinksContainer', dashLinksContainer);
angular.module('grafana.directives').directive('dashLink', dashLink);
angular.module('grafana.directives').controller('DashLinksContainerCtrl', DashLinksContainerCtrl);

View File

@@ -8,14 +8,14 @@
</a>
</div>
<div class="navbar__spacer"></div>
<div class="navbar-buttons navbar-buttons--playlist" ng-if="ctrl.playlistSrv.isPlaying">
<a class="navbar-button navbar-button--tight" ng-click="ctrl.playlistSrv.prev()"><i class="fa fa-step-backward"></i></a>
<a class="navbar-button navbar-button--tight" ng-click="ctrl.playlistSrv.stop()"><i class="fa fa-stop"></i></a>
<a class="navbar-button navbar-button--tight" ng-click="ctrl.playlistSrv.next()"><i class="fa fa-step-forward"></i></a>
</div>
<div class="navbar__spacer"></div>
<div class="navbar-buttons navbar-buttons--actions">
<button class="btn navbar-button navbar-button--add-panel" ng-show="::ctrl.dashboard.meta.canSave" bs-tooltip="'Add panel'" data-placement="bottom" ng-click="ctrl.addPanel()">
<i class="gicon gicon-add-panel"></i>
@@ -25,11 +25,11 @@
<i class="fa" ng-class="{'fa-star-o': !ctrl.dashboard.meta.isStarred, 'fa-star': ctrl.dashboard.meta.isStarred}"></i>
</button>
<button class="btn navbar-button navbar-button--share" ng-show="::ctrl.dashboard.meta.canShare" ng-click="ctrl.shareDashboard(0)" bs-tooltip="'Share dashboard'" data-placement="bottom">
<button class="btn navbar-button navbar-button--share" ng-show="::ctrl.dashboard.meta.canShare" ng-click="ctrl.shareDashboard(0)" bs-tooltip="'Share dashboard'" data-placement="bottom">
<i class="fa fa-share-square-o"></i></a>
</button>
<button class="btn navbar-button navbar-button--save" ng-show="ctrl.dashboard.meta.canSave" ng-click="ctrl.saveDashboard()" bs-tooltip="'Save dashboard <br> CTRL+S'" data-placement="bottom">
<button class="btn navbar-button navbar-button--save" ng-show="ctrl.dashboard.meta.canSave" ng-click="ctrl.saveDashboard()" bs-tooltip="'Save dashboard <br> CTRL+S'" data-placement="bottom">
<i class="fa fa-save"></i>
</button>
@@ -42,6 +42,12 @@
</button>
</div>
<div class="navbar-buttons navbar-buttons--tv">
<button class="btn navbar-button navbar-button--tv" ng-click="ctrl.toggleViewMode()" bs-tooltip="'Cycle view mode'" data-placement="bottom">
<i class="fa fa-desktop"></i>
</button>
</div>
<gf-time-picker class="gf-timepicker-nav" dashboard="ctrl.dashboard" ng-if="!ctrl.dashboard.timepicker.hidden"></gf-time-picker>
<div class="navbar-buttons navbar-buttons--close">

View File

@@ -13,7 +13,7 @@ export class DashNavCtrl {
appEvents.on('save-dashboard', this.saveDashboard.bind(this), $scope);
if (this.dashboard.meta.isSnapshot) {
var meta = this.dashboard.meta;
const meta = this.dashboard.meta;
this.titleTooltip = 'Created: &nbsp;' + moment(meta.created).calendar();
if (meta.expires) {
this.titleTooltip += '<br>Expires: &nbsp;' + moment(meta.expires).fromNow() + '<br>';
@@ -22,7 +22,7 @@ export class DashNavCtrl {
}
toggleSettings() {
let search = this.$location.search();
const search = this.$location.search();
if (search.editview) {
delete search.editview;
} else {
@@ -31,8 +31,12 @@ export class DashNavCtrl {
this.$location.search(search);
}
toggleViewMode() {
appEvents.emit('toggle-kiosk-mode');
}
close() {
let search = this.$location.search();
const search = this.$location.search();
if (search.editview) {
delete search.editview;
} else if (search.fullscreen) {
@@ -51,7 +55,7 @@ export class DashNavCtrl {
}
shareDashboard(tabIndex) {
var modalScope = this.$scope.$new();
const modalScope = this.$scope.$new();
modalScope.tabIndex = tabIndex;
modalScope.dashboard = this.dashboard;

View File

@@ -21,15 +21,15 @@ export class DashExportCtrl {
}
save() {
var blob = new Blob([angular.toJson(this.dash, true)], {
const blob = new Blob([angular.toJson(this.dash, true)], {
type: 'application/json;charset=utf-8',
});
saveAs(blob, this.dash.title + '-' + new Date().getTime() + '.json');
}
saveJson() {
var clone = this.dash;
let editScope = this.$rootScope.$new();
const clone = this.dash;
const editScope = this.$rootScope.$new();
editScope.object = clone;
editScope.enableCopy = true;

View File

@@ -12,23 +12,23 @@ export class DashboardExporter {
// this is pretty hacky and needs to be changed
dashboard.cleanUpRepeats();
var saveModel = dashboard.getSaveModelClone();
const saveModel = dashboard.getSaveModelClone();
saveModel.id = null;
// undo repeat cleanup
dashboard.processRepeats();
var inputs = [];
var requires = {};
var datasources = {};
var promises = [];
var variableLookup: any = {};
const inputs = [];
const requires = {};
const datasources = {};
const promises = [];
const variableLookup: any = {};
for (let variable of saveModel.templating.list) {
for (const variable of saveModel.templating.list) {
variableLookup[variable.name] = variable;
}
var templateizeDatasourceUsage = obj => {
const templateizeDatasourceUsage = obj => {
// ignore data source properties that contain a variable
if (obj.datasource && obj.datasource.indexOf('$') === 0) {
if (variableLookup[obj.datasource.substring(1)]) {
@@ -42,7 +42,7 @@ export class DashboardExporter {
return;
}
var refName = 'DS_' + ds.name.replace(' ', '_').toUpperCase();
const refName = 'DS_' + ds.name.replace(' ', '_').toUpperCase();
datasources[refName] = {
name: refName,
label: ds.name,
@@ -69,14 +69,14 @@ export class DashboardExporter {
}
if (panel.targets) {
for (let target of panel.targets) {
for (const target of panel.targets) {
if (target.datasource !== undefined) {
templateizeDatasourceUsage(target);
}
}
}
var panelDef = config.panels[panel.type];
const panelDef = config.panels[panel.type];
if (panelDef) {
requires['panel' + panelDef.id] = {
type: 'panel',
@@ -88,19 +88,19 @@ export class DashboardExporter {
};
// check up panel data sources
for (let panel of saveModel.panels) {
for (const panel of saveModel.panels) {
processPanel(panel);
// handle collapsed rows
if (panel.collapsed !== undefined && panel.collapsed === true && panel.panels) {
for (let rowPanel of panel.panels) {
for (const rowPanel of panel.panels) {
processPanel(rowPanel);
}
}
}
// templatize template vars
for (let variable of saveModel.templating.list) {
for (const variable of saveModel.templating.list) {
if (variable.type === 'query') {
templateizeDatasourceUsage(variable);
variable.options = [];
@@ -110,7 +110,7 @@ export class DashboardExporter {
}
// templatize annotations vars
for (let annotationDef of saveModel.annotations.list) {
for (const annotationDef of saveModel.annotations.list) {
templateizeDatasourceUsage(annotationDef);
}
@@ -129,9 +129,9 @@ export class DashboardExporter {
});
// templatize constants
for (let variable of saveModel.templating.list) {
for (const variable of saveModel.templating.list) {
if (variable.type === 'constant') {
var refName = 'VAR_' + variable.name.replace(' ', '_').toUpperCase();
const refName = 'VAR_' + variable.name.replace(' ', '_').toUpperCase();
inputs.push({
name: refName,
type: 'constant',
@@ -149,7 +149,7 @@ export class DashboardExporter {
}
// make inputs and requires a top thing
var newObj = {};
const newObj = {};
newObj['__inputs'] = inputs;
newObj['__requires'] = _.sortBy(requires, ['id']);

View File

@@ -5,9 +5,9 @@ import appEvents from 'app/core/app_events';
export class ExportDataModalCtrl {
private data: any[];
private panel: string;
asRows: Boolean = true;
asRows = true;
dateTimeFormat = 'YYYY-MM-DDTHH:mm:ssZ';
excel: false;
excel = false;
export() {
if (this.panel === 'table') {

View File

@@ -131,6 +131,7 @@ export class FolderPickerCtrl {
private loadInitialValue() {
const resetFolder = { text: this.initialTitle, value: null };
const rootFolder = { text: this.rootName, value: 0 };
this.getOptions('').then(result => {
let folder;
if (this.initialFolderId) {
@@ -150,7 +151,7 @@ export class FolderPickerCtrl {
this.folder = folder;
// if this is not the same as our initial value notify parent
if (this.folder.id !== this.initialFolderId) {
if (this.folder.value !== this.initialFolderId) {
this.onChange({ $folder: { id: this.folder.value, title: this.folder.text } });
}
});

View File

@@ -67,7 +67,7 @@ export class HistoryListCtrl {
}
revisionSelectionChanged() {
let selected = _.filter(this.revisions, { checked: true }).length;
const selected = _.filter(this.revisions, { checked: true }).length;
this.canCompare = selected === 2;
}
@@ -134,7 +134,7 @@ export class HistoryListCtrl {
.getHistoryList(this.dashboard, options)
.then(revisions => {
// set formatted dates & default values
for (let rev of revisions) {
for (const rev of revisions) {
rev.createdDateString = this.formatDate(rev.created);
rev.ageString = this.formatBasicDate(rev.created);
rev.checked = false;

View File

@@ -46,7 +46,7 @@ export class PanelModel {
this.events = new Emitter();
// copy properties from persisted model
for (var property in model) {
for (const property in model) {
this[property] = model[property];
}
@@ -58,7 +58,7 @@ export class PanelModel {
getSaveModel() {
const model: any = {};
for (var property in this) {
for (const property in this) {
if (notPersistedProperties[property] || !this.hasOwnProperty(property)) {
continue;
}

View File

@@ -0,0 +1,116 @@
import angular from 'angular';
import _ from 'lodash';
import kbn from 'app/core/utils/kbn';
export class LinkSrv {
/** @ngInject */
constructor(private templateSrv, private timeSrv) {}
getLinkUrl(link) {
const url = this.templateSrv.replace(link.url || '');
const params = {};
if (link.keepTime) {
const range = this.timeSrv.timeRangeForUrl();
params['from'] = range.from;
params['to'] = range.to;
}
if (link.includeVars) {
this.templateSrv.fillVariableValuesForUrl(params);
}
return this.addParamsToUrl(url, params);
}
addParamsToUrl(url, params) {
const paramsArray = [];
_.each(params, (value, key) => {
if (value === null) {
return;
}
if (value === true) {
paramsArray.push(key);
} else if (_.isArray(value)) {
_.each(value, instance => {
paramsArray.push(key + '=' + encodeURIComponent(instance));
});
} else {
paramsArray.push(key + '=' + encodeURIComponent(value));
}
});
if (paramsArray.length === 0) {
return url;
}
return this.appendToQueryString(url, paramsArray.join('&'));
}
appendToQueryString(url, stringToAppend) {
if (!_.isUndefined(stringToAppend) && stringToAppend !== null && stringToAppend !== '') {
const pos = url.indexOf('?');
if (pos !== -1) {
if (url.length - pos > 1) {
url += '&';
}
} else {
url += '?';
}
url += stringToAppend;
}
return url;
}
getAnchorInfo(link) {
const info: any = {};
info.href = this.getLinkUrl(link);
info.title = this.templateSrv.replace(link.title || '');
return info;
}
getPanelLinkAnchorInfo(link, scopedVars) {
const info: any = {};
if (link.type === 'absolute') {
info.target = link.targetBlank ? '_blank' : '_self';
info.href = this.templateSrv.replace(link.url || '', scopedVars);
info.title = this.templateSrv.replace(link.title || '', scopedVars);
} else if (link.url) {
info.href = link.url;
info.title = this.templateSrv.replace(link.title || '', scopedVars);
info.target = link.targetBlank ? '_blank' : '';
} else if (link.dashUri) {
info.href = 'dashboard/' + link.dashUri + '?';
info.title = this.templateSrv.replace(link.title || '', scopedVars);
info.target = link.targetBlank ? '_blank' : '';
} else {
info.title = this.templateSrv.replace(link.title || '', scopedVars);
const slug = kbn.slugifyForUrl(link.dashboard || '');
info.href = 'dashboard/db/' + slug + '?';
}
const params = {};
if (link.keepTime) {
const range = this.timeSrv.timeRangeForUrl();
params['from'] = range.from;
params['to'] = range.to;
}
if (link.includeVars) {
this.templateSrv.fillVariableValuesForUrl(params, scopedVars);
}
info.href = this.addParamsToUrl(info.href, params);
if (link.params) {
info.href = this.appendToQueryString(info.href, this.templateSrv.replace(link.params, scopedVars));
}
return info;
}
}
angular.module('grafana.services').service('linkSrv', LinkSrv);

View File

@@ -0,0 +1,51 @@
<div class="editor-row">
<h5 class="section-heading">
Drilldown / detail link<tip>These links appear in the dropdown menu in the panel menu. </tip></h5>
</h5>
<div class="gf-form-group" ng-repeat="link in panel.links">
<div class="section">
<div class="gf-form max-width-25">
<span class="gf-form-label width-7">Type</span>
<div class="gf-form-select-wrapper gf-form--grow">
<select class="gf-form-input" ng-model="link.type" ng-options="f for f in ['dashboard','absolute']"></select>
</div>
</div>
<div class="gf-form max-width-25">
<span class="gf-form-label width-7" ng-show="link.type === 'dashboard'">Dashboard</span>
<input ng-show="link.type === 'dashboard'" type="text" ng-model="link.dashboard" bs-typeahead="searchDashboards" class="gf-form-input" ng-blur="dashboardChanged(link)">
<span class="gf-form-label width-7" ng-show="link.type === 'absolute'">Url</span>
<input ng-show="link.type === 'absolute'" type="text" ng-model="link.url" class="gf-form-input max-width-14">
</div>
<div class="gf-form max-width-25">
<div class="gf-form-label width-7">Title</div>
<input type="text" ng-model="link.title" class="gf-form-input">
</div>
</div>
<div class="section">
<div class="gf-form">
<span class="gf-form-label width-10">Url params</span>
<input type="text" ng-model="link.params" class="gf-form-input width-10">
</div>
<gf-form-switch class="gf-form" label-class="width-10" label="Include time range" checked="link.keepTime"></gf-form-switch>
<gf-form-switch class="gf-form" label-class="width-10" label="Include variables" checked="link.includeVars"></gf-form-switch>
<gf-form-switch class="gf-form" label-class="width-10" label="Open in new tab " checked="link.targetBlank"></gf-form-switch>
</div>
<div class="section">
<div class="gf-form">
<button class="btn btn-inverse gf-form-btn" ng-click="deleteLink(link)"><i class="fa fa-trash"></i> Remove Link</button>
</div>
</div>
</div>
</div>
<div class="editor-row">
<button class="btn btn-inverse" ng-click="addLink()"><i class="fa fa-plus"></i> Add link</button>
</div>

View File

@@ -0,0 +1,62 @@
import angular from 'angular';
import _ from 'lodash';
import './link_srv';
function panelLinksEditor() {
return {
scope: {
panel: '=',
},
restrict: 'E',
controller: 'PanelLinksEditorCtrl',
templateUrl: 'public/app/features/dashboard/panellinks/module.html',
link: () => {},
};
}
export class PanelLinksEditorCtrl {
/** @ngInject */
constructor($scope, backendSrv) {
$scope.panel.links = $scope.panel.links || [];
$scope.addLink = () => {
$scope.panel.links.push({
type: 'dashboard',
});
};
$scope.searchDashboards = (queryStr, callback) => {
backendSrv.search({ query: queryStr }).then(hits => {
const dashboards = _.map(hits, dash => {
return dash.title;
});
callback(dashboards);
});
};
$scope.dashboardChanged = link => {
backendSrv.search({ query: link.dashboard }).then(hits => {
const dashboard = _.find(hits, { title: link.dashboard });
if (dashboard) {
if (dashboard.url) {
link.url = dashboard.url;
} else {
// To support legacy url's
link.dashUri = dashboard.uri;
}
link.title = dashboard.title;
}
});
};
$scope.deleteLink = link => {
$scope.panel.links = _.without($scope.panel.links, link);
};
}
}
angular
.module('grafana.directives')
.directive('panelLinksEditor', panelLinksEditor)
.controller('PanelLinksEditorCtrl', PanelLinksEditorCtrl);

View File

@@ -0,0 +1,47 @@
import { LinkSrv } from '../link_srv';
import _ from 'lodash';
jest.mock('angular', () => {
const AngularJSMock = require('test/mocks/angular');
return new AngularJSMock();
});
describe('linkSrv', () => {
let linkSrv;
const templateSrvMock = {};
const timeSrvMock = {};
beforeEach(() => {
linkSrv = new LinkSrv(templateSrvMock, timeSrvMock);
});
describe('when appending query strings', () => {
it('add ? to URL if not present', () => {
const url = linkSrv.appendToQueryString('http://example.com', 'foo=bar');
expect(url).toBe('http://example.com?foo=bar');
});
it('do not add & to URL if ? is present but query string is empty', () => {
const url = linkSrv.appendToQueryString('http://example.com?', 'foo=bar');
expect(url).toBe('http://example.com?foo=bar');
});
it('add & to URL if query string is present', () => {
const url = linkSrv.appendToQueryString('http://example.com?foo=bar', 'hello=world');
expect(url).toBe('http://example.com?foo=bar&hello=world');
});
it('do not change the URL if there is nothing to append', () => {
_.each(['', undefined, null], toAppend => {
const url1 = linkSrv.appendToQueryString('http://example.com', toAppend);
expect(url1).toBe('http://example.com');
const url2 = linkSrv.appendToQueryString('http://example.com?', toAppend);
expect(url2).toBe('http://example.com?');
const url3 = linkSrv.appendToQueryString('http://example.com?foo=bar', toAppend);
expect(url3).toBe('http://example.com?foo=bar');
});
});
});
});

View File

@@ -1,5 +0,0 @@
<page-header model="ctrl.navModel"></page-header>
<div class="page-container page-body">
<manage-dashboards />
</div>

View File

@@ -1,13 +1,13 @@
import { coreModule } from 'app/core/core';
var template = `
const template = `
<div class="gf-form-select-wrapper max-width-18">
<select class="gf-form-input" ng-model="panel.repeat" ng-options="f.value as f.text for f in variables" ng-change="optionChanged()">
<option value=""></option>
</div>
`;
/** @ngInject **/
/** @ngInject */
function dashRepeatOptionDirective(variableSrv) {
return {
restrict: 'E',
@@ -15,7 +15,7 @@ function dashRepeatOptionDirective(variableSrv) {
scope: {
panel: '=',
},
link: function(scope, element) {
link: (scope, element) => {
element.css({ display: 'block', width: '100%' });
scope.variables = variableSrv.variables.map(item => {
@@ -36,7 +36,7 @@ function dashRepeatOptionDirective(variableSrv) {
scope.panel.repeatDirection = 'h';
}
scope.optionChanged = function() {
scope.optionChanged = () => {
if (scope.panel.repeat) {
scope.panel.repeatDirection = 'h';
}

View File

@@ -46,7 +46,7 @@ export class SaveDashboardAsModalCtrl {
/** @ngInject */
constructor(private dashboardSrv) {
var dashboard = this.dashboardSrv.getCurrent();
const dashboard = this.dashboardSrv.getCurrent();
this.clone = dashboard.getSaveModelClone();
this.clone.id = null;
this.clone.uid = '';

View File

@@ -94,14 +94,14 @@ export class SaveDashboardModalCtrl {
return;
}
var options = {
const options = {
saveVariables: this.saveVariables,
saveTimerange: this.saveTimerange,
message: this.message,
};
var dashboard = this.dashboardSrv.getCurrent();
var saveModel = dashboard.getSaveModelClone(options);
const dashboard = this.dashboardSrv.getCurrent();
const saveModel = dashboard.getSaveModelClone(options);
this.isSaving = true;

View File

@@ -52,7 +52,7 @@ export class SaveProvisionedDashboardModalCtrl {
}
save() {
var blob = new Blob([angular.toJson(this.dash, true)], {
const blob = new Blob([angular.toJson(this.dash, true)], {
type: 'application/json;charset=utf-8',
});
saveAs(blob, this.dash.title + '-' + new Date().getTime() + '.json');

View File

@@ -109,7 +109,7 @@ export class SettingsCtrl {
const params = this.$location.search();
const url = this.$location.path();
for (let section of this.sections) {
for (const section of this.sections) {
const sectionParams = _.defaults({ editview: section.id }, params);
section.url = config.appSubUrl + url + '?' + $.param(sectionParams);
}
@@ -156,7 +156,7 @@ export class SettingsCtrl {
}
hideSettings() {
var urlParams = this.$location.search();
const urlParams = this.$location.search();
delete urlParams.editview;
setTimeout(() => {
this.$rootScope.$apply(() => {
@@ -179,8 +179,8 @@ export class SettingsCtrl {
}
deleteDashboard() {
var confirmText = '';
var text2 = this.dashboard.title;
let confirmText = '';
let text2 = this.dashboard.title;
const alerts = _.sumBy(this.dashboard.panels, panel => {
return panel.alert ? 1 : 0;

View File

@@ -11,7 +11,7 @@ export function ShareModalCtrl($scope, $rootScope, $location, $timeout, timeSrv,
};
$scope.editor = { index: $scope.tabIndex || 0 };
$scope.init = function() {
$scope.init = () => {
$scope.modeSharePanel = $scope.panel ? true : false;
$scope.tabs = [{ title: 'Link', src: 'shareLink.html' }];
@@ -34,17 +34,17 @@ export function ShareModalCtrl($scope, $rootScope, $location, $timeout, timeSrv,
$scope.buildUrl();
};
$scope.buildUrl = function() {
var baseUrl = $location.absUrl();
var queryStart = baseUrl.indexOf('?');
$scope.buildUrl = () => {
let baseUrl = $location.absUrl();
const queryStart = baseUrl.indexOf('?');
if (queryStart !== -1) {
baseUrl = baseUrl.substring(0, queryStart);
}
var params = angular.copy($location.search());
const params = angular.copy($location.search());
var range = timeSrv.timeRange();
const range = timeSrv.timeRange();
params.from = range.from.valueOf();
params.to = range.to.valueOf();
params.orgId = config.bootData.user.orgId;
@@ -72,7 +72,7 @@ export function ShareModalCtrl($scope, $rootScope, $location, $timeout, timeSrv,
$scope.shareUrl = linkSrv.addParamsToUrl(baseUrl, params);
var soloUrl = baseUrl.replace(config.appSubUrl + '/dashboard/', config.appSubUrl + '/dashboard-solo/');
let soloUrl = baseUrl.replace(config.appSubUrl + '/dashboard/', config.appSubUrl + '/dashboard-solo/');
soloUrl = soloUrl.replace(config.appSubUrl + '/d/', config.appSubUrl + '/d-solo/');
delete params.fullscreen;
delete params.edit;
@@ -90,15 +90,15 @@ export function ShareModalCtrl($scope, $rootScope, $location, $timeout, timeSrv,
// This function will try to return the proper full name of the local timezone
// Chrome does not handle the timezone offset (but phantomjs does)
$scope.getLocalTimeZone = function() {
let utcOffset = '&tz=UTC' + encodeURIComponent(moment().format('Z'));
$scope.getLocalTimeZone = () => {
const utcOffset = '&tz=UTC' + encodeURIComponent(moment().format('Z'));
// Older browser does not the internationalization API
if (!(<any>window).Intl) {
if (!(window as any).Intl) {
return utcOffset;
}
const dateFormat = (<any>window).Intl.DateTimeFormat();
const dateFormat = (window as any).Intl.DateTimeFormat();
if (!dateFormat.resolvedOptions) {
return utcOffset;
}
@@ -111,7 +111,7 @@ export function ShareModalCtrl($scope, $rootScope, $location, $timeout, timeSrv,
return '&tz=' + encodeURIComponent(options.timeZone);
};
$scope.getShareUrl = function() {
$scope.getShareUrl = () => {
return $scope.shareUrl;
};
}

View File

@@ -2,7 +2,7 @@ import angular from 'angular';
import _ from 'lodash';
export class ShareSnapshotCtrl {
/** @ngInject **/
/** @ngInject */
constructor($scope, $rootScope, $location, backendSrv, $timeout, timeSrv) {
$scope.snapshot = {
name: $scope.dashboard.title,
@@ -25,8 +25,8 @@ export class ShareSnapshotCtrl {
{ text: 'Public on the web', value: 3 },
];
$scope.init = function() {
backendSrv.get('/api/snapshot/shared-options').then(function(options) {
$scope.init = () => {
backendSrv.get('/api/snapshot/shared-options').then(options => {
$scope.externalUrl = options['externalSnapshotURL'];
$scope.sharingButtonText = options['externalSnapshotName'];
$scope.externalEnabled = options['externalEnabled'];
@@ -35,7 +35,7 @@ export class ShareSnapshotCtrl {
$scope.apiUrl = '/api/snapshots';
$scope.createSnapshot = function(external) {
$scope.createSnapshot = external => {
$scope.dashboard.snapshot = {
timestamp: new Date(),
};
@@ -49,25 +49,25 @@ export class ShareSnapshotCtrl {
$rootScope.$broadcast('refresh');
$timeout(function() {
$timeout(() => {
$scope.saveSnapshot(external);
}, $scope.snapshot.timeoutSeconds * 1000);
};
$scope.saveSnapshot = function(external) {
var dash = $scope.dashboard.getSaveModelClone();
$scope.saveSnapshot = external => {
const dash = $scope.dashboard.getSaveModelClone();
$scope.scrubDashboard(dash);
var cmdData = {
const cmdData = {
dashboard: dash,
name: dash.title,
expires: $scope.snapshot.expires,
};
var postUrl = external ? $scope.externalUrl + $scope.apiUrl : $scope.apiUrl;
const postUrl = external ? $scope.externalUrl + $scope.apiUrl : $scope.apiUrl;
backendSrv.post(postUrl, cmdData).then(
function(results) {
results => {
$scope.loading = false;
if (external) {
@@ -75,8 +75,8 @@ export class ShareSnapshotCtrl {
$scope.snapshotUrl = results.url;
$scope.saveExternalSnapshotRef(cmdData, results);
} else {
var url = $location.url();
var baseUrl = $location.absUrl();
const url = $location.url();
let baseUrl = $location.absUrl();
if (url !== '/') {
baseUrl = baseUrl.replace(url, '') + '/';
@@ -88,17 +88,17 @@ export class ShareSnapshotCtrl {
$scope.step = 2;
},
function() {
() => {
$scope.loading = false;
}
);
};
$scope.getSnapshotUrl = function() {
$scope.getSnapshotUrl = () => {
return $scope.snapshotUrl;
};
$scope.scrubDashboard = function(dash) {
$scope.scrubDashboard = dash => {
// change title
dash.title = $scope.snapshot.name;
@@ -106,7 +106,7 @@ export class ShareSnapshotCtrl {
dash.time = timeSrv.timeRange();
// remove panel queries & links
_.each(dash.panels, function(panel) {
_.each(dash.panels, panel => {
panel.targets = [];
panel.links = [];
panel.datasource = null;
@@ -114,10 +114,10 @@ export class ShareSnapshotCtrl {
// remove annotation queries
dash.annotations.list = _.chain(dash.annotations.list)
.filter(function(annotation) {
.filter(annotation => {
return annotation.enable;
})
.map(function(annotation) {
.map(annotation => {
return {
name: annotation.name,
enable: annotation.enable,
@@ -131,7 +131,7 @@ export class ShareSnapshotCtrl {
.value();
// remove template queries
_.each(dash.templating.list, function(variable) {
_.each(dash.templating.list, variable => {
variable.query = '';
variable.options = variable.current;
variable.refresh = false;
@@ -139,7 +139,7 @@ export class ShareSnapshotCtrl {
// snapshot single panel
if ($scope.modeSharePanel) {
var singlePanel = $scope.panel.getSaveModel();
const singlePanel = $scope.panel.getSaveModel();
singlePanel.gridPos.w = 24;
singlePanel.gridPos.x = 0;
singlePanel.gridPos.y = 0;
@@ -149,21 +149,21 @@ export class ShareSnapshotCtrl {
// cleanup snapshotData
delete $scope.dashboard.snapshot;
$scope.dashboard.forEachPanel(function(panel) {
$scope.dashboard.forEachPanel(panel => {
delete panel.snapshotData;
});
_.each($scope.dashboard.annotations.list, function(annotation) {
_.each($scope.dashboard.annotations.list, annotation => {
delete annotation.snapshotData;
});
};
$scope.deleteSnapshot = function() {
backendSrv.get($scope.deleteUrl).then(function() {
$scope.deleteSnapshot = () => {
backendSrv.get($scope.deleteUrl).then(() => {
$scope.step = 3;
});
};
$scope.saveExternalSnapshotRef = function(cmdData, results) {
$scope.saveExternalSnapshotRef = (cmdData, results) => {
// save external in local instance as well
cmdData.external = true;
cmdData.key = results.key;

View File

@@ -12,7 +12,7 @@ jest.mock('app/core/services/context_srv', () => ({
describe('ChangeTracker', () => {
let rootScope;
let location;
let timeout;
const timeout = () => {};
let tracker: ChangeTracker;
let dash;
let scope;

View File

@@ -1,8 +1,8 @@
import { DashboardImportCtrl } from '../dashboard_import_ctrl';
import config from '../../../core/config';
describe('DashboardImportCtrl', function() {
var ctx: any = {};
describe('DashboardImportCtrl', () => {
const ctx: any = {};
let navModelSrv;
let backendSrv;
@@ -26,8 +26,8 @@ describe('DashboardImportCtrl', function() {
ctx.ctrl = new DashboardImportCtrl(backendSrv, validationSrv, navModelSrv, {}, {});
});
describe('when uploading json', function() {
beforeEach(function() {
describe('when uploading json', () => {
beforeEach(() => {
config.datasources = {
ds: {
type: 'test-db',
@@ -46,19 +46,19 @@ describe('DashboardImportCtrl', function() {
});
});
it('should build input model', function() {
it('should build input model', () => {
expect(ctx.ctrl.inputs.length).toBe(1);
expect(ctx.ctrl.inputs[0].name).toBe('ds');
expect(ctx.ctrl.inputs[0].info).toBe('Select a Test DB data source');
});
it('should set inputValid to false', function() {
it('should set inputValid to false', () => {
expect(ctx.ctrl.inputsValid).toBe(false);
});
});
describe('when specifying grafana.com url', function() {
beforeEach(function() {
describe('when specifying grafana.com url', () => {
beforeEach(() => {
ctx.ctrl.gnetUrl = 'http://grafana.com/dashboards/123';
// setup api mock
backendSrv.get = jest.fn(() => {
@@ -69,13 +69,13 @@ describe('DashboardImportCtrl', function() {
return ctx.ctrl.checkGnetDashboard();
});
it('should call gnet api with correct dashboard id', function() {
it('should call gnet api with correct dashboard id', () => {
expect(backendSrv.get.mock.calls[0][0]).toBe('api/gnet/dashboards/123');
});
});
describe('when specifying dashboard id', function() {
beforeEach(function() {
describe('when specifying dashboard id', () => {
beforeEach(() => {
ctx.ctrl.gnetUrl = '2342';
// setup api mock
backendSrv.get = jest.fn(() => {
@@ -86,7 +86,7 @@ describe('DashboardImportCtrl', function() {
return ctx.ctrl.checkGnetDashboard();
});
it('should call gnet api with correct dashboard id', function() {
it('should call gnet api with correct dashboard id', () => {
expect(backendSrv.get.mock.calls[0][0]).toBe('api/gnet/dashboards/2342');
});
});

View File

@@ -6,14 +6,14 @@ import { expect } from 'test/lib/common';
jest.mock('app/core/services/context_srv', () => ({}));
describe('DashboardModel', function() {
describe('when creating dashboard with old schema', function() {
var model;
var graph;
var singlestat;
var table;
describe('DashboardModel', () => {
describe('when creating dashboard with old schema', () => {
let model;
let graph;
let singlestat;
let table;
beforeEach(function() {
beforeEach(() => {
model = new DashboardModel({
services: {
filter: { time: { from: 'now-1d', to: 'now' }, list: [{}] },
@@ -65,52 +65,52 @@ describe('DashboardModel', function() {
table = model.panels[2];
});
it('should have title', function() {
it('should have title', () => {
expect(model.title).toBe('No Title');
});
it('should have panel id', function() {
it('should have panel id', () => {
expect(graph.id).toBe(1);
});
it('should move time and filtering list', function() {
it('should move time and filtering list', () => {
expect(model.time.from).toBe('now-1d');
expect(model.templating.list[0].allFormat).toBe('glob');
});
it('graphite panel should change name too graph', function() {
it('graphite panel should change name too graph', () => {
expect(graph.type).toBe('graph');
});
it('single stat panel should have two thresholds', function() {
it('single stat panel should have two thresholds', () => {
expect(singlestat.thresholds).toBe('20,30');
});
it('queries without refId should get it', function() {
it('queries without refId should get it', () => {
expect(graph.targets[1].refId).toBe('B');
});
it('update legend setting', function() {
it('update legend setting', () => {
expect(graph.legend.show).toBe(true);
});
it('move aliasYAxis to series override', function() {
it('move aliasYAxis to series override', () => {
expect(graph.seriesOverrides[0].alias).toBe('test');
expect(graph.seriesOverrides[0].yaxis).toBe(2);
});
it('should move pulldowns to new schema', function() {
it('should move pulldowns to new schema', () => {
expect(model.annotations.list[1].name).toBe('old');
});
it('table panel should only have two thresholds values', function() {
it('table panel should only have two thresholds values', () => {
expect(table.styles[0].thresholds[0]).toBe('20');
expect(table.styles[0].thresholds[1]).toBe('30');
expect(table.styles[1].thresholds[0]).toBe('200');
expect(table.styles[1].thresholds[1]).toBe('300');
});
it('graph grid to yaxes options', function() {
it('graph grid to yaxes options', () => {
expect(graph.yaxes[0].min).toBe(1);
expect(graph.yaxes[0].max).toBe(10);
expect(graph.yaxes[0].format).toBe('kbyte');
@@ -126,11 +126,11 @@ describe('DashboardModel', function() {
expect(graph.y_formats).toBe(undefined);
});
it('dashboard schema version should be set to latest', function() {
it('dashboard schema version should be set to latest', () => {
expect(model.schemaVersion).toBe(16);
});
it('graph thresholds should be migrated', function() {
it('graph thresholds should be migrated', () => {
expect(graph.thresholds.length).toBe(2);
expect(graph.thresholds[0].op).toBe('gt');
expect(graph.thresholds[0].value).toBe(200);
@@ -140,29 +140,29 @@ describe('DashboardModel', function() {
});
});
describe('when migrating to the grid layout', function() {
describe('when migrating to the grid layout', () => {
let model;
beforeEach(function() {
beforeEach(() => {
model = {
rows: [],
};
});
it('should create proper grid', function() {
it('should create proper grid', () => {
model.rows = [createRow({ collapse: false, height: 8 }, [[6], [6]])];
let dashboard = new DashboardModel(model);
let panelGridPos = getGridPositions(dashboard);
let expectedGrid = [{ x: 0, y: 0, w: 12, h: 8 }, { x: 12, y: 0, w: 12, h: 8 }];
const dashboard = new DashboardModel(model);
const panelGridPos = getGridPositions(dashboard);
const expectedGrid = [{ x: 0, y: 0, w: 12, h: 8 }, { x: 12, y: 0, w: 12, h: 8 }];
expect(panelGridPos).toEqual(expectedGrid);
});
it('should add special "row" panel if row is collapsed', function() {
it('should add special "row" panel if row is collapsed', () => {
model.rows = [createRow({ collapse: true, height: 8 }, [[6], [6]]), createRow({ height: 8 }, [[12]])];
let dashboard = new DashboardModel(model);
let panelGridPos = getGridPositions(dashboard);
let expectedGrid = [
const dashboard = new DashboardModel(model);
const panelGridPos = getGridPositions(dashboard);
const expectedGrid = [
{ x: 0, y: 0, w: 24, h: 8 }, // row
{ x: 0, y: 1, w: 24, h: 8 }, // row
{ x: 0, y: 2, w: 24, h: 8 },
@@ -171,14 +171,14 @@ describe('DashboardModel', function() {
expect(panelGridPos).toEqual(expectedGrid);
});
it('should add special "row" panel if row has visible title', function() {
it('should add special "row" panel if row has visible title', () => {
model.rows = [
createRow({ showTitle: true, title: 'Row', height: 8 }, [[6], [6]]),
createRow({ height: 8 }, [[12]]),
];
let dashboard = new DashboardModel(model);
let panelGridPos = getGridPositions(dashboard);
let expectedGrid = [
const dashboard = new DashboardModel(model);
const panelGridPos = getGridPositions(dashboard);
const expectedGrid = [
{ x: 0, y: 0, w: 24, h: 8 }, // row
{ x: 0, y: 1, w: 12, h: 8 },
{ x: 12, y: 1, w: 12, h: 8 },
@@ -189,16 +189,16 @@ describe('DashboardModel', function() {
expect(panelGridPos).toEqual(expectedGrid);
});
it('should not add "row" panel if row has not visible title or not collapsed', function() {
it('should not add "row" panel if row has not visible title or not collapsed', () => {
model.rows = [
createRow({ collapse: true, height: 8 }, [[12]]),
createRow({ height: 8 }, [[12]]),
createRow({ height: 8 }, [[12], [6], [6]]),
createRow({ collapse: true, height: 8 }, [[12]]),
];
let dashboard = new DashboardModel(model);
let panelGridPos = getGridPositions(dashboard);
let expectedGrid = [
const dashboard = new DashboardModel(model);
const panelGridPos = getGridPositions(dashboard);
const expectedGrid = [
{ x: 0, y: 0, w: 24, h: 8 }, // row
{ x: 0, y: 1, w: 24, h: 8 }, // row
{ x: 0, y: 2, w: 24, h: 8 },
@@ -212,11 +212,11 @@ describe('DashboardModel', function() {
expect(panelGridPos).toEqual(expectedGrid);
});
it('should add all rows if even one collapsed or titled row is present', function() {
it('should add all rows if even one collapsed or titled row is present', () => {
model.rows = [createRow({ collapse: true, height: 8 }, [[6], [6]]), createRow({ height: 8 }, [[12]])];
let dashboard = new DashboardModel(model);
let panelGridPos = getGridPositions(dashboard);
let expectedGrid = [
const dashboard = new DashboardModel(model);
const panelGridPos = getGridPositions(dashboard);
const expectedGrid = [
{ x: 0, y: 0, w: 24, h: 8 }, // row
{ x: 0, y: 1, w: 24, h: 8 }, // row
{ x: 0, y: 2, w: 24, h: 8 },
@@ -225,14 +225,14 @@ describe('DashboardModel', function() {
expect(panelGridPos).toEqual(expectedGrid);
});
it('should properly place panels with fixed height', function() {
it('should properly place panels with fixed height', () => {
model.rows = [
createRow({ height: 6 }, [[6], [6, 3], [6, 3]]),
createRow({ height: 6 }, [[4], [4], [4, 3], [4, 3]]),
];
let dashboard = new DashboardModel(model);
let panelGridPos = getGridPositions(dashboard);
let expectedGrid = [
const dashboard = new DashboardModel(model);
const panelGridPos = getGridPositions(dashboard);
const expectedGrid = [
{ x: 0, y: 0, w: 12, h: 6 },
{ x: 12, y: 0, w: 12, h: 3 },
{ x: 12, y: 3, w: 12, h: 3 },
@@ -245,11 +245,11 @@ describe('DashboardModel', function() {
expect(panelGridPos).toEqual(expectedGrid);
});
it('should place panel to the right side of panel having bigger height', function() {
it('should place panel to the right side of panel having bigger height', () => {
model.rows = [createRow({ height: 6 }, [[4], [2, 3], [4, 6], [2, 3], [2, 3]])];
let dashboard = new DashboardModel(model);
let panelGridPos = getGridPositions(dashboard);
let expectedGrid = [
const dashboard = new DashboardModel(model);
const panelGridPos = getGridPositions(dashboard);
const expectedGrid = [
{ x: 0, y: 0, w: 8, h: 6 },
{ x: 8, y: 0, w: 4, h: 3 },
{ x: 12, y: 0, w: 8, h: 6 },
@@ -260,11 +260,11 @@ describe('DashboardModel', function() {
expect(panelGridPos).toEqual(expectedGrid);
});
it('should fill current row if it possible', function() {
it('should fill current row if it possible', () => {
model.rows = [createRow({ height: 9 }, [[4], [2, 3], [4, 6], [2, 3], [2, 3], [8, 3]])];
let dashboard = new DashboardModel(model);
let panelGridPos = getGridPositions(dashboard);
let expectedGrid = [
const dashboard = new DashboardModel(model);
const panelGridPos = getGridPositions(dashboard);
const expectedGrid = [
{ x: 0, y: 0, w: 8, h: 9 },
{ x: 8, y: 0, w: 4, h: 3 },
{ x: 12, y: 0, w: 8, h: 6 },
@@ -276,11 +276,11 @@ describe('DashboardModel', function() {
expect(panelGridPos).toEqual(expectedGrid);
});
it('should fill current row if it possible (2)', function() {
it('should fill current row if it possible (2)', () => {
model.rows = [createRow({ height: 8 }, [[4], [2, 3], [4, 6], [2, 3], [2, 3], [8, 3]])];
let dashboard = new DashboardModel(model);
let panelGridPos = getGridPositions(dashboard);
let expectedGrid = [
const dashboard = new DashboardModel(model);
const panelGridPos = getGridPositions(dashboard);
const expectedGrid = [
{ x: 0, y: 0, w: 8, h: 8 },
{ x: 8, y: 0, w: 4, h: 3 },
{ x: 12, y: 0, w: 8, h: 6 },
@@ -292,11 +292,11 @@ describe('DashboardModel', function() {
expect(panelGridPos).toEqual(expectedGrid);
});
it('should fill current row if panel height more than row height', function() {
it('should fill current row if panel height more than row height', () => {
model.rows = [createRow({ height: 6 }, [[4], [2, 3], [4, 8], [2, 3], [2, 3]])];
let dashboard = new DashboardModel(model);
let panelGridPos = getGridPositions(dashboard);
let expectedGrid = [
const dashboard = new DashboardModel(model);
const panelGridPos = getGridPositions(dashboard);
const expectedGrid = [
{ x: 0, y: 0, w: 8, h: 6 },
{ x: 8, y: 0, w: 4, h: 3 },
{ x: 12, y: 0, w: 8, h: 8 },
@@ -307,11 +307,11 @@ describe('DashboardModel', function() {
expect(panelGridPos).toEqual(expectedGrid);
});
it('should wrap panels to multiple rows', function() {
it('should wrap panels to multiple rows', () => {
model.rows = [createRow({ height: 6 }, [[6], [6], [12], [6], [3], [3]])];
let dashboard = new DashboardModel(model);
let panelGridPos = getGridPositions(dashboard);
let expectedGrid = [
const dashboard = new DashboardModel(model);
const panelGridPos = getGridPositions(dashboard);
const expectedGrid = [
{ x: 0, y: 0, w: 12, h: 6 },
{ x: 12, y: 0, w: 12, h: 6 },
{ x: 0, y: 6, w: 24, h: 6 },
@@ -323,14 +323,14 @@ describe('DashboardModel', function() {
expect(panelGridPos).toEqual(expectedGrid);
});
it('should add repeated row if repeat set', function() {
it('should add repeated row if repeat set', () => {
model.rows = [
createRow({ showTitle: true, title: 'Row', height: 8, repeat: 'server' }, [[6]]),
createRow({ height: 8 }, [[12]]),
];
let dashboard = new DashboardModel(model);
let panelGridPos = getGridPositions(dashboard);
let expectedGrid = [
const dashboard = new DashboardModel(model);
const panelGridPos = getGridPositions(dashboard);
const expectedGrid = [
{ x: 0, y: 0, w: 24, h: 8 },
{ x: 0, y: 1, w: 12, h: 8 },
{ x: 0, y: 9, w: 24, h: 8 },
@@ -344,7 +344,7 @@ describe('DashboardModel', function() {
expect(dashboard.panels[3].repeat).toBeUndefined();
});
it('should ignore repeated row', function() {
it('should ignore repeated row', () => {
model.rows = [
createRow({ showTitle: true, title: 'Row1', height: 8, repeat: 'server' }, [[6]]),
createRow(
@@ -359,24 +359,24 @@ describe('DashboardModel', function() {
),
];
let dashboard = new DashboardModel(model);
const dashboard = new DashboardModel(model);
expect(dashboard.panels[0].repeat).toBe('server');
expect(dashboard.panels.length).toBe(2);
});
it('minSpan should be twice', function() {
it('minSpan should be twice', () => {
model.rows = [createRow({ height: 8 }, [[6]])];
model.rows[0].panels[0] = { minSpan: 12 };
let dashboard = new DashboardModel(model);
const dashboard = new DashboardModel(model);
expect(dashboard.panels[0].minSpan).toBe(24);
});
it('should assign id', function() {
it('should assign id', () => {
model.rows = [createRow({ collapse: true, height: 8 }, [[6], [6]])];
model.rows[0].panels[0] = {};
let dashboard = new DashboardModel(model);
const dashboard = new DashboardModel(model);
expect(dashboard.panels[0].id).toBe(1);
});
});
@@ -384,17 +384,18 @@ describe('DashboardModel', function() {
function createRow(options, panelDescriptions: any[]) {
const PANEL_HEIGHT_STEP = GRID_CELL_HEIGHT + GRID_CELL_VMARGIN;
let { collapse, height, showTitle, title, repeat, repeatIteration } = options;
const { collapse, showTitle, title, repeat, repeatIteration } = options;
let { height } = options;
height = height * PANEL_HEIGHT_STEP;
let panels = [];
const panels = [];
_.each(panelDescriptions, panelDesc => {
let panel = { span: panelDesc[0] };
const panel = { span: panelDesc[0] };
if (panelDesc.length > 1) {
panel['height'] = panelDesc[1] * PANEL_HEIGHT_STEP;
}
panels.push(panel);
});
let row = {
const row = {
collapse,
height,
showTitle,

View File

@@ -4,54 +4,54 @@ import { PanelModel } from '../panel_model';
jest.mock('app/core/services/context_srv', () => ({}));
describe('DashboardModel', function() {
describe('when creating new dashboard model defaults only', function() {
var model;
describe('DashboardModel', () => {
describe('when creating new dashboard model defaults only', () => {
let model;
beforeEach(function() {
beforeEach(() => {
model = new DashboardModel({}, {});
});
it('should have title', function() {
it('should have title', () => {
expect(model.title).toBe('No Title');
});
it('should have meta', function() {
it('should have meta', () => {
expect(model.meta.canSave).toBe(true);
expect(model.meta.canShare).toBe(true);
});
it('should have default properties', function() {
it('should have default properties', () => {
expect(model.panels.length).toBe(0);
});
});
describe('when getting next panel id', function() {
var model;
describe('when getting next panel id', () => {
let model;
beforeEach(function() {
beforeEach(() => {
model = new DashboardModel({
panels: [{ id: 5 }],
});
});
it('should return max id + 1', function() {
it('should return max id + 1', () => {
expect(model.getNextPanelId()).toBe(6);
});
});
describe('getSaveModelClone', function() {
describe('getSaveModelClone', () => {
it('should sort keys', () => {
var model = new DashboardModel({});
var saveModel = model.getSaveModelClone();
var keys = _.keys(saveModel);
const model = new DashboardModel({});
const saveModel = model.getSaveModelClone();
const keys = _.keys(saveModel);
expect(keys[0]).toBe('annotations');
expect(keys[1]).toBe('autoUpdate');
});
it('should remove add panel panels', () => {
var model = new DashboardModel({});
const model = new DashboardModel({});
model.addPanel({
type: 'add-panel',
});
@@ -61,28 +61,28 @@ describe('DashboardModel', function() {
model.addPanel({
type: 'add-panel',
});
var saveModel = model.getSaveModelClone();
var panels = saveModel.panels;
const saveModel = model.getSaveModelClone();
const panels = saveModel.panels;
expect(panels.length).toBe(1);
});
});
describe('row and panel manipulation', function() {
var dashboard;
describe('row and panel manipulation', () => {
let dashboard;
beforeEach(function() {
beforeEach(() => {
dashboard = new DashboardModel({});
});
it('adding panel should new up panel model', function() {
it('adding panel should new up panel model', () => {
dashboard.addPanel({ type: 'test', title: 'test' });
expect(dashboard.panels[0] instanceof PanelModel).toBe(true);
});
it('duplicate panel should try to add to the right if there is space', function() {
var panel = { id: 10, gridPos: { x: 0, y: 0, w: 6, h: 2 } };
it('duplicate panel should try to add to the right if there is space', () => {
const panel = { id: 10, gridPos: { x: 0, y: 0, w: 6, h: 2 } };
dashboard.addPanel(panel);
dashboard.duplicatePanel(dashboard.panels[0]);
@@ -95,8 +95,8 @@ describe('DashboardModel', function() {
});
});
it('duplicate panel should remove repeat data', function() {
var panel = {
it('duplicate panel should remove repeat data', () => {
const panel = {
id: 10,
gridPos: { x: 0, y: 0, w: 6, h: 2 },
repeat: 'asd',
@@ -111,29 +111,29 @@ describe('DashboardModel', function() {
});
});
describe('Given editable false dashboard', function() {
var model;
describe('Given editable false dashboard', () => {
let model;
beforeEach(function() {
beforeEach(() => {
model = new DashboardModel({ editable: false });
});
it('Should set meta canEdit and canSave to false', function() {
it('Should set meta canEdit and canSave to false', () => {
expect(model.meta.canSave).toBe(false);
expect(model.meta.canEdit).toBe(false);
});
it('getSaveModelClone should remove meta', function() {
var clone = model.getSaveModelClone();
it('getSaveModelClone should remove meta', () => {
const clone = model.getSaveModelClone();
expect(clone.meta).toBe(undefined);
});
});
describe('when loading dashboard with old influxdb query schema', function() {
var model;
var target;
describe('when loading dashboard with old influxdb query schema', () => {
let model;
let target;
beforeEach(function() {
beforeEach(() => {
model = new DashboardModel({
panels: [
{
@@ -185,7 +185,7 @@ describe('DashboardModel', function() {
target = model.panels[0].targets[0];
});
it('should update query schema', function() {
it('should update query schema', () => {
expect(target.fields).toBe(undefined);
expect(target.select.length).toBe(2);
expect(target.select[0].length).toBe(4);
@@ -196,10 +196,10 @@ describe('DashboardModel', function() {
});
});
describe('when creating dashboard model with missing list for annoations or templating', function() {
var model;
describe('when creating dashboard model with missing list for annoations or templating', () => {
let model;
beforeEach(function() {
beforeEach(() => {
model = new DashboardModel({
annotations: {
enable: true,
@@ -210,54 +210,54 @@ describe('DashboardModel', function() {
});
});
it('should add empty list', function() {
it('should add empty list', () => {
expect(model.annotations.list.length).toBe(1);
expect(model.templating.list.length).toBe(0);
});
it('should add builtin annotation query', function() {
it('should add builtin annotation query', () => {
expect(model.annotations.list[0].builtIn).toBe(1);
expect(model.templating.list.length).toBe(0);
});
});
describe('Formatting epoch timestamp when timezone is set as utc', function() {
var dashboard;
describe('Formatting epoch timestamp when timezone is set as utc', () => {
let dashboard;
beforeEach(function() {
beforeEach(() => {
dashboard = new DashboardModel({ timezone: 'utc' });
});
it('Should format timestamp with second resolution by default', function() {
it('Should format timestamp with second resolution by default', () => {
expect(dashboard.formatDate(1234567890000)).toBe('2009-02-13 23:31:30');
});
it('Should format timestamp with second resolution even if second format is passed as parameter', function() {
it('Should format timestamp with second resolution even if second format is passed as parameter', () => {
expect(dashboard.formatDate(1234567890007, 'YYYY-MM-DD HH:mm:ss')).toBe('2009-02-13 23:31:30');
});
it('Should format timestamp with millisecond resolution if format is passed as parameter', function() {
it('Should format timestamp with millisecond resolution if format is passed as parameter', () => {
expect(dashboard.formatDate(1234567890007, 'YYYY-MM-DD HH:mm:ss.SSS')).toBe('2009-02-13 23:31:30.007');
});
});
describe('updateSubmenuVisibility with empty lists', function() {
var model;
describe('updateSubmenuVisibility with empty lists', () => {
let model;
beforeEach(function() {
beforeEach(() => {
model = new DashboardModel({});
model.updateSubmenuVisibility();
});
it('should not enable submmenu', function() {
it('should not enable submmenu', () => {
expect(model.meta.submenuEnabled).toBe(false);
});
});
describe('updateSubmenuVisibility with annotation', function() {
var model;
describe('updateSubmenuVisibility with annotation', () => {
let model;
beforeEach(function() {
beforeEach(() => {
model = new DashboardModel({
annotations: {
list: [{}],
@@ -266,15 +266,15 @@ describe('DashboardModel', function() {
model.updateSubmenuVisibility();
});
it('should enable submmenu', function() {
it('should enable submmenu', () => {
expect(model.meta.submenuEnabled).toBe(true);
});
});
describe('updateSubmenuVisibility with template var', function() {
var model;
describe('updateSubmenuVisibility with template var', () => {
let model;
beforeEach(function() {
beforeEach(() => {
model = new DashboardModel({
templating: {
list: [{}],
@@ -283,15 +283,15 @@ describe('DashboardModel', function() {
model.updateSubmenuVisibility();
});
it('should enable submmenu', function() {
it('should enable submmenu', () => {
expect(model.meta.submenuEnabled).toBe(true);
});
});
describe('updateSubmenuVisibility with hidden template var', function() {
var model;
describe('updateSubmenuVisibility with hidden template var', () => {
let model;
beforeEach(function() {
beforeEach(() => {
model = new DashboardModel({
templating: {
list: [{ hide: 2 }],
@@ -300,15 +300,15 @@ describe('DashboardModel', function() {
model.updateSubmenuVisibility();
});
it('should not enable submmenu', function() {
it('should not enable submmenu', () => {
expect(model.meta.submenuEnabled).toBe(false);
});
});
describe('updateSubmenuVisibility with hidden annotation toggle', function() {
var dashboard;
describe('updateSubmenuVisibility with hidden annotation toggle', () => {
let dashboard;
beforeEach(function() {
beforeEach(() => {
dashboard = new DashboardModel({
annotations: {
list: [{ hide: true }],
@@ -317,15 +317,15 @@ describe('DashboardModel', function() {
dashboard.updateSubmenuVisibility();
});
it('should not enable submmenu', function() {
it('should not enable submmenu', () => {
expect(dashboard.meta.submenuEnabled).toBe(false);
});
});
describe('When collapsing row', function() {
var dashboard;
describe('When collapsing row', () => {
let dashboard;
beforeEach(function() {
beforeEach(() => {
dashboard = new DashboardModel({
panels: [
{ id: 1, type: 'graph', gridPos: { x: 0, y: 0, w: 24, h: 2 } },
@@ -338,36 +338,36 @@ describe('DashboardModel', function() {
dashboard.toggleRow(dashboard.panels[1]);
});
it('should remove panels and put them inside collapsed row', function() {
it('should remove panels and put them inside collapsed row', () => {
expect(dashboard.panels.length).toBe(3);
expect(dashboard.panels[1].panels.length).toBe(2);
});
describe('and when removing row and its panels', function() {
beforeEach(function() {
describe('and when removing row and its panels', () => {
beforeEach(() => {
dashboard.removeRow(dashboard.panels[1], true);
});
it('should remove row and its panels', function() {
it('should remove row and its panels', () => {
expect(dashboard.panels.length).toBe(2);
});
});
describe('and when removing only the row', function() {
beforeEach(function() {
describe('and when removing only the row', () => {
beforeEach(() => {
dashboard.removeRow(dashboard.panels[1], false);
});
it('should only remove row', function() {
it('should only remove row', () => {
expect(dashboard.panels.length).toBe(4);
});
});
});
describe('When expanding row', function() {
var dashboard;
describe('When expanding row', () => {
let dashboard;
beforeEach(function() {
beforeEach(() => {
dashboard = new DashboardModel({
panels: [
{ id: 1, type: 'graph', gridPos: { x: 0, y: 0, w: 24, h: 6 } },
@@ -387,16 +387,16 @@ describe('DashboardModel', function() {
dashboard.toggleRow(dashboard.panels[1]);
});
it('should add panels back', function() {
it('should add panels back', () => {
expect(dashboard.panels.length).toBe(5);
});
it('should add them below row in array', function() {
it('should add them below row in array', () => {
expect(dashboard.panels[2].id).toBe(3);
expect(dashboard.panels[3].id).toBe(4);
});
it('should position them below row', function() {
it('should position them below row', () => {
expect(dashboard.panels[2].gridPos).toMatchObject({
x: 0,
y: 7,
@@ -405,7 +405,7 @@ describe('DashboardModel', function() {
});
});
it('should move panels below down', function() {
it('should move panels below down', () => {
expect(dashboard.panels[4].gridPos).toMatchObject({
x: 0,
y: 9,
@@ -414,22 +414,22 @@ describe('DashboardModel', function() {
});
});
describe('and when removing row and its panels', function() {
beforeEach(function() {
describe('and when removing row and its panels', () => {
beforeEach(() => {
dashboard.removeRow(dashboard.panels[1], true);
});
it('should remove row and its panels', function() {
it('should remove row and its panels', () => {
expect(dashboard.panels.length).toBe(2);
});
});
describe('and when removing only the row', function() {
beforeEach(function() {
describe('and when removing only the row', () => {
beforeEach(() => {
dashboard.removeRow(dashboard.panels[1], false);
});
it('should only remove row', function() {
it('should only remove row', () => {
expect(dashboard.panels.length).toBe(4);
});
});
@@ -457,16 +457,16 @@ describe('DashboardModel', function() {
});
it('getSaveModelClone should return original time when saveTimerange=false', () => {
let options = { saveTimerange: false };
let saveModel = model.getSaveModelClone(options);
const options = { saveTimerange: false };
const saveModel = model.getSaveModelClone(options);
expect(saveModel.time.from).toBe('now-6h');
expect(saveModel.time.to).toBe('now');
});
it('getSaveModelClone should return updated time when saveTimerange=true', () => {
let options = { saveTimerange: true };
let saveModel = model.getSaveModelClone(options);
const options = { saveTimerange: true };
const saveModel = model.getSaveModelClone(options);
expect(saveModel.time.from).toBe('now-3h');
expect(saveModel.time.to).toBe('now-1h');
@@ -478,16 +478,16 @@ describe('DashboardModel', function() {
});
it('getSaveModelClone should return original time when saveTimerange=false', () => {
let options = { saveTimerange: false };
let saveModel = model.getSaveModelClone(options);
const options = { saveTimerange: false };
const saveModel = model.getSaveModelClone(options);
expect(saveModel.time.from).toBe('now-6h');
expect(saveModel.time.to).toBe('now');
});
it('getSaveModelClone should return updated time when saveTimerange=true', () => {
let options = { saveTimerange: true };
let saveModel = model.getSaveModelClone(options);
const options = { saveTimerange: true };
const saveModel = model.getSaveModelClone(options);
expect(saveModel.time.from).toBe('now-3h');
expect(saveModel.time.to).toBe('now-1h');
@@ -542,8 +542,8 @@ describe('DashboardModel', function() {
it('getSaveModelClone should return original variable when saveVariables=false', () => {
model.templating.list[0].current.text = 'server_002';
let options = { saveVariables: false };
let saveModel = model.getSaveModelClone(options);
const options = { saveVariables: false };
const saveModel = model.getSaveModelClone(options);
expect(saveModel.templating.list[0].current.text).toBe('server_001');
});
@@ -551,8 +551,8 @@ describe('DashboardModel', function() {
it('getSaveModelClone should return updated variable when saveVariables=true', () => {
model.templating.list[0].current.text = 'server_002';
let options = { saveVariables: true };
let saveModel = model.getSaveModelClone(options);
const options = { saveVariables: true };
const saveModel = model.getSaveModelClone(options);
expect(saveModel.templating.list[0].current.text).toBe('server_002');
});
@@ -620,8 +620,8 @@ describe('DashboardModel', function() {
it('getSaveModelClone should return original variable when saveVariables=false', () => {
model.templating.list[0].filters[0].value = 'server 1';
let options = { saveVariables: false };
let saveModel = model.getSaveModelClone(options);
const options = { saveVariables: false };
const saveModel = model.getSaveModelClone(options);
expect(saveModel.templating.list[0].filters[0].value).toBe('server 20');
});
@@ -629,8 +629,8 @@ describe('DashboardModel', function() {
it('getSaveModelClone should return updated variable when saveVariables=true', () => {
model.templating.list[0].filters[0].value = 'server 1';
let options = { saveVariables: true };
let saveModel = model.getSaveModelClone(options);
const options = { saveVariables: true };
const saveModel = model.getSaveModelClone(options);
expect(saveModel.templating.list[0].filters[0].value).toBe('server 1');
});

View File

@@ -10,7 +10,7 @@ import { DashboardExporter } from '../export/exporter';
import { DashboardModel } from '../dashboard_model';
describe('given dashboard with repeated panels', () => {
var dash, exported;
let dash, exported;
beforeEach(done => {
dash = {
@@ -89,7 +89,7 @@ describe('given dashboard with repeated panels', () => {
config.buildInfo.version = '3.0.2';
//Stubs test function calls
var datasourceSrvStub = { get: jest.fn(arg => getStub(arg)) };
const datasourceSrvStub = { get: jest.fn(arg => getStub(arg)) };
config.panels['graph'] = {
id: 'graph',
@@ -110,7 +110,7 @@ describe('given dashboard with repeated panels', () => {
};
dash = new DashboardModel(dash, {});
var exporter = new DashboardExporter(datasourceSrvStub);
const exporter = new DashboardExporter(datasourceSrvStub);
exporter.makeExportable(dash).then(clean => {
exported = clean;
done();
@@ -118,12 +118,12 @@ describe('given dashboard with repeated panels', () => {
});
it('should replace datasource refs', () => {
var panel = exported.panels[0];
const panel = exported.panels[0];
expect(panel.datasource).toBe('${DS_GFDB}');
});
it('should replace datasource refs in collapsed row', () => {
var panel = exported.panels[5].panels[0];
const panel = exported.panels[5].panels[0];
expect(panel.datasource).toBe('${DS_GFDB}');
});
@@ -145,7 +145,7 @@ describe('given dashboard with repeated panels', () => {
});
it('should add datasource to required', () => {
var require = _.find(exported.__requires, { name: 'TestDB' });
const require = _.find(exported.__requires, { name: 'TestDB' });
expect(require.name).toBe('TestDB');
expect(require.id).toBe('testdb');
expect(require.type).toBe('datasource');
@@ -153,52 +153,52 @@ describe('given dashboard with repeated panels', () => {
});
it('should not add built in datasources to required', () => {
var require = _.find(exported.__requires, { name: 'Mixed' });
const require = _.find(exported.__requires, { name: 'Mixed' });
expect(require).toBe(undefined);
});
it('should add datasources used in mixed mode', () => {
var require = _.find(exported.__requires, { name: 'OtherDB' });
const require = _.find(exported.__requires, { name: 'OtherDB' });
expect(require).not.toBe(undefined);
});
it('should add graph panel to required', () => {
var require = _.find(exported.__requires, { name: 'Graph' });
const require = _.find(exported.__requires, { name: 'Graph' });
expect(require.name).toBe('Graph');
expect(require.id).toBe('graph');
expect(require.version).toBe('1.1.0');
});
it('should add table panel to required', () => {
var require = _.find(exported.__requires, { name: 'Table' });
const require = _.find(exported.__requires, { name: 'Table' });
expect(require.name).toBe('Table');
expect(require.id).toBe('table');
expect(require.version).toBe('1.1.1');
});
it('should add heatmap panel to required', () => {
var require = _.find(exported.__requires, { name: 'Heatmap' });
const require = _.find(exported.__requires, { name: 'Heatmap' });
expect(require.name).toBe('Heatmap');
expect(require.id).toBe('heatmap');
expect(require.version).toBe('1.1.2');
});
it('should add grafana version', () => {
var require = _.find(exported.__requires, { name: 'Grafana' });
const require = _.find(exported.__requires, { name: 'Grafana' });
expect(require.type).toBe('grafana');
expect(require.id).toBe('grafana');
expect(require.version).toBe('3.0.2');
});
it('should add constant template variables as inputs', () => {
var input = _.find(exported.__inputs, { name: 'VAR_PREFIX' });
const input = _.find(exported.__inputs, { name: 'VAR_PREFIX' });
expect(input.type).toBe('constant');
expect(input.label).toBe('prefix');
expect(input.value).toBe('collectd');
});
it('should templatize constant variables', () => {
var variable = _.find(exported.templating.list, { name: 'prefix' });
const variable = _.find(exported.templating.list, { name: 'prefix' });
expect(variable.query).toBe('${VAR_PREFIX}');
expect(variable.current.text).toBe('${VAR_PREFIX}');
expect(variable.current.value).toBe('${VAR_PREFIX}');
@@ -208,7 +208,7 @@ describe('given dashboard with repeated panels', () => {
});
// Stub responses
var stubs = [];
const stubs = [];
stubs['gfdb'] = {
name: 'gfdb',
meta: { id: 'testdb', info: { version: '1.2.1' }, name: 'TestDB' },

View File

@@ -70,7 +70,7 @@ describe('HistoryListCtrl', () => {
});
it('should add a checked property to each revision', () => {
let actual = _.filter(historyListCtrl.revisions, rev => rev.hasOwnProperty('checked'));
const actual = _.filter(historyListCtrl.revisions, rev => rev.hasOwnProperty('checked'));
expect(actual.length).toBe(4);
});
@@ -78,7 +78,7 @@ describe('HistoryListCtrl', () => {
historyListCtrl.revisions[0].checked = true;
historyListCtrl.revisions[2].checked = true;
historyListCtrl.reset();
let actual = _.filter(historyListCtrl.revisions, rev => !rev.checked);
const actual = _.filter(historyListCtrl.revisions, rev => !rev.checked);
expect(actual.length).toBe(4);
});
});

View File

@@ -4,11 +4,11 @@ import { HistorySrv } from '../history/history_srv';
import { DashboardModel } from '../dashboard_model';
jest.mock('app/core/store');
describe('historySrv', function() {
describe('historySrv', () => {
const versionsResponse = versions();
const restoreResponse = restore;
let backendSrv = {
const backendSrv = {
get: jest.fn(() => Promise.resolve({})),
post: jest.fn(() => Promise.resolve({})),
};
@@ -19,42 +19,42 @@ describe('historySrv', function() {
const emptyDash = new DashboardModel({});
const historyListOpts = { limit: 10, start: 0 };
describe('getHistoryList', function() {
it('should return a versions array for the given dashboard id', function() {
describe('getHistoryList', () => {
it('should return a versions array for the given dashboard id', () => {
backendSrv.get = jest.fn(() => Promise.resolve(versionsResponse));
historySrv = new HistorySrv(backendSrv);
return historySrv.getHistoryList(dash, historyListOpts).then(function(versions) {
return historySrv.getHistoryList(dash, historyListOpts).then(versions => {
expect(versions).toEqual(versionsResponse);
});
});
it('should return an empty array when not given an id', function() {
return historySrv.getHistoryList(emptyDash, historyListOpts).then(function(versions) {
it('should return an empty array when not given an id', () => {
return historySrv.getHistoryList(emptyDash, historyListOpts).then(versions => {
expect(versions).toEqual([]);
});
});
it('should return an empty array when not given a dashboard', function() {
return historySrv.getHistoryList(null, historyListOpts).then(function(versions) {
it('should return an empty array when not given a dashboard', () => {
return historySrv.getHistoryList(null, historyListOpts).then(versions => {
expect(versions).toEqual([]);
});
});
});
describe('restoreDashboard', () => {
it('should return a success response given valid parameters', function() {
let version = 6;
it('should return a success response given valid parameters', () => {
const version = 6;
backendSrv.post = jest.fn(() => Promise.resolve(restoreResponse(version)));
historySrv = new HistorySrv(backendSrv);
return historySrv.restoreDashboard(dash, version).then(function(response) {
return historySrv.restoreDashboard(dash, version).then(response => {
expect(response).toEqual(restoreResponse(version));
});
});
it('should return an empty object when not given an id', async () => {
historySrv = new HistorySrv(backendSrv);
let rsp = await historySrv.restoreDashboard(emptyDash, 6);
const rsp = await historySrv.restoreDashboard(emptyDash, 6);
expect(rsp).toEqual({});
});
});

View File

@@ -4,11 +4,11 @@ import { expect } from 'test/lib/common';
jest.mock('app/core/services/context_srv', () => ({}));
describe('given dashboard with panel repeat', function() {
var dashboard;
describe('given dashboard with panel repeat', () => {
let dashboard;
beforeEach(function() {
let dashboardJSON = {
beforeEach(() => {
const dashboardJSON = {
panels: [
{ id: 1, type: 'row', gridPos: { x: 0, y: 0, h: 1, w: 24 } },
{ id: 2, repeat: 'apps', repeatDirection: 'h', gridPos: { x: 0, y: 1, h: 2, w: 8 } },
@@ -35,7 +35,7 @@ describe('given dashboard with panel repeat', function() {
dashboard.processRepeats();
});
it('should repeat panels when row is expanding', function() {
it('should repeat panels when row is expanding', () => {
expect(dashboard.panels.length).toBe(4);
// toggle row
@@ -55,10 +55,10 @@ describe('given dashboard with panel repeat', function() {
});
});
describe('given dashboard with panel repeat in horizontal direction', function() {
var dashboard;
describe('given dashboard with panel repeat in horizontal direction', () => {
let dashboard;
beforeEach(function() {
beforeEach(() => {
dashboard = new DashboardModel({
panels: [
{
@@ -89,22 +89,22 @@ describe('given dashboard with panel repeat in horizontal direction', function()
dashboard.processRepeats();
});
it('should repeat panel 3 times', function() {
it('should repeat panel 3 times', () => {
expect(dashboard.panels.length).toBe(3);
});
it('should mark panel repeated', function() {
it('should mark panel repeated', () => {
expect(dashboard.panels[0].repeat).toBe('apps');
expect(dashboard.panels[1].repeatPanelId).toBe(2);
});
it('should set scopedVars on panels', function() {
it('should set scopedVars on panels', () => {
expect(dashboard.panels[0].scopedVars.apps.value).toBe('se1');
expect(dashboard.panels[1].scopedVars.apps.value).toBe('se2');
expect(dashboard.panels[2].scopedVars.apps.value).toBe('se3');
});
it('should place on first row and adjust width so all fit', function() {
it('should place on first row and adjust width so all fit', () => {
expect(dashboard.panels[0].gridPos).toMatchObject({
x: 0,
y: 0,
@@ -125,23 +125,23 @@ describe('given dashboard with panel repeat in horizontal direction', function()
});
});
describe('After a second iteration', function() {
beforeEach(function() {
describe('After a second iteration', () => {
beforeEach(() => {
dashboard.panels[0].fill = 10;
dashboard.processRepeats();
});
it('reused panel should copy properties from source', function() {
it('reused panel should copy properties from source', () => {
expect(dashboard.panels[1].fill).toBe(10);
});
it('should have same panel count', function() {
it('should have same panel count', () => {
expect(dashboard.panels.length).toBe(3);
});
});
describe('After a second iteration with different variable', function() {
beforeEach(function() {
describe('After a second iteration with different variable', () => {
beforeEach(() => {
dashboard.templating.list.push({
name: 'server',
current: { text: 'se1, se2, se3', value: ['se1'] },
@@ -151,46 +151,46 @@ describe('given dashboard with panel repeat in horizontal direction', function()
dashboard.processRepeats();
});
it('should remove scopedVars value for last variable', function() {
it('should remove scopedVars value for last variable', () => {
expect(dashboard.panels[0].scopedVars.apps).toBe(undefined);
});
it('should have new variable value in scopedVars', function() {
it('should have new variable value in scopedVars', () => {
expect(dashboard.panels[0].scopedVars.server.value).toBe('se1');
});
});
describe('After a second iteration and selected values reduced', function() {
beforeEach(function() {
describe('After a second iteration and selected values reduced', () => {
beforeEach(() => {
dashboard.templating.list[0].options[1].selected = false;
dashboard.processRepeats();
});
it('should clean up repeated panel', function() {
it('should clean up repeated panel', () => {
expect(dashboard.panels.length).toBe(2);
});
});
describe('After a second iteration and panel repeat is turned off', function() {
beforeEach(function() {
describe('After a second iteration and panel repeat is turned off', () => {
beforeEach(() => {
dashboard.panels[0].repeat = null;
dashboard.processRepeats();
});
it('should clean up repeated panel', function() {
it('should clean up repeated panel', () => {
expect(dashboard.panels.length).toBe(1);
});
it('should remove scoped vars from reused panel', function() {
it('should remove scoped vars from reused panel', () => {
expect(dashboard.panels[0].scopedVars).toBe(undefined);
});
});
});
describe('given dashboard with panel repeat in vertical direction', function() {
var dashboard;
describe('given dashboard with panel repeat in vertical direction', () => {
let dashboard;
beforeEach(function() {
beforeEach(() => {
dashboard = new DashboardModel({
panels: [
{ id: 1, type: 'row', gridPos: { x: 0, y: 0, h: 1, w: 24 } },
@@ -218,7 +218,7 @@ describe('given dashboard with panel repeat in vertical direction', function() {
dashboard.processRepeats();
});
it('should place on items on top of each other and keep witdh', function() {
it('should place on items on top of each other and keep witdh', () => {
expect(dashboard.panels[0].gridPos).toMatchObject({ x: 0, y: 0, h: 1, w: 24 }); // first row
expect(dashboard.panels[1].gridPos).toMatchObject({ x: 5, y: 1, h: 2, w: 8 });
@@ -271,8 +271,8 @@ describe('given dashboard with row repeat and panel repeat in horizontal directi
});
it('should panels in self row', () => {
const panel_types = _.map(dashboard.panels, 'type');
expect(panel_types).toEqual([
const panelTypes = _.map(dashboard.panels, 'type');
expect(panelTypes).toEqual([
'row',
'graph',
'graph',
@@ -290,7 +290,7 @@ describe('given dashboard with row repeat and panel repeat in horizontal directi
]);
});
it('should be placed in their places', function() {
it('should be placed in their places', () => {
expect(dashboard.panels[0].gridPos).toMatchObject({ x: 0, y: 0, h: 1, w: 24 }); // 1st row
expect(dashboard.panels[1].gridPos).toMatchObject({ x: 0, y: 1, h: 2, w: 6 });
@@ -311,10 +311,10 @@ describe('given dashboard with row repeat and panel repeat in horizontal directi
});
});
describe('given dashboard with row repeat', function() {
describe('given dashboard with row repeat', () => {
let dashboard, dashboardJSON;
beforeEach(function() {
beforeEach(() => {
dashboardJSON = {
panels: [
{
@@ -349,12 +349,12 @@ describe('given dashboard with row repeat', function() {
dashboard.processRepeats();
});
it('should not repeat only row', function() {
const panel_types = _.map(dashboard.panels, 'type');
expect(panel_types).toEqual(['row', 'graph', 'graph', 'row', 'graph', 'graph', 'row', 'graph']);
it('should not repeat only row', () => {
const panelTypes = _.map(dashboard.panels, 'type');
expect(panelTypes).toEqual(['row', 'graph', 'graph', 'row', 'graph', 'graph', 'row', 'graph']);
});
it('should set scopedVars for each panel', function() {
it('should set scopedVars for each panel', () => {
dashboardJSON.templating.list[0].options[2].selected = true;
dashboard = new DashboardModel(dashboardJSON);
dashboard.processRepeats();
@@ -375,12 +375,12 @@ describe('given dashboard with row repeat', function() {
expect(scopedVars).toEqual(['se1', 'se1', 'se1', 'se2', 'se2', 'se2', 'se3', 'se3', 'se3']);
});
it('should repeat only configured row', function() {
it('should repeat only configured row', () => {
expect(dashboard.panels[6].id).toBe(4);
expect(dashboard.panels[7].id).toBe(5);
});
it('should repeat only row if it is collapsed', function() {
it('should repeat only row if it is collapsed', () => {
dashboardJSON.panels = [
{
id: 1,
@@ -399,13 +399,13 @@ describe('given dashboard with row repeat', function() {
dashboard = new DashboardModel(dashboardJSON);
dashboard.processRepeats();
const panel_types = _.map(dashboard.panels, 'type');
expect(panel_types).toEqual(['row', 'row', 'row', 'graph']);
const panelTypes = _.map(dashboard.panels, 'type');
expect(panelTypes).toEqual(['row', 'row', 'row', 'graph']);
expect(dashboard.panels[0].panels).toHaveLength(2);
expect(dashboard.panels[1].panels).toHaveLength(2);
});
it('should properly repeat multiple rows', function() {
it('should properly repeat multiple rows', () => {
dashboardJSON.panels = [
{
id: 1,
@@ -441,8 +441,8 @@ describe('given dashboard with row repeat', function() {
dashboard = new DashboardModel(dashboardJSON);
dashboard.processRepeats();
const panel_types = _.map(dashboard.panels, 'type');
expect(panel_types).toEqual([
const panelTypes = _.map(dashboard.panels, 'type');
expect(panelTypes).toEqual([
'row',
'graph',
'graph',
@@ -469,7 +469,7 @@ describe('given dashboard with row repeat', function() {
expect(dashboard.panels[12].scopedVars['hosts'].value).toBe('backend02');
});
it('should assign unique ids for repeated panels', function() {
it('should assign unique ids for repeated panels', () => {
dashboardJSON.panels = [
{
id: 1,
@@ -488,7 +488,7 @@ describe('given dashboard with row repeat', function() {
dashboard = new DashboardModel(dashboardJSON);
dashboard.processRepeats();
const panel_ids = _.flattenDeep(
const panelIds = _.flattenDeep(
_.map(dashboard.panels, panel => {
let ids = [];
if (panel.panels && panel.panels.length) {
@@ -498,10 +498,10 @@ describe('given dashboard with row repeat', function() {
return ids;
})
);
expect(panel_ids.length).toEqual(_.uniq(panel_ids).length);
expect(panelIds.length).toEqual(_.uniq(panelIds).length);
});
it('should place new panels in proper order', function() {
it('should place new panels in proper order', () => {
dashboardJSON.panels = [
{ id: 1, type: 'row', gridPos: { x: 0, y: 0, h: 1, w: 24 }, repeat: 'apps' },
{ id: 2, type: 'graph', gridPos: { x: 0, y: 1, h: 3, w: 12 } },
@@ -511,10 +511,10 @@ describe('given dashboard with row repeat', function() {
dashboard = new DashboardModel(dashboardJSON);
dashboard.processRepeats();
const panel_types = _.map(dashboard.panels, 'type');
expect(panel_types).toEqual(['row', 'graph', 'graph', 'graph', 'row', 'graph', 'graph', 'graph']);
const panel_y_positions = _.map(dashboard.panels, p => p.gridPos.y);
expect(panel_y_positions).toEqual([0, 1, 1, 5, 7, 8, 8, 12]);
const panelTypes = _.map(dashboard.panels, 'type');
expect(panelTypes).toEqual(['row', 'graph', 'graph', 'graph', 'row', 'graph', 'graph', 'graph']);
const panelYPositions = _.map(dashboard.panels, p => p.gridPos.y);
expect(panelYPositions).toEqual([0, 1, 1, 5, 7, 8, 8, 12]);
});
});
@@ -566,8 +566,8 @@ describe('given dashboard with row and panel repeat', () => {
});
it('should repeat row and panels for each row', () => {
const panel_types = _.map(dashboard.panels, 'type');
expect(panel_types).toEqual(['row', 'graph', 'graph', 'row', 'graph', 'graph']);
const panelTypes = _.map(dashboard.panels, 'type');
expect(panelTypes).toEqual(['row', 'graph', 'graph', 'row', 'graph', 'graph']);
});
it('should clean up old repeated panels', () => {
@@ -592,8 +592,8 @@ describe('given dashboard with row and panel repeat', () => {
dashboard = new DashboardModel(dashboardJSON);
dashboard.processRepeats();
const panel_types = _.map(dashboard.panels, 'type');
expect(panel_types).toEqual(['row', 'graph', 'graph', 'row', 'graph', 'graph']);
const panelTypes = _.map(dashboard.panels, 'type');
expect(panelTypes).toEqual(['row', 'graph', 'graph', 'row', 'graph', 'graph']);
});
it('should set scopedVars for each row', () => {
@@ -646,7 +646,7 @@ describe('given dashboard with row and panel repeat', () => {
});
});
it('should repeat panels when row is expanding', function() {
it('should repeat panels when row is expanding', () => {
dashboard = new DashboardModel(dashboardJSON);
dashboard.processRepeats();

View File

@@ -4,25 +4,25 @@ import { describe, it, expect } from 'test/lib/common';
describe('saving dashboard as', () => {
function scenario(name, panel, verify) {
describe(name, () => {
var json = {
const json = {
title: 'name',
panels: [panel],
};
var mockDashboardSrv = {
getCurrent: function() {
const mockDashboardSrv = {
getCurrent: () => {
return {
id: 5,
meta: {},
getSaveModelClone: function() {
getSaveModelClone: () => {
return json;
},
};
},
};
var ctrl = new SaveDashboardAsModalCtrl(mockDashboardSrv);
var ctx: any = {
const ctrl = new SaveDashboardAsModalCtrl(mockDashboardSrv);
const ctx: any = {
clone: ctrl.clone,
ctrl: ctrl,
panel: panel,
@@ -35,14 +35,14 @@ describe('saving dashboard as', () => {
}
scenario('default values', {}, ctx => {
var clone = ctx.clone;
const clone = ctx.clone;
expect(clone.id).toBe(null);
expect(clone.title).toBe('name Copy');
expect(clone.editable).toBe(true);
expect(clone.hideControls).toBe(false);
});
var graphPanel = {
const graphPanel = {
id: 1,
type: 'graph',
alert: { rule: 1 },

View File

@@ -1,24 +1,24 @@
import { SaveProvisionedDashboardModalCtrl } from '../save_provisioned_modal';
describe('SaveProvisionedDashboardModalCtrl', () => {
var json = {
const json = {
title: 'name',
id: 5,
};
var mockDashboardSrv = {
getCurrent: function() {
const mockDashboardSrv = {
getCurrent: () => {
return {
id: 5,
meta: {},
getSaveModelClone: function() {
getSaveModelClone: () => {
return json;
},
};
},
};
var ctrl = new SaveProvisionedDashboardModalCtrl(mockDashboardSrv);
const ctrl = new SaveProvisionedDashboardModalCtrl(mockDashboardSrv);
it('should remove id from dashboard model', () => {
expect(ctrl.dash.id).toBeUndefined();

View File

@@ -1,10 +1,10 @@
import '../shareModalCtrl';
import { ShareModalCtrl } from '../shareModalCtrl';
import config from 'app/core/config';
import { LinkSrv } from 'app/features/panellinks/link_srv';
import { LinkSrv } from 'app/features/dashboard/panellinks/link_srv';
describe('ShareModalCtrl', () => {
var ctx = <any>{
const ctx = {
timeSrv: {
timeRange: () => {
return { from: new Date(1000), to: new Date(2000) };
@@ -26,9 +26,9 @@ describe('ShareModalCtrl', () => {
templateSrv: {
fillVariableValuesForUrl: () => {},
},
};
} as any;
(<any>window).Intl.DateTimeFormat = () => {
(window as any).Intl.DateTimeFormat = () => {
return {
resolvedOptions: () => {
return { timeZone: 'UTC' };
@@ -68,8 +68,8 @@ describe('ShareModalCtrl', () => {
ctx.scope.panel = { id: 22 };
ctx.scope.init();
var base = 'http://dashboards.grafana.com/render/d-solo/abcdefghi/my-dash';
var params = '?from=1000&to=2000&orgId=1&panelId=22&width=1000&height=500&tz=UTC';
const base = 'http://dashboards.grafana.com/render/d-solo/abcdefghi/my-dash';
const params = '?from=1000&to=2000&orgId=1&panelId=22&width=1000&height=500&tz=UTC';
expect(ctx.scope.imageUrl).toContain(base + params);
});
@@ -79,8 +79,8 @@ describe('ShareModalCtrl', () => {
ctx.scope.panel = { id: 22 };
ctx.scope.init();
var base = 'http://dashboards.grafana.com/render/dashboard-solo/script/my-dash.js';
var params = '?from=1000&to=2000&orgId=1&panelId=22&width=1000&height=500&tz=UTC';
const base = 'http://dashboards.grafana.com/render/dashboard-solo/script/my-dash.js';
const params = '?from=1000&to=2000&orgId=1&panelId=22&width=1000&height=500&tz=UTC';
expect(ctx.scope.imageUrl).toContain(base + params);
});
@@ -136,7 +136,7 @@ describe('ShareModalCtrl', () => {
ctx.$location.absUrl = () => 'http://server/#!/test';
ctx.scope.options.includeTemplateVars = true;
ctx.templateSrv.fillVariableValuesForUrl = function(params) {
ctx.templateSrv.fillVariableValuesForUrl = params => {
params['var-app'] = 'mupp';
params['var-server'] = 'srv-01';
};

View File

@@ -2,53 +2,53 @@ import { TimeSrv } from '../time_srv';
import '../time_srv';
import moment from 'moment';
describe('timeSrv', function() {
var rootScope = {
describe('timeSrv', () => {
const rootScope = {
$on: jest.fn(),
onAppEvent: jest.fn(),
appEvent: jest.fn(),
};
var timer = {
const timer = {
register: jest.fn(),
cancel: jest.fn(),
cancelAll: jest.fn(),
};
var location = {
let location = {
search: jest.fn(() => ({})),
};
var timeSrv;
let timeSrv;
var _dashboard: any = {
const _dashboard: any = {
time: { from: 'now-6h', to: 'now' },
getTimezone: jest.fn(() => 'browser'),
};
beforeEach(function() {
beforeEach(() => {
timeSrv = new TimeSrv(rootScope, jest.fn(), location, timer, { isGrafanaVisibile: jest.fn() });
timeSrv.init(_dashboard);
});
describe('timeRange', function() {
it('should return unparsed when parse is false', function() {
describe('timeRange', () => {
it('should return unparsed when parse is false', () => {
timeSrv.setTime({ from: 'now', to: 'now-1h' });
var time = timeSrv.timeRange();
const time = timeSrv.timeRange();
expect(time.raw.from).toBe('now');
expect(time.raw.to).toBe('now-1h');
});
it('should return parsed when parse is true', function() {
it('should return parsed when parse is true', () => {
timeSrv.setTime({ from: 'now', to: 'now-1h' });
var time = timeSrv.timeRange();
const time = timeSrv.timeRange();
expect(moment.isMoment(time.from)).toBe(true);
expect(moment.isMoment(time.to)).toBe(true);
});
});
describe('init time from url', function() {
it('should handle relative times', function() {
describe('init time from url', () => {
it('should handle relative times', () => {
location = {
search: jest.fn(() => ({
from: 'now-2d',
@@ -58,12 +58,12 @@ describe('timeSrv', function() {
timeSrv = new TimeSrv(rootScope, jest.fn(), location, timer, { isGrafanaVisibile: jest.fn() });
timeSrv.init(_dashboard);
var time = timeSrv.timeRange();
const time = timeSrv.timeRange();
expect(time.raw.from).toBe('now-2d');
expect(time.raw.to).toBe('now');
});
it('should handle formatted dates', function() {
it('should handle formatted dates', () => {
location = {
search: jest.fn(() => ({
from: '20140410T052010',
@@ -74,12 +74,12 @@ describe('timeSrv', function() {
timeSrv = new TimeSrv(rootScope, jest.fn(), location, timer, { isGrafanaVisibile: jest.fn() });
timeSrv.init(_dashboard);
var time = timeSrv.timeRange();
const time = timeSrv.timeRange();
expect(time.from.valueOf()).toEqual(new Date('2014-04-10T05:20:10Z').getTime());
expect(time.to.valueOf()).toEqual(new Date('2014-05-20T03:10:22Z').getTime());
});
it('should handle formatted dates without time', function() {
it('should handle formatted dates without time', () => {
location = {
search: jest.fn(() => ({
from: '20140410',
@@ -90,12 +90,12 @@ describe('timeSrv', function() {
timeSrv = new TimeSrv(rootScope, jest.fn(), location, timer, { isGrafanaVisibile: jest.fn() });
timeSrv.init(_dashboard);
var time = timeSrv.timeRange();
const time = timeSrv.timeRange();
expect(time.from.valueOf()).toEqual(new Date('2014-04-10T00:00:00Z').getTime());
expect(time.to.valueOf()).toEqual(new Date('2014-05-20T00:00:00Z').getTime());
});
it('should handle epochs', function() {
it('should handle epochs', () => {
location = {
search: jest.fn(() => ({
from: '1410337646373',
@@ -106,12 +106,12 @@ describe('timeSrv', function() {
timeSrv = new TimeSrv(rootScope, jest.fn(), location, timer, { isGrafanaVisibile: jest.fn() });
timeSrv.init(_dashboard);
var time = timeSrv.timeRange();
const time = timeSrv.timeRange();
expect(time.from.valueOf()).toEqual(1410337646373);
expect(time.to.valueOf()).toEqual(1410337665699);
});
it('should handle bad dates', function() {
it('should handle bad dates', () => {
location = {
search: jest.fn(() => ({
from: '20151126T00010%3C%2Fp%3E%3Cspan%20class',
@@ -128,22 +128,22 @@ describe('timeSrv', function() {
});
});
describe('setTime', function() {
it('should return disable refresh if refresh is disabled for any range', function() {
describe('setTime', () => {
it('should return disable refresh if refresh is disabled for any range', () => {
_dashboard.refresh = false;
timeSrv.setTime({ from: '2011-01-01', to: '2015-01-01' });
expect(_dashboard.refresh).toBe(false);
});
it('should restore refresh for absolute time range', function() {
it('should restore refresh for absolute time range', () => {
_dashboard.refresh = '30s';
timeSrv.setTime({ from: '2011-01-01', to: '2015-01-01' });
expect(_dashboard.refresh).toBe('30s');
});
it('should restore refresh after relative time range is set', function() {
it('should restore refresh after relative time range is set', () => {
_dashboard.refresh = '10s';
timeSrv.setTime({
from: moment([2011, 1, 1]),
@@ -154,7 +154,7 @@ describe('timeSrv', function() {
expect(_dashboard.refresh).toBe('10s');
});
it('should keep refresh after relative time range is changed and now delay exists', function() {
it('should keep refresh after relative time range is changed and now delay exists', () => {
_dashboard.refresh = '10s';
timeSrv.setTime({ from: 'now-1h', to: 'now-10s' });
expect(_dashboard.refresh).toBe('10s');

View File

@@ -4,12 +4,12 @@ import config from 'app/core/config';
import { DashboardViewState } from '../view_state_srv';
describe('when updating view state', () => {
let location = {
const location = {
replace: jest.fn(),
search: jest.fn(),
};
let $scope = {
const $scope = {
onAppEvent: jest.fn(() => {}),
dashboard: {
meta: {},
@@ -17,7 +17,6 @@ describe('when updating view state', () => {
},
};
let $rootScope = {};
let viewState;
beforeEach(() => {
@@ -33,11 +32,11 @@ describe('when updating view state', () => {
location.search = jest.fn(() => {
return { fullscreen: true, edit: true, panelId: 1 };
});
viewState = new DashboardViewState($scope, location, {}, $rootScope);
viewState = new DashboardViewState($scope, location, {});
});
it('should update querystring and view state', () => {
var updateState = { fullscreen: true, edit: true, panelId: 1 };
const updateState = { fullscreen: true, edit: true, panelId: 1 };
viewState.update(updateState);
@@ -55,7 +54,7 @@ describe('when updating view state', () => {
describe('to fullscreen false', () => {
beforeEach(() => {
viewState = new DashboardViewState($scope, location, {}, $rootScope);
viewState = new DashboardViewState($scope, location, {});
});
it('should remove params from query string', () => {
viewState.update({ fullscreen: true, panelId: 1, edit: true });

View File

@@ -21,7 +21,7 @@ export class SubmenuCtrl {
}
openEditView(editview) {
var search = _.extend(this.$location.search(), { editview: editview });
const search = _.extend(this.$location.search(), { editview: editview });
this.$location.search(search);
}
}

View File

@@ -13,7 +13,7 @@ export class TimeSrv {
timeAtLoad: any;
private autoRefreshBlocked: boolean;
/** @ngInject **/
/** @ngInject */
constructor(private $rootScope, private $timeout, private $location, private timer, private contextSrv) {
// default time
this.time = { from: '6h', to: 'now' };
@@ -69,7 +69,7 @@ export class TimeSrv {
}
if (!isNaN(value)) {
var epoch = parseInt(value);
const epoch = parseInt(value, 10);
return moment.utc(epoch);
}
@@ -77,7 +77,7 @@ export class TimeSrv {
}
private initTimeFromUrl() {
var params = this.$location.search();
const params = this.$location.search();
if (params.from) {
this.time.from = this.parseUrlParam(params.from) || this.time.from;
}
@@ -90,8 +90,8 @@ export class TimeSrv {
}
private routeUpdated() {
var params = this.$location.search();
var urlRange = this.timeRangeForUrl();
const params = this.$location.search();
const urlRange = this.timeRangeForUrl();
// check if url has time range
if (params.from && params.to) {
// is it different from what our current time range?
@@ -113,7 +113,7 @@ export class TimeSrv {
this.dashboard.refresh = interval;
this.cancelNextRefresh();
if (interval) {
var intervalMs = kbn.interval_to_ms(interval);
const intervalMs = kbn.interval_to_ms(interval);
this.refreshTimer = this.timer.register(
this.$timeout(() => {
@@ -124,7 +124,7 @@ export class TimeSrv {
}
// update url
var params = this.$location.search();
const params = this.$location.search();
if (interval) {
params.refresh = interval;
this.$location.search(params);
@@ -170,8 +170,8 @@ export class TimeSrv {
// update url
if (fromRouteUpdate !== true) {
var urlRange = this.timeRangeForUrl();
var urlParams = this.$location.search();
const urlRange = this.timeRangeForUrl();
const urlParams = this.$location.search();
urlParams.from = urlRange.from;
urlParams.to = urlRange.to;
this.$location.search(urlParams);
@@ -182,7 +182,7 @@ export class TimeSrv {
}
timeRangeForUrl() {
var range = this.timeRange().raw;
const range = this.timeRange().raw;
if (moment.isMoment(range.from)) {
range.from = range.from.valueOf().toString();
@@ -196,12 +196,12 @@ export class TimeSrv {
timeRange() {
// make copies if they are moment (do not want to return out internal moment, because they are mutable!)
var raw = {
const raw = {
from: moment.isMoment(this.time.from) ? moment(this.time.from) : this.time.from,
to: moment.isMoment(this.time.to) ? moment(this.time.to) : this.time.to,
};
var timezone = this.dashboard && this.dashboard.getTimezone();
const timezone = this.dashboard && this.dashboard.getTimezone();
return {
from: dateMath.parse(raw.from, false, timezone),
@@ -211,16 +211,16 @@ export class TimeSrv {
}
zoomOut(e, factor) {
var range = this.timeRange();
const range = this.timeRange();
var timespan = range.to.valueOf() - range.from.valueOf();
var center = range.to.valueOf() - timespan / 2;
const timespan = range.to.valueOf() - range.from.valueOf();
const center = range.to.valueOf() - timespan / 2;
var to = center + timespan * factor / 2;
var from = center - timespan * factor / 2;
let to = center + timespan * factor / 2;
let from = center - timespan * factor / 2;
if (to > Date.now() && range.to <= Date.now()) {
var offset = to - Date.now();
const offset = to - Date.now();
from = from - offset;
to = Date.now();
}

View File

@@ -5,10 +5,10 @@ export function inputDateDirective() {
return {
restrict: 'A',
require: 'ngModel',
link: function($scope, $elem, attrs, ngModel) {
var format = 'YYYY-MM-DD HH:mm:ss';
link: ($scope, $elem, attrs, ngModel) => {
const format = 'YYYY-MM-DD HH:mm:ss';
var fromUser = function(text) {
const fromUser = text => {
if (text.indexOf('now') !== -1) {
if (!dateMath.isValid(text)) {
ngModel.$setValidity('error', false);
@@ -18,7 +18,7 @@ export function inputDateDirective() {
return text;
}
var parsed;
let parsed;
if ($scope.ctrl.isUtc) {
parsed = moment.utc(text, format);
} else {
@@ -34,7 +34,7 @@ export function inputDateDirective() {
return parsed;
};
var toUser = function(currentValue) {
const toUser = currentValue => {
if (moment.isMoment(currentValue)) {
return currentValue.format(format);
} else {

View File

@@ -1,18 +1,8 @@
<div class="navbar-buttons navbar-buttons--zoom">
<button class="btn navbar-button navbar-button--tight" ng-click='ctrl.move(-1)'>
<div class="navbar-buttons">
<button class="btn navbar-button navbar-button--tight" ng-click='ctrl.move(-1)' ng-if="ctrl.isAbsolute">
<i class="fa fa-chevron-left"></i>
</button>
<button class="btn navbar-button" bs-tooltip="'Time range zoom out <br> CTRL+Z'" data-placement="bottom" ng-click='ctrl.zoom(2)'>
<i class="fa fa-search-minus"></i>
</button>
<button class="btn navbar-button navbar-button--tight" ng-click='ctrl.move(1)'>
<i class="fa fa-chevron-right"></i>
</button>
</div>
<div class="navbar-buttons">
<button bs-tooltip="ctrl.tooltip" data-placement="bottom" ng-click="ctrl.openDropdown()" class="btn navbar-button gf-timepicker-nav-btn">
<i class="fa fa-clock-o"></i>
<span ng-bind="ctrl.rangeString"></span>
@@ -20,7 +10,15 @@
<span ng-show="ctrl.dashboard.refresh" class="text-warning">&nbsp; Refresh every {{ctrl.dashboard.refresh}}</span>
</button>
<button class="btn navbar-button navbar-button--refresh" ng-click="ctrl.timeSrv.refreshDashboard()">
<button class="btn navbar-button navbar-button--tight" ng-click='ctrl.move(1)' ng-if="ctrl.isAbsolute">
<i class="fa fa-chevron-right"></i>
</button>
<button class="btn navbar-button navbar-button--zoom" bs-tooltip="'Time range zoom out <br> CTRL+Z'" data-placement="bottom" ng-click='ctrl.zoom(2)'>
<i class="fa fa-search-minus"></i>
</button>
<button class="btn navbar-button navbar-button--refresh" ng-click="ctrl.timeSrv.refreshDashboard()">
<i class="fa fa-refresh"></i>
</button>
</div>

View File

@@ -23,6 +23,7 @@ export class TimePickerCtrl {
isUtc: boolean;
firstDayOfWeek: number;
isOpen: boolean;
isAbsolute: boolean;
/** @ngInject */
constructor(private $scope, private $rootScope, private timeSrv) {
@@ -44,8 +45,8 @@ export class TimePickerCtrl {
}
onRefresh() {
var time = angular.copy(this.timeSrv.timeRange());
var timeRaw = angular.copy(time.raw);
const time = angular.copy(this.timeSrv.timeRange());
const timeRaw = angular.copy(time.raw);
if (!this.dashboard.isTimezoneUtc()) {
time.from.local();
@@ -66,6 +67,7 @@ export class TimePickerCtrl {
this.tooltip = this.dashboard.formatDate(time.from) + ' <br>to<br>';
this.tooltip += this.dashboard.formatDate(time.to);
this.timeRaw = timeRaw;
this.isAbsolute = moment.isMoment(this.timeRaw.to);
}
zoom(factor) {
@@ -73,10 +75,10 @@ export class TimePickerCtrl {
}
move(direction) {
var range = this.timeSrv.timeRange();
const range = this.timeSrv.timeRange();
var timespan = (range.to.valueOf() - range.from.valueOf()) / 2;
var to, from;
const timespan = (range.to.valueOf() - range.from.valueOf()) / 2;
let to, from;
if (direction === -1) {
to = range.to.valueOf() - timespan;
from = range.from.valueOf() - timespan;
@@ -143,7 +145,7 @@ export class TimePickerCtrl {
}
setRelativeFilter(timespan) {
var range = { from: timespan.from, to: timespan.to };
const range = { from: timespan.from, to: timespan.to };
if (this.panel.nowDelay && range.to === 'now') {
range.to = 'now-' + this.panel.nowDelay;

View File

@@ -2,7 +2,7 @@ import angular from 'angular';
import { ChangeTracker } from './change_tracker';
/** @ngInject */
export function unsavedChangesSrv($rootScope, $q, $location, $timeout, contextSrv, dashboardSrv, $window) {
export function unsavedChangesSrv(this: any, $rootScope, $q, $location, $timeout, contextSrv, dashboardSrv, $window) {
this.init = function(dashboard, scope) {
this.tracker = new ChangeTracker(dashboard, scope, 1000, $location, $window, $timeout, contextSrv, $rootScope);
return this.tracker;

View File

@@ -1,6 +1,6 @@
import coreModule from 'app/core/core_module';
var template = `
const template = `
<input type="file" id="dashupload" name="dashupload" class="hide"/>
<label class="btn btn-success" for="dashupload">
<i class="fa fa-upload"></i>
@@ -16,12 +16,12 @@ function uploadDashboardDirective(timer, alertSrv, $location) {
scope: {
onUpload: '&',
},
link: function(scope) {
link: scope => {
function file_selected(evt) {
var files = evt.target.files; // FileList object
var readerOnload = function() {
return function(e) {
var dash;
const files = evt.target.files; // FileList object
const readerOnload = () => {
return e => {
let dash;
try {
dash = JSON.parse(e.target.result);
} catch (err) {
@@ -30,20 +30,25 @@ function uploadDashboardDirective(timer, alertSrv, $location) {
return;
}
scope.$apply(function() {
scope.$apply(() => {
scope.onUpload({ dash: dash });
});
};
};
for (var i = 0, f; (f = files[i]); i++) {
var reader = new FileReader();
let i = 0;
let file = files[i];
while (file) {
const reader = new FileReader();
reader.onload = readerOnload();
reader.readAsText(f);
reader.readAsText(file);
i += 1;
file = files[i];
}
}
var wnd: any = window;
const wnd: any = window;
// Check for the various File API support.
if (wnd.File && wnd.FileReader && wnd.FileList && wnd.Blob) {
// Something

View File

@@ -37,7 +37,7 @@ export class ValidationSrv {
});
}
let deferred = this.$q.defer();
const deferred = this.$q.defer();
const promises = [];
promises.push(this.backendSrv.search({ type: hitTypes.FOLDER, folderIds: [folderId], query: name }));
@@ -54,7 +54,7 @@ export class ValidationSrv {
hits = hits.concat(res[1]);
}
for (let hit of hits) {
for (const hit of hits) {
if (nameLowerCased === hit.title.toLowerCase()) {
deferred.reject({
type: 'EXISTING',

View File

@@ -17,20 +17,20 @@ export class DashboardViewState {
/** @ngInject */
constructor($scope, private $location, private $timeout) {
var self = this;
const self = this;
self.state = {};
self.panelScopes = [];
self.$scope = $scope;
self.dashboard = $scope.dashboard;
$scope.onAppEvent('$routeUpdate', function() {
var urlState = self.getQueryStringState();
$scope.onAppEvent('$routeUpdate', () => {
const urlState = self.getQueryStringState();
if (self.needsSync(urlState)) {
self.update(urlState, true);
}
});
$scope.onAppEvent('panel-change-view', function(evt, payload) {
$scope.onAppEvent('panel-change-view', (evt, payload) => {
self.update(payload);
});
@@ -45,8 +45,8 @@ export class DashboardViewState {
}
getQueryStringState() {
var state = this.$location.search();
state.panelId = parseInt(state.panelId) || null;
const state = this.$location.search();
state.panelId = parseInt(state.panelId, 10) || null;
state.fullscreen = state.fullscreen ? true : null;
state.edit = state.edit === 'true' || state.edit === true || null;
state.editview = state.editview || null;
@@ -55,7 +55,7 @@ export class DashboardViewState {
}
serializeToUrl() {
var urlState = _.clone(this.state);
const urlState = _.clone(this.state);
urlState.fullscreen = this.state.fullscreen ? true : null;
urlState.edit = this.state.edit ? true : null;
return urlState;
@@ -108,9 +108,9 @@ export class DashboardViewState {
}
toggleCollapsedPanelRow(panelId) {
for (let panel of this.dashboard.panels) {
for (const panel of this.dashboard.panels) {
if (panel.collapsed) {
for (let rowPanel of panel.panels) {
for (const rowPanel of panel.panels) {
if (rowPanel.id === panelId) {
this.dashboard.toggleRow(panel);
return;
@@ -122,7 +122,7 @@ export class DashboardViewState {
syncState() {
if (this.dashboard.meta.fullscreen) {
var panel = this.dashboard.getPanelById(this.state.panelId);
const panel = this.dashboard.getPanelById(this.state.panelId);
if (!panel) {
return;
@@ -178,7 +178,7 @@ export class DashboardViewState {
/** @ngInject */
export function dashboardViewStateSrv($location, $timeout) {
return {
create: function($scope) {
create: $scope => {
return new DashboardViewState($scope, $location, $timeout);
},
};