Merge branch 'master' into postgres-query-builder

This commit is contained in:
Sven Klemm 2018-08-31 19:02:46 +02:00
commit 265d5daf57
183 changed files with 1048 additions and 2225 deletions

View File

@ -1,5 +1,6 @@
# 5.3.0 (unreleased)
* **Dashboard**: TV & Kiosk mode changes, new cycle view mode button in dashboard toolbar [#13025](https://github.com/grafana/grafana/pull/13025)
* **OAuth**: Gitlab OAuth with support for filter by groups [#5623](https://github.com/grafana/grafana/issues/5623), thx [@BenoitKnecht](https://github.com/BenoitKnecht)
* **Dataproxy**: Pass configured/auth headers to a Datasource [#10971](https://github.com/grafana/grafana/issues/10971), thx [@mrsiano](https://github.com/mrsiano)
* **Cleanup**: Make temp file time to live configurable [#11607](https://github.com/grafana/grafana/issues/11607), thx [@xapon](https://github.com/xapon)
@ -62,6 +63,8 @@ om/grafana/grafana/issues/12668)
### Breaking changes
* Postgres datasource no longer automatically adds time column alias when using the $__timeGroup alias. However, there's code in place which should make this change backward compatible and shouldn't create any issues.
* Kiosk mode now also hides submenu (variables)
* ?inactive url parameter no longer supported, replaced with kiosk=tv url parameter
### New experimental features

8
Gopkg.lock generated
View File

@ -427,12 +427,6 @@
revision = "1744e2970ca51c86172c8190fadad617561ed6e7"
version = "v1.0.0"
[[projects]]
branch = "master"
name = "github.com/shurcooL/sanitized_anchor_name"
packages = ["."]
revision = "86672fcb3f950f35f2e675df2240550f2a50762f"
[[projects]]
name = "github.com/smartystreets/assertions"
packages = [
@ -679,6 +673,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "cb8e7fd81f23ec987fc4d5dd9d31ae0f1164bc2f30cbea2fe86e0d97dd945beb"
inputs-digest = "81a37e747b875cf870c1b9486fa3147e704dea7db8ba86f7cb942d3ddc01d3e3"
solver-name = "gps-cdcl"
solver-version = 1

View File

@ -101,7 +101,7 @@
"build": "grunt build",
"test": "grunt test",
"test:coverage": "grunt test --coverage=true",
"lint": "tslint -c tslint.json --project tsconfig.json --type-check",
"lint": "tslint -c tslint.json --project tsconfig.json",
"jest": "jest --notify --watch",
"api-tests": "jest --notify --watch --config=tests/api/jest.js",
"precommit": "lint-staged && grunt precommit"

View File

@ -42,6 +42,8 @@ func returnOsDefault(currentOs string) string {
return "/usr/local/var/lib/grafana/plugins"
case "freebsd":
return "/var/db/grafana/plugins"
case "openbsd":
return "/var/grafana/plugins"
default: //"linux"
return "/var/lib/grafana/plugins"
}

View File

@ -173,6 +173,12 @@ export class Explore extends React.Component<any, ExploreState> {
datasource.init();
}
// Keep queries but reset edit state
const nextQueries = this.state.queries.map(q => ({
...q,
edited: false,
}));
this.setState(
{
datasource,
@ -182,6 +188,7 @@ export class Explore extends React.Component<any, ExploreState> {
supportsLogs,
supportsTable,
datasourceLoading: false,
queries: nextQueries,
},
() => datasourceError === null && this.onSubmit()
);

View File

@ -1,7 +1,7 @@
// Based on underscore.js debounce()
export default function debounce(func, wait) {
let timeout;
return function() {
return function(this: any) {
const context = this;
const args = arguments;
const later = function() {

View File

@ -1,6 +1,6 @@
// Node.closest() polyfill
if ('Element' in window && !Element.prototype.closest) {
Element.prototype.closest = function(s) {
Element.prototype.closest = function(this: any, s) {
const matches = (this.document || this.ownerDocument).querySelectorAll(s);
let el = this;
let i;

View File

@ -2,7 +2,6 @@ import { react2AngularDirective } from 'app/core/utils/react2angular';
import { PasswordStrength } from './components/PasswordStrength';
import PageHeader from './components/PageHeader/PageHeader';
import EmptyListCTA from './components/EmptyListCTA/EmptyListCTA';
import LoginBackground from './components/Login/LoginBackground';
import { SearchResult } from './components/search/SearchResult';
import { TagFilter } from './components/TagFilter/TagFilter';
import DashboardPermissions from './components/Permissions/DashboardPermissions';
@ -11,7 +10,6 @@ export function registerAngularDirectives() {
react2AngularDirective('passwordStrength', PasswordStrength, ['password']);
react2AngularDirective('pageHeader', PageHeader, ['model', 'noTabs']);
react2AngularDirective('emptyListCta', EmptyListCTA, ['model']);
react2AngularDirective('loginBackground', LoginBackground, []);
react2AngularDirective('searchResult', SearchResult, []);
react2AngularDirective('tagFilter', TagFilter, [
'tags',

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
import _ from 'lodash';
import coreModule from '../../core_module';
function typeaheadMatcher(item) {
var str = this.query;
function typeaheadMatcher(this: any, item) {
let str = this.query;
if (str === '') {
return true;
}
@ -36,7 +36,7 @@ export class FormDropdownCtrl {
startOpen: any;
debounce: number;
/** @ngInject **/
/** @ngInject */
constructor(private $scope, $element, private $sce, private templateSrv, private $q) {
this.inputElement = $element.find('input').first();
this.linkElement = $element.find('a').first();

View File

@ -50,7 +50,7 @@ export class GrafanaCtrl {
$rootScope.onAppEvent = function(name, callback, localScope) {
const unbind = $rootScope.$on(name, callback);
var callerScope = this;
let callerScope = this;
if (callerScope.$id === 1 && !localScope) {
console.log('warning rootScope onAppEvent called without localscope');
}
@ -69,18 +69,44 @@ export class GrafanaCtrl {
}
}
function setViewModeBodyClass(body, mode, sidemenuOpen: boolean) {
body.removeClass('view-mode--tv');
body.removeClass('view-mode--kiosk');
body.removeClass('view-mode--inactive');
switch (mode) {
case 'tv': {
body.removeClass('sidemenu-open');
body.addClass('view-mode--tv');
break;
}
// 1 & true for legacy states
case 1:
case true: {
body.removeClass('sidemenu-open');
body.addClass('view-mode--kiosk');
break;
}
default: {
body.toggleClass('sidemenu-open', sidemenuOpen);
}
}
}
/** @ngInject */
export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScope, $location) {
return {
restrict: 'E',
controller: GrafanaCtrl,
link: (scope, elem) => {
var sidemenuOpen;
let sidemenuOpen;
const body = $('body');
// see https://github.com/zenorocha/clipboard.js/issues/155
$.fn.modal.Constructor.prototype.enforceFocus = function() {};
$('.preloader').remove();
sidemenuOpen = scope.contextSrv.sidemenu;
body.toggleClass('sidemenu-open', sidemenuOpen);
@ -98,7 +124,7 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
});
scope.$watch(() => playlistSrv.isPlaying, function(newValue) {
elem.toggleClass('playlist-active', newValue === true);
elem.toggleClass('view-mode--playlist', newValue === true);
});
// check if we are in server side render
@ -108,7 +134,7 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
// tooltip removal fix
// manage page classes
var pageClass;
let pageClass;
scope.$on('$routeChangeSuccess', function(evt, data) {
if (pageClass) {
body.removeClass(pageClass);
@ -127,17 +153,7 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
$('#tooltip, .tooltip').remove();
// check for kiosk url param
if (data.params.kiosk) {
appEvents.emit('toggle-kiosk-mode');
}
// check for 'inactive' url param for clean looks like kiosk, but with title
if (data.params.inactive) {
body.addClass('user-activity-low');
// for some reason, with this class it looks cleanest
body.addClass('sidemenu-open');
}
setViewModeBodyClass(body, data.params.kiosk, sidemenuOpen);
// close all drops
for (const drop of Drop.drops) {
@ -146,15 +162,37 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
});
// handle kiosk mode
appEvents.on('toggle-kiosk-mode', () => {
body.toggleClass('page-kiosk-mode');
appEvents.on('toggle-kiosk-mode', options => {
const search = $location.search();
if (options && options.exit) {
search.kiosk = 1;
}
switch (search.kiosk) {
case 'tv': {
search.kiosk = 1;
appEvents.emit('alert-success', ['Press ESC to exit Kiosk mode']);
break;
}
case 1:
case true: {
delete search.kiosk;
break;
}
default: {
search.kiosk = 'tv';
}
}
$location.search(search);
setViewModeBodyClass(body, search.kiosk, sidemenuOpen);
});
// handle in active view state class
var lastActivity = new Date().getTime();
var activeUser = true;
const inActiveTimeLimit = 60 * 1000;
var sidemenuHidden = false;
let lastActivity = new Date().getTime();
let activeUser = true;
const inActiveTimeLimit = 60 * 5000;
function checkForInActiveUser() {
if (!activeUser) {
@ -167,15 +205,8 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
if (new Date().getTime() - lastActivity > inActiveTimeLimit) {
activeUser = false;
body.addClass('user-activity-low');
// hide sidemenu
if (sidemenuOpen) {
sidemenuHidden = true;
body.removeClass('sidemenu-open');
$timeout(function() {
$rootScope.$broadcast('render');
}, 100);
}
body.addClass('view-mode--inactive');
body.removeClass('sidemenu-open');
}
}
@ -183,17 +214,8 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
lastActivity = new Date().getTime();
if (!activeUser) {
activeUser = true;
body.removeClass('user-activity-low');
// restore sidemenu
if (sidemenuHidden) {
sidemenuHidden = false;
body.addClass('sidemenu-open');
appEvents.emit('toggle-inactive-mode');
$timeout(function() {
$rootScope.$broadcast('render');
}, 100);
}
body.removeClass('view-mode--inactive');
body.toggleClass('sidemenu-open', sidemenuOpen);
}
}

View File

@ -21,7 +21,7 @@ export function isObject(value: any): boolean {
* From http://stackoverflow.com/a/332429
*
*/
export function getObjectName(object: Object): string {
export function getObjectName(object: object): string {
if (object === undefined) {
return '';
}
@ -44,7 +44,7 @@ export function getObjectName(object: Object): string {
/*
* Gets type of an object. Returns "null" for null objects
*/
export function getType(object: Object): string {
export function getType(object: object): string {
if (object === null) {
return 'null';
}
@ -54,7 +54,7 @@ export function getType(object: Object): string {
/*
* Generates inline preview for a JavaScript object based on a value
*/
export function getValuePreview(object: Object, value: string): string {
export function getValuePreview(object: object, value: string): string {
const type = getType(object);
if (type === 'null' || type === 'undefined') {
@ -79,15 +79,15 @@ export function getValuePreview(object: Object, value: string): string {
/*
* Generates inline preview for a JavaScript object
*/
export function getPreview(object: string): string {
let value = '';
if (isObject(object)) {
value = getObjectName(object);
if (Array.isArray(object)) {
value += '[' + object.length + ']';
let value = '';
export function getPreview(obj: object): string {
if (isObject(obj)) {
value = getObjectName(obj);
if (Array.isArray(obj)) {
value += '[' + obj.length + ']';
}
} else {
value = getValuePreview(object, object);
value = getValuePreview(obj, obj.toString());
}
return value;
}

View File

@ -15,7 +15,7 @@ const template = `
export class LayoutSelectorCtrl {
mode: string;
/** @ngInject **/
/** @ngInject */
constructor(private $rootScope) {
this.mode = store.get('grafana.list.layout.mode') || 'grid';
}
@ -33,7 +33,7 @@ export class LayoutSelectorCtrl {
}
}
/** @ngInject **/
/** @ngInject */
export function layoutSelector() {
return {
restrict: 'E',
@ -45,14 +45,14 @@ export function layoutSelector() {
};
}
/** @ngInject **/
/** @ngInject */
export function layoutMode($rootScope) {
return {
restrict: 'A',
scope: {},
link: function(scope, elem) {
const layout = store.get('grafana.list.layout.mode') || 'grid';
var className = 'card-list-layout-' + layout;
let className = 'card-list-layout-' + layout;
elem.addClass(className);
$rootScope.onAppEvent(

View File

@ -14,7 +14,7 @@ class Query {
}
export class ManageDashboardsCtrl {
public sections: any[];
sections: any[];
query: Query;
navModel: any;

View File

@ -74,7 +74,7 @@ export class QueryPart {
return;
}
var text = this.def.type + '(';
let text = this.def.type + '(';
text += this.params.join(', ');
text += ')';
this.text = text;

View File

@ -33,7 +33,7 @@ export function queryPartEditorDirective($compile, templateSrv) {
$scope.partActions = [];
function clickFuncParam(paramIndex) {
function clickFuncParam(this: any, paramIndex) {
/*jshint validthis:true */
const $link = $(this);
const $input = $link.next();
@ -53,7 +53,7 @@ export function queryPartEditorDirective($compile, templateSrv) {
}
}
function inputBlur(paramIndex) {
function inputBlur(this: any, paramIndex) {
/*jshint validthis:true */
const $input = $(this);
const $link = $input.prev();
@ -72,14 +72,14 @@ export function queryPartEditorDirective($compile, templateSrv) {
$link.show();
}
function inputKeyPress(paramIndex, e) {
function inputKeyPress(this: any, paramIndex, e) {
/*jshint validthis:true */
if (e.which === 13) {
inputBlur.call(this, paramIndex);
}
}
function inputKeyDown() {
function inputKeyDown(this: any) {
/*jshint validthis:true */
this.style.width = (3 + this.value.length) * 8 + 'px';
}
@ -91,7 +91,7 @@ export function queryPartEditorDirective($compile, templateSrv) {
const typeaheadSource = function(query, callback) {
if (param.options) {
var options = param.options;
let options = param.options;
if (param.type === 'int') {
options = _.map(options, function(val) {
return val.toString();

View File

@ -1,7 +1,6 @@
import $ from 'jquery';
import baron from 'baron';
import coreModule from 'app/core/core_module';
import appEvents from 'app/core/app_events';
const scrollBarHTML = `
<div class="baron__track">
@ -39,43 +38,6 @@ export function geminiScrollbar() {
const scrollbar = baron(scrollParams);
let lastPos = 0;
appEvents.on(
'dash-scroll',
evt => {
if (evt.restore) {
elem[0].scrollTop = lastPos;
return;
}
lastPos = elem[0].scrollTop;
if (evt.animate) {
elem.animate({ scrollTop: evt.pos }, 500);
} else {
elem[0].scrollTop = evt.pos;
}
},
scope
);
// force updating dashboard width
appEvents.on('toggle-sidemenu', forceUpdate, scope);
appEvents.on('toggle-sidemenu-hidden', forceUpdate, scope);
appEvents.on('toggle-view-mode', forceUpdate, scope);
appEvents.on('toggle-kiosk-mode', forceUpdate, scope);
appEvents.on('toggle-inactive-mode', forceUpdate, scope);
function forceUpdate() {
scrollbar.scroll();
}
scope.$on('$routeChangeSuccess', () => {
lastPos = 0;
elem[0].scrollTop = 0;
});
scope.$on('$destroy', () => {
scrollbar.dispose();
});

View File

@ -2,7 +2,7 @@ import _ from 'lodash';
import $ from 'jquery';
import coreModule from 'app/core/core_module';
let template = `
const template = `
<div class="dropdown cascade-open">
<a ng-click="showActionsMenu()" class="query-part-name pointer dropdown-toggle" data-toggle="dropdown">{{part.label}}</a>
<span>{{part.def.wrapOpen}}</span><span class="query-part-parameters"></span><span>{{part.def.wrapClose}}</span>
@ -15,7 +15,7 @@ let template = `
/** @ngInject */
export function sqlPartEditorDirective($compile, templateSrv) {
let paramTemplate = '<input type="text" class="hide input-mini"></input>';
const paramTemplate = '<input type="text" class="hide input-mini"></input>';
return {
restrict: 'E',
@ -26,18 +26,18 @@ export function sqlPartEditorDirective($compile, templateSrv) {
debounce: '@',
},
link: function postLink($scope, elem) {
let part = $scope.part;
let partDef = part.def;
let $paramsContainer = elem.find('.query-part-parameters');
let debounceLookup = $scope.debounce;
const part = $scope.part;
const partDef = part.def;
const $paramsContainer = elem.find('.query-part-parameters');
const debounceLookup = $scope.debounce;
let cancelBlur = null;
$scope.partActions = [];
function clickFuncParam(paramIndex) {
function clickFuncParam(this: any, paramIndex) {
/*jshint validthis:true */
let $link = $(this);
let $input = $link.next();
const $link = $(this);
const $input = $link.next();
$input.val(part.params[paramIndex]);
$input.css('width', $link.width() + 16 + 'px');
@ -47,7 +47,7 @@ export function sqlPartEditorDirective($compile, templateSrv) {
$input.focus();
$input.select();
let typeahead = $input.data('typeahead');
const typeahead = $input.data('typeahead');
if (typeahead) {
$input.val('');
typeahead.lookup();
@ -62,8 +62,8 @@ export function sqlPartEditorDirective($compile, templateSrv) {
function switchToLink($input, paramIndex) {
/*jshint validthis:true */
let $link = $input.prev();
let newValue = $input.val();
const $link = $input.prev();
const newValue = $input.val();
if (newValue !== '' || part.def.params[paramIndex].optional) {
$link.html(templateSrv.highlightVariablesAsHtml(newValue));
@ -78,14 +78,14 @@ export function sqlPartEditorDirective($compile, templateSrv) {
$link.show();
}
function inputKeyPress(paramIndex, e) {
function inputKeyPress(this: any, paramIndex, e) {
/*jshint validthis:true */
if (e.which === 13) {
switchToLink($(this), paramIndex);
}
}
function inputKeyDown() {
function inputKeyDown(this: any) {
/*jshint validthis:true */
this.style.width = (3 + this.value.length) * 8 + 'px';
}
@ -95,7 +95,7 @@ export function sqlPartEditorDirective($compile, templateSrv) {
return;
}
let typeaheadSource = function(query, callback) {
const typeaheadSource = function(query, callback) {
if (param.options) {
let options = param.options;
if (param.type === 'int') {
@ -108,7 +108,7 @@ export function sqlPartEditorDirective($compile, templateSrv) {
$scope.$apply(function() {
$scope.handleEvent({ $event: { name: 'get-param-options', param: param } }).then(function(result) {
let dynamicOptions = _.map(result, function(op) {
const dynamicOptions = _.map(result, function(op) {
return op.value;
});
@ -138,10 +138,10 @@ export function sqlPartEditorDirective($compile, templateSrv) {
},
});
let typeahead = $input.data('typeahead');
const typeahead = $input.data('typeahead');
typeahead.lookup = function() {
this.query = this.$element.val() || '';
let items = this.source(this.query, $.proxy(this.process, this));
const items = this.source(this.query, $.proxy(this.process, this));
return items ? this.process(items) : items;
};
@ -170,9 +170,9 @@ export function sqlPartEditorDirective($compile, templateSrv) {
$('<span>' + partDef.separator + '</span>').appendTo($paramsContainer);
}
let paramValue = templateSrv.highlightVariablesAsHtml(part.params[index]);
let $paramLink = $('<a class="graphite-func-param-link pointer">' + paramValue + '</a>');
let $input = $(paramTemplate);
const paramValue = templateSrv.highlightVariablesAsHtml(part.params[index]);
const $paramLink = $('<a class="graphite-func-param-link pointer">' + paramValue + '</a>');
const $input = $(paramTemplate);
$paramLink.appendTo($paramsContainer);
$input.appendTo($paramsContainer);

View File

@ -9,7 +9,7 @@ function tip($compile) {
return {
restrict: 'E',
link: function(scope, elem, attrs) {
var _t =
let _t =
'<i class="grafana-tip fa fa-' +
(attrs.icon || 'question-circle') +
'" bs-tooltip="\'' +
@ -125,7 +125,7 @@ function editorCheckbox($compile, $interpolate) {
const tip = attrs.tip ? ' <tip>' + attrs.tip + '</tip>' : '';
const label = '<label for="' + scope.$id + model + '" class="checkbox-label">' + text + tip + '</label>';
var template =
let template =
'<input class="cr1" id="' +
scope.$id +
model +
@ -163,7 +163,7 @@ function gfDropdown($parse, $compile, $timeout) {
continue;
}
var li =
let li =
'<li' +
(item.submenu && item.submenu.length ? ' class="dropdown-submenu"' : '') +
'>' +

View File

@ -2,11 +2,11 @@ import $ from 'jquery';
import coreModule from '../core_module';
function getBlockNodes(nodes) {
var node = nodes[0];
let node = nodes[0];
const endNode = nodes[nodes.length - 1];
var blockNodes;
let blockNodes;
for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
for (let i = 1; node !== endNode && (node = node.nextSibling); i++) {
if (blockNodes || nodes[i] !== node) {
if (!blockNodes) {
blockNodes = $([].slice.call(nodes, 0, i));
@ -18,7 +18,7 @@ function getBlockNodes(nodes) {
return blockNodes || nodes;
}
/** @ngInject **/
/** @ngInject */
function rebuildOnChange($animate) {
return {
multiElement: true,
@ -27,7 +27,7 @@ function rebuildOnChange($animate) {
priority: 600,
restrict: 'E',
link: function(scope, elem, attrs, ctrl, transclude) {
var block, childScope, previousElements;
let block, childScope, previousElements;
function cleanUp() {
if (previousElements) {

View File

@ -69,7 +69,7 @@ function bootstrapTagsinput() {
},
});
select.on('itemAdded', function(event) {
select.on('itemAdded', event => {
if (scope.model.indexOf(event.item) === -1) {
scope.model.push(event.item);
if (scope.onTagsUpdated) {
@ -79,7 +79,7 @@ function bootstrapTagsinput() {
const tagElement = select
.next()
.children('span')
.filter(function() {
.filter(() => {
return $(this).text() === event.item;
});
setColor(event.item, tagElement);
@ -104,7 +104,7 @@ function bootstrapTagsinput() {
select.tagsinput('removeAll');
for (var i = 0; i < scope.model.length; i++) {
for (let i = 0; i < scope.model.length; i++) {
select.tagsinput('add', scope.model[i]);
}
},

View File

@ -56,7 +56,7 @@ coreModule.filter('noXml', function() {
/** @ngInject */
function interpolateTemplateVars(templateSrv) {
const filterFunc: any = function(text, scope) {
var scopedVars;
let scopedVars;
if (scope.ctrl) {
scopedVars = (scope.ctrl.panel || scope.ctrl.row).scopedVars;
} else {

View File

@ -9,10 +9,10 @@ $.fn.place_tt = (function() {
offset: 5,
};
return function(x, y, opts) {
return function(this: any, x, y, opts) {
opts = $.extend(true, {}, defaults, opts);
return this.each(function() {
return this.each(() => {
const $tooltip = $(this);
let width, height;

View File

@ -38,7 +38,7 @@ export class NavModelSrv {
}
getNav(...args) {
var children = this.navItems;
let children = this.navItems;
const nav = new NavModel();
for (const id of args) {

View File

@ -1,4 +1,4 @@
var templates = (<any>require).context('../', true, /\.html$/);
let templates = (<any>require).context('../', true, /\.html$/);
templates.keys().forEach(function(key) {
templates(key);
});

View File

@ -69,7 +69,7 @@ export class Profiler {
// measure digest performance
const rootDigestStart = window.performance.now();
for (var i = 0; i < 30; i++) {
for (let i = 0; i < 30; i++) {
this.$rootScope.$apply();
}
@ -78,8 +78,8 @@ export class Profiler {
}
getTotalWatcherCount() {
var count = 0;
var scopes = 0;
let count = 0;
let scopes = 0;
const root = $(document.getElementsByTagName('body'));
const f = function(element) {

View File

@ -43,7 +43,7 @@ export class BackendSrv {
return;
}
var data = err.data || { message: 'Unexpected error' };
let data = err.data || { message: 'Unexpected error' };
if (_.isString(data)) {
data = { message: data };
}

View File

@ -7,7 +7,7 @@ export class ImpressionSrv {
addDashboardImpression(dashboardId) {
const impressionsKey = this.impressionKey(config);
var impressions = [];
let impressions = [];
if (store.exists(impressionsKey)) {
impressions = JSON.parse(store.get(impressionsKey));
if (!_.isArray(impressions)) {
@ -28,7 +28,7 @@ export class ImpressionSrv {
}
getDashboardOpened() {
var impressions = store.get(this.impressionKey(config)) || '[]';
let impressions = store.get(this.impressionKey(config)) || '[]';
impressions = JSON.parse(impressions);

View File

@ -77,15 +77,15 @@ export class KeybindingSrv {
appEvents.emit('hide-modal');
if (!this.modalOpen) {
if (this.timepickerOpen) {
this.$rootScope.appEvent('closeTimepicker');
this.timepickerOpen = false;
} else {
this.$rootScope.appEvent('panel-change-view', { fullscreen: false, edit: false });
}
} else {
if (this.modalOpen) {
this.modalOpen = false;
return;
}
if (this.timepickerOpen) {
this.$rootScope.appEvent('closeTimepicker');
this.timepickerOpen = false;
return;
}
// close settings view
@ -93,6 +93,16 @@ export class KeybindingSrv {
if (search.editview) {
delete search.editview;
this.$location.search(search);
return;
}
if (search.fullscreen) {
this.$rootScope.appEvent('panel-change-view', { fullscreen: false, edit: false });
return;
}
if (search.kiosk) {
this.$rootScope.appEvent('toggle-kiosk-mode', { exit: true });
}
}

View File

@ -27,7 +27,7 @@ function getReactComponent(name, $injector) {
}
// ensure the specified React component is accessible, and fail fast if it's not
var reactComponent;
let reactComponent;
try {
reactComponent = $injector.get(name);
} catch (e) {}
@ -204,7 +204,7 @@ const reactComponent = function($injector) {
attrs.props ? watchProps(attrs.watchDepth, scope, [attrs.props], renderMyComponent) : renderMyComponent();
// cleanup when scope is destroyed
scope.$on('$destroy', function() {
scope.$on('$destroy', () => {
if (!attrs.onScopeDestroy) {
ReactDOM.unmountComponentAtNode(elem[0]);
} else {
@ -256,7 +256,7 @@ const reactDirective = function($injector) {
// for each of the properties, get their scope value and set it to scope.props
const renderMyComponent = function() {
var scopeProps = {};
let scopeProps = {};
const config = {};
props.forEach(function(prop) {
@ -280,7 +280,7 @@ const reactDirective = function($injector) {
props.length ? watchProps(attrs.watchDepth, scope, propExpressions, renderMyComponent) : renderMyComponent();
// cleanup when scope is destroyed
scope.$on('$destroy', function() {
scope.$on('$destroy', () => {
if (!attrs.onScopeDestroy) {
ReactDOM.unmountComponentAtNode(elem[0]);
} else {

View File

@ -2,8 +2,8 @@ import _ from 'lodash';
import coreModule from 'app/core/core_module';
import Drop from 'tether-drop';
/** @ngInject **/
function popoverSrv($compile, $rootScope, $timeout) {
/** @ngInject */
function popoverSrv(this: any, $compile, $rootScope, $timeout) {
let openDrop = null;
this.close = function() {

View File

@ -2,10 +2,10 @@ import _ from 'lodash';
import coreModule from '../core_module';
/** @ngInject */
export function uiSegmentSrv($sce, templateSrv) {
export function uiSegmentSrv(this: any, $sce, templateSrv) {
const self = this;
function MetricSegment(options) {
function MetricSegment(this: any, options) {
if (options === '*' || options.value === '*') {
this.value = '*';
this.html = $sce.trustAsHtml('<i class="fa fa-asterisk"><i>');

View File

@ -55,8 +55,8 @@ describe('DateMath', () => {
});
describe('subtraction', () => {
var now;
var anchored;
let now;
let anchored;
beforeEach(() => {
clock = sinon.useFakeTimers(unix);
@ -83,7 +83,7 @@ describe('DateMath', () => {
});
describe('rounding', () => {
var now;
let now;
beforeEach(() => {
clock = sinon.useFakeTimers(unix);

View File

@ -26,7 +26,7 @@ describe('when sorting table desc', () => {
});
describe('when sorting table asc', () => {
var table;
let table;
const panel = {
sort: { col: 1, desc: false },
};
@ -46,8 +46,8 @@ describe('when sorting table asc', () => {
});
describe('when sorting with nulls', () => {
var table;
var values;
let table;
let values;
beforeEach(() => {
table = new TableModel();

View File

@ -174,7 +174,7 @@ describe('TimeSeries', function() {
});
describe('can detect if series contains ms precision', function() {
var fakedata;
let fakedata;
beforeEach(function() {
fakedata = testData;
@ -194,7 +194,7 @@ describe('TimeSeries', function() {
});
describe('series overrides', function() {
var series;
let series;
beforeEach(function() {
series = new TimeSeries(testData);
});
@ -313,7 +313,7 @@ describe('TimeSeries', function() {
});
describe('value formatter', function() {
var series;
let series;
beforeEach(function() {
series = new TimeSeries(testData);
});

View File

@ -124,7 +124,7 @@ export default class TimeSeries {
delete this.stack;
delete this.bars.show;
for (var i = 0; i < overrides.length; i++) {
for (let i = 0; i < overrides.length; i++) {
const override = overrides[i];
if (!matchSeriesOverride(override.alias, this.alias)) {
continue;
@ -211,14 +211,14 @@ export default class TimeSeries {
const ignoreNulls = fillStyle === 'connected';
const nullAsZero = fillStyle === 'null as zero';
var currentTime;
var currentValue;
var nonNulls = 0;
var previousTime;
var previousValue = 0;
var previousDeltaUp = true;
let currentTime;
let currentValue;
let nonNulls = 0;
let previousTime;
let previousValue = 0;
let previousDeltaUp = true;
for (var i = 0; i < this.datapoints.length; i++) {
for (let i = 0; i < this.datapoints.length; i++) {
currentValue = this.datapoints[i][0];
currentTime = this.datapoints[i][1];
@ -328,7 +328,7 @@ export default class TimeSeries {
}
isMsResolutionNeeded() {
for (var i = 0; i < this.datapoints.length; i++) {
for (let i = 0; i < this.datapoints.length; i++) {
if (this.datapoints[i][1] !== null) {
const timestamp = this.datapoints[i][1].toString();
if (timestamp.length === 13 && timestamp % 1000 !== 0) {

View File

@ -11,7 +11,7 @@ for (let i = 0; i < links.length; i++) {
const isWebkit = !!window.navigator.userAgent.match(/AppleWebKit\/([^ ;]*)/);
const webkitLoadCheck = function(link, callback) {
setTimeout(function() {
for (var i = 0; i < document.styleSheets.length; i++) {
for (let i = 0; i < document.styleSheets.length; i++) {
const sheet = document.styleSheets[i];
if (sheet.href === link.href) {
return callback();
@ -68,7 +68,7 @@ export function fetch(load): any {
}
// don't reload styles loaded in the head
for (var i = 0; i < linkHrefs.length; i++) {
for (let i = 0; i < linkHrefs.length; i++) {
if (load.address === linkHrefs[i]) {
return '';
}

View File

@ -14,10 +14,10 @@ export function parse(text, roundUp?, timezone?) {
return moment(text);
}
var time;
var mathString = '';
var index;
var parseString;
let time;
let mathString = '';
let index;
let parseString;
if (text.substring(0, 3) === 'now') {
if (timezone === 'utc') {
@ -61,14 +61,14 @@ export function isValid(text) {
export function parseDateMath(mathString, time, roundUp?) {
const dateTime = time;
var i = 0;
let i = 0;
const len = mathString.length;
while (i < len) {
const c = mathString.charAt(i++);
var type;
var num;
var unit;
let type;
let num;
let unit;
if (c === '/') {
type = 0;

View File

@ -169,8 +169,8 @@ kbn.intervals_in_seconds = {
};
kbn.calculateInterval = function(range, resolution, lowLimitInterval) {
var lowLimitMs = 1; // 1 millisecond default low limit
var intervalMs;
let lowLimitMs = 1; // 1 millisecond default low limit
let intervalMs;
if (lowLimitInterval) {
if (lowLimitInterval[0] === '>') {
@ -304,7 +304,7 @@ kbn.formatBuilders.scaledUnits = function(factor, extArray) {
return '';
}
var steps = 0;
let steps = 0;
const limit = extArray.length;
while (Math.abs(size) >= factor) {
@ -328,7 +328,7 @@ kbn.formatBuilders.scaledUnits = function(factor, extArray) {
// offset is given, it adjusts the starting units at the given prefix; a value
// of 0 starts at no scale; -3 drops to nano, +2 starts at mega, etc.
kbn.formatBuilders.decimalSIPrefix = function(unit, offset) {
var prefixes = ['n', 'µ', 'm', '', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
let prefixes = ['n', 'µ', 'm', '', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
prefixes = prefixes.slice(3 + (offset || 0));
const units = prefixes.map(function(p) {
return ' ' + p + unit;
@ -790,8 +790,8 @@ kbn.toDuration = function(size, decimals, timeScale) {
const strings = [];
// after first value >= 1 print only $decimals more
var decrementDecimals = false;
for (var i = 0; i < units.length && decimals >= 0; i++) {
let decrementDecimals = false;
for (let i = 0; i < units.length && decimals >= 0; i++) {
const interval = kbn.intervals_in_seconds[units[i].short] * 1000;
const value = size / interval;
if (value >= 1 || decrementDecimals) {

View File

@ -75,7 +75,7 @@ export function getTagColorsFromName(name: string): { color: string; borderColor
function djb2(str) {
let hash = 5381;
for (var i = 0; i < str.length; i++) {
for (let i = 0; i < str.length; i++) {
hash = (hash << 5) + hash + str.charCodeAt(i); /* hash * 33 + c */
}
return hash;

View File

@ -20,7 +20,7 @@ export function toUrlParams(a) {
};
const buildParams = function(prefix, obj) {
var i, len, key;
let i, len, key;
if (prefix) {
if (isArray(obj)) {

View File

@ -8,7 +8,7 @@ import coreModule from 'app/core/core_module';
class AdminSettingsCtrl {
navModel: any;
/** @ngInject **/
/** @ngInject */
constructor($scope, backendSrv, navModelSrv) {
this.navModel = navModelSrv.getNav('cfg', 'admin', 'server-settings', 1);
@ -21,7 +21,7 @@ class AdminSettingsCtrl {
class AdminHomeCtrl {
navModel: any;
/** @ngInject **/
/** @ngInject */
constructor(navModelSrv) {
this.navModel = navModelSrv.getNav('cfg', 'admin', 1);
}

View File

@ -26,7 +26,7 @@ export default class AdminListUsersCtrl {
this.showPaging = this.totalPages > 1;
this.pages = [];
for (var i = 1; i < this.totalPages + 1; i++) {
for (let i = 1; i < this.totalPages + 1; i++) {
this.pages.push({ page: i, current: i === this.page });
}
});

View File

@ -1,6 +1,6 @@
export class ThresholdMapper {
static alertToGraphThresholds(panel) {
for (var i = 0; i < panel.alert.conditions.length; i++) {
for (let i = 0; i < panel.alert.conditions.length; i++) {
const condition = panel.alert.conditions[i];
if (condition.type !== 'query') {
continue;

View File

@ -3,7 +3,7 @@ import $ from 'jquery';
import coreModule from 'app/core/core_module';
import alertDef from '../alerting/alert_def';
/** @ngInject **/
/** @ngInject */
export function annotationTooltipDirective($sanitize, dashboardSrv, contextSrv, $compile) {
function sanitizeString(str) {
try {
@ -22,12 +22,12 @@ export function annotationTooltipDirective($sanitize, dashboardSrv, contextSrv,
},
link: function(scope, element) {
const event = scope.event;
var title = event.title;
var text = event.text;
let title = event.title;
let text = event.text;
const dashboard = dashboardSrv.getCurrent();
var tooltip = '<div class="graph-annotation">';
var titleStateClass = '';
let tooltip = '<div class="graph-annotation">';
let titleStateClass = '';
if (event.alertId) {
const stateModel = alertDef.getStateDisplayModel(event.newState);
@ -42,7 +42,7 @@ export function annotationTooltipDirective($sanitize, dashboardSrv, contextSrv,
title = '';
}
var header = `<div class="graph-annotation__header">`;
let header = `<div class="graph-annotation__header">`;
if (event.login) {
header += `<div class="graph-annotation__user" bs-tooltip="'Created by ${event.login}'"><img src="${
event.avatarUrl

View File

@ -25,7 +25,7 @@ export class AnnotationsSrv {
.all([this.getGlobalAnnotations(options), this.getAlertStates(options)])
.then(results => {
// combine the annotations and flatten results
var annotations = _.flattenDeep(results[0]);
let annotations = _.flattenDeep(results[0]);
// filter out annotations that do not belong to requesting panel
annotations = _.filter(annotations, item => {

View File

@ -12,7 +12,7 @@ export class EventEditorCtrl {
close: any;
timeFormated: string;
/** @ngInject **/
/** @ngInject */
constructor(private annotationsSrv) {
this.event.panelId = this.panelCtrl.panel.id;
this.event.dashboardId = this.panelCtrl.dashboard.id;

View File

@ -102,7 +102,7 @@ export class EventManager {
}
} else {
// annotations from query
for (var i = 0; i < annotations.length; i++) {
for (let i = 0; i < annotations.length; i++) {
const item = annotations[i];
// add properties used by jquery flot events

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

@ -144,7 +144,7 @@ export class DashboardCtrl implements PanelContainer {
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

@ -36,7 +36,7 @@ export class DashboardLoaderSrv {
}
loadDashboard(type, slug, uid) {
var promise;
let promise;
if (type === 'script') {
promise = this._loadScriptedDashboard(slug);

View File

@ -18,7 +18,7 @@ export class DashboardMigrator {
}
updateSchema(old) {
var i, j, k, n;
let i, j, k, n;
const oldVersion = this.dashboard.schemaVersion;
const panelUpgrades = [];
this.dashboard.schemaVersion = 16;
@ -83,7 +83,7 @@ export class DashboardMigrator {
// schema version 3 changes
if (oldVersion < 3) {
// ensure panel ids
var maxId = this.dashboard.getNextPanelId();
let maxId = this.dashboard.getNextPanelId();
panelUpgrades.push(function(panel) {
if (!panel.id) {
panel.id = maxId;
@ -140,15 +140,12 @@ 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);
}
});
});
}

View File

@ -144,7 +144,7 @@ export class DashboardModel {
});
// make clone
var copy: any = {};
let copy: any = {};
for (const property in this) {
if (DashboardModel.nonPersistedProperties[property] || !this.hasOwnProperty(property)) {
continue;
@ -842,12 +842,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

@ -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

@ -31,6 +31,10 @@ export class DashNavCtrl {
this.$location.search(search);
}
toggleViewMode() {
appEvents.emit('toggle-kiosk-mode');
}
close() {
const search = this.$location.search();
if (search.editview) {

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

@ -7,7 +7,7 @@ const template = `
</div>
`;
/** @ngInject **/
/** @ngInject */
function dashRepeatOptionDirective(variableSrv) {
return {
restrict: 'E',

View File

@ -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

@ -35,7 +35,7 @@ export function ShareModalCtrl($scope, $rootScope, $location, $timeout, timeSrv,
};
$scope.buildUrl = function() {
var baseUrl = $location.absUrl();
let baseUrl = $location.absUrl();
const queryStart = baseUrl.indexOf('?');
if (queryStart !== -1) {
@ -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;

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,

View File

@ -5,7 +5,7 @@ import { expect } from 'test/lib/common';
jest.mock('app/core/services/context_srv', () => ({}));
describe('given dashboard with panel repeat', function() {
var dashboard;
let dashboard;
beforeEach(function() {
const dashboardJSON = {
@ -56,7 +56,7 @@ describe('given dashboard with panel repeat', function() {
});
describe('given dashboard with panel repeat in horizontal direction', function() {
var dashboard;
let dashboard;
beforeEach(function() {
dashboard = new DashboardModel({
@ -188,7 +188,7 @@ describe('given dashboard with panel repeat in horizontal direction', function()
});
describe('given dashboard with panel repeat in vertical direction', function() {
var dashboard;
let dashboard;
beforeEach(function() {
dashboard = new DashboardModel({

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' };

View File

@ -18,7 +18,7 @@ export function inputDateDirective() {
return text;
}
var parsed;
let parsed;
if ($scope.ctrl.isUtc) {
parsed = moment.utc(text, 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) {
@ -65,6 +66,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) {
@ -75,7 +77,7 @@ export class TimePickerCtrl {
const range = this.timeSrv.timeRange();
const timespan = (range.to.valueOf() - range.from.valueOf()) / 2;
var to, from;
let to, from;
if (direction === -1) {
to = range.to.valueOf() - timespan;
from = range.from.valueOf() - timespan;

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

@ -21,7 +21,7 @@ function uploadDashboardDirective(timer, alertSrv, $location) {
const files = evt.target.files; // FileList object
const readerOnload = function() {
return function(e) {
var dash;
let dash;
try {
dash = JSON.parse(e.target.result);
} catch (err) {
@ -36,7 +36,7 @@ function uploadDashboardDirective(timer, alertSrv, $location) {
};
};
for (var i = 0, f; (f = files[i]); i++) {
for (let i = 0, f; (f = files[i]); i++) {
const reader = new FileReader();
reader.onload = readerOnload();
reader.readAsText(f);

View File

@ -1,7 +1,7 @@
import angular from 'angular';
import _ from 'lodash';
export var iconMap = {
export let iconMap = {
'external link': 'fa-external-link',
dashboard: 'fa-th-large',
question: 'fa-question',

View File

@ -20,7 +20,7 @@ function dashLink($compile, $sanitize, linkSrv) {
restrict: 'E',
link: function(scope, elem) {
const link = scope.link;
var template =
let template =
'<div class="gf-form">' +
'<a class="pointer gf-form-label" data-placement="bottom"' +
(link.asDropdown ? ' ng-click="fillDropdown(link)" data-toggle="dropdown"' : '') +

View File

@ -2,7 +2,7 @@ import angular from 'angular';
import config from 'app/core/config';
export class ChangePasswordCtrl {
/** @ngInject **/
/** @ngInject */
constructor($scope, backendSrv, $location, navModelSrv) {
$scope.command = {};
$scope.authProxyEnabled = config.authProxyEnabled;

View File

@ -5,7 +5,7 @@ export default class CreateTeamCtrl {
email: string;
navModel: any;
/** @ngInject **/
/** @ngInject */
constructor(private backendSrv, private $location, navModelSrv) {
this.navModel = navModelSrv.getNav('cfg', 'teams', 0);
}

View File

@ -2,7 +2,7 @@ import angular from 'angular';
import config from 'app/core/config';
export class NewOrgCtrl {
/** @ngInject **/
/** @ngInject */
constructor($scope, $http, backendSrv, navModelSrv) {
$scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs', 1);
$scope.newOrg = { name: '' };

View File

@ -1,7 +1,7 @@
import angular from 'angular';
export class OrgApiKeysCtrl {
/** @ngInject **/
/** @ngInject */
constructor($scope, $http, backendSrv, navModelSrv) {
$scope.navModel = navModelSrv.getNav('cfg', 'apikeys', 0);

View File

@ -1,7 +1,7 @@
import angular from 'angular';
export class OrgDetailsCtrl {
/** @ngInject **/
/** @ngInject */
constructor($scope, $http, backendSrv, contextSrv, navModelSrv) {
$scope.init = function() {
$scope.getOrgInfo();

View File

@ -14,7 +14,7 @@ export class PrefsControlCtrl {
];
themes: any = [{ value: '', text: 'Default' }, { value: 'dark', text: 'Dark' }, { value: 'light', text: 'Light' }];
/** @ngInject **/
/** @ngInject */
constructor(private backendSrv, private $location) {}
$onInit() {

View File

@ -12,7 +12,7 @@ export class ProfileCtrl {
readonlyLoginFields = config.disableLoginForm;
navModel: any;
/** @ngInject **/
/** @ngInject */
constructor(private backendSrv, private contextSrv, private $location, navModelSrv) {
this.getUser();
this.getUserTeams();

View File

@ -2,7 +2,7 @@ import angular from 'angular';
import config from 'app/core/config';
export class SelectOrgCtrl {
/** @ngInject **/
/** @ngInject */
constructor($scope, backendSrv, contextSrv) {
contextSrv.sidemenu = false;

View File

@ -5,7 +5,7 @@ export class UserInviteCtrl {
invite: any;
inviteForm: any;
/** @ngInject **/
/** @ngInject */
constructor(private backendSrv, navModelSrv, private $location) {
this.navModel = navModelSrv.getNav('cfg', 'users', 0);

View File

@ -75,7 +75,7 @@ class MetricsPanelCtrl extends PanelCtrl {
// if we have snapshot data use that
if (this.panel.snapshotData) {
this.updateTimeRange();
var data = this.panel.snapshotData;
let data = this.panel.snapshotData;
// backward compatibility
if (!_.isArray(data)) {
data = data.data;
@ -155,7 +155,7 @@ class MetricsPanelCtrl extends PanelCtrl {
}
calculateInterval() {
var intervalOverride = this.panel.interval;
let intervalOverride = this.panel.interval;
// if no panel interval check datasource
if (intervalOverride) {

View File

@ -110,7 +110,7 @@ export class MetricsTabCtrl {
}
}
/** @ngInject **/
/** @ngInject */
export function metricsTabDirective() {
'use strict';
return {

View File

@ -317,7 +317,7 @@ export class PanelCtrl {
}
getInfoContent(options) {
var markdown = this.panel.description;
let markdown = this.panel.description;
if (options.mode === 'tooltip') {
markdown = this.error || this.panel.description;
@ -327,7 +327,7 @@ export class PanelCtrl {
const sanitize = this.$injector.get('$sanitize');
const templateSrv = this.$injector.get('templateSrv');
const interpolatedMarkdown = templateSrv.replace(markdown, this.panel.scopedVars);
var html = '<div class="markdown-html">';
let html = '<div class="markdown-html">';
html += new Remarkable().render(interpolatedMarkdown);

View File

@ -80,7 +80,7 @@ function createMenuTemplate(ctrl) {
return html;
}
/** @ngInject **/
/** @ngInject */
function panelHeader($compile) {
return {
restrict: 'E',

View File

@ -87,7 +87,7 @@ export class QueryRowCtrl {
}
}
/** @ngInject **/
/** @ngInject */
function queryEditorRowDirective() {
return {
restrict: 'E',

View File

@ -40,7 +40,7 @@ export class QueryTroubleshooterCtrl {
mockedResponse: string;
jsonExplorer: JsonExplorer;
/** @ngInject **/
/** @ngInject */
constructor($scope, private $timeout) {
this.onRequestErrorEventListener = this.onRequestError.bind(this);
this.onRequestResponseEventListener = this.onRequestResponse.bind(this);
@ -87,7 +87,7 @@ export class QueryTroubleshooterCtrl {
}
handleMocking(data) {
var mockedData;
let mockedData;
try {
mockedData = JSON.parse(this.mockedResponse);
} catch (err) {

View File

@ -1,9 +1,9 @@
<page-header model="ctrl.navModel"></page-header>
<div class="page-container page-body" ng-form="playlistEditForm">
<div class="page-container page-body" ng-form="ctrl.playlistEditForm">
<h3 class="page-sub-heading" ng-hide="ctrl.isNew">Edit Playlist</h3>
<h3 class="page-sub-heading" ng-show="ctrl.isNew">New Playlist</h3>
<h3 class="page-sub-heading" ng-hide="ctrl.isNew">Edit Playlist</h3>
<h3 class="page-sub-heading" ng-show="ctrl.isNew">New Playlist</h3>
<p class="playlist-description">A playlist rotates through a pre-selected list of Dashboards. A Playlist can be a great way to build situational awareness, or just show off your metrics to your team or visitors.</p>
@ -20,79 +20,71 @@
<div class="gf-form-group">
<h3 class="page-headering">Dashboards</h3>
<table class="filter-table playlist-available-list">
<tr ng-repeat="playlistItem in ctrl.playlistItems">
<td ng-if="playlistItem.type === 'dashboard_by_id'">
<i class="icon-gf icon-gf-dashboard"></i>&nbsp;&nbsp;{{playlistItem.title}}
</td>
<td ng-if="playlistItem.type === 'dashboard_by_tag'">
<a class="search-result-tag label label-tag" tag-color-from-name="playlistItem.title">
<i class="fa fa-tag"></i>
<span>{{playlistItem.title}}</span>
</a>
</td>
<td class="selected-playlistitem-settings">
<button class="btn btn-inverse btn-mini" ng-hide="$first" ng-click="ctrl.movePlaylistItemUp(playlistItem)">
<i class="fa fa-arrow-up"></i>
</button>
<button class="btn btn-inverse btn-mini" ng-hide="$last" ng-click="ctrl.movePlaylistItemDown(playlistItem)">
<i class="fa fa-arrow-down"></i>
</button>
<button class="btn btn-inverse btn-mini" ng-click="ctrl.removePlaylistItem(playlistItem)">
<i class="fa fa-remove"></i>
</button>
</td>
</tr>
<tr ng-if="ctrl.playlistItems.length === 0">
<td><em>Playlist is empty, add dashboards below.</em></td>
</tr>
</table>
</div>
<div class="row">
<div class="col-lg-6">
<div class="playlist-search-containerwrapper">
<div class="max-width-32">
<h5 class="page-headering playlist-column-header">Available</h5>
<div style="">
<playlist-search class="playlist-search-container" search-started="ctrl.searchStarted(promise)"></playlist-search>
</div>
</div>
</div>
<div class="gf-form-group">
<h3 class="page-headering">Add dashboards</h3>
<playlist-search class="playlist-search-container" search-started="ctrl.searchStarted(promise)"></playlist-search>
<div ng-if="ctrl.filteredDashboards.length > 0">
<table class="filter-table playlist-available-list">
<tr ng-repeat="playlistItem in ctrl.filteredDashboards">
<td>
<i class="icon-gf icon-gf-dashboard"></i>
&nbsp;&nbsp;{{playlistItem.title}}
<i class="fa fa-star" ng-show="playlistItem.isStarred"></i>
</td>
<td class="add-dashboard">
<button class="btn btn-inverse btn-mini pull-right" ng-click="ctrl.addPlaylistItem(playlistItem)">
<i class="fa fa-plus"></i>
Add to playlist
</button>
</td>
</tr>
</table>
</div>
<div class="playlist-search-results-container" ng-if="ctrl.filteredTags.length > 0;">
<table class="filter-table playlist-available-list">
<tr ng-repeat="tag in ctrl.filteredTags">
<td>
<a class="search-result-tag label label-tag" tag-color-from-name="tag.term">
<i class="fa fa-tag"></i>
<span>{{tag.term}} &nbsp;({{tag.count}})</span>
</a>
</td>
<td class="add-dashboard">
<button class="btn btn-inverse btn-mini pull-right" ng-click="ctrl.addTagPlaylistItem(tag)">
<i class="fa fa-plus"></i>
Add to playlist
</button>
</td>
</tr>
</table>
</div>
</div>
<div class="col-lg-6">
<h5 class="page headering playlist-column-header">Selected</h5>
<div ng-if="ctrl.filteredDashboards.length > 0">
<table class="filter-table playlist-available-list">
<tr ng-repeat="playlistItem in ctrl.playlistItems">
<td ng-if="playlistItem.type === 'dashboard_by_id'">
<i class="icon-gf icon-gf-dashboard"></i>&nbsp;&nbsp;{{playlistItem.title}}
<tr ng-repeat="playlistItem in ctrl.filteredDashboards">
<td>
<i class="icon-gf icon-gf-dashboard"></i>
&nbsp;&nbsp;{{playlistItem.title}}
<i class="fa fa-star" ng-show="playlistItem.isStarred"></i>
</td>
<td ng-if="playlistItem.type === 'dashboard_by_tag'">
<a class="search-result-tag label label-tag" tag-color-from-name="playlistItem.title">
<td class="add-dashboard">
<button class="btn btn-inverse btn-mini pull-right" ng-click="ctrl.addPlaylistItem(playlistItem)">
<i class="fa fa-plus"></i>
Add to playlist
</button>
</td>
</tr>
</table>
</div>
<div class="playlist-search-results-container" ng-if="ctrl.filteredTags.length > 0;">
<table class="filter-table playlist-available-list">
<tr ng-repeat="tag in ctrl.filteredTags">
<td>
<a class="search-result-tag label label-tag" tag-color-from-name="tag.term">
<i class="fa fa-tag"></i>
<span>{{playlistItem.title}}</span>
<span>{{tag.term}} &nbsp;({{tag.count}})</span>
</a>
</td>
<td class="selected-playlistitem-settings">
<button class="btn btn-inverse btn-mini" ng-hide="$first" ng-click="ctrl.movePlaylistItemUp(playlistItem)">
<i class="fa fa-arrow-up"></i>
</button>
<button class="btn btn-inverse btn-mini" ng-hide="$last" ng-click="ctrl.movePlaylistItemDown(playlistItem)">
<i class="fa fa-arrow-down"></i>
</button>
<button class="btn btn-inverse btn-mini" ng-click="ctrl.removePlaylistItem(playlistItem)">
<i class="fa fa-remove"></i>
<td class="add-dashboard">
<button class="btn btn-inverse btn-mini pull-right" ng-click="ctrl.addTagPlaylistItem(tag)">
<i class="fa fa-plus"></i>
Add to playlist
</button>
</td>
</tr>
@ -103,12 +95,8 @@
<div class="clearfix"></div>
<div class="gf-form-button-row">
<a class="btn btn-success " ng-show="ctrl.isNew"
ng-disabled="ctrl.playlistEditForm.$invalid || ctrl.isPlaylistEmpty()"
ng-click="ctrl.savePlaylist(ctrl.playlist, ctrl.playlistItems)">Create new playlist</a>
<a class="btn btn-success" ng-show="!ctrl.isNew()"
ng-disabled="ctrl.playlistEditForm.$invalid || ctrl.isPlaylistEmpty()"
ng-click="ctrl.savePlaylist(ctrl.playlist, ctrl.playlistItems)">Save</a>
<a class="btn btn-success" ng-show="ctrl.isNew" ng-disabled="ctrl.playlistEditForm.$invalid || ctrl.isPlaylistEmpty()" ng-click="ctrl.savePlaylist(ctrl.playlist, ctrl.playlistItems)">Create</a>
<a class="btn btn-success" ng-show="!ctrl.isNew" ng-disabled="ctrl.playlistEditForm.$invalid || ctrl.isPlaylistEmpty()" ng-click="ctrl.savePlaylist(ctrl.playlist, ctrl.playlistItems)">Save</a>
<a class="btn-text" ng-click="ctrl.backToList()">Cancel</a>
</div>
</div>

View File

@ -10,38 +10,42 @@
</a>
</div>
<table class="filter-table">
<table class="filter-table filter-table--hover">
<thead>
<th>
<strong>Name</strong>
</th>
<th>
<strong>Start url</strong>
</th>
<th><strong>Name</strong></th>
<th style="width: 100px"></th>
<th style="width: 78px"></th>
<th style="width: 78px"></th>
<th style="width: 25px"></th>
</thead>
<tr ng-repeat="playlist in ctrl.playlists">
<td>
<td class="link-td">
<a href="playlists/edit/{{playlist.id}}">{{playlist.name}}</a>
</td>
<td>
<a href="playlists/play/{{playlist.id}}">playlists/play/{{playlist.id}}</a>
<td class="dropdown">
<button class="btn btn-inverse btn-small" data-toggle="dropdown">
Start playlist
<i class="fa fa-caret-down"></i>
</button>
<ul class="dropdown-menu" role="menu">
<li>
<a href="{{playlist.startUrl}}">
<i class="fa fa-play"></i> In Normal mode</span>
</a>
<a href="{{playlist.startUrl}}?kiosk=tv">
<i class="fa fa-play"></i> In TV mode</span>
</a>
<a href="{{playlist.startUrl}}?kiosk=tv&autofitpanels">
<i class="fa fa-play"></i> In TV mode <span class="muted">(with auto fit panels)</span>
</a>
<a href="{{playlist.startUrl}}?kiosk">
<i class="fa fa-play"></i> In Kiosk mode</span>
</a>
<a ng-href="{{playlist.startUrl}}?kiosk&autofitpanels">
<i class="fa fa-play"></i> In Kiosk mode <span class="muted">(with auto fit panels)</span>
</a>
</li>
</ul>
</td>
<td class="text-center">
<a href="playlists/play/{{playlist.id}}" class="btn btn-inverse btn-small">
<i class="fa fa-play"></i>
Play
</a>
</td>
<td class="text-right">
<a href="playlists/edit/{{playlist.id}}" class="btn btn-inverse btn-small">
<i class="fa fa-edit"></i>
Edit
</a>
</td>
<td class="text-right">
<td class="text-right">
<a ng-click="ctrl.removePlaylist(playlist)" class="btn btn-danger btn-small">
<i class="fa fa-remove"></i>
</a>
@ -49,18 +53,16 @@
</tr>
</table>
</div>
<div ng-if="ctrl.playlists.length === 0">
<empty-list-cta model="{
title: 'There are no playlists created yet',
buttonIcon: 'fa fa-plus',
buttonLink: 'playlists/create',
buttonTitle: ' Create Playlist',
proTip: 'You can run the playlist in Kiosk Mode.',
proTip: 'You can use playlists to remove control TVs',
proTipLink: 'http://docs.grafana.org/reference/playlist/',
proTipLinkTitle: 'Learn more',
proTipTarget: '_blank'
}" />
</div>
</div>

View File

@ -19,29 +19,18 @@ export class PlaylistEditCtrl {
/** @ngInject */
constructor(private $scope, private backendSrv, private $location, $route, navModelSrv) {
this.navModel = navModelSrv.getNav('dashboards', 'playlists', 0);
this.isNew = $route.current.params.id;
this.isNew = !$route.current.params.id;
if ($route.current.params.id) {
const playlistId = $route.current.params.id;
backendSrv.get('/api/playlists/' + playlistId).then(result => {
this.playlist = result;
this.navModel.node = {
text: result.name,
icon: this.navModel.node.icon,
};
this.navModel.breadcrumbs.push(this.navModel.node);
});
backendSrv.get('/api/playlists/' + playlistId + '/items').then(result => {
this.playlistItems = result;
});
} else {
this.navModel.node = {
text: 'New playlist',
icon: this.navModel.node.icon,
};
this.navModel.breadcrumbs.push(this.navModel.node);
}
}
@ -88,7 +77,7 @@ export class PlaylistEditCtrl {
}
savePlaylist(playlist, playlistItems) {
var savePromise;
let savePromise;
playlist.items = playlistItems;

View File

@ -19,9 +19,7 @@ function grafanaRoutes($routeProvider) {
controller: 'PlaylistEditCtrl',
})
.when('/playlists/play/:id', {
templateUrl: 'public/app/features/playlist/partials/playlists.html',
controllerAs: 'ctrl',
controller: 'PlaylistsCtrl',
template: '',
resolve: {
init: function(playlistSrv, $route) {
const playlistId = $route.current.params.id;

View File

@ -8,7 +8,7 @@ export class PlaylistSearchCtrl {
/** @ngInject */
constructor($timeout, private backendSrv) {
this.query = { query: '', tag: [], starred: false, limit: 30 };
this.query = { query: '', tag: [], starred: false, limit: 20 };
$timeout(() => {
this.query.query = '';

View File

@ -1,6 +1,8 @@
import coreModule from '../../core/core_module';
import kbn from 'app/core/utils/kbn';
import appEvents from 'app/core/app_events';
import _ from 'lodash';
import { toUrlParams } from 'app/core/utils/url';
class PlaylistSrv {
private cancelPromise: any;
@ -8,45 +10,30 @@ class PlaylistSrv {
private index: number;
private interval: any;
private startUrl: string;
public isPlaying: boolean;
isPlaying: boolean;
/** @ngInject */
constructor(private $location: any, private $timeout: any, private backendSrv: any, private $routeParams: any) {}
constructor(private $location: any, private $timeout: any, private backendSrv: any) {}
next() {
this.$timeout.cancel(this.cancelPromise);
const playedAllDashboards = this.index > this.dashboards.length - 1;
if (playedAllDashboards) {
window.location.href = this.getUrlWithKioskMode();
window.location.href = this.startUrl;
return;
}
const dash = this.dashboards[this.index];
this.$location.url('dashboard/' + dash.uri);
const queryParams = this.$location.search();
const filteredParams = _.pickBy(queryParams, value => value !== null);
this.$location.url('dashboard/' + dash.uri + '?' + toUrlParams(filteredParams));
this.index++;
this.cancelPromise = this.$timeout(() => this.next(), this.interval);
}
getUrlWithKioskMode() {
const inKioskMode = document.body.classList.contains('page-kiosk-mode');
// check if should add kiosk query param
if (inKioskMode && this.startUrl.indexOf('kiosk') === -1) {
return this.startUrl + '?kiosk=true';
}
// check if should remove kiosk query param
if (!inKioskMode) {
return this.startUrl.split('?')[0];
}
// already has kiosk query param, just return startUrl
return this.startUrl;
}
prev() {
this.index = Math.max(this.index - 2, 0);
this.next();
@ -59,10 +46,6 @@ class PlaylistSrv {
this.index = 0;
this.isPlaying = true;
if (this.$routeParams.kiosk) {
appEvents.emit('toggle-kiosk-mode');
}
this.backendSrv.get(`/api/playlists/${playlistId}`).then(playlist => {
this.backendSrv.get(`/api/playlists/${playlistId}/dashboards`).then(dashboards => {
this.dashboards = dashboards;
@ -73,6 +56,13 @@ class PlaylistSrv {
}
stop() {
if (this.isPlaying) {
const queryParams = this.$location.search();
if (queryParams.kiosk) {
appEvents.emit('toggle-kiosk-mode', { exit: true });
}
}
this.index = 0;
this.isPlaying = false;

View File

@ -10,7 +10,10 @@ export class PlaylistsCtrl {
this.navModel = navModelSrv.getNav('dashboards', 'playlists', 0);
backendSrv.get('/api/playlists').then(result => {
this.playlists = result;
this.playlists = result.map(item => {
item.startUrl = `playlists/play/${item.id}`;
return item;
});
});
}

View File

@ -2,7 +2,7 @@ import '../playlist_edit_ctrl';
import { PlaylistEditCtrl } from '../playlist_edit_ctrl';
describe('PlaylistEditCtrl', () => {
var ctx: any;
let ctx: any;
beforeEach(() => {
const navModelSrv = {
getNav: () => {

View File

@ -136,13 +136,13 @@ export class DatasourceSrv {
addDataSourceVariables(list) {
// look for data source variables
for (var i = 0; i < this.templateSrv.variables.length; i++) {
for (let i = 0; i < this.templateSrv.variables.length; i++) {
const variable = this.templateSrv.variables[i];
if (variable.type !== 'datasource') {
continue;
}
var first = variable.current.value;
let first = variable.current.value;
if (first === 'default') {
first = config.defaultDatasource;
}

View File

@ -4,7 +4,7 @@ import config from 'app/core/config';
import { coreModule, appEvents } from 'app/core/core';
import { store } from 'app/stores/store';
var datasourceTypes = [];
let datasourceTypes = [];
const defaults = {
name: '',
@ -16,7 +16,7 @@ const defaults = {
secureJsonData: {},
};
var datasourceCreated = false;
let datasourceCreated = false;
export class DataSourceEditCtrl {
isNew: boolean;

View File

@ -7,7 +7,7 @@ import { importPluginModule } from './plugin_loader';
import { UnknownPanelCtrl } from 'app/plugins/panel/unknown/module';
/** @ngInject **/
/** @ngInject */
function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $templateCache) {
function getTemplate(component) {
if (component.template) {
@ -69,7 +69,7 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $
};
const panelInfo = config.panels[scope.panel.type];
var panelCtrlPromise = Promise.resolve(UnknownPanelCtrl);
let panelCtrlPromise = Promise.resolve(UnknownPanelCtrl);
if (panelInfo) {
panelCtrlPromise = importPluginModule(panelInfo.module).then(function(panelModule) {
return panelModule.PanelCtrl;

View File

@ -8,7 +8,7 @@ class StyleGuideCtrl {
buttonVariants = ['-'];
navModel: any;
/** @ngInject **/
/** @ngInject */
constructor(private $routeParams, private backendSrv, navModelSrv) {
this.navModel = navModelSrv.getNav('cfg', 'admin', 'styleguide', 1);
this.theme = config.bootData.user.lightTheme ? 'light' : 'dark';

View File

@ -15,7 +15,7 @@ export class AdhocVariable implements Variable {
skipUrlSync: false,
};
/** @ngInject **/
/** @ngInject */
constructor(private model) {
assignModelProperties(this, model, this.defaults);
}

View File

@ -17,7 +17,7 @@ export class ConstantVariable implements Variable {
skipUrlSync: false,
};
/** @ngInject **/
/** @ngInject */
constructor(private model, private variableSrv) {
assignModelProperties(this, model, this.defaults);
}

View File

@ -23,7 +23,7 @@ export class CustomVariable implements Variable {
skipUrlSync: false,
};
/** @ngInject **/
/** @ngInject */
constructor(private model, private variableSrv) {
assignModelProperties(this, model, this.defaults);
}

View File

@ -22,7 +22,7 @@ export class DatasourceVariable implements Variable {
skipUrlSync: false,
};
/** @ngInject **/
/** @ngInject */
constructor(private model, private datasourceSrv, private variableSrv, private templateSrv) {
assignModelProperties(this, model, this.defaults);
this.refresh = 1;
@ -43,14 +43,14 @@ export class DatasourceVariable implements Variable {
updateOptions() {
const options = [];
const sources = this.datasourceSrv.getMetricSources({ skipVariables: true });
var regex;
let regex;
if (this.regex) {
regex = this.templateSrv.replace(this.regex, null, 'regex');
regex = kbn.stringToJsRegex(regex);
}
for (var i = 0; i < sources.length; i++) {
for (let i = 0; i < sources.length; i++) {
const source = sources[i];
// must match on type
if (source.meta.id !== this.query) {

Some files were not shown because too many files have changed in this diff Show More