tech: ran pretttier on all typescript files

This commit is contained in:
Torkel Ödegaard
2017-12-19 16:06:54 +01:00
parent b1621e1e8f
commit fadfc665e4
355 changed files with 20624 additions and 14931 deletions

View File

@@ -1,32 +1,32 @@
import 'babel-polyfill'; import "babel-polyfill";
import 'file-saver'; import "file-saver";
import 'lodash'; import "lodash";
import 'jquery'; import "jquery";
import 'angular'; import "angular";
import 'angular-route'; import "angular-route";
import 'angular-sanitize'; import "angular-sanitize";
import 'angular-native-dragdrop'; import "angular-native-dragdrop";
import 'angular-bindonce'; import "angular-bindonce";
import 'react'; import "react";
import 'react-dom'; import "react-dom";
import 'vendor/bootstrap/bootstrap'; import "vendor/bootstrap/bootstrap";
import 'vendor/angular-ui/ui-bootstrap-tpls'; import "vendor/angular-ui/ui-bootstrap-tpls";
import 'vendor/angular-other/angular-strap'; import "vendor/angular-other/angular-strap";
import $ from 'jquery'; import $ from "jquery";
import angular from 'angular'; import angular from "angular";
import config from 'app/core/config'; import config from "app/core/config";
import _ from 'lodash'; import _ from "lodash";
import moment from 'moment'; import moment from "moment";
// add move to lodash for backward compatabiltiy // add move to lodash for backward compatabiltiy
_.move = function (array, fromIndex, toIndex) { _.move = function(array, fromIndex, toIndex) {
array.splice(toIndex, 0, array.splice(fromIndex, 1)[0]); array.splice(toIndex, 0, array.splice(fromIndex, 1)[0]);
return array; return array;
}; };
import {coreModule, registerAngularDirectives} from './core/core'; import { coreModule, registerAngularDirectives } from "./core/core";
export class GrafanaApp { export class GrafanaApp {
registerFunctions: any; registerFunctions: any;
@@ -50,58 +50,78 @@ export class GrafanaApp {
} }
init() { init() {
var app = angular.module('grafana', []); var app = angular.module("grafana", []);
moment.locale(config.bootData.user.locale); moment.locale(config.bootData.user.locale);
app.config(($locationProvider, $controllerProvider, $compileProvider, $filterProvider, $httpProvider, $provide) => { app.config(
// pre assing bindings before constructor calls (
$compileProvider.preAssignBindingsEnabled(true); $locationProvider,
$controllerProvider,
$compileProvider,
$filterProvider,
$httpProvider,
$provide
) => {
// pre assing bindings before constructor calls
$compileProvider.preAssignBindingsEnabled(true);
if (config.buildInfo.env !== 'development') { if (config.buildInfo.env !== "development") {
$compileProvider.debugInfoEnabled(false); $compileProvider.debugInfoEnabled(false);
} }
$httpProvider.useApplyAsync(true); $httpProvider.useApplyAsync(true);
this.registerFunctions.controller = $controllerProvider.register; this.registerFunctions.controller = $controllerProvider.register;
this.registerFunctions.directive = $compileProvider.directive; this.registerFunctions.directive = $compileProvider.directive;
this.registerFunctions.factory = $provide.factory; this.registerFunctions.factory = $provide.factory;
this.registerFunctions.service = $provide.service; this.registerFunctions.service = $provide.service;
this.registerFunctions.filter = $filterProvider.register; this.registerFunctions.filter = $filterProvider.register;
$provide.decorator("$http", ["$delegate", "$templateCache", function($delegate, $templateCache) { $provide.decorator("$http", [
var get = $delegate.get; "$delegate",
$delegate.get = function(url, config) { "$templateCache",
if (url.match(/\.html$/)) { function($delegate, $templateCache) {
// some template's already exist in the cache var get = $delegate.get;
if (!$templateCache.get(url)) { $delegate.get = function(url, config) {
url += "?v=" + new Date().getTime(); if (url.match(/\.html$/)) {
} // some template's already exist in the cache
if (!$templateCache.get(url)) {
url += "?v=" + new Date().getTime();
}
}
return get(url, config);
};
return $delegate;
} }
return get(url, config); ]);
}; }
return $delegate; );
}]);
});
this.ngModuleDependencies = [ this.ngModuleDependencies = [
'grafana.core', "grafana.core",
'ngRoute', "ngRoute",
'ngSanitize', "ngSanitize",
'$strap.directives', "$strap.directives",
'ang-drag-drop', "ang-drag-drop",
'grafana', "grafana",
'pasvaz.bindonce', "pasvaz.bindonce",
'ui.bootstrap', "ui.bootstrap",
'ui.bootstrap.tpls', "ui.bootstrap.tpls",
'react' "react"
]; ];
var module_types = ['controllers', 'directives', 'factories', 'services', 'filters', 'routes']; var module_types = [
"controllers",
"directives",
"factories",
"services",
"filters",
"routes"
];
_.each(module_types, type => { _.each(module_types, type => {
var moduleName = 'grafana.' + type; var moduleName = "grafana." + type;
this.useModule(angular.module(moduleName, [])); this.useModule(angular.module(moduleName, []));
}); });
@@ -111,22 +131,24 @@ export class GrafanaApp {
// register react angular wrappers // register react angular wrappers
registerAngularDirectives(); registerAngularDirectives();
var preBootRequires = [System.import('app/features/all')]; var preBootRequires = [System.import("app/features/all")];
Promise.all(preBootRequires).then(() => { Promise.all(preBootRequires)
// disable tool tip animation .then(() => {
$.fn.tooltip.defaults.animation = false; // disable tool tip animation
// bootstrap the app $.fn.tooltip.defaults.animation = false;
angular.bootstrap(document, this.ngModuleDependencies).invoke(() => { // bootstrap the app
_.each(this.preBootModules, module => { angular.bootstrap(document, this.ngModuleDependencies).invoke(() => {
_.extend(module, this.registerFunctions); _.each(this.preBootModules, module => {
_.extend(module, this.registerFunctions);
});
this.preBootModules = null;
}); });
})
this.preBootModules = null; .catch(function(err) {
console.log("Application boot failed:", err);
}); });
}).catch(function(err) {
console.log('Application boot failed:', err);
});
} }
} }

View File

@@ -1,4 +1,4 @@
import {Emitter} from './utils/emitter'; import { Emitter } from "./utils/emitter";
var appEvents = new Emitter(); var appEvents = new Emitter();
export default appEvents; export default appEvents;

View File

@@ -26,20 +26,20 @@
* Ctrl-Enter (Command-Enter): run onChange() function * Ctrl-Enter (Command-Enter): run onChange() function
*/ */
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import config from 'app/core/config'; import config from "app/core/config";
import ace from 'brace'; import ace from "brace";
import './theme-grafana-dark'; import "./theme-grafana-dark";
import 'brace/ext/language_tools'; import "brace/ext/language_tools";
import 'brace/theme/textmate'; import "brace/theme/textmate";
import 'brace/mode/text'; import "brace/mode/text";
import 'brace/snippets/text'; import "brace/snippets/text";
import 'brace/mode/sql'; import "brace/mode/sql";
import 'brace/snippets/sql'; import "brace/snippets/sql";
import 'brace/mode/markdown'; import "brace/mode/markdown";
import 'brace/snippets/markdown'; import "brace/snippets/markdown";
import 'brace/mode/json'; import "brace/mode/json";
import 'brace/snippets/json'; import "brace/snippets/json";
const DEFAULT_THEME_DARK = "ace/theme/grafana-dark"; const DEFAULT_THEME_DARK = "ace/theme/grafana-dark";
const DEFAULT_THEME_LIGHT = "ace/theme/textmate"; const DEFAULT_THEME_LIGHT = "ace/theme/textmate";
@@ -56,7 +56,9 @@ function link(scope, elem, attrs) {
let maxLines = attrs.maxLines || DEFAULT_MAX_LINES; let maxLines = attrs.maxLines || DEFAULT_MAX_LINES;
let showGutter = attrs.showGutter !== undefined; let showGutter = attrs.showGutter !== undefined;
let tabSize = attrs.tabSize || DEFAULT_TAB_SIZE; let tabSize = attrs.tabSize || DEFAULT_TAB_SIZE;
let behavioursEnabled = attrs.behavioursEnabled ? attrs.behavioursEnabled === 'true' : DEFAULT_BEHAVIOURS; let behavioursEnabled = attrs.behavioursEnabled
? attrs.behavioursEnabled === "true"
: DEFAULT_BEHAVIOURS;
// Initialize editor // Initialize editor
let aceElem = elem.get(0); let aceElem = elem.get(0);
@@ -88,10 +90,10 @@ function link(scope, elem, attrs) {
// Add classes // Add classes
elem.addClass("gf-code-editor"); elem.addClass("gf-code-editor");
let textarea = elem.find("textarea"); let textarea = elem.find("textarea");
textarea.addClass('gf-form-input'); textarea.addClass("gf-form-input");
if (scope.codeEditorFocus) { if (scope.codeEditorFocus) {
setTimeout(function () { setTimeout(function() {
textarea.focus(); textarea.focus();
var domEl = textarea[0]; var domEl = textarea[0];
if (domEl.setSelectionRange) { if (domEl.setSelectionRange) {
@@ -102,7 +104,7 @@ function link(scope, elem, attrs) {
} }
// Event handlers // Event handlers
editorSession.on('change', (e) => { editorSession.on("change", e => {
scope.$apply(() => { scope.$apply(() => {
let newValue = codeEditor.getValue(); let newValue = codeEditor.getValue();
scope.content = newValue; scope.content = newValue;
@@ -110,7 +112,7 @@ function link(scope, elem, attrs) {
}); });
// Sync with outer scope - update editor content if model has been changed from outside of directive. // Sync with outer scope - update editor content if model has been changed from outside of directive.
scope.$watch('content', (newValue, oldValue) => { scope.$watch("content", (newValue, oldValue) => {
let editorValue = codeEditor.getValue(); let editorValue = codeEditor.getValue();
if (newValue !== editorValue && newValue !== oldValue) { if (newValue !== editorValue && newValue !== oldValue) {
scope.$$postDigest(function() { scope.$$postDigest(function() {
@@ -119,7 +121,7 @@ function link(scope, elem, attrs) {
} }
}); });
codeEditor.on('blur', () => { codeEditor.on("blur", () => {
scope.onChange(); scope.onChange();
}); });
@@ -129,8 +131,8 @@ function link(scope, elem, attrs) {
// Keybindings // Keybindings
codeEditor.commands.addCommand({ codeEditor.commands.addCommand({
name: 'executeQuery', name: "executeQuery",
bindKey: {win: 'Ctrl-Enter', mac: 'Command-Enter'}, bindKey: { win: "Ctrl-Enter", mac: "Command-Enter" },
exec: () => { exec: () => {
scope.onChange(); scope.onChange();
} }
@@ -172,7 +174,7 @@ function link(scope, elem, attrs) {
export function codeEditorDirective() { export function codeEditorDirective() {
return { return {
restrict: 'E', restrict: "E",
template: editorTemplate, template: editorTemplate,
scope: { scope: {
content: "=", content: "=",
@@ -185,4 +187,4 @@ export function codeEditorDirective() {
}; };
} }
coreModule.directive('codeEditor', codeEditorDirective); coreModule.directive("codeEditor", codeEditorDirective);

View File

@@ -3,22 +3,23 @@
* Allows remaining <spectrum-picker> untouched in outdated plugins. * Allows remaining <spectrum-picker> untouched in outdated plugins.
* Technically, it's just a wrapper for react component with two-way data binding support. * Technically, it's just a wrapper for react component with two-way data binding support.
*/ */
import coreModule from '../../core_module'; import coreModule from "../../core_module";
/** @ngInject */ /** @ngInject */
export function spectrumPicker() { export function spectrumPicker() {
return { return {
restrict: 'E', restrict: "E",
require: 'ngModel', require: "ngModel",
scope: true, scope: true,
replace: true, replace: true,
template: '<color-picker color="ngModel.$viewValue" onChange="onColorChange"></color-picker>', template:
'<color-picker color="ngModel.$viewValue" onChange="onColorChange"></color-picker>',
link: function(scope, element, attrs, ngModel) { link: function(scope, element, attrs, ngModel) {
scope.ngModel = ngModel; scope.ngModel = ngModel;
scope.onColorChange = (color) => { scope.onColorChange = color => {
ngModel.$setViewValue(color); ngModel.$setViewValue(color);
}; };
} }
}; };
} }
coreModule.directive('spectrumPicker', spectrumPicker); coreModule.directive("spectrumPicker", spectrumPicker);

View File

@@ -1,4 +1,4 @@
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
var template = ` var template = `
<select class="gf-form-input" ng-model="ctrl.model" ng-options="f.value as f.text for f in ctrl.options"></select> <select class="gf-form-input" ng-model="ctrl.model" ng-options="f.value as f.text for f in ctrl.options"></select>
@@ -9,15 +9,14 @@ export class DashboardSelectorCtrl {
options: any; options: any;
/** @ngInject */ /** @ngInject */
constructor(private backendSrv) { constructor(private backendSrv) {}
}
$onInit() { $onInit() {
this.options = [{value: 0, text: 'Default'}]; this.options = [{ value: 0, text: "Default" }];
return this.backendSrv.search({starred: true}).then(res => { return this.backendSrv.search({ starred: true }).then(res => {
res.forEach(dash => { res.forEach(dash => {
this.options.push({value: dash.id, text: dash.title}); this.options.push({ value: dash.id, text: dash.title });
}); });
}); });
} }
@@ -25,15 +24,15 @@ export class DashboardSelectorCtrl {
export function dashboardSelector() { export function dashboardSelector() {
return { return {
restrict: 'E', restrict: "E",
controller: DashboardSelectorCtrl, controller: DashboardSelectorCtrl,
bindToController: true, bindToController: true,
controllerAs: 'ctrl', controllerAs: "ctrl",
template: template, template: template,
scope: { scope: {
model: '=' model: "="
} }
}; };
} }
coreModule.directive('dashboardSelector', dashboardSelector); coreModule.directive("dashboardSelector", dashboardSelector);

View File

@@ -1,11 +1,15 @@
import _ from 'lodash'; import _ from "lodash";
import $ from 'jquery'; import $ from "jquery";
import coreModule from '../../core_module'; import coreModule from "../../core_module";
function typeaheadMatcher(item) { function typeaheadMatcher(item) {
var str = this.query; var str = this.query;
if (str[0] === '/') { str = str.substring(1); } if (str[0] === "/") {
if (str[str.length - 1] === '/') { str = str.substring(0, str.length-1); } str = str.substring(1);
}
if (str[str.length - 1] === "/") {
str = str.substring(0, str.length - 1);
}
return item.toLowerCase().match(str.toLowerCase()); return item.toLowerCase().match(str.toLowerCase());
} }
@@ -28,9 +32,15 @@ export class FormDropdownCtrl {
lookupText: boolean; lookupText: boolean;
/** @ngInject **/ /** @ngInject **/
constructor(private $scope, $element, private $sce, private templateSrv, private $q) { constructor(
this.inputElement = $element.find('input').first(); private $scope,
this.linkElement = $element.find('a').first(); $element,
private $sce,
private templateSrv,
private $q
) {
this.inputElement = $element.find("input").first();
this.linkElement = $element.find("a").first();
this.linkMode = true; this.linkMode = true;
this.cancelBlur = null; this.cancelBlur = null;
@@ -38,25 +48,26 @@ export class FormDropdownCtrl {
$scope.$watch("ctrl.model", this.modelChanged.bind(this)); $scope.$watch("ctrl.model", this.modelChanged.bind(this));
if (this.labelMode) { if (this.labelMode) {
this.cssClasses = 'gf-form-label ' + this.cssClass; this.cssClasses = "gf-form-label " + this.cssClass;
} else { } else {
this.cssClasses = 'gf-form-input gf-form-input--dropdown ' + this.cssClass; this.cssClasses =
"gf-form-input gf-form-input--dropdown " + this.cssClass;
} }
this.inputElement.attr('data-provide', 'typeahead'); this.inputElement.attr("data-provide", "typeahead");
this.inputElement.typeahead({ this.inputElement.typeahead({
source: this.typeaheadSource.bind(this), source: this.typeaheadSource.bind(this),
minLength: 0, minLength: 0,
items: 10000, items: 10000,
updater: this.typeaheadUpdater.bind(this), updater: this.typeaheadUpdater.bind(this),
matcher: typeaheadMatcher, matcher: typeaheadMatcher
}); });
// modify typeahead lookup // modify typeahead lookup
// this = typeahead // this = typeahead
var typeahead = this.inputElement.data('typeahead'); var typeahead = this.inputElement.data("typeahead");
typeahead.lookup = function () { typeahead.lookup = function() {
this.query = this.$element.val() || ''; this.query = this.$element.val() || "";
var items = this.source(this.query, $.proxy(this.process, this)); var items = this.source(this.query, $.proxy(this.process, this));
return items ? this.process(items) : items; return items ? this.process(items) : items;
}; };
@@ -80,7 +91,7 @@ export class FormDropdownCtrl {
} }
getOptionsInternal(query) { getOptionsInternal(query) {
var result = this.getOptions({$query: query}); var result = this.getOptions({ $query: query });
if (this.isPromiseLike(result)) { if (this.isPromiseLike(result)) {
return result; return result;
} }
@@ -88,7 +99,7 @@ export class FormDropdownCtrl {
} }
isPromiseLike(obj) { isPromiseLike(obj) {
return obj && (typeof obj.then === 'function'); return obj && typeof obj.then === "function";
} }
modelChanged() { modelChanged() {
@@ -98,7 +109,7 @@ export class FormDropdownCtrl {
// if we have text use it // if we have text use it
if (this.lookupText) { if (this.lookupText) {
this.getOptionsInternal("").then(options => { this.getOptionsInternal("").then(options => {
var item = _.find(options, {value: this.model}); var item = _.find(options, { value: this.model });
this.updateDisplay(item ? item.text : this.model); this.updateDisplay(item ? item.text : this.model);
}); });
} else { } else {
@@ -140,7 +151,9 @@ export class FormDropdownCtrl {
} }
switchToLink(fromClick) { switchToLink(fromClick) {
if (this.linkMode && !fromClick) { return; } if (this.linkMode && !fromClick) {
return;
}
clearTimeout(this.cancelBlur); clearTimeout(this.cancelBlur);
this.cancelBlur = null; this.cancelBlur = null;
@@ -159,12 +172,12 @@ export class FormDropdownCtrl {
updateValue(text) { updateValue(text) {
text = _.unescape(text); text = _.unescape(text);
if (text === '' || this.text === text) { if (text === "" || this.text === text) {
return; return;
} }
this.$scope.$apply(() => { this.$scope.$apply(() => {
var option = _.find(this.optionCache, {text: text}); var option = _.find(this.optionCache, { text: text });
if (option) { if (option) {
if (_.isObject(this.model)) { if (_.isObject(this.model)) {
@@ -186,20 +199,24 @@ export class FormDropdownCtrl {
// property is synced with outerscope // property is synced with outerscope
this.$scope.$$postDigest(() => { this.$scope.$$postDigest(() => {
this.$scope.$apply(() => { this.$scope.$apply(() => {
this.onChange({$option: option}); this.onChange({ $option: option });
}); });
}); });
}); });
} }
updateDisplay(text) { updateDisplay(text) {
this.text = text; this.text = text;
this.display = this.$sce.trustAsHtml(this.templateSrv.highlightVariablesAsHtml(text)); this.display = this.$sce.trustAsHtml(
this.templateSrv.highlightVariablesAsHtml(text)
);
} }
open() { open() {
this.inputElement.css('width', (Math.max(this.linkElement.width(), 80) + 16) + 'px'); this.inputElement.css(
"width",
Math.max(this.linkElement.width(), 80) + 16 + "px"
);
this.inputElement.show(); this.inputElement.show();
this.inputElement.focus(); this.inputElement.focus();
@@ -207,15 +224,15 @@ export class FormDropdownCtrl {
this.linkElement.hide(); this.linkElement.hide();
this.linkMode = false; this.linkMode = false;
var typeahead = this.inputElement.data('typeahead'); var typeahead = this.inputElement.data("typeahead");
if (typeahead) { if (typeahead) {
this.inputElement.val(''); this.inputElement.val("");
typeahead.lookup(); typeahead.lookup();
} }
} }
} }
const template = ` const template = `
<input type="text" <input type="text"
data-provide="typeahead" data-provide="typeahead"
class="gf-form-input" class="gf-form-input"
@@ -232,11 +249,11 @@ const template = `
export function formDropdownDirective() { export function formDropdownDirective() {
return { return {
restrict: 'E', restrict: "E",
template: template, template: template,
controller: FormDropdownCtrl, controller: FormDropdownCtrl,
bindToController: true, bindToController: true,
controllerAs: 'ctrl', controllerAs: "ctrl",
scope: { scope: {
model: "=", model: "=",
getOptions: "&", getOptions: "&",
@@ -244,9 +261,9 @@ export function formDropdownDirective() {
cssClass: "@", cssClass: "@",
allowCustom: "@", allowCustom: "@",
labelMode: "@", labelMode: "@",
lookupText: "@", lookupText: "@"
}, }
}; };
} }
coreModule.directive('gfFormDropdown', formDropdownDirective); coreModule.directive("gfFormDropdown", formDropdownDirective);

View File

@@ -1,6 +1,6 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
const template = ` const template = `
<div class="scroll-canvas"> <div class="scroll-canvas">
@@ -24,14 +24,14 @@ const template = `
export function gfPageDirective() { export function gfPageDirective() {
return { return {
restrict: 'E', restrict: "E",
template: template, template: template,
scope: { scope: {
"model": "=", model: "="
}, },
transclude: { transclude: {
'header': '?gfPageHeader', header: "?gfPageHeader",
'body': 'gfPageBody', body: "gfPageBody"
}, },
link: function(scope, elem, attrs) { link: function(scope, elem, attrs) {
console.log(scope); console.log(scope);
@@ -39,4 +39,4 @@ export function gfPageDirective() {
}; };
} }
coreModule.directive('gfPage', gfPageDirective); coreModule.directive("gfPage", gfPageDirective);

View File

@@ -1,17 +1,23 @@
import config from 'app/core/config'; import config from "app/core/config";
import _ from 'lodash'; import _ from "lodash";
import $ from 'jquery'; import $ from "jquery";
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import {profiler} from 'app/core/profiler'; import { profiler } from "app/core/profiler";
import appEvents from 'app/core/app_events'; import appEvents from "app/core/app_events";
import Drop from 'tether-drop'; import Drop from "tether-drop";
export class GrafanaCtrl { export class GrafanaCtrl {
/** @ngInject */ /** @ngInject */
constructor($scope, alertSrv, utilSrv, $rootScope, $controller, contextSrv, globalEventSrv) { constructor(
$scope,
alertSrv,
utilSrv,
$rootScope,
$controller,
contextSrv,
globalEventSrv
) {
$scope.init = function() { $scope.init = function() {
$scope.contextSrv = contextSrv; $scope.contextSrv = contextSrv;
@@ -28,19 +34,19 @@ export class GrafanaCtrl {
$scope.initDashboard = function(dashboardData, viewScope) { $scope.initDashboard = function(dashboardData, viewScope) {
$scope.appEvent("dashboard-fetch-end", dashboardData); $scope.appEvent("dashboard-fetch-end", dashboardData);
$controller('DashboardCtrl', { $scope: viewScope }).init(dashboardData); $controller("DashboardCtrl", { $scope: viewScope }).init(dashboardData);
}; };
$rootScope.onAppEvent = function(name, callback, localScope) { $rootScope.onAppEvent = function(name, callback, localScope) {
var unbind = $rootScope.$on(name, callback); var unbind = $rootScope.$on(name, callback);
var callerScope = this; var callerScope = this;
if (callerScope.$id === 1 && !localScope) { if (callerScope.$id === 1 && !localScope) {
console.log('warning rootScope onAppEvent called without localscope'); console.log("warning rootScope onAppEvent called without localscope");
} }
if (localScope) { if (localScope) {
callerScope = localScope; callerScope = localScope;
} }
callerScope.$on('$destroy', unbind); callerScope.$on("$destroy", unbind);
}; };
$rootScope.appEvent = function(name, payload) { $rootScope.appEvent = function(name, payload) {
@@ -49,13 +55,62 @@ export class GrafanaCtrl {
}; };
$rootScope.colors = [ $rootScope.colors = [
"#7EB26D","#EAB839","#6ED0E0","#EF843C","#E24D42","#1F78C1","#BA43A9","#705DA0", "#7EB26D",
"#508642","#CCA300","#447EBC","#C15C17","#890F02","#0A437C","#6D1F62","#584477", "#EAB839",
"#B7DBAB","#F4D598","#70DBED","#F9BA8F","#F29191","#82B5D8","#E5A8E2","#AEA2E0", "#6ED0E0",
"#629E51","#E5AC0E","#64B0C8","#E0752D","#BF1B00","#0A50A1","#962D82","#614D93", "#EF843C",
"#9AC48A","#F2C96D","#65C5DB","#F9934E","#EA6460","#5195CE","#D683CE","#806EB7", "#E24D42",
"#3F6833","#967302","#2F575E","#99440A","#58140C","#052B51","#511749","#3F2B5B", "#1F78C1",
"#E0F9D7","#FCEACA","#CFFAFF","#F9E2D2","#FCE2DE","#BADFF4","#F9D9F9","#DEDAF7" "#BA43A9",
"#705DA0",
"#508642",
"#CCA300",
"#447EBC",
"#C15C17",
"#890F02",
"#0A437C",
"#6D1F62",
"#584477",
"#B7DBAB",
"#F4D598",
"#70DBED",
"#F9BA8F",
"#F29191",
"#82B5D8",
"#E5A8E2",
"#AEA2E0",
"#629E51",
"#E5AC0E",
"#64B0C8",
"#E0752D",
"#BF1B00",
"#0A50A1",
"#962D82",
"#614D93",
"#9AC48A",
"#F2C96D",
"#65C5DB",
"#F9934E",
"#EA6460",
"#5195CE",
"#D683CE",
"#806EB7",
"#3F6833",
"#967302",
"#2F575E",
"#99440A",
"#58140C",
"#052B51",
"#511749",
"#3F2B5B",
"#E0F9D7",
"#FCEACA",
"#CFFAFF",
"#F9E2D2",
"#FCE2DE",
"#BADFF4",
"#F9D9F9",
"#DEDAF7"
]; ];
$scope.init(); $scope.init();
@@ -63,30 +118,35 @@ export class GrafanaCtrl {
} }
/** @ngInject */ /** @ngInject */
export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScope) { export function grafanaAppDirective(
playlistSrv,
contextSrv,
$timeout,
$rootScope
) {
return { return {
restrict: 'E', restrict: "E",
controller: GrafanaCtrl, controller: GrafanaCtrl,
link: (scope, elem) => { link: (scope, elem) => {
var sidemenuOpen; var sidemenuOpen;
var body = $('body'); var body = $("body");
// see https://github.com/zenorocha/clipboard.js/issues/155 // see https://github.com/zenorocha/clipboard.js/issues/155
$.fn.modal.Constructor.prototype.enforceFocus = function() {}; $.fn.modal.Constructor.prototype.enforceFocus = function() {};
sidemenuOpen = scope.contextSrv.sidemenu; sidemenuOpen = scope.contextSrv.sidemenu;
body.toggleClass('sidemenu-open', sidemenuOpen); body.toggleClass("sidemenu-open", sidemenuOpen);
appEvents.on('toggle-sidemenu', () => { appEvents.on("toggle-sidemenu", () => {
body.toggleClass('sidemenu-open'); body.toggleClass("sidemenu-open");
}); });
appEvents.on('toggle-sidemenu-mobile', () => { appEvents.on("toggle-sidemenu-mobile", () => {
body.toggleClass('sidemenu-open--xs'); body.toggleClass("sidemenu-open--xs");
}); });
appEvents.on('toggle-sidemenu-hidden', () => { appEvents.on("toggle-sidemenu-hidden", () => {
body.toggleClass('sidemenu-hidden'); body.toggleClass("sidemenu-hidden");
}); });
// tooltip removal fix // tooltip removal fix
@@ -105,13 +165,13 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
} }
// clear body class sidemenu states // clear body class sidemenu states
body.removeClass('sidemenu-open--xs'); body.removeClass("sidemenu-open--xs");
$("#tooltip, .tooltip").remove(); $("#tooltip, .tooltip").remove();
// check for kiosk url param // check for kiosk url param
if (data.params.kiosk) { if (data.params.kiosk) {
appEvents.emit('toggle-kiosk-mode'); appEvents.emit("toggle-kiosk-mode");
} }
// close all drops // close all drops
@@ -121,8 +181,8 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
}); });
// handle kiosk mode // handle kiosk mode
appEvents.on('toggle-kiosk-mode', () => { appEvents.on("toggle-kiosk-mode", () => {
body.toggleClass('page-kiosk-mode'); body.toggleClass("page-kiosk-mode");
}); });
// handle in active view state class // handle in active view state class
@@ -136,17 +196,17 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
return; return;
} }
// only go to activity low mode on dashboard page // only go to activity low mode on dashboard page
if (!body.hasClass('page-dashboard')) { if (!body.hasClass("page-dashboard")) {
return; return;
} }
if ((new Date().getTime() - lastActivity) > inActiveTimeLimit) { if (new Date().getTime() - lastActivity > inActiveTimeLimit) {
activeUser = false; activeUser = false;
body.addClass('user-activity-low'); body.addClass("user-activity-low");
// hide sidemenu // hide sidemenu
if (sidemenuOpen) { if (sidemenuOpen) {
sidemenuHidden = true; sidemenuHidden = true;
body.removeClass('sidemenu-open'); body.removeClass("sidemenu-open");
$timeout(function() { $timeout(function() {
$rootScope.$broadcast("render"); $rootScope.$broadcast("render");
}, 100); }, 100);
@@ -158,12 +218,12 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
lastActivity = new Date().getTime(); lastActivity = new Date().getTime();
if (!activeUser) { if (!activeUser) {
activeUser = true; activeUser = true;
body.removeClass('user-activity-low'); body.removeClass("user-activity-low");
// restore sidemenu // restore sidemenu
if (sidemenuHidden) { if (sidemenuHidden) {
sidemenuHidden = false; sidemenuHidden = false;
body.addClass('sidemenu-open'); body.addClass("sidemenu-open");
$timeout(function() { $timeout(function() {
$rootScope.$broadcast("render"); $rootScope.$broadcast("render");
}, 100); }, 100);
@@ -175,12 +235,12 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
body.mousemove(userActivityDetected); body.mousemove(userActivityDetected);
body.keydown(userActivityDetected); body.keydown(userActivityDetected);
// treat tab change as activity // treat tab change as activity
document.addEventListener('visibilitychange', userActivityDetected); document.addEventListener("visibilitychange", userActivityDetected);
// check every 2 seconds // check every 2 seconds
setInterval(checkForInActiveUser, 2000); setInterval(checkForInActiveUser, 2000);
appEvents.on('toggle-view-mode', () => { appEvents.on("toggle-view-mode", () => {
lastActivity = 0; lastActivity = 0;
checkForInActiveUser(); checkForInActiveUser();
}); });
@@ -194,7 +254,7 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
// for stuff that animates, slides out etc, clicking it needs to // for stuff that animates, slides out etc, clicking it needs to
// hide it right away // hide it right away
var clickAutoHide = target.closest('[data-click-hide]'); var clickAutoHide = target.closest("[data-click-hide]");
if (clickAutoHide.length) { if (clickAutoHide.length) {
var clickAutoHideParent = clickAutoHide.parent(); var clickAutoHideParent = clickAutoHide.parent();
clickAutoHide.detach(); clickAutoHide.detach();
@@ -203,22 +263,28 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
}, 100); }, 100);
} }
if (target.parents('.navbar-buttons--playlist').length === 0) { if (target.parents(".navbar-buttons--playlist").length === 0) {
playlistSrv.stop(); playlistSrv.stop();
} }
// hide search // hide search
if (body.find('.search-container').length > 0) { if (body.find(".search-container").length > 0) {
if (target.parents('.search-results-container, .search-field-wrapper').length === 0) { if (
target.parents(".search-results-container, .search-field-wrapper")
.length === 0
) {
scope.$apply(function() { scope.$apply(function() {
scope.appEvent('hide-dash-search'); scope.appEvent("hide-dash-search");
}); });
} }
} }
// hide popovers // hide popovers
var popover = elem.find('.popover'); var popover = elem.find(".popover");
if (popover.length > 0 && target.parents('.graph-legend').length === 0) { if (
popover.length > 0 &&
target.parents(".graph-legend").length === 0
) {
popover.hide(); popover.hide();
} }
}); });
@@ -226,4 +292,4 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
}; };
} }
coreModule.directive('grafanaApp', grafanaAppDirective); coreModule.directive("grafanaApp", grafanaAppDirective);

View File

@@ -1,7 +1,7 @@
///<reference path="../../../headers/common.d.ts" /> ///<reference path="../../../headers/common.d.ts" />
import coreModule from '../../core_module'; import coreModule from "../../core_module";
import appEvents from 'app/core/app_events'; import appEvents from "app/core/app_events";
export class HelpCtrl { export class HelpCtrl {
tabIndex: any; tabIndex: any;
@@ -11,58 +11,64 @@ export class HelpCtrl {
constructor() { constructor() {
this.tabIndex = 0; this.tabIndex = 0;
this.shortcuts = { this.shortcuts = {
'Global': [ Global: [
{keys: ['g', 'h'], description: 'Go to Home Dashboard'}, { keys: ["g", "h"], description: "Go to Home Dashboard" },
{keys: ['g', 'p'], description: 'Go to Profile'}, { keys: ["g", "p"], description: "Go to Profile" },
{keys: ['s', 'o'], description: 'Open search'}, { keys: ["s", "o"], description: "Open search" },
{keys: ['s', 's'], description: 'Open search with starred filter'}, { keys: ["s", "s"], description: "Open search with starred filter" },
{keys: ['s', 't'], description: 'Open search in tags view'}, { keys: ["s", "t"], description: "Open search in tags view" },
{keys: ['esc'], description: 'Exit edit/setting views'}, { keys: ["esc"], description: "Exit edit/setting views" }
], ],
'Dashboard': [ Dashboard: [
{keys: ['mod+s'], description: 'Save dashboard'}, { keys: ["mod+s"], description: "Save dashboard" },
{keys: ['mod+h'], description: 'Hide row controls'}, { keys: ["mod+h"], description: "Hide row controls" },
{keys: ['d', 'r'], description: 'Refresh all panels'}, { keys: ["d", "r"], description: "Refresh all panels" },
{keys: ['d', 's'], description: 'Dashboard settings'}, { keys: ["d", "s"], description: "Dashboard settings" },
{keys: ['d', 'v'], description: 'Toggle in-active / view mode'}, { keys: ["d", "v"], description: "Toggle in-active / view mode" },
{keys: ['d', 'k'], description: 'Toggle kiosk mode (hides top nav)'}, { keys: ["d", "k"], description: "Toggle kiosk mode (hides top nav)" },
{keys: ['d', 'E'], description: 'Expand all rows'}, { keys: ["d", "E"], description: "Expand all rows" },
{keys: ['d', 'C'], description: 'Collapse all rows'}, { keys: ["d", "C"], description: "Collapse all rows" },
{keys: ['mod+o'], description: 'Toggle shared graph crosshair'}, { keys: ["mod+o"], description: "Toggle shared graph crosshair" }
], ],
'Focused Panel': [ "Focused Panel": [
{keys: ['e'], description: 'Toggle panel edit view'}, { keys: ["e"], description: "Toggle panel edit view" },
{keys: ['v'], description: 'Toggle panel fullscreen view'}, { keys: ["v"], description: "Toggle panel fullscreen view" },
{keys: ['p', 's'], description: 'Open Panel Share Modal'}, { keys: ["p", "s"], description: "Open Panel Share Modal" },
{keys: ['p', 'r'], description: 'Remove Panel'}, { keys: ["p", "r"], description: "Remove Panel" }
], ],
'Focused Row': [ "Focused Row": [
{keys: ['r', 'c'], description: 'Collapse Row'}, { keys: ["r", "c"], description: "Collapse Row" },
{keys: ['r', 'r'], description: 'Remove Row'}, { keys: ["r", "r"], description: "Remove Row" }
],
'Time Range': [
{keys: ['t', 'z'], description: 'Zoom out time range'},
{keys: ['t', '<i class="fa fa-long-arrow-left"></i>'], description: 'Move time range back'},
{keys: ['t', '<i class="fa fa-long-arrow-right"></i>'], description: 'Move time range forward'},
], ],
"Time Range": [
{ keys: ["t", "z"], description: "Zoom out time range" },
{
keys: ["t", '<i class="fa fa-long-arrow-left"></i>'],
description: "Move time range back"
},
{
keys: ["t", '<i class="fa fa-long-arrow-right"></i>'],
description: "Move time range forward"
}
]
}; };
} }
dismiss() { dismiss() {
appEvents.emit('hide-modal'); appEvents.emit("hide-modal");
} }
} }
export function helpModal() { export function helpModal() {
return { return {
restrict: 'E', restrict: "E",
templateUrl: 'public/app/core/components/help/help.html', templateUrl: "public/app/core/components/help/help.html",
controller: HelpCtrl, controller: HelpCtrl,
bindToController: true, bindToController: true,
transclude: true, transclude: true,
controllerAs: 'ctrl', controllerAs: "ctrl",
scope: {}, scope: {}
}; };
} }
coreModule.directive('helpModal', helpModal); coreModule.directive("helpModal", helpModal);

View File

@@ -1,35 +1,35 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import _ from 'lodash'; import _ from "lodash";
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import Drop from 'tether-drop'; import Drop from "tether-drop";
export function infoPopover() { export function infoPopover() {
return { return {
restrict: 'E', restrict: "E",
template: '<i class="fa fa-info-circle"></i>', template: '<i class="fa fa-info-circle"></i>',
transclude: true, transclude: true,
link: function(scope, elem, attrs, ctrl, transclude) { link: function(scope, elem, attrs, ctrl, transclude) {
var offset = attrs.offset || '0 -10px'; var offset = attrs.offset || "0 -10px";
var position = attrs.position || 'right middle'; var position = attrs.position || "right middle";
var classes = 'drop-help drop-hide-out-of-bounds'; var classes = "drop-help drop-hide-out-of-bounds";
var openOn = 'hover'; var openOn = "hover";
elem.addClass('gf-form-help-icon'); elem.addClass("gf-form-help-icon");
if (attrs.wide) { if (attrs.wide) {
classes += ' drop-wide'; classes += " drop-wide";
} }
if (attrs.mode) { if (attrs.mode) {
elem.addClass('gf-form-help-icon--' + attrs.mode); elem.addClass("gf-form-help-icon--" + attrs.mode);
} }
transclude(function(clone, newScope) { transclude(function(clone, newScope) {
var content = document.createElement("div"); var content = document.createElement("div");
content.className = 'markdown-html'; content.className = "markdown-html";
_.each(clone, (node) => { _.each(clone, node => {
content.appendChild(node); content.appendChild(node);
}); });
@@ -43,23 +43,22 @@ export function infoPopover() {
tetherOptions: { tetherOptions: {
offset: offset, offset: offset,
constraints: [ constraints: [
{ {
to: 'window', to: "window",
attachment: 'together', attachment: "together",
pin: true pin: true
} }
], ]
} }
}); });
var unbind = scope.$on('$destroy', function() { var unbind = scope.$on("$destroy", function() {
drop.destroy(); drop.destroy();
unbind(); unbind();
}); });
}); });
} }
}; };
} }
coreModule.directive('infoPopover', infoPopover); coreModule.directive("infoPopover", infoPopover);

View File

@@ -5,7 +5,7 @@
* Escapes `"` charachters from string * Escapes `"` charachters from string
*/ */
function escapeString(str: string): string { function escapeString(str: string): string {
return str.replace('"', '\"'); return str.replace('"', '"');
} }
/* /*
@@ -13,7 +13,7 @@ function escapeString(str: string): string {
*/ */
export function isObject(value: any): boolean { export function isObject(value: any): boolean {
var type = typeof value; var type = typeof value;
return !!value && (type === 'object'); return !!value && type === "object";
} }
/* /*
@@ -23,21 +23,21 @@ export function isObject(value: any): boolean {
*/ */
export function getObjectName(object: Object): string { export function getObjectName(object: Object): string {
if (object === undefined) { if (object === undefined) {
return ''; return "";
} }
if (object === null) { if (object === null) {
return 'Object'; return "Object";
} }
if (typeof object === 'object' && !object.constructor) { if (typeof object === "object" && !object.constructor) {
return 'Object'; return "Object";
} }
const funcNameRegex = /function ([^(]*)/; const funcNameRegex = /function ([^(]*)/;
const results = (funcNameRegex).exec((object).constructor.toString()); const results = funcNameRegex.exec(object.constructor.toString());
if (results && results.length > 1) { if (results && results.length > 1) {
return results[1]; return results[1];
} else { } else {
return ''; return "";
} }
} }
@@ -45,27 +45,33 @@ export function getObjectName(object: Object): string {
* Gets type of an object. Returns "null" for null objects * 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'; } if (object === null) {
return "null";
}
return typeof object; return typeof object;
} }
/* /*
* Generates inline preview for a JavaScript object based on a value * 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 {
var type = getType(object); var type = getType(object);
if (type === 'null' || type === 'undefined') { return type; } if (type === "null" || type === "undefined") {
return type;
}
if (type === 'string') { if (type === "string") {
value = '"' + escapeString(value) + '"'; value = '"' + escapeString(value) + '"';
} }
if (type === 'function') { if (type === "function") {
// Remove content of the function // Remove content of the function
return object.toString() return (
.replace(/[\r\n]/g, '') object
.replace(/\{.*\}/, '') + '{…}'; .toString()
.replace(/[\r\n]/g, "")
.replace(/\{.*\}/, "") + "{…}"
);
} }
return value; return value;
} }
@@ -74,11 +80,11 @@ export function getValuePreview (object: Object, value: string): string {
* Generates inline preview for a JavaScript object * Generates inline preview for a JavaScript object
*/ */
export function getPreview(object: string): string { export function getPreview(object: string): string {
let value = ''; let value = "";
if (isObject(object)) { if (isObject(object)) {
value = getObjectName(object); value = getObjectName(object);
if (Array.isArray(object)) { if (Array.isArray(object)) {
value += '[' + object.length + ']'; value += "[" + object.length + "]";
} }
} else { } else {
value = getValuePreview(object, object); value = getValuePreview(object, object);
@@ -97,7 +103,11 @@ export function cssClass(className: string): string {
* Creates a new DOM element wiht given type and class * Creates a new DOM element wiht given type and class
* TODO: move me to helpers * TODO: move me to helpers
*/ */
export function createElement(type: string, className?: string, content?: Element|string): Element { export function createElement(
type: string,
className?: string,
content?: Element | string
): Element {
const el = document.createElement(type); const el = document.createElement(type);
if (className) { if (className) {
el.classList.add(cssClass(className)); el.classList.add(cssClass(className));

View File

@@ -8,9 +8,9 @@ import {
getValuePreview, getValuePreview,
cssClass, cssClass,
createElement createElement
} from './helpers'; } from "./helpers";
import _ from 'lodash'; import _ from "lodash";
const DATE_STRING_REGEX = /(^\d{1,4}[\.|\\/|-]\d{1,2}[\.|\\/|-]\d{1,4})(\s*(?:0?[1-9]:[0-5]|1(?=[012])\d:[0-5])\d\s*[ap]m)?$/; const DATE_STRING_REGEX = /(^\d{1,4}[\.|\\/|-]\d{1,2}[\.|\\/|-]\d{1,4})(\s*(?:0?[1-9]:[0-5]|1(?=[012])\d:[0-5])\d\s*[ap]m)?$/;
const PARTIAL_DATE_REGEX = /\d{2}:\d{2}:\d{2} GMT-\d{4}/; const PARTIAL_DATE_REGEX = /\d{2}:\d{2}:\d{2} GMT-\d{4}/;
@@ -19,7 +19,12 @@ const JSON_DATE_REGEX = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/;
// When toggleing, don't animated removal or addition of more than a few items // When toggleing, don't animated removal or addition of more than a few items
const MAX_ANIMATED_TOGGLE_ITEMS = 10; const MAX_ANIMATED_TOGGLE_ITEMS = 10;
const requestAnimationFrame = window.requestAnimationFrame || function(cb: ()=>void) { cb(); return 0; }; const requestAnimationFrame =
window.requestAnimationFrame ||
function(cb: () => void) {
cb();
return 0;
};
export interface JsonExplorerConfig { export interface JsonExplorerConfig {
animateOpen?: boolean; animateOpen?: boolean;
@@ -33,15 +38,13 @@ const _defaultConfig: JsonExplorerConfig = {
theme: null theme: null
}; };
/** /**
* @class JsonExplorer * @class JsonExplorer
* *
* JsonExplorer allows you to render JSON objects in HTML with a * JsonExplorer allows you to render JSON objects in HTML with a
* **collapsible** navigation. * **collapsible** navigation.
*/ */
export class JsonExplorer { export class JsonExplorer {
// Hold the open state after the toggler is used // Hold the open state after the toggler is used
private _isOpen: boolean = null; private _isOpen: boolean = null;
@@ -77,9 +80,13 @@ export class JsonExplorer {
* *
* @param {string} [key=undefined] The key that this object in it's parent * @param {string} [key=undefined] The key that this object in it's parent
* context * context
*/ */
constructor(public json: any, private open = 1, private config: JsonExplorerConfig = _defaultConfig, private key?: string) { constructor(
} public json: any,
private open = 1,
private config: JsonExplorerConfig = _defaultConfig,
private key?: string
) {}
/* /*
* is formatter open? * is formatter open?
@@ -103,17 +110,19 @@ export class JsonExplorer {
* is this a date string? * is this a date string?
*/ */
private get isDate(): boolean { private get isDate(): boolean {
return (this.type === 'string') && return (
this.type === "string" &&
(DATE_STRING_REGEX.test(this.json) || (DATE_STRING_REGEX.test(this.json) ||
JSON_DATE_REGEX.test(this.json) || JSON_DATE_REGEX.test(this.json) ||
PARTIAL_DATE_REGEX.test(this.json)); PARTIAL_DATE_REGEX.test(this.json))
);
} }
/* /*
* is this a URL string? * is this a URL string?
*/ */
private get isUrl(): boolean { private get isUrl(): boolean {
return this.type === 'string' && (this.json.indexOf('http') === 0); return this.type === "string" && this.json.indexOf("http") === 0;
} }
/* /*
@@ -142,7 +151,9 @@ export class JsonExplorer {
* is this an empty object or array? * is this an empty object or array?
*/ */
private get isEmpty(): boolean { private get isEmpty(): boolean {
return this.isEmptyObject || (this.keys && !this.keys.length && this.isArray); return (
this.isEmptyObject || (this.keys && !this.keys.length && this.isArray)
);
} }
/* /*
@@ -150,7 +161,7 @@ export class JsonExplorer {
* This means that the formatter was called as a sub formatter of a parent formatter * This means that the formatter was called as a sub formatter of a parent formatter
*/ */
private get hasKey(): boolean { private get hasKey(): boolean {
return typeof this.key !== 'undefined'; return typeof this.key !== "undefined";
} }
/* /*
@@ -174,7 +185,7 @@ export class JsonExplorer {
*/ */
private get keys(): string[] { private get keys(): string[] {
if (this.isObject) { if (this.isObject) {
return Object.keys(this.json).map((key)=> key ? key : '""'); return Object.keys(this.json).map(key => (key ? key : '""'));
} else { } else {
return []; return [];
} }
@@ -183,7 +194,7 @@ export class JsonExplorer {
/** /**
* Toggles `isOpen` state * Toggles `isOpen` state
* *
*/ */
toggleOpen() { toggleOpen() {
this.isOpen = !this.isOpen; this.isOpen = !this.isOpen;
@@ -193,58 +204,65 @@ export class JsonExplorer {
} else { } else {
this.removeChildren(this.config.animateClose); this.removeChildren(this.config.animateClose);
} }
this.element.classList.toggle(cssClass('open')); this.element.classList.toggle(cssClass("open"));
} }
} }
/** /**
* Open all children up to a certain depth. * Open all children up to a certain depth.
* Allows actions such as expand all/collapse all * Allows actions such as expand all/collapse all
* *
*/ */
openAtDepth(depth = 1) { openAtDepth(depth = 1) {
if (depth < 0) { if (depth < 0) {
return; return;
} }
this.open = depth; this.open = depth;
this.isOpen = (depth !== 0); this.isOpen = depth !== 0;
if (this.element) { if (this.element) {
this.removeChildren(false); this.removeChildren(false);
if (depth === 0) { if (depth === 0) {
this.element.classList.remove(cssClass('open')); this.element.classList.remove(cssClass("open"));
} else { } else {
this.appendChildren(this.config.animateOpen); this.appendChildren(this.config.animateOpen);
this.element.classList.add(cssClass('open')); this.element.classList.add(cssClass("open"));
} }
} }
} }
isNumberArray() { isNumberArray() {
return (this.json.length > 0 && this.json.length < 4) && return (
(_.isNumber(this.json[0]) || _.isNumber(this.json[1])); this.json.length > 0 &&
this.json.length < 4 &&
(_.isNumber(this.json[0]) || _.isNumber(this.json[1]))
);
} }
renderArray() { renderArray() {
const arrayWrapperSpan = createElement('span'); const arrayWrapperSpan = createElement("span");
arrayWrapperSpan.appendChild(createElement('span', 'bracket', '[')); arrayWrapperSpan.appendChild(createElement("span", "bracket", "["));
// some pretty handling of number arrays // some pretty handling of number arrays
if (this.isNumberArray()) { if (this.isNumberArray()) {
this.json.forEach((val, index) => { this.json.forEach((val, index) => {
if (index > 0) { if (index > 0) {
arrayWrapperSpan.appendChild(createElement('span', 'array-comma', ',')); arrayWrapperSpan.appendChild(
createElement("span", "array-comma", ",")
);
} }
arrayWrapperSpan.appendChild(createElement('span', 'number', val)); arrayWrapperSpan.appendChild(createElement("span", "number", val));
}); });
this.skipChildren = true; this.skipChildren = true;
} else { } else {
arrayWrapperSpan.appendChild(createElement('span', 'number', (this.json.length))); arrayWrapperSpan.appendChild(
createElement("span", "number", this.json.length)
);
} }
arrayWrapperSpan.appendChild(createElement('span', 'bracket', ']')); arrayWrapperSpan.appendChild(createElement("span", "bracket", "]"));
return arrayWrapperSpan; return arrayWrapperSpan;
} }
@@ -255,11 +273,11 @@ export class JsonExplorer {
*/ */
render(skipRoot = false): HTMLDivElement { render(skipRoot = false): HTMLDivElement {
// construct the root element and assign it to this.element // construct the root element and assign it to this.element
this.element = createElement('div', 'row'); this.element = createElement("div", "row");
// construct the toggler link // construct the toggler link
const togglerLink = createElement('a', 'toggler-link'); const togglerLink = createElement("a", "toggler-link");
const togglerIcon = createElement('span', 'toggler'); const togglerIcon = createElement("span", "toggler");
// if this is an object we need a wrapper span (toggler) // if this is an object we need a wrapper span (toggler)
if (this.isObject) { if (this.isObject) {
@@ -268,19 +286,23 @@ export class JsonExplorer {
// if this is child of a parent formatter we need to append the key // if this is child of a parent formatter we need to append the key
if (this.hasKey) { if (this.hasKey) {
togglerLink.appendChild(createElement('span', 'key', `${this.key}:`)); togglerLink.appendChild(createElement("span", "key", `${this.key}:`));
} }
// Value for objects and arrays // Value for objects and arrays
if (this.isObject) { if (this.isObject) {
// construct the value holder element // construct the value holder element
const value = createElement('span', 'value'); const value = createElement("span", "value");
// we need a wrapper span for objects // we need a wrapper span for objects
const objectWrapperSpan = createElement('span'); const objectWrapperSpan = createElement("span");
// get constructor name and append it to wrapper span // get constructor name and append it to wrapper span
var constructorName = createElement('span', 'constructor-name', this.constructorName); var constructorName = createElement(
"span",
"constructor-name",
this.constructorName
);
objectWrapperSpan.appendChild(constructorName); objectWrapperSpan.appendChild(constructorName);
// if it's an array append the array specific elements like brackets and length // if it's an array append the array specific elements like brackets and length
@@ -294,18 +316,17 @@ export class JsonExplorer {
togglerLink.appendChild(value); togglerLink.appendChild(value);
// Primitive values // Primitive values
} else { } else {
// make a value holder element // make a value holder element
const value = this.isUrl ? createElement('a') : createElement('span'); const value = this.isUrl ? createElement("a") : createElement("span");
// add type and other type related CSS classes // add type and other type related CSS classes
value.classList.add(cssClass(this.type)); value.classList.add(cssClass(this.type));
if (this.isDate) { if (this.isDate) {
value.classList.add(cssClass('date')); value.classList.add(cssClass("date"));
} }
if (this.isUrl) { if (this.isUrl) {
value.classList.add(cssClass('url')); value.classList.add(cssClass("url"));
value.setAttribute('href', this.json); value.setAttribute("href", this.json);
} }
// Append value content to value element // Append value content to value element
@@ -317,17 +338,17 @@ export class JsonExplorer {
} }
// construct a children element // construct a children element
const children = createElement('div', 'children'); const children = createElement("div", "children");
// set CSS classes for children // set CSS classes for children
if (this.isObject) { if (this.isObject) {
children.classList.add(cssClass('object')); children.classList.add(cssClass("object"));
} }
if (this.isArray) { if (this.isArray) {
children.classList.add(cssClass('array')); children.classList.add(cssClass("array"));
} }
if (this.isEmpty) { if (this.isEmpty) {
children.classList.add(cssClass('empty')); children.classList.add(cssClass("empty"));
} }
// set CSS classes for root element // set CSS classes for root element
@@ -335,7 +356,7 @@ export class JsonExplorer {
this.element.classList.add(cssClass(this.config.theme)); this.element.classList.add(cssClass(this.config.theme));
} }
if (this.isOpen) { if (this.isOpen) {
this.element.classList.add(cssClass('open')); this.element.classList.add(cssClass("open"));
} }
// append toggler and children elements to root element // append toggler and children elements to root element
@@ -357,7 +378,7 @@ export class JsonExplorer {
// add event listener for toggling // add event listener for toggling
if (this.isObject) { if (this.isObject) {
togglerLink.addEventListener('click', this.toggleOpen.bind(this)); togglerLink.addEventListener("click", this.toggleOpen.bind(this));
} }
return this.element as HTMLDivElement; return this.element as HTMLDivElement;
@@ -366,17 +387,24 @@ export class JsonExplorer {
/** /**
* Appends all the children to children element * Appends all the children to children element
* Animated option is used when user triggers this via a click * Animated option is used when user triggers this via a click
*/ */
appendChildren(animated = false) { appendChildren(animated = false) {
const children = this.element.querySelector(`div.${cssClass('children')}`); const children = this.element.querySelector(`div.${cssClass("children")}`);
if (!children || this.isEmpty) { return; } if (!children || this.isEmpty) {
return;
}
if (animated) { if (animated) {
let index = 0; let index = 0;
const addAChild = ()=> { const addAChild = () => {
const key = this.keys[index]; const key = this.keys[index];
const formatter = new JsonExplorer(this.json[key], this.open - 1, this.config, key); const formatter = new JsonExplorer(
this.json[key],
this.open - 1,
this.config,
key
);
children.appendChild(formatter.render()); children.appendChild(formatter.render());
index += 1; index += 1;
@@ -391,10 +419,14 @@ export class JsonExplorer {
}; };
requestAnimationFrame(addAChild); requestAnimationFrame(addAChild);
} else { } else {
this.keys.forEach(key => { this.keys.forEach(key => {
const formatter = new JsonExplorer(this.json[key], this.open - 1, this.config, key); const formatter = new JsonExplorer(
this.json[key],
this.open - 1,
this.config,
key
);
children.appendChild(formatter.render()); children.appendChild(formatter.render());
}); });
} }
@@ -403,13 +435,15 @@ export class JsonExplorer {
/** /**
* Removes all the children from children element * Removes all the children from children element
* Animated option is used when user triggers this via a click * Animated option is used when user triggers this via a click
*/ */
removeChildren(animated = false) { removeChildren(animated = false) {
const childrenElement = this.element.querySelector(`div.${cssClass('children')}`) as HTMLDivElement; const childrenElement = this.element.querySelector(
`div.${cssClass("children")}`
) as HTMLDivElement;
if (animated) { if (animated) {
let childrenRemoved = 0; let childrenRemoved = 0;
const removeAChild = ()=> { const removeAChild = () => {
if (childrenElement && childrenElement.children.length) { if (childrenElement && childrenElement.children.length) {
childrenElement.removeChild(childrenElement.children[0]); childrenElement.removeChild(childrenElement.children[0]);
childrenRemoved += 1; childrenRemoved += 1;
@@ -423,7 +457,7 @@ export class JsonExplorer {
requestAnimationFrame(removeAChild); requestAnimationFrame(removeAChild);
} else { } else {
if (childrenElement) { if (childrenElement) {
childrenElement.innerHTML = ''; childrenElement.innerHTML = "";
} }
} }
} }

View File

@@ -1,22 +1,23 @@
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import {JsonExplorer} from '../json_explorer/json_explorer'; import { JsonExplorer } from "../json_explorer/json_explorer";
coreModule.directive('jsonTree', [function jsonTreeDirective() { coreModule.directive("jsonTree", [
return{ function jsonTreeDirective() {
restrict: 'E', return {
scope: { restrict: "E",
object: '=', scope: {
startExpanded: '@', object: "=",
rootName: '@', startExpanded: "@",
}, rootName: "@"
link: function(scope, elem) { },
link: function(scope, elem) {
var jsonExp = new JsonExplorer(scope.object, 3, {
animateOpen: true
});
var jsonExp = new JsonExplorer(scope.object, 3, { const html = jsonExp.render(true);
animateOpen: true elem.html(html);
}); }
};
const html = jsonExp.render(true); }
elem.html(html); ]);
}
};
}]);

View File

@@ -1,5 +1,5 @@
import store from 'app/core/store'; import store from "app/core/store";
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
var template = ` var template = `
<div class="layout-selector"> <div class="layout-selector">
@@ -17,53 +17,56 @@ export class LayoutSelectorCtrl {
/** @ngInject **/ /** @ngInject **/
constructor(private $rootScope) { constructor(private $rootScope) {
this.mode = store.get('grafana.list.layout.mode') || 'grid'; this.mode = store.get("grafana.list.layout.mode") || "grid";
} }
listView() { listView() {
this.mode = 'list'; this.mode = "list";
store.set('grafana.list.layout.mode', 'list'); store.set("grafana.list.layout.mode", "list");
this.$rootScope.appEvent('layout-mode-changed', 'list'); this.$rootScope.appEvent("layout-mode-changed", "list");
} }
gridView() { gridView() {
this.mode = 'grid'; this.mode = "grid";
store.set('grafana.list.layout.mode', 'grid'); store.set("grafana.list.layout.mode", "grid");
this.$rootScope.appEvent('layout-mode-changed', 'grid'); this.$rootScope.appEvent("layout-mode-changed", "grid");
} }
} }
/** @ngInject **/ /** @ngInject **/
export function layoutSelector() { export function layoutSelector() {
return { return {
restrict: 'E', restrict: "E",
controller: LayoutSelectorCtrl, controller: LayoutSelectorCtrl,
bindToController: true, bindToController: true,
controllerAs: 'ctrl', controllerAs: "ctrl",
scope: {}, scope: {},
template: template, template: template
}; };
} }
/** @ngInject **/ /** @ngInject **/
export function layoutMode($rootScope) { export function layoutMode($rootScope) {
return { return {
restrict: 'A', restrict: "A",
scope: {}, scope: {},
link: function(scope, elem) { link: function(scope, elem) {
var layout = store.get('grafana.list.layout.mode') || 'grid'; var layout = store.get("grafana.list.layout.mode") || "grid";
var className = 'card-list-layout-' + layout; var className = "card-list-layout-" + layout;
elem.addClass(className); elem.addClass(className);
$rootScope.onAppEvent('layout-mode-changed', (evt, newLayout) => { $rootScope.onAppEvent(
elem.removeClass(className); "layout-mode-changed",
className = 'card-list-layout-' + newLayout; (evt, newLayout) => {
elem.addClass(className); elem.removeClass(className);
}, scope); className = "card-list-layout-" + newLayout;
elem.addClass(className);
},
scope
);
} }
}; };
} }
coreModule.directive('layoutSelector', layoutSelector); coreModule.directive("layoutSelector", layoutSelector);
coreModule.directive('layoutMode', layoutMode); coreModule.directive("layoutMode", layoutMode);

View File

@@ -1,7 +1,7 @@
import _ from 'lodash'; import _ from "lodash";
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import appEvents from 'app/core/app_events'; import appEvents from "app/core/app_events";
import { SearchSrv } from 'app/core/services/search_srv'; import { SearchSrv } from "app/core/services/search_srv";
export class ManageDashboardsCtrl { export class ManageDashboardsCtrl {
public sections: any[]; public sections: any[];
@@ -13,13 +13,24 @@ export class ManageDashboardsCtrl {
canMove = false; canMove = false;
hasFilters = false; hasFilters = false;
selectAllChecked = false; selectAllChecked = false;
starredFilterOptions = [{ text: 'Filter by Starred', disabled: true }, { text: 'Yes' }, { text: 'No' }]; starredFilterOptions = [
{ text: "Filter by Starred", disabled: true },
{ text: "Yes" },
{ text: "No" }
];
selectedStarredFilter: any; selectedStarredFilter: any;
folderId?: number; folderId?: number;
/** @ngInject */ /** @ngInject */
constructor(private backendSrv, navModelSrv, private searchSrv: SearchSrv) { constructor(private backendSrv, navModelSrv, private searchSrv: SearchSrv) {
this.query = { query: '', mode: 'tree', tag: [], starred: false, skipRecent: true, skipStarred: true }; this.query = {
query: "",
mode: "tree",
tag: [],
starred: false,
skipRecent: true,
skipStarred: true
};
if (this.folderId) { if (this.folderId) {
this.query.folderIds = [this.folderId]; this.query.folderIds = [this.folderId];
@@ -33,7 +44,7 @@ export class ManageDashboardsCtrl {
} }
getDashboards() { getDashboards() {
return this.searchSrv.search(this.query).then((result) => { return this.searchSrv.search(this.query).then(result => {
return this.initDashboardList(result); return this.initDashboardList(result);
}); });
} }
@@ -42,7 +53,10 @@ export class ManageDashboardsCtrl {
this.canMove = false; this.canMove = false;
this.canDelete = false; this.canDelete = false;
this.selectAllChecked = false; this.selectAllChecked = false;
this.hasFilters = this.query.query.length > 0 || this.query.tag.length > 0 || this.query.starred; this.hasFilters =
this.query.query.length > 0 ||
this.query.tag.length > 0 ||
this.query.starred;
if (!result) { if (!result) {
this.sections = []; this.sections = [];
@@ -87,7 +101,7 @@ export class ManageDashboardsCtrl {
selectedDashboards.folders.push(section.slug); selectedDashboards.folders.push(section.slug);
} else { } else {
const selected = _.filter(section.items, { checked: true }); const selected = _.filter(section.items, { checked: true });
selectedDashboards.dashboards.push(..._.map(selected, 'slug')); selectedDashboards.dashboards.push(..._.map(selected, "slug"));
} }
} }
@@ -108,24 +122,30 @@ export class ManageDashboardsCtrl {
const data = this.getFoldersAndDashboardsToDelete(); const data = this.getFoldersAndDashboardsToDelete();
const folderCount = data.folders.length; const folderCount = data.folders.length;
const dashCount = data.dashboards.length; const dashCount = data.dashboards.length;
let text = 'Do you want to delete the '; let text = "Do you want to delete the ";
let text2; let text2;
if (folderCount > 0 && dashCount > 0) { if (folderCount > 0 && dashCount > 0) {
text += `selected folder${folderCount === 1 ? '' : 's'} and dashboard${dashCount === 1 ? '' : 's'}?`; text += `selected folder${folderCount === 1 ? "" : "s"} and dashboard${
text2 = `All dashboards of the selected folder${folderCount === 1 ? '' : 's'} will also be deleted`; dashCount === 1 ? "" : "s"
}?`;
text2 = `All dashboards of the selected folder${
folderCount === 1 ? "" : "s"
} will also be deleted`;
} else if (folderCount > 0) { } else if (folderCount > 0) {
text += `selected folder${folderCount === 1 ? '' : 's'} and all its dashboards?`; text += `selected folder${
folderCount === 1 ? "" : "s"
} and all its dashboards?`;
} else { } else {
text += `selected dashboard${dashCount === 1 ? '' : 's'}?`; text += `selected dashboard${dashCount === 1 ? "" : "s"}?`;
} }
appEvents.emit('confirm-modal', { appEvents.emit("confirm-modal", {
title: 'Delete', title: "Delete",
text: text, text: text,
text2: text2, text2: text2,
icon: 'fa-trash', icon: "fa-trash",
yesText: 'Delete', yesText: "Delete",
onConfirm: () => { onConfirm: () => {
const foldersAndDashboards = data.folders.concat(data.dashboards); const foldersAndDashboards = data.folders.concat(data.dashboards);
this.deleteFoldersAndDashboards(foldersAndDashboards); this.deleteFoldersAndDashboards(foldersAndDashboards);
@@ -145,28 +165,36 @@ export class ManageDashboardsCtrl {
let msg; let msg;
if (folderCount > 0 && dashCount > 0) { if (folderCount > 0 && dashCount > 0) {
header = `Folder${folderCount === 1 ? '' : 's'} And Dashboard${dashCount === 1 ? '' : 's'} Deleted`; header = `Folder${folderCount === 1 ? "" : "s"} And Dashboard${
msg = `${folderCount} folder${folderCount === 1 ? '' : 's'} `; dashCount === 1 ? "" : "s"
msg += `and ${dashCount} dashboard${dashCount === 1 ? '' : 's'} has been deleted`; } Deleted`;
msg = `${folderCount} folder${folderCount === 1 ? "" : "s"} `;
msg += `and ${dashCount} dashboard${
dashCount === 1 ? "" : "s"
} has been deleted`;
} else if (folderCount > 0) { } else if (folderCount > 0) {
header = `Folder${folderCount === 1 ? '' : 's'} Deleted`; header = `Folder${folderCount === 1 ? "" : "s"} Deleted`;
if (folderCount === 1) { if (folderCount === 1) {
msg = `${folders[0].dashboard.title} has been deleted`; msg = `${folders[0].dashboard.title} has been deleted`;
} else { } else {
msg = `${folderCount} folder${folderCount === 1 ? '' : 's'} has been deleted`; msg = `${folderCount} folder${
folderCount === 1 ? "" : "s"
} has been deleted`;
} }
} else if (dashCount > 0) { } else if (dashCount > 0) {
header = `Dashboard${dashCount === 1 ? '' : 's'} Deleted`; header = `Dashboard${dashCount === 1 ? "" : "s"} Deleted`;
if (dashCount === 1) { if (dashCount === 1) {
msg = `${dashboards[0].dashboard.title} has been deleted`; msg = `${dashboards[0].dashboard.title} has been deleted`;
} else { } else {
msg = `${dashCount} dashboard${dashCount === 1 ? '' : 's'} has been deleted`; msg = `${dashCount} dashboard${
dashCount === 1 ? "" : "s"
} has been deleted`;
} }
} }
appEvents.emit('alert-success', [header, msg]); appEvents.emit("alert-success", [header, msg]);
} }
this.getDashboards(); this.getDashboards();
@@ -178,7 +206,7 @@ export class ManageDashboardsCtrl {
for (const section of this.sections) { for (const section of this.sections) {
const selected = _.filter(section.items, { checked: true }); const selected = _.filter(section.items, { checked: true });
selectedDashboards.push(..._.map(selected, 'slug')); selectedDashboards.push(..._.map(selected, "slug"));
} }
return selectedDashboards; return selectedDashboards;
@@ -187,19 +215,25 @@ export class ManageDashboardsCtrl {
moveTo() { moveTo() {
const selectedDashboards = this.getDashboardsToMove(); const selectedDashboards = this.getDashboardsToMove();
const template = '<move-to-folder-modal dismiss="dismiss()" ' + const template =
'<move-to-folder-modal dismiss="dismiss()" ' +
'dashboards="model.dashboards" after-save="model.afterSave()">' + 'dashboards="model.dashboards" after-save="model.afterSave()">' +
'</move-to-folder-modal>`'; "</move-to-folder-modal>`";
appEvents.emit('show-modal', { appEvents.emit("show-modal", {
templateHtml: template, templateHtml: template,
modalClass: 'modal--narrow', modalClass: "modal--narrow",
model: { dashboards: selectedDashboards, afterSave: this.getDashboards.bind(this) } model: {
dashboards: selectedDashboards,
afterSave: this.getDashboards.bind(this)
}
}); });
} }
getTags() { getTags() {
return this.searchSrv.getDashboardTags().then((results) => { return this.searchSrv.getDashboardTags().then(results => {
this.tagFilterOptions = [{ term: 'Filter By Tag', disabled: true }].concat(results); this.tagFilterOptions = [
{ term: "Filter By Tag", disabled: true }
].concat(results);
this.selectedTagFilter = this.tagFilterOptions[0]; this.selectedTagFilter = this.tagFilterOptions[0];
}); });
} }
@@ -237,7 +271,7 @@ export class ManageDashboardsCtrl {
} }
onStarredFilterChange() { onStarredFilterChange() {
this.query.starred = this.selectedStarredFilter.text === 'Yes'; this.query.starred = this.selectedStarredFilter.text === "Yes";
this.selectedStarredFilter = this.starredFilterOptions[0]; this.selectedStarredFilter = this.starredFilterOptions[0];
return this.getDashboards(); return this.getDashboards();
} }
@@ -248,7 +282,7 @@ export class ManageDashboardsCtrl {
section.checked = this.selectAllChecked; section.checked = this.selectAllChecked;
} }
section.items = _.map(section.items, (item) => { section.items = _.map(section.items, item => {
item.checked = this.selectAllChecked; item.checked = this.selectAllChecked;
return item; return item;
}); });
@@ -258,7 +292,7 @@ export class ManageDashboardsCtrl {
} }
clearFilters() { clearFilters() {
this.query.query = ''; this.query.query = "";
this.query.tag = []; this.query.tag = [];
this.query.starred = false; this.query.starred = false;
this.getDashboards(); this.getDashboards();
@@ -267,15 +301,16 @@ export class ManageDashboardsCtrl {
export function manageDashboardsDirective() { export function manageDashboardsDirective() {
return { return {
restrict: 'E', restrict: "E",
templateUrl: 'public/app/core/components/manage_dashboards/manage_dashboards.html', templateUrl:
"public/app/core/components/manage_dashboards/manage_dashboards.html",
controller: ManageDashboardsCtrl, controller: ManageDashboardsCtrl,
bindToController: true, bindToController: true,
controllerAs: 'ctrl', controllerAs: "ctrl",
scope: { scope: {
folderId: '=' folderId: "="
} }
}; };
} }
coreModule.directive('manageDashboards', manageDashboardsDirective); coreModule.directive("manageDashboards", manageDashboardsDirective);

View File

@@ -1,6 +1,6 @@
import coreModule from '../../core_module'; import coreModule from "../../core_module";
import {NavModel} from '../../nav_model_srv'; import { NavModel } from "../../nav_model_srv";
import appEvents from 'app/core/app_events'; import appEvents from "app/core/app_events";
export class NavbarCtrl { export class NavbarCtrl {
model: NavModel; model: NavModel;
@@ -9,7 +9,7 @@ export class NavbarCtrl {
constructor() {} constructor() {}
showSearch() { showSearch() {
appEvents.emit('show-dash-search'); appEvents.emit("show-dash-search");
} }
navItemClicked(navItem, evt) { navItemClicked(navItem, evt) {
@@ -22,22 +22,21 @@ export class NavbarCtrl {
export function navbarDirective() { export function navbarDirective() {
return { return {
restrict: 'E', restrict: "E",
templateUrl: 'public/app/core/components/navbar/navbar.html', templateUrl: "public/app/core/components/navbar/navbar.html",
controller: NavbarCtrl, controller: NavbarCtrl,
bindToController: true, bindToController: true,
controllerAs: 'ctrl', controllerAs: "ctrl",
scope: { scope: {
model: "=", model: "="
}, },
link: function(scope, elem) { link: function(scope, elem) {}
}
}; };
} }
export function pageH1() { export function pageH1() {
return { return {
restrict: 'E', restrict: "E",
template: ` template: `
<h1 class="page-header__title"> <h1 class="page-header__title">
<i class="page-header__icon {{::model.header.icon}}" ng-if="::model.header.icon"></i> <i class="page-header__icon {{::model.header.icon}}" ng-if="::model.header.icon"></i>
@@ -46,11 +45,10 @@ export function pageH1() {
</h1> </h1>
`, `,
scope: { scope: {
model: "=", model: "="
} }
}; };
} }
coreModule.directive("pageH1", pageH1);
coreModule.directive('pageH1', pageH1); coreModule.directive("navbar", navbarDirective);
coreModule.directive('navbar', navbarDirective);

View File

@@ -1,7 +1,7 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import {contextSrv} from 'app/core/services/context_srv'; import { contextSrv } from "app/core/services/context_srv";
const template = ` const template = `
<div class="modal-body"> <div class="modal-body">
@@ -55,15 +55,17 @@ export class OrgSwitchCtrl {
} }
getUserOrgs() { getUserOrgs() {
this.backendSrv.get('/api/user/orgs').then(orgs => { this.backendSrv.get("/api/user/orgs").then(orgs => {
this.orgs = orgs; this.orgs = orgs;
}); });
} }
setUsingOrg(org) { setUsingOrg(org) {
return this.backendSrv.post('/api/user/using/' + org.orgId).then(() => { return this.backendSrv.post("/api/user/using/" + org.orgId).then(() => {
const re = /orgId=\d+/gi; const re = /orgId=\d+/gi;
this.setWindowLocationHref(this.getWindowLocationHref().replace(re, 'orgId=' + org.orgId)); this.setWindowLocationHref(
this.getWindowLocationHref().replace(re, "orgId=" + org.orgId)
);
}); });
} }
@@ -78,13 +80,13 @@ export class OrgSwitchCtrl {
export function orgSwitcher() { export function orgSwitcher() {
return { return {
restrict: 'E', restrict: "E",
template: template, template: template,
controller: OrgSwitchCtrl, controller: OrgSwitchCtrl,
bindToController: true, bindToController: true,
controllerAs: 'ctrl', controllerAs: "ctrl",
scope: {dismiss: "&"}, scope: { dismiss: "&" }
}; };
} }
coreModule.directive('orgSwitcher', orgSwitcher); coreModule.directive("orgSwitcher", orgSwitcher);

View File

@@ -1,6 +1,6 @@
///<reference path="../../../headers/common.d.ts" /> ///<reference path="../../../headers/common.d.ts" />
import _ from 'lodash'; import _ from "lodash";
export class QueryPartDef { export class QueryPartDef {
type: string; type: string;
@@ -30,7 +30,7 @@ export class QueryPart {
this.part = part; this.part = part;
this.def = def; this.def = def;
if (!this.def) { if (!this.def) {
throw {message: 'Could not find query part ' + part.type}; throw { message: "Could not find query part " + part.type };
} }
part.params = part.params || _.clone(this.def.defaultParams); part.params = part.params || _.clone(this.def.defaultParams);
@@ -42,25 +42,25 @@ export class QueryPart {
return this.def.renderer(this, innerExpr); return this.def.renderer(this, innerExpr);
} }
hasMultipleParamsInString (strValue, index) { hasMultipleParamsInString(strValue, index) {
if (strValue.indexOf(',') === -1) { if (strValue.indexOf(",") === -1) {
return false; return false;
} }
return this.def.params[index + 1] && this.def.params[index + 1].optional; return this.def.params[index + 1] && this.def.params[index + 1].optional;
} }
updateParam (strValue, index) { updateParam(strValue, index) {
// handle optional parameters // handle optional parameters
// if string contains ',' and next param is optional, split and update both // if string contains ',' and next param is optional, split and update both
if (this.hasMultipleParamsInString(strValue, index)) { if (this.hasMultipleParamsInString(strValue, index)) {
_.each(strValue.split(','), (partVal, idx) => { _.each(strValue.split(","), (partVal, idx) => {
this.updateParam(partVal.trim(), idx); this.updateParam(partVal.trim(), idx);
}); });
return; return;
} }
if (strValue === '' && this.def.params[index].optional) { if (strValue === "" && this.def.params[index].optional) {
this.params.splice(index, 1); this.params.splice(index, 1);
} else { } else {
this.params[index] = strValue; this.params[index] = strValue;
@@ -72,29 +72,29 @@ export class QueryPart {
updateText() { updateText() {
if (this.params.length === 0) { if (this.params.length === 0) {
this.text = this.def.type + '()'; this.text = this.def.type + "()";
return; return;
} }
var text = this.def.type + '('; var text = this.def.type + "(";
text += this.params.join(', '); text += this.params.join(", ");
text += ')'; text += ")";
this.text = text; this.text = text;
} }
} }
export function functionRenderer(part, innerExpr) { export function functionRenderer(part, innerExpr) {
var str = part.def.type + '('; var str = part.def.type + "(";
var parameters = _.map(part.params, (value, index) => { var parameters = _.map(part.params, (value, index) => {
var paramType = part.def.params[index]; var paramType = part.def.params[index];
if (paramType.type === 'time') { if (paramType.type === "time") {
if (value === 'auto') { if (value === "auto") {
value = '$__interval'; value = "$__interval";
} }
} }
if (paramType.quote === 'single') { if (paramType.quote === "single") {
return "'" + value + "'"; return "'" + value + "'";
} else if (paramType.quote === 'double') { } else if (paramType.quote === "double") {
return '"' + value + '"'; return '"' + value + '"';
} }
@@ -104,12 +104,11 @@ export function functionRenderer(part, innerExpr) {
if (innerExpr) { if (innerExpr) {
parameters.unshift(innerExpr); parameters.unshift(innerExpr);
} }
return str + parameters.join(', ') + ')'; return str + parameters.join(", ") + ")";
} }
export function suffixRenderer(part, innerExpr) { export function suffixRenderer(part, innerExpr) {
return innerExpr + ' ' + part.params[0]; return innerExpr + " " + part.params[0];
} }
export function identityRenderer(part, innerExpr) { export function identityRenderer(part, innerExpr) {

View File

@@ -1,8 +1,8 @@
///<reference path="../../../headers/common.d.ts" /> ///<reference path="../../../headers/common.d.ts" />
import _ from 'lodash'; import _ from "lodash";
import $ from 'jquery'; import $ from "jquery";
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
var template = ` var template = `
<div class="dropdown cascade-open"> <div class="dropdown cascade-open">
@@ -15,22 +15,22 @@ var template = `
</ul> </ul>
`; `;
/** @ngInject */ /** @ngInject */
export function queryPartEditorDirective($compile, templateSrv) { export function queryPartEditorDirective($compile, templateSrv) {
var paramTemplate =
var paramTemplate = '<input type="text" class="hide input-mini tight-form-func-param"></input>'; '<input type="text" class="hide input-mini tight-form-func-param"></input>';
return { return {
restrict: 'E', restrict: "E",
template: template, template: template,
scope: { scope: {
part: "=", part: "=",
handleEvent: "&", handleEvent: "&"
}, },
link: function postLink($scope, elem) { link: function postLink($scope, elem) {
var part = $scope.part; var part = $scope.part;
var partDef = part.def; var partDef = part.def;
var $paramsContainer = elem.find('.query-part-parameters'); var $paramsContainer = elem.find(".query-part-parameters");
$scope.partActions = []; $scope.partActions = [];
@@ -40,16 +40,16 @@ export function queryPartEditorDirective($compile, templateSrv) {
var $input = $link.next(); var $input = $link.next();
$input.val(part.params[paramIndex]); $input.val(part.params[paramIndex]);
$input.css('width', ($link.width() + 16) + 'px'); $input.css("width", $link.width() + 16 + "px");
$link.hide(); $link.hide();
$input.show(); $input.show();
$input.focus(); $input.focus();
$input.select(); $input.select();
var typeahead = $input.data('typeahead'); var typeahead = $input.data("typeahead");
if (typeahead) { if (typeahead) {
$input.val(''); $input.val("");
typeahead.lookup(); typeahead.lookup();
} }
} }
@@ -60,12 +60,12 @@ export function queryPartEditorDirective($compile, templateSrv) {
var $link = $input.prev(); var $link = $input.prev();
var newValue = $input.val(); var newValue = $input.val();
if (newValue !== '' || part.def.params[paramIndex].optional) { if (newValue !== "" || part.def.params[paramIndex].optional) {
$link.html(templateSrv.highlightVariablesAsHtml(newValue)); $link.html(templateSrv.highlightVariablesAsHtml(newValue));
part.updateParam($input.val(), paramIndex); part.updateParam($input.val(), paramIndex);
$scope.$apply(() => { $scope.$apply(() => {
$scope.handleEvent({$event: {name: 'part-param-changed'}}); $scope.handleEvent({ $event: { name: "part-param-changed" } });
}); });
} }
@@ -82,7 +82,7 @@ export function queryPartEditorDirective($compile, templateSrv) {
function inputKeyDown() { function inputKeyDown() {
/*jshint validthis:true */ /*jshint validthis:true */
this.style.width = (3 + this.value.length) * 8 + 'px'; this.style.width = (3 + this.value.length) * 8 + "px";
} }
function addTypeahead($input, param, paramIndex) { function addTypeahead($input, param, paramIndex) {
@@ -90,30 +90,36 @@ export function queryPartEditorDirective($compile, templateSrv) {
return; return;
} }
var typeaheadSource = function (query, callback) { var typeaheadSource = function(query, callback) {
if (param.options) { if (param.options) {
var options = param.options; var options = param.options;
if (param.type === 'int') { if (param.type === "int") {
options = _.map(options, function(val) { return val.toString(); }); options = _.map(options, function(val) {
return val.toString();
});
} }
return options; return options;
} }
$scope.$apply(function() { $scope.$apply(function() {
$scope.handleEvent({$event: {name: 'get-param-options'}}).then(function(result) { $scope
var dynamicOptions = _.map(result, function(op) { return op.value; }); .handleEvent({ $event: { name: "get-param-options" } })
callback(dynamicOptions); .then(function(result) {
}); var dynamicOptions = _.map(result, function(op) {
return op.value;
});
callback(dynamicOptions);
});
}); });
}; };
$input.attr('data-provide', 'typeahead'); $input.attr("data-provide", "typeahead");
$input.typeahead({ $input.typeahead({
source: typeaheadSource, source: typeaheadSource,
minLength: 0, minLength: 0,
items: 1000, items: 1000,
updater: function (value) { updater: function(value) {
setTimeout(function() { setTimeout(function() {
inputBlur.call($input[0], paramIndex); inputBlur.call($input[0], paramIndex);
}, 0); }, 0);
@@ -121,22 +127,24 @@ export function queryPartEditorDirective($compile, templateSrv) {
} }
}); });
var typeahead = $input.data('typeahead'); var typeahead = $input.data("typeahead");
typeahead.lookup = function () { typeahead.lookup = function() {
this.query = this.$element.val() || ''; this.query = this.$element.val() || "";
var items = this.source(this.query, $.proxy(this.process, this)); var items = this.source(this.query, $.proxy(this.process, this));
return items ? this.process(items) : items; return items ? this.process(items) : items;
}; };
} }
$scope.showActionsMenu = function() { $scope.showActionsMenu = function() {
$scope.handleEvent({$event: {name: 'get-part-actions'}}).then(res => { $scope
$scope.partActions = res; .handleEvent({ $event: { name: "get-part-actions" } })
}); .then(res => {
$scope.partActions = res;
});
}; };
$scope.triggerPartAction = function(action) { $scope.triggerPartAction = function(action) {
$scope.handleEvent({$event: {name: 'action', action: action}}); $scope.handleEvent({ $event: { name: "action", action: action } });
}; };
function addElementsAndCompile() { function addElementsAndCompile() {
@@ -146,11 +154,15 @@ export function queryPartEditorDirective($compile, templateSrv) {
} }
if (index > 0) { if (index > 0) {
$('<span>, </span>').appendTo($paramsContainer); $("<span>, </span>").appendTo($paramsContainer);
} }
var paramValue = templateSrv.highlightVariablesAsHtml(part.params[index]); var paramValue = templateSrv.highlightVariablesAsHtml(
var $paramLink = $('<a class="graphite-func-param-link pointer">' + paramValue + '</a>'); part.params[index]
);
var $paramLink = $(
'<a class="graphite-func-param-link pointer">' + paramValue + "</a>"
);
var $input = $(paramTemplate); var $input = $(paramTemplate);
$paramLink.appendTo($paramsContainer); $paramLink.appendTo($paramsContainer);
@@ -175,4 +187,4 @@ export function queryPartEditorDirective($compile, templateSrv) {
}; };
} }
coreModule.directive('queryPartEditor', queryPartEditorDirective); coreModule.directive("queryPartEditor", queryPartEditorDirective);

View File

@@ -1,27 +1,25 @@
import PerfectScrollbar from 'perfect-scrollbar'; import PerfectScrollbar from "perfect-scrollbar";
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
export function geminiScrollbar() { export function geminiScrollbar() {
return { return {
restrict: 'A', restrict: "A",
link: function(scope, elem, attrs) { link: function(scope, elem, attrs) {
let scrollbar = new PerfectScrollbar(elem[0]); let scrollbar = new PerfectScrollbar(elem[0]);
scope.$on('$routeChangeSuccess', () => { scope.$on("$routeChangeSuccess", () => {
elem[0].scrollTop = 0; elem[0].scrollTop = 0;
}); });
scope.$on('$routeUpdate', () => { scope.$on("$routeUpdate", () => {
elem[0].scrollTop = 0; elem[0].scrollTop = 0;
}); });
scope.$on('$destroy', () => { scope.$on("$destroy", () => {
scrollbar.destroy(); scrollbar.destroy();
}); });
} }
}; };
} }
coreModule.directive('grafanaScrollbar', geminiScrollbar); coreModule.directive("grafanaScrollbar", geminiScrollbar);

View File

@@ -1,7 +1,7 @@
import _ from 'lodash'; import _ from "lodash";
import coreModule from '../../core_module'; import coreModule from "../../core_module";
import { SearchSrv } from 'app/core/services/search_srv'; import { SearchSrv } from "app/core/services/search_srv";
import appEvents from 'app/core/app_events'; import appEvents from "app/core/app_events";
export class SearchCtrl { export class SearchCtrl {
isOpen: boolean; isOpen: boolean;
@@ -17,9 +17,14 @@ export class SearchCtrl {
initialFolderFilterTitle: string; initialFolderFilterTitle: string;
/** @ngInject */ /** @ngInject */
constructor($scope, private $location, private $timeout, private searchSrv: SearchSrv) { constructor(
appEvents.on('show-dash-search', this.openSearch.bind(this), $scope); $scope,
appEvents.on('hide-dash-search', this.closeSearch.bind(this), $scope); private $location,
private $timeout,
private searchSrv: SearchSrv
) {
appEvents.on("show-dash-search", this.openSearch.bind(this), $scope);
appEvents.on("hide-dash-search", this.closeSearch.bind(this), $scope);
this.initialFolderFilterTitle = "All"; this.initialFolderFilterTitle = "All";
} }
@@ -38,7 +43,7 @@ export class SearchCtrl {
this.giveSearchFocus = 0; this.giveSearchFocus = 0;
this.selectedIndex = -1; this.selectedIndex = -1;
this.results = []; this.results = [];
this.query = { query: '', tag: [], starred: false }; this.query = { query: "", tag: [], starred: false };
this.currentSearchId = 0; this.currentSearchId = 0;
this.ignoreClose = true; this.ignoreClose = true;
this.isLoading = true; this.isLoading = true;
@@ -70,7 +75,9 @@ export class SearchCtrl {
if (currentItem) { if (currentItem) {
if (currentItem.dashboardIndex !== undefined) { if (currentItem.dashboardIndex !== undefined) {
const selectedDash = this.results[currentItem.folderIndex].items[currentItem.dashboardIndex]; const selectedDash = this.results[currentItem.folderIndex].items[
currentItem.dashboardIndex
];
if (selectedDash) { if (selectedDash) {
this.$location.search({}); this.$location.search({});
@@ -98,7 +105,9 @@ export class SearchCtrl {
if (currentItem) { if (currentItem) {
if (currentItem.dashboardIndex !== undefined) { if (currentItem.dashboardIndex !== undefined) {
this.results[currentItem.folderIndex].items[currentItem.dashboardIndex].selected = false; this.results[currentItem.folderIndex].items[
currentItem.dashboardIndex
].selected = false;
} else { } else {
this.results[currentItem.folderIndex].selected = false; this.results[currentItem.folderIndex].selected = false;
} }
@@ -111,10 +120,13 @@ export class SearchCtrl {
const max = flattenedResult.length; const max = flattenedResult.length;
let newIndex = this.selectedIndex + direction; let newIndex = this.selectedIndex + direction;
this.selectedIndex = ((newIndex %= max) < 0) ? newIndex + max : newIndex; this.selectedIndex = (newIndex %= max) < 0 ? newIndex + max : newIndex;
const selectedItem = flattenedResult[this.selectedIndex]; const selectedItem = flattenedResult[this.selectedIndex];
if (selectedItem.dashboardIndex === undefined && this.results[selectedItem.folderIndex].id === 0) { if (
selectedItem.dashboardIndex === undefined &&
this.results[selectedItem.folderIndex].id === 0
) {
this.moveSelection(direction); this.moveSelection(direction);
return; return;
} }
@@ -125,7 +137,9 @@ export class SearchCtrl {
return; return;
} }
this.results[selectedItem.folderIndex].items[selectedItem.dashboardIndex].selected = true; this.results[selectedItem.folderIndex].items[
selectedItem.dashboardIndex
].selected = true;
return; return;
} }
@@ -142,7 +156,9 @@ export class SearchCtrl {
var localSearchId = this.currentSearchId; var localSearchId = this.currentSearchId;
return this.searchSrv.search(this.query).then(results => { return this.searchSrv.search(this.query).then(results => {
if (localSearchId < this.currentSearchId) { return; } if (localSearchId < this.currentSearchId) {
return;
}
this.results = results || []; this.results = results || [];
this.isLoading = false; this.isLoading = false;
this.moveSelection(1); this.moveSelection(1);
@@ -151,7 +167,9 @@ export class SearchCtrl {
queryHasNoFilters() { queryHasNoFilters() {
var query = this.query; var query = this.query;
return query.query === '' && query.starred === false && query.tag.length === 0; return (
query.query === "" && query.starred === false && query.tag.length === 0
);
} }
filterByTag(tag) { filterByTag(tag) {
@@ -171,7 +189,7 @@ export class SearchCtrl {
} }
getTags() { getTags() {
return this.searchSrv.getDashboardTags().then((results) => { return this.searchSrv.getDashboardTags().then(results => {
this.results = results; this.results = results;
this.giveSearchFocus = this.giveSearchFocus + 1; this.giveSearchFocus = this.giveSearchFocus + 1;
}); });
@@ -196,7 +214,7 @@ export class SearchCtrl {
private getFlattenedResultForNavigation() { private getFlattenedResultForNavigation() {
let folderIndex = 0; let folderIndex = 0;
return _.flatMap(this.results, (s) => { return _.flatMap(this.results, s => {
let result = []; let result = [];
result.push({ result.push({
@@ -205,12 +223,14 @@ export class SearchCtrl {
let dashboardIndex = 0; let dashboardIndex = 0;
result = result.concat(_.map(s.items || [], (i) => { result = result.concat(
return { _.map(s.items || [], i => {
folderIndex: folderIndex, return {
dashboardIndex: dashboardIndex++ folderIndex: folderIndex,
}; dashboardIndex: dashboardIndex++
})); };
})
);
folderIndex++; folderIndex++;
return result; return result;
@@ -220,13 +240,13 @@ export class SearchCtrl {
export function searchDirective() { export function searchDirective() {
return { return {
restrict: 'E', restrict: "E",
templateUrl: 'public/app/core/components/search/search.html', templateUrl: "public/app/core/components/search/search.html",
controller: SearchCtrl, controller: SearchCtrl,
bindToController: true, bindToController: true,
controllerAs: 'ctrl', controllerAs: "ctrl",
scope: {}, scope: {}
}; };
} }
coreModule.directive('dashboardSearch', searchDirective); coreModule.directive("dashboardSearch", searchDirective);

View File

@@ -1,6 +1,6 @@
import _ from 'lodash'; import _ from "lodash";
import coreModule from '../../core_module'; import coreModule from "../../core_module";
import appEvents from 'app/core/app_events'; import appEvents from "app/core/app_events";
export class SearchResultsCtrl { export class SearchResultsCtrl {
results: any; results: any;
@@ -64,13 +64,13 @@ export class SearchResultsCtrl {
onItemClick(item) { onItemClick(item) {
if (this.$location.path().indexOf(item.url) > -1) { if (this.$location.path().indexOf(item.url) > -1) {
appEvents.emit('hide-dash-search'); appEvents.emit("hide-dash-search");
} }
} }
selectTag(tag, evt) { selectTag(tag, evt) {
if (this.onTagSelected) { if (this.onTagSelected) {
this.onTagSelected({$tag: tag}); this.onTagSelected({ $tag: tag });
} }
if (evt) { if (evt) {
@@ -82,19 +82,19 @@ export class SearchResultsCtrl {
export function searchResultsDirective() { export function searchResultsDirective() {
return { return {
restrict: 'E', restrict: "E",
templateUrl: 'public/app/core/components/search/search_results.html', templateUrl: "public/app/core/components/search/search_results.html",
controller: SearchResultsCtrl, controller: SearchResultsCtrl,
bindToController: true, bindToController: true,
controllerAs: 'ctrl', controllerAs: "ctrl",
scope: { scope: {
editable: '@', editable: "@",
results: '=', results: "=",
onSelectionChanged: '&', onSelectionChanged: "&",
onTagSelected: '&', onTagSelected: "&",
onFolderExpanding: '&' onFolderExpanding: "&"
}, }
}; };
} }
coreModule.directive('dashboardSearchResults', searchResultsDirective); coreModule.directive("dashboardSearchResults", searchResultsDirective);

View File

@@ -1,8 +1,8 @@
import _ from 'lodash'; import _ from "lodash";
import config from 'app/core/config'; import config from "app/core/config";
import $ from 'jquery'; import $ from "jquery";
import coreModule from '../../core_module'; import coreModule from "../../core_module";
import appEvents from 'app/core/app_events'; import appEvents from "app/core/app_events";
export class SideMenuCtrl { export class SideMenuCtrl {
user: any; user: any;
@@ -13,47 +13,63 @@ export class SideMenuCtrl {
isOpenMobile: boolean; isOpenMobile: boolean;
/** @ngInject */ /** @ngInject */
constructor(private $scope, private $rootScope, private $location, private contextSrv, private $timeout) { constructor(
private $scope,
private $rootScope,
private $location,
private contextSrv,
private $timeout
) {
this.isSignedIn = contextSrv.isSignedIn; this.isSignedIn = contextSrv.isSignedIn;
this.user = contextSrv.user; this.user = contextSrv.user;
this.mainLinks = _.filter(config.bootData.navTree, item => !item.hideFromMenu); this.mainLinks = _.filter(
this.bottomNav = _.filter(config.bootData.navTree, item => item.hideFromMenu); config.bootData.navTree,
this.loginUrl = 'login?redirect=' + encodeURIComponent(this.$location.path()); item => !item.hideFromMenu
);
this.bottomNav = _.filter(
config.bootData.navTree,
item => item.hideFromMenu
);
this.loginUrl =
"login?redirect=" + encodeURIComponent(this.$location.path());
if (contextSrv.user.orgCount > 1) { if (contextSrv.user.orgCount > 1) {
let profileNode = _.find(this.bottomNav, {id: 'profile'}); let profileNode = _.find(this.bottomNav, { id: "profile" });
if (profileNode) { if (profileNode) {
profileNode.showOrgSwitcher = true; profileNode.showOrgSwitcher = true;
} }
} }
this.$scope.$on('$routeChangeSuccess', () => { this.$scope.$on("$routeChangeSuccess", () => {
this.loginUrl = 'login?redirect=' + encodeURIComponent(this.$location.path()); this.loginUrl =
"login?redirect=" + encodeURIComponent(this.$location.path());
}); });
} }
toggleSideMenu() { toggleSideMenu() {
this.contextSrv.toggleSideMenu(); this.contextSrv.toggleSideMenu();
appEvents.emit('toggle-sidemenu'); appEvents.emit("toggle-sidemenu");
this.$timeout(() => { this.$timeout(() => {
this.$rootScope.$broadcast('render'); this.$rootScope.$broadcast("render");
}); });
} }
toggleSideMenuSmallBreakpoint() { toggleSideMenuSmallBreakpoint() {
appEvents.emit('toggle-sidemenu-mobile'); appEvents.emit("toggle-sidemenu-mobile");
} }
switchOrg() { switchOrg() {
this.$rootScope.appEvent('show-modal', { this.$rootScope.appEvent("show-modal", {
templateHtml: '<org-switcher dismiss="dismiss()"></org-switcher>', templateHtml: '<org-switcher dismiss="dismiss()"></org-switcher>'
}); });
} }
itemClicked(item, evt) { itemClicked(item, evt) {
if (item.url === '/shortcuts') { if (item.url === "/shortcuts") {
appEvents.emit('show-modal', {templateHtml: '<help-modal></help-modal>'}); appEvents.emit("show-modal", {
templateHtml: "<help-modal></help-modal>"
});
evt.preventDefault(); evt.preventDefault();
} }
} }
@@ -61,16 +77,16 @@ export class SideMenuCtrl {
export function sideMenuDirective() { export function sideMenuDirective() {
return { return {
restrict: 'E', restrict: "E",
templateUrl: 'public/app/core/components/sidemenu/sidemenu.html', templateUrl: "public/app/core/components/sidemenu/sidemenu.html",
controller: SideMenuCtrl, controller: SideMenuCtrl,
bindToController: true, bindToController: true,
controllerAs: 'ctrl', controllerAs: "ctrl",
scope: {}, scope: {},
link: function(scope, elem) { link: function(scope, elem) {
// hack to hide dropdown menu // hack to hide dropdown menu
elem.on('click.dropdown', '.dropdown-menu a', function(evt) { elem.on("click.dropdown", ".dropdown-menu a", function(evt) {
var menu = $(evt.target).parents('.dropdown-menu'); var menu = $(evt.target).parents(".dropdown-menu");
var parent = menu.parent(); var parent = menu.parent();
menu.detach(); menu.detach();
@@ -82,4 +98,4 @@ export function sideMenuDirective() {
}; };
} }
coreModule.directive('sidemenu', sideMenuDirective); coreModule.directive("sidemenu", sideMenuDirective);

View File

@@ -1,6 +1,6 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
var template = ` var template = `
<label for="check-{{ctrl.id}}" class="gf-form-label {{ctrl.labelClass}} pointer" ng-show="ctrl.label"> <label for="check-{{ctrl.id}}" class="gf-form-label {{ctrl.labelClass}} pointer" ng-show="ctrl.label">
@@ -33,14 +33,13 @@ export class SwitchCtrl {
return this.onChange(); return this.onChange();
}); });
} }
} }
export function switchDirective() { export function switchDirective() {
return { return {
restrict: 'E', restrict: "E",
controller: SwitchCtrl, controller: SwitchCtrl,
controllerAs: 'ctrl', controllerAs: "ctrl",
bindToController: true, bindToController: true,
scope: { scope: {
checked: "=", checked: "=",
@@ -48,10 +47,10 @@ export function switchDirective() {
labelClass: "@", labelClass: "@",
tooltip: "@", tooltip: "@",
switchClass: "@", switchClass: "@",
onChange: "&", onChange: "&"
}, },
template: template, template: template
}; };
} }
coreModule.directive('gfFormSwitch', switchDirective); coreModule.directive("gfFormSwitch", switchDirective);

View File

@@ -1,5 +1,5 @@
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import _ from 'lodash'; import _ from "lodash";
const template = ` const template = `
<div class="dropdown"> <div class="dropdown">
@@ -17,36 +17,43 @@ export class TeamPickerCtrl {
/** @ngInject */ /** @ngInject */
constructor(private backendSrv) { constructor(private backendSrv) {
this.debouncedSearchGroups = _.debounce(this.searchGroups, 500, {'leading': true, 'trailing': false}); this.debouncedSearchGroups = _.debounce(this.searchGroups, 500, {
leading: true,
trailing: false
});
this.reset(); this.reset();
} }
reset() { reset() {
this.group = {text: 'Choose', value: null}; this.group = { text: "Choose", value: null };
} }
searchGroups(query: string) { searchGroups(query: string) {
return Promise.resolve(this.backendSrv.get('/api/teams/search?perpage=10&page=1&query=' + query).then(result => { return Promise.resolve(
return _.map(result.teams, ug => { this.backendSrv
return {text: ug.name, value: ug}; .get("/api/teams/search?perpage=10&page=1&query=" + query)
}); .then(result => {
})); return _.map(result.teams, ug => {
return { text: ug.name, value: ug };
});
})
);
} }
onChange(option) { onChange(option) {
this.teamPicked({$group: option.value}); this.teamPicked({ $group: option.value });
} }
} }
export function teamPicker() { export function teamPicker() {
return { return {
restrict: 'E', restrict: "E",
template: template, template: template,
controller: TeamPickerCtrl, controller: TeamPickerCtrl,
bindToController: true, bindToController: true,
controllerAs: 'ctrl', controllerAs: "ctrl",
scope: { scope: {
teamPicked: '&', teamPicked: "&"
}, },
link: function(scope, elem, attrs, ctrl) { link: function(scope, elem, attrs, ctrl) {
scope.$on("team-picker-reset", () => { scope.$on("team-picker-reset", () => {
@@ -56,4 +63,4 @@ export function teamPicker() {
}; };
} }
coreModule.directive('teamPicker', teamPicker); coreModule.directive("teamPicker", teamPicker);

View File

@@ -1,5 +1,5 @@
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import _ from 'lodash'; import _ from "lodash";
const template = ` const template = `
<div class="dropdown"> <div class="dropdown">
@@ -18,23 +18,30 @@ export class UserPickerCtrl {
/** @ngInject */ /** @ngInject */
constructor(private backendSrv) { constructor(private backendSrv) {
this.reset(); this.reset();
this.debouncedSearchUsers = _.debounce(this.searchUsers, 500, {'leading': true, 'trailing': false}); this.debouncedSearchUsers = _.debounce(this.searchUsers, 500, {
leading: true,
trailing: false
});
} }
searchUsers(query: string) { searchUsers(query: string) {
return Promise.resolve(this.backendSrv.get('/api/users/search?perpage=10&page=1&query=' + query).then(result => { return Promise.resolve(
return _.map(result.users, user => { this.backendSrv
return {text: user.login + ' - ' + user.email, value: user}; .get("/api/users/search?perpage=10&page=1&query=" + query)
}); .then(result => {
})); return _.map(result.users, user => {
return { text: user.login + " - " + user.email, value: user };
});
})
);
} }
onChange(option) { onChange(option) {
this.userPicked({$user: option.value}); this.userPicked({ $user: option.value });
} }
reset() { reset() {
this.user = {text: 'Choose', value: null}; this.user = { text: "Choose", value: null };
} }
} }
@@ -47,13 +54,13 @@ export interface User {
export function userPicker() { export function userPicker() {
return { return {
restrict: 'E', restrict: "E",
template: template, template: template,
controller: UserPickerCtrl, controller: UserPickerCtrl,
bindToController: true, bindToController: true,
controllerAs: 'ctrl', controllerAs: "ctrl",
scope: { scope: {
userPicked: '&', userPicked: "&"
}, },
link: function(scope, elem, attrs, ctrl) { link: function(scope, elem, attrs, ctrl) {
scope.$on("user-picker-reset", () => { scope.$on("user-picker-reset", () => {
@@ -63,4 +70,4 @@ export function userPicker() {
}; };
} }
coreModule.directive('userPicker', userPicker); coreModule.directive("userPicker", userPicker);

View File

@@ -1,39 +1,39 @@
import _ from 'lodash'; import _ from "lodash";
class Settings { class Settings {
datasources: any; datasources: any;
panels: any; panels: any;
appSubUrl: string; appSubUrl: string;
window_title_prefix: string; window_title_prefix: string;
buildInfo: any; buildInfo: any;
new_panel_title: string; new_panel_title: string;
bootData: any; bootData: any;
externalUserMngLinkUrl: string; externalUserMngLinkUrl: string;
externalUserMngLinkName: string; externalUserMngLinkName: string;
externalUserMngInfo: string; externalUserMngInfo: string;
allowOrgCreate: boolean; allowOrgCreate: boolean;
disableLoginForm: boolean; disableLoginForm: boolean;
defaultDatasource: string; defaultDatasource: string;
alertingEnabled: boolean; alertingEnabled: boolean;
authProxyEnabled: boolean; authProxyEnabled: boolean;
ldapEnabled: boolean; ldapEnabled: boolean;
oauth: any; oauth: any;
disableUserSignUp: boolean; disableUserSignUp: boolean;
loginHint: any; loginHint: any;
loginError: any; loginError: any;
constructor(options) { constructor(options) {
var defaults = { var defaults = {
datasources: {}, datasources: {},
window_title_prefix: 'Grafana - ', window_title_prefix: "Grafana - ",
panels: {}, panels: {},
new_panel_title: 'Panel Title', new_panel_title: "Panel Title",
playlist_timespan: "1m", playlist_timespan: "1m",
unsaved_changes_warning: true, unsaved_changes_warning: true,
appSubUrl: "" appSubUrl: ""
}; };
_.extend(this, defaults, options); _.extend(this, defaults, options);
} }
} }
var bootData = (<any>window).grafanaBootData || { settings: {} }; var bootData = (<any>window).grafanaBootData || { settings: {} };

View File

@@ -1,8 +1,7 @@
export const GRID_CELL_HEIGHT = 30; export const GRID_CELL_HEIGHT = 30;
export const GRID_CELL_VMARGIN = 10; export const GRID_CELL_VMARGIN = 10;
export const GRID_COLUMN_COUNT = 24; export const GRID_COLUMN_COUNT = 24;
export const REPEAT_DIR_VERTICAL = 'v'; export const REPEAT_DIR_VERTICAL = "v";
export const DEFAULT_PANEL_SPAN = 4; export const DEFAULT_PANEL_SPAN = 4;
export const DEFAULT_ROW_HEIGHT = 250; export const DEFAULT_ROW_HEIGHT = 250;

View File

@@ -1,24 +1,23 @@
import config from 'app/core/config'; import config from "app/core/config";
import coreModule from '../core_module'; import coreModule from "../core_module";
import appEvents from 'app/core/app_events'; import appEvents from "app/core/app_events";
export class ErrorCtrl { export class ErrorCtrl {
/** @ngInject */ /** @ngInject */
constructor($scope, contextSrv, navModelSrv) { constructor($scope, contextSrv, navModelSrv) {
$scope.navModel = navModelSrv.getNotFoundNav(); $scope.navModel = navModelSrv.getNotFoundNav();
$scope.appSubUrl = config.appSubUrl; $scope.appSubUrl = config.appSubUrl;
if (!contextSrv.isSignedIn) { if (!contextSrv.isSignedIn) {
appEvents.emit('toggle-sidemenu-hidden'); appEvents.emit("toggle-sidemenu-hidden");
} }
$scope.$on("destroy", () => { $scope.$on("destroy", () => {
if (!contextSrv.isSignedIn) { if (!contextSrv.isSignedIn) {
appEvents.emit('toggle-sidemenu-hidden'); appEvents.emit("toggle-sidemenu-hidden");
} }
}); });
} }
} }
coreModule.controller('ErrorCtrl', ErrorCtrl); coreModule.controller("ErrorCtrl", ErrorCtrl);

View File

@@ -1,18 +1,17 @@
import angular from 'angular'; import angular from "angular";
import _ from 'lodash'; import _ from "lodash";
import $ from 'jquery'; import $ from "jquery";
import coreModule from '../core_module'; import coreModule from "../core_module";
export class InspectCtrl { export class InspectCtrl {
/** @ngInject */ /** @ngInject */
constructor($scope, $sanitize) { constructor($scope, $sanitize) {
var model = $scope.inspector; var model = $scope.inspector;
$scope.init = function () { $scope.init = function() {
$scope.editor = { index: 0 }; $scope.editor = { index: 0 };
if (!model.error) { if (!model.error) {
return; return;
} }
@@ -29,8 +28,11 @@ export class InspectCtrl {
} }
if (model.error.config && model.error.config.params) { if (model.error.config && model.error.config.params) {
$scope.request_parameters = _.map(model.error.config.params, function(value, key) { $scope.request_parameters = _.map(model.error.config.params, function(
return { key: key, value: value}; value,
key
) {
return { key: key, value: value };
}); });
} }
@@ -44,10 +46,15 @@ export class InspectCtrl {
$scope.editor.index = 2; $scope.editor.index = 2;
if (_.isString(model.error.config.data)) { if (_.isString(model.error.config.data)) {
$scope.request_parameters = this.getParametersFromQueryString(model.error.config.data); $scope.request_parameters = this.getParametersFromQueryString(
} else { model.error.config.data
$scope.request_parameters = _.map(model.error.config.data, function(value, key) { );
return {key: key, value: angular.toJson(value, true)}; } else {
$scope.request_parameters = _.map(model.error.config.data, function(
value,
key
) {
return { key: key, value: angular.toJson(value, true) };
}); });
} }
} }
@@ -59,11 +66,14 @@ export class InspectCtrl {
for (var i = 0; i < parameters.length; i++) { for (var i = 0; i < parameters.length; i++) {
var keyValue = parameters[i].split("="); var keyValue = parameters[i].split("=");
if (keyValue[1].length > 0) { if (keyValue[1].length > 0) {
result.push({ key: keyValue[0], value: (<any>window).unescape(keyValue[1]) }); result.push({
key: keyValue[0],
value: (<any>window).unescape(keyValue[1])
});
} }
} }
return result; return result;
} }
} }
coreModule.controller('InspectCtrl', InspectCtrl); coreModule.controller("InspectCtrl", InspectCtrl);

View File

@@ -1,8 +1,7 @@
import coreModule from '../core_module'; import coreModule from "../core_module";
import config from 'app/core/config'; import config from "app/core/config";
export class InvitedCtrl { export class InvitedCtrl {
/** @ngInject */ /** @ngInject */
constructor($scope, $routeParams, contextSrv, backendSrv) { constructor($scope, $routeParams, contextSrv, backendSrv) {
contextSrv.sidemenu = false; contextSrv.sidemenu = false;
@@ -10,25 +9,24 @@ export class InvitedCtrl {
$scope.navModel = { $scope.navModel = {
main: { main: {
icon: 'gicon gicon-branding', icon: "gicon gicon-branding",
subTitle: 'Register your Grafana account', subTitle: "Register your Grafana account",
breadcrumbs: [ breadcrumbs: [{ title: "Login", url: "/login" }, { title: "Invite" }]
{ title: 'Login', url: '/login' },
{ title: 'Invite' },
]
} }
}; };
$scope.init = function() { $scope.init = function() {
backendSrv.get('/api/user/invite/' + $routeParams.code).then(function(invite) { backendSrv
$scope.formModel.name = invite.name; .get("/api/user/invite/" + $routeParams.code)
$scope.formModel.email = invite.email; .then(function(invite) {
$scope.formModel.username = invite.email; $scope.formModel.name = invite.name;
$scope.formModel.inviteCode = $routeParams.code; $scope.formModel.email = invite.email;
$scope.formModel.username = invite.email;
$scope.formModel.inviteCode = $routeParams.code;
$scope.greeting = invite.name || invite.email || invite.username; $scope.greeting = invite.name || invite.email || invite.username;
$scope.invitedBy = invite.invitedBy; $scope.invitedBy = invite.invitedBy;
}); });
}; };
$scope.submit = function() { $scope.submit = function() {
@@ -36,13 +34,15 @@ export class InvitedCtrl {
return; return;
} }
backendSrv.post('/api/user/invite/complete', $scope.formModel).then(function() { backendSrv
window.location.href = config.appSubUrl + '/'; .post("/api/user/invite/complete", $scope.formModel)
}); .then(function() {
window.location.href = config.appSubUrl + "/";
});
}; };
$scope.init(); $scope.init();
} }
} }
coreModule.controller('InvitedCtrl', InvitedCtrl); coreModule.controller("InvitedCtrl", InvitedCtrl);

View File

@@ -1,18 +1,18 @@
import angular from 'angular'; import angular from "angular";
import coreModule from '../core_module'; import coreModule from "../core_module";
export class JsonEditorCtrl { export class JsonEditorCtrl {
/** @ngInject */ /** @ngInject */
constructor($scope) { constructor($scope) {
$scope.json = angular.toJson($scope.object, true); $scope.json = angular.toJson($scope.object, true);
$scope.canUpdate = $scope.updateHandler !== void 0 && $scope.contextSrv.isEditor; $scope.canUpdate =
$scope.updateHandler !== void 0 && $scope.contextSrv.isEditor;
$scope.update = function () { $scope.update = function() {
var newObject = angular.fromJson($scope.json); var newObject = angular.fromJson($scope.json);
$scope.updateHandler(newObject, $scope.object); $scope.updateHandler(newObject, $scope.object);
}; };
} }
} }
coreModule.controller('JsonEditorCtrl', JsonEditorCtrl); coreModule.controller("JsonEditorCtrl", JsonEditorCtrl);

View File

@@ -1,15 +1,14 @@
import _ from 'lodash'; import _ from "lodash";
import coreModule from '../core_module'; import coreModule from "../core_module";
import config from 'app/core/config'; import config from "app/core/config";
export class LoginCtrl { export class LoginCtrl {
/** @ngInject */ /** @ngInject */
constructor($scope, backendSrv, contextSrv, $location) { constructor($scope, backendSrv, contextSrv, $location) {
$scope.formModel = { $scope.formModel = {
user: '', user: "",
email: '', email: "",
password: '', password: ""
}; };
contextSrv.sidemenu = false; contextSrv.sidemenu = false;
@@ -19,16 +18,16 @@ export class LoginCtrl {
$scope.disableLoginForm = config.disableLoginForm; $scope.disableLoginForm = config.disableLoginForm;
$scope.disableUserSignUp = config.disableUserSignUp; $scope.disableUserSignUp = config.disableUserSignUp;
$scope.loginHint = config.loginHint; $scope.loginHint = config.loginHint;
$scope.loginMode = true; $scope.loginMode = true;
$scope.submitBtnText = 'Log in'; $scope.submitBtnText = "Log in";
$scope.init = function() { $scope.init = function() {
$scope.$watch("loginMode", $scope.loginModeChanged); $scope.$watch("loginMode", $scope.loginModeChanged);
if (config.loginError) { if (config.loginError) {
$scope.appEvent('alert-warning', ['Login Failed', config.loginError]); $scope.appEvent("alert-warning", ["Login Failed", config.loginError]);
} }
}; };
@@ -41,7 +40,7 @@ export class LoginCtrl {
}; };
$scope.loginModeChanged = function(newValue) { $scope.loginModeChanged = function(newValue) {
$scope.submitBtnText = newValue ? 'Log in' : 'Sign up'; $scope.submitBtnText = newValue ? "Log in" : "Sign up";
}; };
$scope.signUp = function() { $scope.signUp = function() {
@@ -49,13 +48,15 @@ export class LoginCtrl {
return; return;
} }
backendSrv.post('/api/user/signup', $scope.formModel).then(function(result) { backendSrv
if (result.status === 'SignUpCreated') { .post("/api/user/signup", $scope.formModel)
$location.path('/signup').search({email: $scope.formModel.email}); .then(function(result) {
} else { if (result.status === "SignUpCreated") {
window.location.href = config.appSubUrl + '/'; $location.path("/signup").search({ email: $scope.formModel.email });
} } else {
}); window.location.href = config.appSubUrl + "/";
}
});
}; };
$scope.login = function() { $scope.login = function() {
@@ -65,15 +66,15 @@ export class LoginCtrl {
return; return;
} }
backendSrv.post('/login', $scope.formModel).then(function(result) { backendSrv.post("/login", $scope.formModel).then(function(result) {
var params = $location.search(); var params = $location.search();
if (params.redirect && params.redirect[0] === '/') { if (params.redirect && params.redirect[0] === "/") {
window.location.href = config.appSubUrl + params.redirect; window.location.href = config.appSubUrl + params.redirect;
} else if (result.redirectUrl) { } else if (result.redirectUrl) {
window.location.href = result.redirectUrl; window.location.href = result.redirectUrl;
} else { } else {
window.location.href = config.appSubUrl + '/'; window.location.href = config.appSubUrl + "/";
} }
}); });
}; };
@@ -82,4 +83,4 @@ export class LoginCtrl {
} }
} }
coreModule.controller('LoginCtrl', LoginCtrl); coreModule.controller("LoginCtrl", LoginCtrl);

View File

@@ -1,26 +1,25 @@
import coreModule from '../core_module'; import coreModule from "../core_module";
export class ResetPasswordCtrl { export class ResetPasswordCtrl {
/** @ngInject */ /** @ngInject */
constructor($scope, contextSrv, backendSrv, $location) { constructor($scope, contextSrv, backendSrv, $location) {
contextSrv.sidemenu = false; contextSrv.sidemenu = false;
$scope.formModel = {}; $scope.formModel = {};
$scope.mode = 'send'; $scope.mode = "send";
var params = $location.search(); var params = $location.search();
if (params.code) { if (params.code) {
$scope.mode = 'reset'; $scope.mode = "reset";
$scope.formModel.code = params.code; $scope.formModel.code = params.code;
} }
$scope.navModel = { $scope.navModel = {
main: { main: {
icon: 'gicon gicon-branding', icon: "gicon gicon-branding",
subTitle: 'Reset your Grafana password', subTitle: "Reset your Grafana password",
breadcrumbs: [ breadcrumbs: [
{ title: 'Login', url: '/login' }, { title: "Login", url: "/login" },
{ title: 'Reset Password' }, { title: "Reset Password" }
] ]
} }
}; };
@@ -29,24 +28,30 @@ export class ResetPasswordCtrl {
if (!$scope.sendResetForm.$valid) { if (!$scope.sendResetForm.$valid) {
return; return;
} }
backendSrv.post('/api/user/password/send-reset-email', $scope.formModel).then(function() { backendSrv
$scope.mode = 'email-sent'; .post("/api/user/password/send-reset-email", $scope.formModel)
}); .then(function() {
$scope.mode = "email-sent";
});
}; };
$scope.submitReset = function() { $scope.submitReset = function() {
if (!$scope.resetForm.$valid) { return; } if (!$scope.resetForm.$valid) {
if ($scope.formModel.newPassword !== $scope.formModel.confirmPassword) {
$scope.appEvent('alert-warning', ['New passwords do not match', '']);
return; return;
} }
backendSrv.post('/api/user/password/reset', $scope.formModel).then(function() { if ($scope.formModel.newPassword !== $scope.formModel.confirmPassword) {
$location.path('login'); $scope.appEvent("alert-warning", ["New passwords do not match", ""]);
}); return;
}
backendSrv
.post("/api/user/password/reset", $scope.formModel)
.then(function() {
$location.path("login");
});
}; };
} }
} }
coreModule.controller('ResetPasswordCtrl', ResetPasswordCtrl); coreModule.controller("ResetPasswordCtrl", ResetPasswordCtrl);

View File

@@ -1,17 +1,16 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import config from 'app/core/config'; import config from "app/core/config";
import coreModule from '../core_module'; import coreModule from "../core_module";
export class SignUpCtrl { export class SignUpCtrl {
/** @ngInject */ /** @ngInject */
constructor( constructor(
private $scope: any, private $scope: any,
private backendSrv: any, private backendSrv: any,
$location: any, $location: any,
contextSrv: any) { contextSrv: any
) {
contextSrv.sidemenu = false; contextSrv.sidemenu = false;
$scope.ctrl = this; $scope.ctrl = this;
@@ -28,35 +27,34 @@ export class SignUpCtrl {
$scope.navModel = { $scope.navModel = {
main: { main: {
icon: 'gicon gicon-branding', icon: "gicon gicon-branding",
subTitle: 'Register your Grafana account', subTitle: "Register your Grafana account",
breadcrumbs: [ breadcrumbs: [{ title: "Login", url: "/login" }, { title: "Sign Up" }]
{ title: 'Login', url: '/login' },
{ title: 'Sign Up' },
]
} }
}; };
backendSrv.get('/api/user/signup/options').then(options => { backendSrv.get("/api/user/signup/options").then(options => {
$scope.verifyEmailEnabled = options.verifyEmailEnabled; $scope.verifyEmailEnabled = options.verifyEmailEnabled;
$scope.autoAssignOrg = options.autoAssignOrg; $scope.autoAssignOrg = options.autoAssignOrg;
}); });
} }
submit () { submit() {
if (!this.$scope.signUpForm.$valid) { if (!this.$scope.signUpForm.$valid) {
return; return;
} }
this.backendSrv.post('/api/user/signup/step2', this.$scope.formModel).then(rsp => { this.backendSrv
if (rsp.code === 'redirect-to-select-org') { .post("/api/user/signup/step2", this.$scope.formModel)
window.location.href = config.appSubUrl + '/profile/select-org?signup=1'; .then(rsp => {
} else { if (rsp.code === "redirect-to-select-org") {
window.location.href = config.appSubUrl + '/'; window.location.href =
} config.appSubUrl + "/profile/select-org?signup=1";
}); } else {
window.location.href = config.appSubUrl + "/";
}
});
} }
} }
coreModule.controller('SignUpCtrl', SignUpCtrl); coreModule.controller("SignUpCtrl", SignUpCtrl);

View File

@@ -9,54 +9,54 @@ import "./directives/value_select_dropdown";
import "./directives/rebuild_on_change"; import "./directives/rebuild_on_change";
import "./directives/give_focus"; import "./directives/give_focus";
import "./directives/diff-view"; import "./directives/diff-view";
import './jquery_extended'; import "./jquery_extended";
import './partials'; import "./partials";
import './components/jsontree/jsontree'; import "./components/jsontree/jsontree";
import './components/code_editor/code_editor'; import "./components/code_editor/code_editor";
import './utils/outline'; import "./utils/outline";
import './components/colorpicker/ColorPicker'; import "./components/colorpicker/ColorPicker";
import './components/colorpicker/SeriesColorPicker'; import "./components/colorpicker/SeriesColorPicker";
import './components/colorpicker/spectrum_picker'; import "./components/colorpicker/spectrum_picker";
import './services/search_srv'; import "./services/search_srv";
import './services/ng_react'; import "./services/ng_react";
import {grafanaAppDirective} from './components/grafana_app'; import { grafanaAppDirective } from "./components/grafana_app";
import {sideMenuDirective} from './components/sidemenu/sidemenu'; import { sideMenuDirective } from "./components/sidemenu/sidemenu";
import {searchDirective} from './components/search/search'; import { searchDirective } from "./components/search/search";
import {infoPopover} from './components/info_popover'; import { infoPopover } from "./components/info_popover";
import {navbarDirective} from './components/navbar/navbar'; import { navbarDirective } from "./components/navbar/navbar";
import {arrayJoin} from './directives/array_join'; import { arrayJoin } from "./directives/array_join";
import {liveSrv} from './live/live_srv'; import { liveSrv } from "./live/live_srv";
import {Emitter} from './utils/emitter'; import { Emitter } from "./utils/emitter";
import {layoutSelector} from './components/layout_selector/layout_selector'; import { layoutSelector } from "./components/layout_selector/layout_selector";
import {switchDirective} from './components/switch'; import { switchDirective } from "./components/switch";
import {dashboardSelector} from './components/dashboard_selector'; import { dashboardSelector } from "./components/dashboard_selector";
import {queryPartEditorDirective} from './components/query_part/query_part_editor'; import { queryPartEditorDirective } from "./components/query_part/query_part_editor";
import {formDropdownDirective} from './components/form_dropdown/form_dropdown'; import { formDropdownDirective } from "./components/form_dropdown/form_dropdown";
import 'app/core/controllers/all'; import "app/core/controllers/all";
import 'app/core/services/all'; import "app/core/services/all";
import 'app/core/routes/routes'; import "app/core/routes/routes";
import './filters/filters'; import "./filters/filters";
import coreModule from './core_module'; import coreModule from "./core_module";
import appEvents from './app_events'; import appEvents from "./app_events";
import colors from './utils/colors'; import colors from "./utils/colors";
import {assignModelProperties} from './utils/model_utils'; import { assignModelProperties } from "./utils/model_utils";
import {contextSrv} from './services/context_srv'; import { contextSrv } from "./services/context_srv";
import {KeybindingSrv} from './services/keybindingSrv'; import { KeybindingSrv } from "./services/keybindingSrv";
import {helpModal} from './components/help/help'; import { helpModal } from "./components/help/help";
import {JsonExplorer} from './components/json_explorer/json_explorer'; import { JsonExplorer } from "./components/json_explorer/json_explorer";
import {NavModelSrv, NavModel} from './nav_model_srv'; import { NavModelSrv, NavModel } from "./nav_model_srv";
import {userPicker} from './components/user_picker'; import { userPicker } from "./components/user_picker";
import {teamPicker} from './components/team_picker'; import { teamPicker } from "./components/team_picker";
import {geminiScrollbar} from './components/scroll/scroll'; import { geminiScrollbar } from "./components/scroll/scroll";
import {gfPageDirective} from './components/gf_page'; import { gfPageDirective } from "./components/gf_page";
import {orgSwitcher} from './components/org_switcher'; import { orgSwitcher } from "./components/org_switcher";
import {profiler} from './profiler'; import { profiler } from "./profiler";
import {registerAngularDirectives} from './angular_wrappers'; import { registerAngularDirectives } from "./angular_wrappers";
import {updateLegendValues} from './time_series2'; import { updateLegendValues } from "./time_series2";
import TimeSeries from './time_series2'; import TimeSeries from "./time_series2";
import {searchResultsDirective} from './components/search/search_results'; import { searchResultsDirective } from "./components/search/search_results";
import {manageDashboardsDirective} from './components/manage_dashboards/manage_dashboards'; import { manageDashboardsDirective } from "./components/manage_dashboards/manage_dashboards";
export { export {
profiler, profiler,

View File

@@ -1,23 +1,22 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import _ from 'lodash'; import _ from "lodash";
import coreModule from '../core_module'; import coreModule from "../core_module";
export function arrayJoin() { export function arrayJoin() {
'use strict'; "use strict";
return { return {
restrict: 'A', restrict: "A",
require: 'ngModel', require: "ngModel",
link: function(scope, element, attr, ngModel) { link: function(scope, element, attr, ngModel) {
function split_array(text) { function split_array(text) {
return (text || '').split(','); return (text || "").split(",");
} }
function join_array(text) { function join_array(text) {
if (_.isArray(text)) { if (_.isArray(text)) {
return (text || '').join(','); return (text || "").join(",");
} else { } else {
return text; return text;
} }
@@ -29,5 +28,4 @@ export function arrayJoin() {
}; };
} }
coreModule.directive('arrayJoin', arrayJoin); coreModule.directive("arrayJoin", arrayJoin);

View File

@@ -1,17 +1,16 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import angular from 'angular'; import angular from "angular";
import coreModule from '../core_module'; import coreModule from "../core_module";
export class DeltaCtrl { export class DeltaCtrl {
observer: any; observer: any;
/** @ngInject */ /** @ngInject */
constructor(private $rootScope) { constructor(private $rootScope) {
const waitForCompile = mutations => {
const waitForCompile = (mutations) => {
if (mutations.length === 1) { if (mutations.length === 1) {
this.$rootScope.appEvent('json-diff-ready'); this.$rootScope.appEvent("json-diff-ready");
} }
}; };
@@ -19,13 +18,13 @@ export class DeltaCtrl {
const observerConfig = { const observerConfig = {
attributes: true, attributes: true,
attributeFilter: ['class'], attributeFilter: ["class"],
characterData: false, characterData: false,
childList: true, childList: true,
subtree: false, subtree: false
}; };
this.observer.observe(angular.element('.delta-html')[0], observerConfig); this.observer.observe(angular.element(".delta-html")[0], observerConfig);
} }
$onDestroy() { $onDestroy() {
@@ -37,10 +36,10 @@ export function delta() {
return { return {
controller: DeltaCtrl, controller: DeltaCtrl,
replace: false, replace: false,
restrict: 'A', restrict: "A"
}; };
} }
coreModule.directive('diffDelta', delta); coreModule.directive("diffDelta", delta);
// Link to JSON line number // Link to JSON line number
export class LinkJSONCtrl { export class LinkJSONCtrl {
@@ -56,7 +55,7 @@ export class LinkJSONCtrl {
}; };
this.$scope.switchView().then(() => { this.$scope.switchView().then(() => {
unbind = this.$rootScope.$on('json-diff-ready', scroll.bind(this)); unbind = this.$rootScope.$on("json-diff-ready", scroll.bind(this));
}); });
} }
} }
@@ -64,15 +63,15 @@ export class LinkJSONCtrl {
export function linkJson() { export function linkJson() {
return { return {
controller: LinkJSONCtrl, controller: LinkJSONCtrl,
controllerAs: 'ctrl', controllerAs: "ctrl",
replace: true, replace: true,
restrict: 'E', restrict: "E",
scope: { scope: {
line: '@lineDisplay', line: "@lineDisplay",
link: '@lineLink', link: "@lineLink",
switchView: '&', switchView: "&"
}, },
template: `<a class="diff-linenum btn btn-inverse btn-small" ng-click="ctrl.goToLine(link)">Line {{ line }}</a>` template: `<a class="diff-linenum btn btn-inverse btn-small" ng-click="ctrl.goToLine(link)">Line {{ line }}</a>`
}; };
} }
coreModule.directive('diffLinkJson', linkJson); coreModule.directive("diffLinkJson", linkJson);

View File

@@ -1,26 +1,30 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import coreModule from '../core_module'; import coreModule from "../core_module";
coreModule.directive('giveFocus', function() { coreModule.directive("giveFocus", function() {
return function(scope, element, attrs) { return function(scope, element, attrs) {
element.click(function(e) { element.click(function(e) {
e.stopPropagation(); e.stopPropagation();
}); });
scope.$watch(attrs.giveFocus, function (newValue) { scope.$watch(
if (!newValue) { attrs.giveFocus,
return; function(newValue) {
} if (!newValue) {
setTimeout(function() { return;
element.focus();
var domEl = element[0];
if (domEl.setSelectionRange) {
var pos = element.val().length * 2;
domEl.setSelectionRange(pos, pos);
} }
}, 200); setTimeout(function() {
}, true); element.focus();
var domEl = element[0];
if (domEl.setSelectionRange) {
var pos = element.val().length * 2;
domEl.setSelectionRange(pos, pos);
}
}, 200);
},
true
);
}; };
}); });

View File

@@ -1,18 +1,18 @@
import coreModule from '../core_module'; import coreModule from "../core_module";
import * as rangeUtil from 'app/core/utils/rangeutil'; import * as rangeUtil from "app/core/utils/rangeutil";
function ngModelOnBlur() { function ngModelOnBlur() {
return { return {
restrict: 'A', restrict: "A",
priority: 1, priority: 1,
require: 'ngModel', require: "ngModel",
link: function(scope, elm, attr, ngModelCtrl) { link: function(scope, elm, attr, ngModelCtrl) {
if (attr.type === 'radio' || attr.type === 'checkbox') { if (attr.type === "radio" || attr.type === "checkbox") {
return; return;
} }
elm.off('input keydown change'); elm.off("input keydown change");
elm.bind('blur', function() { elm.bind("blur", function() {
scope.$apply(function() { scope.$apply(function() {
ngModelCtrl.$setViewValue(elm.val()); ngModelCtrl.$setViewValue(elm.val());
}); });
@@ -23,11 +23,13 @@ function ngModelOnBlur() {
function emptyToNull() { function emptyToNull() {
return { return {
restrict: 'A', restrict: "A",
require: 'ngModel', require: "ngModel",
link: function (scope, elm, attrs, ctrl) { link: function(scope, elm, attrs, ctrl) {
ctrl.$parsers.push(function (viewValue) { ctrl.$parsers.push(function(viewValue) {
if (viewValue === "") { return null; } if (viewValue === "") {
return null;
}
return viewValue; return viewValue;
}); });
} }
@@ -36,13 +38,13 @@ function emptyToNull() {
function validTimeSpan() { function validTimeSpan() {
return { return {
require: 'ngModel', require: "ngModel",
link: function(scope, elm, attrs, ctrl) { link: function(scope, elm, attrs, ctrl) {
ctrl.$validators.integer = function(modelValue, viewValue) { ctrl.$validators.integer = function(modelValue, viewValue) {
if (ctrl.$isEmpty(modelValue)) { if (ctrl.$isEmpty(modelValue)) {
return true; return true;
} }
if (viewValue.indexOf('$') === 0 || viewValue.indexOf('+$') === 0) { if (viewValue.indexOf("$") === 0 || viewValue.indexOf("+$") === 0) {
return true; // allow template variable return true; // allow template variable
} }
var info = rangeUtil.describeTextRange(viewValue); var info = rangeUtil.describeTextRange(viewValue);
@@ -52,6 +54,6 @@ function validTimeSpan() {
}; };
} }
coreModule.directive('ngModelOnblur', ngModelOnBlur); coreModule.directive("ngModelOnblur", ngModelOnBlur);
coreModule.directive('emptyToNull', emptyToNull); coreModule.directive("emptyToNull", emptyToNull);
coreModule.directive('validTimeSpan', validTimeSpan); coreModule.directive("validTimeSpan", validTimeSpan);

View File

@@ -1,5 +1,5 @@
import $ from 'jquery'; import $ from "jquery";
import coreModule from '../core_module'; import coreModule from "../core_module";
function getBlockNodes(nodes) { function getBlockNodes(nodes) {
var node = nodes[0]; var node = nodes[0];
@@ -20,13 +20,12 @@ function getBlockNodes(nodes) {
/** @ngInject **/ /** @ngInject **/
function rebuildOnChange($animate) { function rebuildOnChange($animate) {
return { return {
multiElement: true, multiElement: true,
terminal: true, terminal: true,
transclude: true, transclude: true,
priority: 600, priority: 600,
restrict: 'E', restrict: "E",
link: function(scope, elem, attrs, ctrl, transclude) { link: function(scope, elem, attrs, ctrl, transclude) {
var block, childScope, previousElements; var block, childScope, previousElements;
@@ -48,7 +47,10 @@ function rebuildOnChange($animate) {
} }
} }
scope.$watch(attrs.property, function rebuildOnChangeAction(value, oldValue) { scope.$watch(attrs.property, function rebuildOnChangeAction(
value,
oldValue
) {
if (childScope && value !== oldValue) { if (childScope && value !== oldValue) {
cleanUp(); cleanUp();
} }
@@ -56,8 +58,10 @@ function rebuildOnChange($animate) {
if (!childScope && (value || attrs.showNull)) { if (!childScope && (value || attrs.showNull)) {
transclude(function(clone, newScope) { transclude(function(clone, newScope) {
childScope = newScope; childScope = newScope;
clone[clone.length++] = document.createComment(' end rebuild on change '); clone[clone.length++] = document.createComment(
block = {clone: clone}; " end rebuild on change "
);
block = { clone: clone };
$animate.enter(clone, elem.parent(), elem); $animate.enter(clone, elem.parent(), elem);
}); });
} else { } else {
@@ -68,4 +72,4 @@ function rebuildOnChange($animate) {
}; };
} }
coreModule.directive('rebuildOnChange', rebuildOnChange); coreModule.directive("rebuildOnChange", rebuildOnChange);

View File

@@ -1,12 +1,12 @@
import angular from 'angular'; import angular from "angular";
import $ from 'jquery'; import $ from "jquery";
import coreModule from '../core_module'; import coreModule from "../core_module";
import 'vendor/tagsinput/bootstrap-tagsinput.js'; import "vendor/tagsinput/bootstrap-tagsinput.js";
function djb2(str) { function djb2(str) {
var hash = 5381; var hash = 5381;
for (var i = 0; i < str.length; i++) { for (var i = 0; i < str.length; i++) {
hash = ((hash << 5) + hash) + str.charCodeAt(i); /* hash * 33 + c */ hash = (hash << 5) + hash + str.charCodeAt(i); /* hash * 33 + c */
} }
return hash; return hash;
} }
@@ -14,20 +14,66 @@ function djb2(str) {
function setColor(name, element) { function setColor(name, element) {
var hash = djb2(name.toLowerCase()); var hash = djb2(name.toLowerCase());
var colors = [ var colors = [
"#E24D42","#1F78C1","#BA43A9","#705DA0","#466803", "#E24D42",
"#508642","#447EBC","#C15C17","#890F02","#757575", "#1F78C1",
"#0A437C","#6D1F62","#584477","#629E51","#2F4F4F", "#BA43A9",
"#BF1B00","#806EB7","#8a2eb8", "#699e00","#000000", "#705DA0",
"#3F6833","#2F575E","#99440A","#E0752D","#0E4AB4", "#466803",
"#58140C","#052B51","#511749","#3F2B5B", "#508642",
"#447EBC",
"#C15C17",
"#890F02",
"#757575",
"#0A437C",
"#6D1F62",
"#584477",
"#629E51",
"#2F4F4F",
"#BF1B00",
"#806EB7",
"#8a2eb8",
"#699e00",
"#000000",
"#3F6833",
"#2F575E",
"#99440A",
"#E0752D",
"#0E4AB4",
"#58140C",
"#052B51",
"#511749",
"#3F2B5B"
]; ];
var borderColors = [ var borderColors = [
"#FF7368","#459EE7","#E069CF","#9683C6","#6C8E29", "#FF7368",
"#76AC68","#6AA4E2","#E7823D","#AF3528","#9B9B9B", "#459EE7",
"#3069A2","#934588","#7E6A9D","#88C477","#557575", "#E069CF",
"#E54126","#A694DD","#B054DE", "#8FC426","#262626", "#9683C6",
"#658E59","#557D84","#BF6A30","#FF9B53","#3470DA", "#6C8E29",
"#7E3A32","#2B5177","#773D6F","#655181", "#76AC68",
"#6AA4E2",
"#E7823D",
"#AF3528",
"#9B9B9B",
"#3069A2",
"#934588",
"#7E6A9D",
"#88C477",
"#557575",
"#E54126",
"#A694DD",
"#B054DE",
"#8FC426",
"#262626",
"#658E59",
"#557D84",
"#BF6A30",
"#FF9B53",
"#3470DA",
"#7E3A32",
"#2B5177",
"#773D6F",
"#655181"
]; ];
var color = colors[Math.abs(hash % colors.length)]; var color = colors[Math.abs(hash % colors.length)];
var borderColor = borderColors[Math.abs(hash % borderColors.length)]; var borderColor = borderColors[Math.abs(hash % borderColors.length)];
@@ -38,7 +84,7 @@ function setColor(name, element) {
function tagColorFromName() { function tagColorFromName() {
return { return {
scope: { tagColorFromName: "=" }, scope: { tagColorFromName: "=" },
link: function (scope, element) { link: function(scope, element) {
setColor(scope.tagColorFromName, element); setColor(scope.tagColorFromName, element);
} }
}; };
@@ -60,48 +106,57 @@ function bootstrapTagsinput() {
} }
return { return {
restrict: 'EA', restrict: "EA",
scope: { scope: {
model: '=ngModel', model: "=ngModel",
onTagsUpdated: "&", onTagsUpdated: "&"
}, },
template: '<select multiple></select>', template: "<select multiple></select>",
replace: false, replace: false,
link: function(scope, element, attrs) { link: function(scope, element, attrs) {
if (!angular.isArray(scope.model)) { if (!angular.isArray(scope.model)) {
scope.model = []; scope.model = [];
} }
var select = $('select', element); var select = $("select", element);
if (attrs.placeholder) { if (attrs.placeholder) {
select.attr('placeholder', attrs.placeholder); select.attr("placeholder", attrs.placeholder);
} }
select.tagsinput({ select.tagsinput({
typeahead: { typeahead: {
source: angular.isFunction(scope.$parent[attrs.typeaheadSource]) ? scope.$parent[attrs.typeaheadSource] : null source: angular.isFunction(scope.$parent[attrs.typeaheadSource])
? scope.$parent[attrs.typeaheadSource]
: null
}, },
widthClass: attrs.widthClass, widthClass: attrs.widthClass,
itemValue: getItemProperty(scope, attrs.itemvalue), itemValue: getItemProperty(scope, attrs.itemvalue),
itemText : getItemProperty(scope, attrs.itemtext), itemText: getItemProperty(scope, attrs.itemtext),
tagClass : angular.isFunction(scope.$parent[attrs.tagclass]) ? tagClass: angular.isFunction(scope.$parent[attrs.tagclass])
scope.$parent[attrs.tagclass] : function() { return attrs.tagclass; } ? scope.$parent[attrs.tagclass]
: function() {
return attrs.tagclass;
}
}); });
select.on('itemAdded', function(event) { select.on("itemAdded", function(event) {
if (scope.model.indexOf(event.item) === -1) { if (scope.model.indexOf(event.item) === -1) {
scope.model.push(event.item); scope.model.push(event.item);
if (scope.onTagsUpdated) { if (scope.onTagsUpdated) {
scope.onTagsUpdated(); scope.onTagsUpdated();
} }
} }
var tagElement = select.next().children("span").filter(function() { return $(this).text() === event.item; }); var tagElement = select
.next()
.children("span")
.filter(function() {
return $(this).text() === event.item;
});
setColor(event.item, tagElement); setColor(event.item, tagElement);
}); });
select.on('itemRemoved', function(event) { select.on("itemRemoved", function(event) {
var idx = scope.model.indexOf(event.item); var idx = scope.model.indexOf(event.item);
if (idx !== -1) { if (idx !== -1) {
scope.model.splice(idx, 1); scope.model.splice(idx, 1);
@@ -111,21 +166,24 @@ function bootstrapTagsinput() {
} }
}); });
scope.$watch("model", function() { scope.$watch(
if (!angular.isArray(scope.model)) { "model",
scope.model = []; function() {
} if (!angular.isArray(scope.model)) {
scope.model = [];
}
select.tagsinput('removeAll'); select.tagsinput("removeAll");
for (var i = 0; i < scope.model.length; i++) { for (var i = 0; i < scope.model.length; i++) {
select.tagsinput('add', scope.model[i]); select.tagsinput("add", scope.model[i]);
} }
},
}, true); true
);
} }
}; };
} }
coreModule.directive('tagColorFromName', tagColorFromName); coreModule.directive("tagColorFromName", tagColorFromName);
coreModule.directive('bootstrapTagsinput', bootstrapTagsinput); coreModule.directive("bootstrapTagsinput", bootstrapTagsinput);

View File

@@ -1,17 +1,17 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import _ from 'lodash'; import _ from "lodash";
import angular from 'angular'; import angular from "angular";
import moment from 'moment'; import moment from "moment";
import coreModule from '../core_module'; import coreModule from "../core_module";
coreModule.filter('stringSort', function() { coreModule.filter("stringSort", function() {
return function(input) { return function(input) {
return input.sort(); return input.sort();
}; };
}); });
coreModule.filter('slice', function() { coreModule.filter("slice", function() {
return function(arr, start, end) { return function(arr, start, end) {
if (!_.isUndefined(arr)) { if (!_.isUndefined(arr)) {
return arr.slice(start, end); return arr.slice(start, end);
@@ -19,7 +19,7 @@ coreModule.filter('slice', function() {
}; };
}); });
coreModule.filter('stringify', function() { coreModule.filter("stringify", function() {
return function(arr) { return function(arr) {
if (_.isObject(arr) && !_.isArray(arr)) { if (_.isObject(arr) && !_.isArray(arr)) {
return angular.toJson(arr); return angular.toJson(arr);
@@ -29,31 +29,29 @@ coreModule.filter('stringify', function() {
}; };
}); });
coreModule.filter('moment', function() { coreModule.filter("moment", function() {
return function(date, mode) { return function(date, mode) {
switch (mode) { switch (mode) {
case 'ago': case "ago":
return moment(date).fromNow(); return moment(date).fromNow();
} }
return moment(date).fromNow(); return moment(date).fromNow();
}; };
}); });
coreModule.filter('noXml', function() { coreModule.filter("noXml", function() {
var noXml = function(text) { var noXml = function(text) {
return _.isString(text) return _.isString(text)
? text ? text
.replace(/&/g, '&amp;') .replace(/&/g, "&amp;")
.replace(/</g, '&lt;') .replace(/</g, "&lt;")
.replace(/>/g, '&gt;') .replace(/>/g, "&gt;")
.replace(/'/g, '&#39;') .replace(/'/g, "&#39;")
.replace(/"/g, '&quot;') .replace(/"/g, "&quot;")
: text; : text;
}; };
return function(text) { return function(text) {
return _.isArray(text) return _.isArray(text) ? _.map(text, noXml) : noXml(text);
? _.map(text, noXml)
: noXml(text);
}; };
}); });
@@ -74,5 +72,5 @@ function interpolateTemplateVars(templateSrv) {
return filterFunc; return filterFunc;
} }
coreModule.filter('interpolateTemplateVars', interpolateTemplateVars); coreModule.filter("interpolateTemplateVars", interpolateTemplateVars);
export default {}; export default {};

View File

@@ -1,7 +1,7 @@
import _ from 'lodash'; import _ from "lodash";
import config from 'app/core/config'; import config from "app/core/config";
import {Observable} from 'rxjs/Observable'; import { Observable } from "rxjs/Observable";
export class LiveSrv { export class LiveSrv {
conn: any; conn: any;
@@ -14,7 +14,12 @@ export class LiveSrv {
getWebSocketUrl() { getWebSocketUrl() {
var l = window.location; var l = window.location;
return ((l.protocol === "https:") ? "wss://" : "ws://") + l.host + config.appSubUrl + '/ws'; return (
(l.protocol === "https:" ? "wss://" : "ws://") +
l.host +
config.appSubUrl +
"/ws"
);
} }
getConnection() { getConnection() {
@@ -27,29 +32,29 @@ export class LiveSrv {
} }
this.initPromise = new Promise((resolve, reject) => { this.initPromise = new Promise((resolve, reject) => {
console.log('Live: connecting...'); console.log("Live: connecting...");
this.conn = new WebSocket(this.getWebSocketUrl()); this.conn = new WebSocket(this.getWebSocketUrl());
this.conn.onclose = (evt) => { this.conn.onclose = evt => {
console.log("Live: websocket onclose", evt); console.log("Live: websocket onclose", evt);
reject({message: 'Connection closed'}); reject({ message: "Connection closed" });
this.initPromise = null; this.initPromise = null;
setTimeout(this.reconnect.bind(this), 2000); setTimeout(this.reconnect.bind(this), 2000);
}; };
this.conn.onmessage = (evt) => { this.conn.onmessage = evt => {
this.handleMessage(evt.data); this.handleMessage(evt.data);
}; };
this.conn.onerror = (evt) => { this.conn.onerror = evt => {
this.initPromise = null; this.initPromise = null;
reject({message: 'Connection error'}); reject({ message: "Connection error" });
console.log("Live: websocket error", evt); console.log("Live: websocket error", evt);
}; };
this.conn.onopen = (evt) => { this.conn.onopen = evt => {
console.log('opened'); console.log("opened");
this.initPromise = null; this.initPromise = null;
resolve(this.conn); resolve(this.conn);
}; };
@@ -81,11 +86,11 @@ export class LiveSrv {
return; return;
} }
console.log('LiveSrv: Reconnecting'); console.log("LiveSrv: Reconnecting");
this.getConnection().then(conn => { this.getConnection().then(conn => {
_.each(this.observers, (value, key) => { _.each(this.observers, (value, key) => {
this.send({action: 'subscribe', stream: key}); this.send({ action: "subscribe", stream: key });
}); });
}); });
} }
@@ -98,21 +103,21 @@ export class LiveSrv {
this.observers[stream] = observer; this.observers[stream] = observer;
this.getConnection().then(conn => { this.getConnection().then(conn => {
this.send({action: 'subscribe', stream: stream}); this.send({ action: "subscribe", stream: stream });
}); });
} }
removeObserver(stream, observer) { removeObserver(stream, observer) {
console.log('unsubscribe', stream); console.log("unsubscribe", stream);
delete this.observers[stream]; delete this.observers[stream];
this.getConnection().then(conn => { this.getConnection().then(conn => {
this.send({action: 'unsubscribe', stream: stream}); this.send({ action: "unsubscribe", stream: stream });
}); });
} }
subscribe(streamName) { subscribe(streamName) {
console.log('LiveSrv.subscribe: ' + streamName); console.log("LiveSrv.subscribe: " + streamName);
return Observable.create(observer => { return Observable.create(observer => {
this.addObserver(streamName, observer); this.addObserver(streamName, observer);
@@ -126,8 +131,7 @@ export class LiveSrv {
// this.send({action: 'subscribe', stream: name}); // this.send({action: 'subscribe', stream: name});
// }); // });
} }
} }
var instance = new LiveSrv(); var instance = new LiveSrv();
export {instance as liveSrv}; export { instance as liveSrv };

View File

@@ -1,18 +1,14 @@
declare module "app/core/controllers/all" { declare module "app/core/controllers/all" {
let json: any; let json: any;
export {json}; export { json };
} }
declare module "app/core/routes/all" { declare module "app/core/routes/all" {
let json: any; let json: any;
export {json}; export { json };
} }
declare module "app/core/services/all" { declare module "app/core/services/all" {
let json: any; let json: any;
export default json; export default json;
} }

View File

@@ -1,6 +1,6 @@
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import config from 'app/core/config'; import config from "app/core/config";
import _ from 'lodash'; import _ from "lodash";
export interface NavModelItem { export interface NavModelItem {
text: string; text: string;
@@ -34,7 +34,7 @@ export class NavModelSrv {
} }
getCfgNode() { getCfgNode() {
return _.find(this.navItems, {id: 'cfg'}); return _.find(this.navItems, { id: "cfg" });
} }
getNav(...args) { getNav(...args) {
@@ -48,7 +48,7 @@ export class NavModelSrv {
break; break;
} }
let node = _.find(children, {id: id}); let node = _.find(children, { id: id });
nav.breadcrumbs.push(node); nav.breadcrumbs.push(node);
nav.node = node; nav.node = node;
nav.main = node; nav.main = node;
@@ -83,4 +83,4 @@ export class NavModelSrv {
} }
} }
coreModule.service('navModelSrv', NavModelSrv); coreModule.service("navModelSrv", NavModelSrv);

View File

@@ -1,5 +1,5 @@
import $ from 'jquery'; import $ from "jquery";
import angular from 'angular'; import angular from "angular";
export class Profiler { export class Profiler {
panelsRendered: number; panelsRendered: number;
@@ -11,7 +11,7 @@ export class Profiler {
scopeCount: any; scopeCount: any;
init(config, $rootScope) { init(config, $rootScope) {
this.enabled = config.buildInfo.env === 'development'; this.enabled = config.buildInfo.env === "development";
this.timings = {}; this.timings = {};
this.timings.appStart = { loadStart: new Date().getTime() }; this.timings.appStart = { loadStart: new Date().getTime() };
this.$rootScope = $rootScope; this.$rootScope = $rootScope;
@@ -20,15 +20,30 @@ export class Profiler {
return; return;
} }
$rootScope.$watch(() => { $rootScope.$watch(
this.digestCounter++; () => {
return false; this.digestCounter++;
}, () => {}); return false;
},
() => {}
);
$rootScope.onAppEvent('refresh', this.refresh.bind(this), $rootScope); $rootScope.onAppEvent("refresh", this.refresh.bind(this), $rootScope);
$rootScope.onAppEvent('dashboard-fetch-end', this.dashboardFetched.bind(this), $rootScope); $rootScope.onAppEvent(
$rootScope.onAppEvent('dashboard-initialized', this.dashboardInitialized.bind(this), $rootScope); "dashboard-fetch-end",
$rootScope.onAppEvent('panel-initialized', this.panelInitialized.bind(this), $rootScope); this.dashboardFetched.bind(this),
$rootScope
);
$rootScope.onAppEvent(
"dashboard-initialized",
this.dashboardInitialized.bind(this),
$rootScope
);
$rootScope.onAppEvent(
"panel-initialized",
this.panelInitialized.bind(this),
$rootScope
);
} }
refresh() { refresh() {
@@ -36,10 +51,10 @@ export class Profiler {
this.timings.render = 0; this.timings.render = 0;
setTimeout(() => { setTimeout(() => {
console.log('panel count: ' + this.panelsInitCount); console.log("panel count: " + this.panelsInitCount);
console.log('total query: ' + this.timings.query); console.log("total query: " + this.timings.query);
console.log('total render: ' + this.timings.render); console.log("total render: " + this.timings.render);
console.log('avg render: ' + this.timings.render / this.panelsInitCount); console.log("avg render: " + this.timings.render / this.panelsInitCount);
}, 5000); }, 5000);
} }
@@ -55,12 +70,21 @@ export class Profiler {
dashboardInitialized() { dashboardInitialized() {
setTimeout(() => { setTimeout(() => {
console.log("Dashboard::Performance Total Digests: " + this.digestCounter); console.log(
console.log("Dashboard::Performance Total Watchers: " + this.getTotalWatcherCount()); "Dashboard::Performance Total Digests: " + this.digestCounter
console.log("Dashboard::Performance Total ScopeCount: " + this.scopeCount); );
console.log(
"Dashboard::Performance Total Watchers: " + this.getTotalWatcherCount()
);
console.log(
"Dashboard::Performance Total ScopeCount: " + this.scopeCount
);
var timeTaken = this.timings.lastPanelInitializedAt - this.timings.dashboardLoadStart; var timeTaken =
console.log("Dashboard::Performance All panels initialized in " + timeTaken + " ms"); this.timings.lastPanelInitializedAt - this.timings.dashboardLoadStart;
console.log(
"Dashboard::Performance All panels initialized in " + timeTaken + " ms"
);
// measure digest performance // measure digest performance
var rootDigestStart = window.performance.now(); var rootDigestStart = window.performance.now();
@@ -68,24 +92,27 @@ export class Profiler {
this.$rootScope.$apply(); this.$rootScope.$apply();
} }
console.log("Dashboard::Performance Root Digest " + ((window.performance.now() - rootDigestStart) / 30)); console.log(
"Dashboard::Performance Root Digest " +
(window.performance.now() - rootDigestStart) / 30
);
}, 3000); }, 3000);
} }
getTotalWatcherCount() { getTotalWatcherCount() {
var count = 0; var count = 0;
var scopes = 0; var scopes = 0;
var root = $(document.getElementsByTagName('body')); var root = $(document.getElementsByTagName("body"));
var f = function (element) { var f = function(element) {
if (element.data().hasOwnProperty('$scope')) { if (element.data().hasOwnProperty("$scope")) {
scopes++; scopes++;
angular.forEach(element.data().$scope.$$watchers, function () { angular.forEach(element.data().$scope.$$watchers, function() {
count++; count++;
}); });
} }
angular.forEach(element.children(), function (childElement) { angular.forEach(element.children(), function(childElement) {
f($(childElement)); f($(childElement));
}); });
}; };
@@ -116,8 +143,7 @@ export class Profiler {
this.panelsInitCount++; this.panelsInitCount++;
this.timings.lastPanelInitializedAt = new Date().getTime(); this.timings.lastPanelInitializedAt = new Date().getTime();
} }
} }
var profiler = new Profiler(); var profiler = new Profiler();
export {profiler}; export { profiler };

View File

@@ -4,19 +4,23 @@ export class BundleLoader {
constructor(bundleName) { constructor(bundleName) {
var defer = null; var defer = null;
this.lazy = ["$q", "$route", "$rootScope", ($q, $route, $rootScope) => { this.lazy = [
if (defer) { "$q",
"$route",
"$rootScope",
($q, $route, $rootScope) => {
if (defer) {
return defer.promise;
}
defer = $q.defer();
System.import(bundleName).then(() => {
defer.resolve();
});
return defer.promise; return defer.promise;
} }
];
defer = $q.defer();
System.import(bundleName).then(() => {
defer.resolve();
});
return defer.promise;
}];
} }
} }

View File

@@ -1,15 +1,14 @@
import coreModule from '../core_module'; import coreModule from "../core_module";
export class LoadDashboardCtrl { export class LoadDashboardCtrl {
/** @ngInject */ /** @ngInject */
constructor($scope, $routeParams, dashboardLoaderSrv, backendSrv, $location) { constructor($scope, $routeParams, dashboardLoaderSrv, backendSrv, $location) {
$scope.appEvent("dashboard-fetch-start"); $scope.appEvent("dashboard-fetch-start");
if (!$routeParams.slug) { if (!$routeParams.slug) {
backendSrv.get('/api/dashboards/home').then(function(homeDash) { backendSrv.get("/api/dashboards/home").then(function(homeDash) {
if (homeDash.redirectUri) { if (homeDash.redirectUri) {
$location.path('dashboard/' + homeDash.redirectUri); $location.path("dashboard/" + homeDash.redirectUri);
} else { } else {
var meta = homeDash.meta; var meta = homeDash.meta;
meta.canSave = meta.canShare = meta.canStar = false; meta.canSave = meta.canShare = meta.canStar = false;
@@ -19,35 +18,39 @@ export class LoadDashboardCtrl {
return; return;
} }
dashboardLoaderSrv.loadDashboard($routeParams.type, $routeParams.slug).then(function(result) { dashboardLoaderSrv
if ($routeParams.keepRows) { .loadDashboard($routeParams.type, $routeParams.slug)
result.meta.keepRows = true; .then(function(result) {
} if ($routeParams.keepRows) {
$scope.initDashboard(result, $scope); result.meta.keepRows = true;
}); }
$scope.initDashboard(result, $scope);
});
} }
} }
export class NewDashboardCtrl { export class NewDashboardCtrl {
/** @ngInject */ /** @ngInject */
constructor($scope, $routeParams) { constructor($scope, $routeParams) {
$scope.initDashboard({ $scope.initDashboard(
meta: { canStar: false, canShare: false, isNew: true }, {
dashboard: { meta: { canStar: false, canShare: false, isNew: true },
title: "New dashboard", dashboard: {
panels: [ title: "New dashboard",
{ panels: [
type: 'add-panel', {
gridPos: {x: 0, y: 0, w: 12, h: 9}, type: "add-panel",
title: 'Panel Title', gridPos: { x: 0, y: 0, w: 12, h: 9 },
} title: "Panel Title"
], }
folderId: Number($routeParams.folderId) ],
folderId: Number($routeParams.folderId)
}
}, },
}, $scope); $scope
);
} }
} }
coreModule.controller('LoadDashboardCtrl', LoadDashboardCtrl); coreModule.controller("LoadDashboardCtrl", LoadDashboardCtrl);
coreModule.controller('NewDashboardCtrl', NewDashboardCtrl); coreModule.controller("NewDashboardCtrl", NewDashboardCtrl);

View File

@@ -1,282 +1,304 @@
import './dashboard_loaders'; import "./dashboard_loaders";
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
/** @ngInject **/ /** @ngInject **/
function setupAngularRoutes($routeProvider, $locationProvider) { function setupAngularRoutes($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true); $locationProvider.html5Mode(true);
var loadOrgBundle = { var loadOrgBundle = {
lazy: ["$q", "$route", "$rootScope", ($q, $route, $rootScope) => { lazy: [
return System.import('app/features/org/all'); "$q",
}] "$route",
"$rootScope",
($q, $route, $rootScope) => {
return System.import("app/features/org/all");
}
]
}; };
var loadAdminBundle = { var loadAdminBundle = {
lazy: ["$q", "$route", "$rootScope", ($q, $route, $rootScope) => { lazy: [
return System.import('app/features/admin/admin'); "$q",
}] "$route",
"$rootScope",
($q, $route, $rootScope) => {
return System.import("app/features/admin/admin");
}
]
}; };
var loadAlertingBundle = { var loadAlertingBundle = {
lazy: ["$q", "$route", "$rootScope", ($q, $route, $rootScope) => { lazy: [
return System.import('app/features/alerting/all'); "$q",
}] "$route",
"$rootScope",
($q, $route, $rootScope) => {
return System.import("app/features/alerting/all");
}
]
}; };
$routeProvider $routeProvider
.when('/', { .when("/", {
templateUrl: 'public/app/partials/dashboard.html', templateUrl: "public/app/partials/dashboard.html",
controller : 'LoadDashboardCtrl', controller: "LoadDashboardCtrl",
reloadOnSearch: false, reloadOnSearch: false,
pageClass: 'page-dashboard', pageClass: "page-dashboard"
}) })
.when('/dashboard/:type/:slug', { .when("/dashboard/:type/:slug", {
templateUrl: 'public/app/partials/dashboard.html', templateUrl: "public/app/partials/dashboard.html",
controller : 'LoadDashboardCtrl', controller: "LoadDashboardCtrl",
reloadOnSearch: false, reloadOnSearch: false,
pageClass: 'page-dashboard', pageClass: "page-dashboard"
}) })
.when('/dashboard-solo/:type/:slug', { .when("/dashboard-solo/:type/:slug", {
templateUrl: 'public/app/features/panel/partials/soloPanel.html', templateUrl: "public/app/features/panel/partials/soloPanel.html",
controller : 'SoloPanelCtrl', controller: "SoloPanelCtrl",
reloadOnSearch: false, reloadOnSearch: false,
pageClass: 'page-dashboard', pageClass: "page-dashboard"
}) })
.when('/dashboard/new', { .when("/dashboard/new", {
templateUrl: 'public/app/partials/dashboard.html', templateUrl: "public/app/partials/dashboard.html",
controller : 'NewDashboardCtrl', controller: "NewDashboardCtrl",
reloadOnSearch: false, reloadOnSearch: false,
pageClass: 'page-dashboard', pageClass: "page-dashboard"
}) })
.when('/dashboard/import', { .when("/dashboard/import", {
templateUrl: 'public/app/features/dashboard/partials/dashboardImport.html', templateUrl:
controller : 'DashboardImportCtrl', "public/app/features/dashboard/partials/dashboardImport.html",
controllerAs: 'ctrl', controller: "DashboardImportCtrl",
}) controllerAs: "ctrl"
.when('/datasources', { })
templateUrl: 'public/app/features/plugins/partials/ds_list.html', .when("/datasources", {
controller : 'DataSourcesCtrl', templateUrl: "public/app/features/plugins/partials/ds_list.html",
controllerAs: 'ctrl', controller: "DataSourcesCtrl",
}) controllerAs: "ctrl"
.when('/datasources/edit/:id', { })
templateUrl: 'public/app/features/plugins/partials/ds_edit.html', .when("/datasources/edit/:id", {
controller : 'DataSourceEditCtrl', templateUrl: "public/app/features/plugins/partials/ds_edit.html",
controllerAs: 'ctrl', controller: "DataSourceEditCtrl",
}) controllerAs: "ctrl"
.when('/datasources/new', { })
templateUrl: 'public/app/features/plugins/partials/ds_edit.html', .when("/datasources/new", {
controller : 'DataSourceEditCtrl', templateUrl: "public/app/features/plugins/partials/ds_edit.html",
controllerAs: 'ctrl', controller: "DataSourceEditCtrl",
}) controllerAs: "ctrl"
.when('/dashboards', { })
templateUrl: 'public/app/features/dashboard/partials/dashboard_list.html', .when("/dashboards", {
controller : 'DashboardListCtrl', templateUrl: "public/app/features/dashboard/partials/dashboard_list.html",
controllerAs: 'ctrl', controller: "DashboardListCtrl",
}) controllerAs: "ctrl"
.when('/dashboards/folder/new', { })
templateUrl: 'public/app/features/dashboard/partials/create_folder.html', .when("/dashboards/folder/new", {
controller : 'CreateFolderCtrl', templateUrl: "public/app/features/dashboard/partials/create_folder.html",
controllerAs: 'ctrl', controller: "CreateFolderCtrl",
}) controllerAs: "ctrl"
.when('/dashboards/folder/:folderId/:slug/permissions', { })
templateUrl: 'public/app/features/dashboard/partials/folder_permissions.html', .when("/dashboards/folder/:folderId/:slug/permissions", {
controller : 'FolderPermissionsCtrl', templateUrl:
controllerAs: 'ctrl', "public/app/features/dashboard/partials/folder_permissions.html",
}) controller: "FolderPermissionsCtrl",
.when('/dashboards/folder/:folderId/:slug/settings', { controllerAs: "ctrl"
templateUrl: 'public/app/features/dashboard/partials/folder_settings.html', })
controller : 'FolderSettingsCtrl', .when("/dashboards/folder/:folderId/:slug/settings", {
controllerAs: 'ctrl', templateUrl:
}) "public/app/features/dashboard/partials/folder_settings.html",
.when('/dashboards/folder/:folderId/:slug', { controller: "FolderSettingsCtrl",
templateUrl: 'public/app/features/dashboard/partials/folder_dashboards.html', controllerAs: "ctrl"
controller : 'FolderDashboardsCtrl', })
controllerAs: 'ctrl', .when("/dashboards/folder/:folderId/:slug", {
}) templateUrl:
.when('/org', { "public/app/features/dashboard/partials/folder_dashboards.html",
templateUrl: 'public/app/features/org/partials/orgDetails.html', controller: "FolderDashboardsCtrl",
controller : 'OrgDetailsCtrl', controllerAs: "ctrl"
resolve: loadOrgBundle, })
}) .when("/org", {
.when('/org/new', { templateUrl: "public/app/features/org/partials/orgDetails.html",
templateUrl: 'public/app/features/org/partials/newOrg.html', controller: "OrgDetailsCtrl",
controller : 'NewOrgCtrl', resolve: loadOrgBundle
resolve: loadOrgBundle, })
}) .when("/org/new", {
.when('/org/users', { templateUrl: "public/app/features/org/partials/newOrg.html",
templateUrl: 'public/app/features/org/partials/orgUsers.html', controller: "NewOrgCtrl",
controller : 'OrgUsersCtrl', resolve: loadOrgBundle
controllerAs: 'ctrl', })
resolve: loadOrgBundle, .when("/org/users", {
}) templateUrl: "public/app/features/org/partials/orgUsers.html",
.when('/org/users/invite', { controller: "OrgUsersCtrl",
templateUrl: 'public/app/features/org/partials/invite.html', controllerAs: "ctrl",
controller : 'UserInviteCtrl', resolve: loadOrgBundle
controllerAs: 'ctrl', })
resolve: loadOrgBundle, .when("/org/users/invite", {
}) templateUrl: "public/app/features/org/partials/invite.html",
.when('/org/apikeys', { controller: "UserInviteCtrl",
templateUrl: 'public/app/features/org/partials/orgApiKeys.html', controllerAs: "ctrl",
controller : 'OrgApiKeysCtrl', resolve: loadOrgBundle
resolve: loadOrgBundle, })
}) .when("/org/apikeys", {
.when('/org/teams', { templateUrl: "public/app/features/org/partials/orgApiKeys.html",
templateUrl: 'public/app/features/org/partials/teams.html', controller: "OrgApiKeysCtrl",
controller : 'TeamsCtrl', resolve: loadOrgBundle
controllerAs: 'ctrl', })
resolve: loadOrgBundle, .when("/org/teams", {
}) templateUrl: "public/app/features/org/partials/teams.html",
.when('/org/teams/edit/:id', { controller: "TeamsCtrl",
templateUrl: 'public/app/features/org/partials/team_details.html', controllerAs: "ctrl",
controller : 'TeamDetailsCtrl', resolve: loadOrgBundle
controllerAs: 'ctrl', })
resolve: loadOrgBundle, .when("/org/teams/edit/:id", {
}) templateUrl: "public/app/features/org/partials/team_details.html",
.when('/profile', { controller: "TeamDetailsCtrl",
templateUrl: 'public/app/features/org/partials/profile.html', controllerAs: "ctrl",
controller : 'ProfileCtrl', resolve: loadOrgBundle
controllerAs: 'ctrl', })
resolve: loadOrgBundle, .when("/profile", {
}) templateUrl: "public/app/features/org/partials/profile.html",
.when('/profile/password', { controller: "ProfileCtrl",
templateUrl: 'public/app/features/org/partials/change_password.html', controllerAs: "ctrl",
controller : 'ChangePasswordCtrl', resolve: loadOrgBundle
resolve: loadOrgBundle, })
}) .when("/profile/password", {
.when('/profile/select-org', { templateUrl: "public/app/features/org/partials/change_password.html",
templateUrl: 'public/app/features/org/partials/select_org.html', controller: "ChangePasswordCtrl",
controller : 'SelectOrgCtrl', resolve: loadOrgBundle
resolve: loadOrgBundle, })
}) .when("/profile/select-org", {
// ADMIN templateUrl: "public/app/features/org/partials/select_org.html",
.when('/admin', { controller: "SelectOrgCtrl",
templateUrl: 'public/app/features/admin/partials/admin_home.html', resolve: loadOrgBundle
controller : 'AdminHomeCtrl', })
controllerAs: 'ctrl', // ADMIN
resolve: loadAdminBundle, .when("/admin", {
}) templateUrl: "public/app/features/admin/partials/admin_home.html",
.when('/admin/settings', { controller: "AdminHomeCtrl",
templateUrl: 'public/app/features/admin/partials/settings.html', controllerAs: "ctrl",
controller : 'AdminSettingsCtrl', resolve: loadAdminBundle
controllerAs: 'ctrl', })
resolve: loadAdminBundle, .when("/admin/settings", {
}) templateUrl: "public/app/features/admin/partials/settings.html",
.when('/admin/users', { controller: "AdminSettingsCtrl",
templateUrl: 'public/app/features/admin/partials/users.html', controllerAs: "ctrl",
controller : 'AdminListUsersCtrl', resolve: loadAdminBundle
controllerAs: 'ctrl', })
resolve: loadAdminBundle, .when("/admin/users", {
}) templateUrl: "public/app/features/admin/partials/users.html",
.when('/admin/users/create', { controller: "AdminListUsersCtrl",
templateUrl: 'public/app/features/admin/partials/new_user.html', controllerAs: "ctrl",
controller : 'AdminEditUserCtrl', resolve: loadAdminBundle
resolve: loadAdminBundle, })
}) .when("/admin/users/create", {
.when('/admin/users/edit/:id', { templateUrl: "public/app/features/admin/partials/new_user.html",
templateUrl: 'public/app/features/admin/partials/edit_user.html', controller: "AdminEditUserCtrl",
controller : 'AdminEditUserCtrl', resolve: loadAdminBundle
resolve: loadAdminBundle, })
}) .when("/admin/users/edit/:id", {
.when('/admin/orgs', { templateUrl: "public/app/features/admin/partials/edit_user.html",
templateUrl: 'public/app/features/admin/partials/orgs.html', controller: "AdminEditUserCtrl",
controller : 'AdminListOrgsCtrl', resolve: loadAdminBundle
controllerAs: 'ctrl', })
resolve: loadAdminBundle, .when("/admin/orgs", {
}) templateUrl: "public/app/features/admin/partials/orgs.html",
.when('/admin/orgs/edit/:id', { controller: "AdminListOrgsCtrl",
templateUrl: 'public/app/features/admin/partials/edit_org.html', controllerAs: "ctrl",
controller : 'AdminEditOrgCtrl', resolve: loadAdminBundle
controllerAs: 'ctrl', })
resolve: loadAdminBundle, .when("/admin/orgs/edit/:id", {
}) templateUrl: "public/app/features/admin/partials/edit_org.html",
.when('/admin/stats', { controller: "AdminEditOrgCtrl",
templateUrl: 'public/app/features/admin/partials/stats.html', controllerAs: "ctrl",
controller : 'AdminStatsCtrl', resolve: loadAdminBundle
controllerAs: 'ctrl', })
resolve: loadAdminBundle, .when("/admin/stats", {
}) templateUrl: "public/app/features/admin/partials/stats.html",
// LOGIN / SIGNUP controller: "AdminStatsCtrl",
.when('/login', { controllerAs: "ctrl",
templateUrl: 'public/app/partials/login.html', resolve: loadAdminBundle
controller : 'LoginCtrl', })
pageClass: 'login-page sidemenu-hidden', // LOGIN / SIGNUP
}) .when("/login", {
.when('/invite/:code', { templateUrl: "public/app/partials/login.html",
templateUrl: 'public/app/partials/signup_invited.html', controller: "LoginCtrl",
controller : 'InvitedCtrl', pageClass: "login-page sidemenu-hidden"
pageClass: 'sidemenu-hidden', })
}) .when("/invite/:code", {
.when('/signup', { templateUrl: "public/app/partials/signup_invited.html",
templateUrl: 'public/app/partials/signup_step2.html', controller: "InvitedCtrl",
controller : 'SignUpCtrl', pageClass: "sidemenu-hidden"
pageClass: 'sidemenu-hidden', })
}) .when("/signup", {
.when('/user/password/send-reset-email', { templateUrl: "public/app/partials/signup_step2.html",
templateUrl: 'public/app/partials/reset_password.html', controller: "SignUpCtrl",
controller : 'ResetPasswordCtrl', pageClass: "sidemenu-hidden"
pageClass: 'sidemenu-hidden', })
}) .when("/user/password/send-reset-email", {
.when('/user/password/reset', { templateUrl: "public/app/partials/reset_password.html",
templateUrl: 'public/app/partials/reset_password.html', controller: "ResetPasswordCtrl",
controller : 'ResetPasswordCtrl', pageClass: "sidemenu-hidden"
pageClass: 'sidemenu-hidden', })
}) .when("/user/password/reset", {
.when('/dashboard/snapshots', { templateUrl: "public/app/partials/reset_password.html",
templateUrl: 'public/app/features/snapshot/partials/snapshots.html', controller: "ResetPasswordCtrl",
controller : 'SnapshotsCtrl', pageClass: "sidemenu-hidden"
controllerAs: 'ctrl', })
}) .when("/dashboard/snapshots", {
.when('/plugins', { templateUrl: "public/app/features/snapshot/partials/snapshots.html",
templateUrl: 'public/app/features/plugins/partials/plugin_list.html', controller: "SnapshotsCtrl",
controller: 'PluginListCtrl', controllerAs: "ctrl"
controllerAs: 'ctrl', })
}) .when("/plugins", {
.when('/plugins/:pluginId/edit', { templateUrl: "public/app/features/plugins/partials/plugin_list.html",
templateUrl: 'public/app/features/plugins/partials/plugin_edit.html', controller: "PluginListCtrl",
controller: 'PluginEditCtrl', controllerAs: "ctrl"
controllerAs: 'ctrl', })
}) .when("/plugins/:pluginId/edit", {
.when('/plugins/:pluginId/page/:slug', { templateUrl: "public/app/features/plugins/partials/plugin_edit.html",
templateUrl: 'public/app/features/plugins/partials/plugin_page.html', controller: "PluginEditCtrl",
controller: 'AppPageCtrl', controllerAs: "ctrl"
controllerAs: 'ctrl', })
}) .when("/plugins/:pluginId/page/:slug", {
.when('/styleguide/:page?', { templateUrl: "public/app/features/plugins/partials/plugin_page.html",
controller: 'StyleGuideCtrl', controller: "AppPageCtrl",
controllerAs: 'ctrl', controllerAs: "ctrl"
templateUrl: 'public/app/features/styleguide/styleguide.html', })
}) .when("/styleguide/:page?", {
.when('/alerting', { controller: "StyleGuideCtrl",
redirectTo: '/alerting/list' controllerAs: "ctrl",
}) templateUrl: "public/app/features/styleguide/styleguide.html"
.when('/alerting/list', { })
templateUrl: 'public/app/features/alerting/partials/alert_list.html', .when("/alerting", {
controller: 'AlertListCtrl', redirectTo: "/alerting/list"
controllerAs: 'ctrl', })
resolve: loadAlertingBundle, .when("/alerting/list", {
}) templateUrl: "public/app/features/alerting/partials/alert_list.html",
.when('/alerting/notifications', { controller: "AlertListCtrl",
templateUrl: 'public/app/features/alerting/partials/notifications_list.html', controllerAs: "ctrl",
controller: 'AlertNotificationsListCtrl', resolve: loadAlertingBundle
controllerAs: 'ctrl', })
resolve: loadAlertingBundle, .when("/alerting/notifications", {
}) templateUrl:
.when('/alerting/notification/new', { "public/app/features/alerting/partials/notifications_list.html",
templateUrl: 'public/app/features/alerting/partials/notification_edit.html', controller: "AlertNotificationsListCtrl",
controller: 'AlertNotificationEditCtrl', controllerAs: "ctrl",
controllerAs: 'ctrl', resolve: loadAlertingBundle
resolve: loadAlertingBundle, })
}) .when("/alerting/notification/new", {
.when('/alerting/notification/:id/edit', { templateUrl:
templateUrl: 'public/app/features/alerting/partials/notification_edit.html', "public/app/features/alerting/partials/notification_edit.html",
controller: 'AlertNotificationEditCtrl', controller: "AlertNotificationEditCtrl",
controllerAs: 'ctrl', controllerAs: "ctrl",
resolve: loadAlertingBundle, resolve: loadAlertingBundle
}) })
.otherwise({ .when("/alerting/notification/:id/edit", {
templateUrl: 'public/app/partials/error.html', templateUrl:
controller: 'ErrorCtrl' "public/app/features/alerting/partials/notification_edit.html",
}); controller: "AlertNotificationEditCtrl",
controllerAs: "ctrl",
resolve: loadAlertingBundle
})
.otherwise({
templateUrl: "public/app/partials/error.html",
controller: "ErrorCtrl"
});
} }
coreModule.config(setupAngularRoutes); coreModule.config(setupAngularRoutes);

View File

@@ -1,9 +1,9 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import angular from 'angular'; import angular from "angular";
import _ from 'lodash'; import _ from "lodash";
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import appEvents from 'app/core/app_events'; import appEvents from "app/core/app_events";
export class AlertSrv { export class AlertSrv {
list: any[]; list: any[];
@@ -14,44 +14,65 @@ export class AlertSrv {
} }
init() { init() {
this.$rootScope.onAppEvent('alert-error', (e, alert) => { this.$rootScope.onAppEvent(
this.set(alert[0], alert[1], 'error', 12000); "alert-error",
}, this.$rootScope); (e, alert) => {
this.set(alert[0], alert[1], "error", 12000);
},
this.$rootScope
);
this.$rootScope.onAppEvent('alert-warning', (e, alert) => { this.$rootScope.onAppEvent(
this.set(alert[0], alert[1], 'warning', 5000); "alert-warning",
}, this.$rootScope); (e, alert) => {
this.set(alert[0], alert[1], "warning", 5000);
},
this.$rootScope
);
this.$rootScope.onAppEvent('alert-success', (e, alert) => { this.$rootScope.onAppEvent(
this.set(alert[0], alert[1], 'success', 3000); "alert-success",
}, this.$rootScope); (e, alert) => {
this.set(alert[0], alert[1], "success", 3000);
},
this.$rootScope
);
appEvents.on('alert-warning', options => this.set(options[0], options[1], 'warning', 5000)); appEvents.on("alert-warning", options =>
appEvents.on('alert-success', options => this.set(options[0], options[1], 'success', 3000)); this.set(options[0], options[1], "warning", 5000)
appEvents.on('alert-error', options => this.set(options[0], options[1], 'error', 7000)); );
appEvents.on('confirm-modal', this.showConfirmModal.bind(this)); appEvents.on("alert-success", options =>
this.set(options[0], options[1], "success", 3000)
);
appEvents.on("alert-error", options =>
this.set(options[0], options[1], "error", 7000)
);
appEvents.on("confirm-modal", this.showConfirmModal.bind(this));
} }
getIconForSeverity(severity) { getIconForSeverity(severity) {
switch (severity) { switch (severity) {
case 'success': return 'fa fa-check'; case "success":
case 'error': return 'fa fa-exclamation-triangle'; return "fa fa-check";
default: return 'fa fa-exclamation'; case "error":
return "fa fa-exclamation-triangle";
default:
return "fa fa-exclamation";
} }
} }
set(title, text, severity, timeout) { set(title, text, severity, timeout) {
if (_.isObject(text)) { if (_.isObject(text)) {
console.log('alert error', text); console.log("alert error", text);
if (text.statusText) { if (text.statusText) {
text = `HTTP Error (${text.status}) ${text.statusText}`; text = `HTTP Error (${text.status}) ${text.statusText}`;
} }
} }
var newAlert = { var newAlert = {
title: title || '', title: title || "",
text: text || '', text: text || "",
severity: severity || 'info', severity: severity || "info",
icon: this.getIconForSeverity(severity) icon: this.getIconForSeverity(severity)
}; };
@@ -73,7 +94,7 @@ export class AlertSrv {
this.$rootScope.$digest(); this.$rootScope.$digest();
} }
return(newAlert); return newAlert;
} }
clear(alert) { clear(alert) {
@@ -93,7 +114,8 @@ export class AlertSrv {
}; };
scope.updateConfirmText = function(value) { scope.updateConfirmText = function(value) {
scope.confirmTextValid = payload.confirmText.toLowerCase() === value.toLowerCase(); scope.confirmTextValid =
payload.confirmText.toLowerCase() === value.toLowerCase();
}; };
scope.title = payload.title; scope.title = payload.title;
@@ -110,18 +132,18 @@ export class AlertSrv {
scope.confirmTextValid = scope.confirmText ? false : true; scope.confirmTextValid = scope.confirmText ? false : true;
var confirmModal = this.$modal({ var confirmModal = this.$modal({
template: 'public/app/partials/confirm_modal.html', template: "public/app/partials/confirm_modal.html",
persist: false, persist: false,
modalClass: 'confirm-modal', modalClass: "confirm-modal",
show: false, show: false,
scope: scope, scope: scope,
keyboard: false keyboard: false
}); });
confirmModal.then(function(modalEl) { confirmModal.then(function(modalEl) {
modalEl.modal('show'); modalEl.modal("show");
}); });
} }
} }
coreModule.service('alertSrv', AlertSrv); coreModule.service("alertSrv", AlertSrv);

View File

@@ -1,26 +1,29 @@
import $ from 'jquery'; import $ from "jquery";
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import config from 'app/core/config'; import config from "app/core/config";
export class Analytics { export class Analytics {
/** @ngInject */ /** @ngInject */
constructor(private $rootScope, private $location) { constructor(private $rootScope, private $location) {}
}
gaInit() { gaInit() {
$.getScript('https://www.google-analytics.com/analytics.js'); // jQuery shortcut $.getScript("https://www.google-analytics.com/analytics.js"); // jQuery shortcut
var ga = (<any>window).ga = (<any>window).ga || function () { (ga.q = ga.q || []).push(arguments); }; ga.l = +new Date; var ga = ((<any>window).ga =
ga('create', (<any>config).googleAnalyticsId, 'auto'); (<any>window).ga ||
function() {
(ga.q = ga.q || []).push(arguments);
});
ga.l = +new Date();
ga("create", (<any>config).googleAnalyticsId, "auto");
return ga; return ga;
} }
init() { init() {
this.$rootScope.$on('$viewContentLoaded', () => { this.$rootScope.$on("$viewContentLoaded", () => {
var track = { page: this.$location.url() }; var track = { page: this.$location.url() };
var ga = (<any>window).ga || this.gaInit(); var ga = (<any>window).ga || this.gaInit();
ga('set', track); ga("set", track);
ga('send', 'pageview'); ga("send", "pageview");
}); });
} }
} }
@@ -32,5 +35,4 @@ function startAnalytics(googleAnalyticsSrv) {
} }
} }
coreModule.service('googleAnalyticsSrv', Analytics).run(startAnalytics); coreModule.service("googleAnalyticsSrv", Analytics).run(startAnalytics);

View File

@@ -1,9 +1,9 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import _ from 'lodash'; import _ from "lodash";
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import appEvents from 'app/core/app_events'; import appEvents from "app/core/app_events";
import { DashboardModel } from 'app/features/dashboard/dashboard_model'; import { DashboardModel } from "app/features/dashboard/dashboard_model";
export class BackendSrv { export class BackendSrv {
private inFlightRequests = {}; private inFlightRequests = {};
@@ -11,27 +11,32 @@ export class BackendSrv {
private noBackendCache: boolean; private noBackendCache: boolean;
/** @ngInject */ /** @ngInject */
constructor(private $http, private alertSrv, private $q, private $timeout, private contextSrv) { constructor(
} private $http,
private alertSrv,
private $q,
private $timeout,
private contextSrv
) {}
get(url, params?) { get(url, params?) {
return this.request({ method: 'GET', url: url, params: params }); return this.request({ method: "GET", url: url, params: params });
} }
delete(url) { delete(url) {
return this.request({ method: 'DELETE', url: url }); return this.request({ method: "DELETE", url: url });
} }
post(url, data) { post(url, data) {
return this.request({ method: 'POST', url: url, data: data }); return this.request({ method: "POST", url: url, data: data });
} }
patch(url, data) { patch(url, data) {
return this.request({ method: 'PATCH', url: url, data: data }); return this.request({ method: "PATCH", url: url, data: data });
} }
put(url, data) { put(url, data) {
return this.request({ method: 'PUT', url: url, data: data }); return this.request({ method: "PUT", url: url, data: data });
} }
withNoBackendCache(callback) { withNoBackendCache(callback) {
@@ -46,7 +51,7 @@ export class BackendSrv {
return; return;
} }
var data = err.data || { message: 'Unexpected error' }; var data = err.data || { message: "Unexpected error" };
if (_.isString(data)) { if (_.isString(data)) {
data = { message: data }; data = { message: data };
} }
@@ -56,7 +61,7 @@ export class BackendSrv {
throw data; throw data;
} }
data.severity = 'error'; data.severity = "error";
if (err.status < 500) { if (err.status < 500) {
data.severity = "warning"; data.severity = "warning";
@@ -83,7 +88,7 @@ export class BackendSrv {
if (requestIsLocal) { if (requestIsLocal) {
if (this.contextSrv.user && this.contextSrv.user.orgId) { if (this.contextSrv.user && this.contextSrv.user.orgId) {
options.headers = options.headers || {}; options.headers = options.headers || {};
options.headers['X-Grafana-Org-Id'] = this.contextSrv.user.orgId; options.headers["X-Grafana-Org-Id"] = this.contextSrv.user.orgId;
} }
if (options.url.indexOf("/") === 0) { if (options.url.indexOf("/") === 0) {
@@ -91,27 +96,34 @@ export class BackendSrv {
} }
} }
return this.$http(options).then(results => { return this.$http(options).then(
if (options.method !== 'GET') { results => {
if (results && results.data.message) { if (options.method !== "GET") {
if (options.showSuccessAlert !== false) { if (results && results.data.message) {
this.alertSrv.set(results.data.message, '', 'success', 3000); if (options.showSuccessAlert !== false) {
this.alertSrv.set(results.data.message, "", "success", 3000);
}
} }
} }
} return results.data;
return results.data; },
}, err => { err => {
// handle unauthorized // handle unauthorized
if (err.status === 401 && this.contextSrv.user.isSignedIn && firstAttempt) { if (
return this.loginPing().then(() => { err.status === 401 &&
options.retry = 1; this.contextSrv.user.isSignedIn &&
return this.request(options); firstAttempt
}); ) {
} return this.loginPing().then(() => {
options.retry = 1;
return this.request(options);
});
}
this.$timeout(this.requestErrorHandler.bind(this, err), 50); this.$timeout(this.requestErrorHandler.bind(this, err), 50);
throw err; throw err;
}); }
);
} }
addCanceler(requestId, canceler) { addCanceler(requestId, canceler) {
@@ -151,7 +163,7 @@ export class BackendSrv {
if (requestIsLocal) { if (requestIsLocal) {
if (this.contextSrv.user && this.contextSrv.user.orgId) { if (this.contextSrv.user && this.contextSrv.user.orgId) {
options.headers = options.headers || {}; options.headers = options.headers || {};
options.headers['X-Grafana-Org-Id'] = this.contextSrv.user.orgId; options.headers["X-Grafana-Org-Id"] = this.contextSrv.user.orgId;
} }
if (options.url.indexOf("/") === 0) { if (options.url.indexOf("/") === 0) {
@@ -159,78 +171,80 @@ export class BackendSrv {
} }
if (options.headers && options.headers.Authorization) { if (options.headers && options.headers.Authorization) {
options.headers['X-DS-Authorization'] = options.headers.Authorization; options.headers["X-DS-Authorization"] = options.headers.Authorization;
delete options.headers.Authorization; delete options.headers.Authorization;
} }
if (this.noBackendCache) { if (this.noBackendCache) {
options.headers['X-Grafana-NoCache'] = 'true'; options.headers["X-Grafana-NoCache"] = "true";
} }
} }
return this.$http(options).then(response => { return this.$http(options)
appEvents.emit('ds-request-response', response); .then(response => {
return response; appEvents.emit("ds-request-response", response);
}).catch(err => { return response;
if (err.status === this.HTTP_REQUEST_CANCELLED) { })
throw {err, cancelled: true}; .catch(err => {
} if (err.status === this.HTTP_REQUEST_CANCELLED) {
throw { err, cancelled: true };
}
// handle unauthorized for backend requests // handle unauthorized for backend requests
if (requestIsLocal && firstAttempt && err.status === 401) { if (requestIsLocal && firstAttempt && err.status === 401) {
return this.loginPing().then(() => { return this.loginPing().then(() => {
options.retry = 1; options.retry = 1;
if (canceler) { if (canceler) {
canceler.resolve(); canceler.resolve();
} }
return this.datasourceRequest(options); return this.datasourceRequest(options);
}); });
} }
// populate error obj on Internal Error // populate error obj on Internal Error
if (_.isString(err.data) && err.status === 500) { if (_.isString(err.data) && err.status === 500) {
err.data = { err.data = {
error: err.statusText, error: err.statusText,
response: err.data, response: err.data
}; };
} }
// for Prometheus // for Prometheus
if (err.data && !err.data.message && _.isString(err.data.error)) { if (err.data && !err.data.message && _.isString(err.data.error)) {
err.data.message = err.data.error; err.data.message = err.data.error;
} }
appEvents.emit('ds-request-error', err); appEvents.emit("ds-request-error", err);
throw err; throw err;
})
}).finally(() => { .finally(() => {
// clean up // clean up
if (options.requestId) { if (options.requestId) {
this.inFlightRequests[options.requestId].shift(); this.inFlightRequests[options.requestId].shift();
} }
}); });
} }
loginPing() { loginPing() {
return this.request({url: '/api/login/ping', method: 'GET', retry: 1 }); return this.request({ url: "/api/login/ping", method: "GET", retry: 1 });
} }
search(query) { search(query) {
return this.get('/api/search', query); return this.get("/api/search", query);
} }
getDashboard(type, slug) { getDashboard(type, slug) {
return this.get('/api/dashboards/' + type + '/' + slug); return this.get("/api/dashboards/" + type + "/" + slug);
} }
saveDashboard(dash, options) { saveDashboard(dash, options) {
options = (options || {}); options = options || {};
return this.post('/api/dashboards/db/', { return this.post("/api/dashboards/db/", {
dashboard: dash, dashboard: dash,
folderId: dash.folderId, folderId: dash.folderId,
overwrite: options.overwrite === true, overwrite: options.overwrite === true,
message: options.message || '', message: options.message || ""
}); });
} }
@@ -242,24 +256,27 @@ export class BackendSrv {
panels: [] panels: []
}; };
return this.post('/api/dashboards/db/', {dashboard: dash, isFolder: true, overwrite: false}) return this.post("/api/dashboards/db/", {
.then(res => { dashboard: dash,
return this.getDashboard('db', res.slug); isFolder: true,
overwrite: false
}).then(res => {
return this.getDashboard("db", res.slug);
}); });
} }
deleteDashboard(slug) { deleteDashboard(slug) {
let deferred = this.$q.defer(); let deferred = this.$q.defer();
this.getDashboard('db', slug) this.getDashboard("db", slug).then(fullDash => {
.then(fullDash => { this.delete(`/api/dashboards/db/${slug}`)
this.delete(`/api/dashboards/db/${slug}`) .then(() => {
.then(() => { deferred.resolve(fullDash);
deferred.resolve(fullDash); })
}).catch(err => { .catch(err => {
deferred.reject(err); deferred.reject(err);
}); });
}); });
return deferred.promise; return deferred.promise;
} }
@@ -278,28 +295,31 @@ export class BackendSrv {
const tasks = []; const tasks = [];
for (let slug of dashboardSlugs) { for (let slug of dashboardSlugs) {
tasks.push(this.createTask(this.moveDashboard.bind(this), true, slug, toFolder)); tasks.push(
this.createTask(this.moveDashboard.bind(this), true, slug, toFolder)
);
} }
return this.executeInOrder(tasks, []) return this.executeInOrder(tasks, []).then(result => {
.then(result => { return {
return { totalCount: result.length,
totalCount: result.length, successCount: _.filter(result, { succeeded: true }).length,
successCount: _.filter(result, { succeeded: true }).length, alreadyInFolderCount: _.filter(result, { alreadyInFolder: true }).length
alreadyInFolderCount: _.filter(result, { alreadyInFolder: true }).length };
}; });
});
} }
private moveDashboard(slug, toFolder) { private moveDashboard(slug, toFolder) {
let deferred = this.$q.defer(); let deferred = this.$q.defer();
this.getDashboard('db', slug).then(fullDash => { this.getDashboard("db", slug).then(fullDash => {
const model = new DashboardModel(fullDash.dashboard, fullDash.meta); const model = new DashboardModel(fullDash.dashboard, fullDash.meta);
if ((!fullDash.meta.folderId && toFolder.id === 0) || if (
fullDash.meta.folderId === toFolder.id) { (!fullDash.meta.folderId && toFolder.id === 0) ||
deferred.resolve({alreadyInFolder: true}); fullDash.meta.folderId === toFolder.id
) {
deferred.resolve({ alreadyInFolder: true });
return; return;
} }
@@ -310,19 +330,21 @@ export class BackendSrv {
this.saveDashboard(clone, {}) this.saveDashboard(clone, {})
.then(() => { .then(() => {
deferred.resolve({succeeded: true}); deferred.resolve({ succeeded: true });
}).catch(err => { })
.catch(err => {
if (err.data && err.data.status === "plugin-dashboard") { if (err.data && err.data.status === "plugin-dashboard") {
err.isHandled = true; err.isHandled = true;
this.saveDashboard(clone, {overwrite: true}) this.saveDashboard(clone, { overwrite: true })
.then(() => { .then(() => {
deferred.resolve({succeeded: true}); deferred.resolve({ succeeded: true });
}).catch(err => { })
deferred.resolve({succeeded: false}); .catch(err => {
deferred.resolve({ succeeded: false });
}); });
} else { } else {
deferred.resolve({succeeded: false}); deferred.resolve({ succeeded: false });
} }
}); });
}); });
@@ -331,11 +353,13 @@ export class BackendSrv {
} }
private createTask(fn, ignoreRejections, ...args: any[]) { private createTask(fn, ignoreRejections, ...args: any[]) {
return (result) => { return result => {
return fn.apply(null, args) return fn
.apply(null, args)
.then(res => { .then(res => {
return Array.prototype.concat(result, [res]); return Array.prototype.concat(result, [res]);
}).catch(err => { })
.catch(err => {
if (ignoreRejections) { if (ignoreRejections) {
return result; return result;
} }
@@ -350,5 +374,4 @@ export class BackendSrv {
} }
} }
coreModule.service("backendSrv", BackendSrv);
coreModule.service('backendSrv', BackendSrv);

View File

@@ -1,7 +1,7 @@
import config from 'app/core/config'; import config from "app/core/config";
import _ from 'lodash'; import _ from "lodash";
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import store from 'app/core/store'; import store from "app/core/store";
export class User { export class User {
isGrafanaAdmin: any; isGrafanaAdmin: any;
@@ -30,20 +30,20 @@ export class ContextSrv {
sidemenuSmallBreakpoint = false; sidemenuSmallBreakpoint = false;
constructor() { constructor() {
this.sidemenu = store.getBool('grafana.sidemenu', true); this.sidemenu = store.getBool("grafana.sidemenu", true);
if (!config.buildInfo) { if (!config.buildInfo) {
config.buildInfo = {}; config.buildInfo = {};
} }
if (!config.bootData) { if (!config.bootData) {
config.bootData = {user: {}, settings: {}}; config.bootData = { user: {}, settings: {} };
} }
this.version = config.buildInfo.version; this.version = config.buildInfo.version;
this.user = new User(); this.user = new User();
this.isSignedIn = this.user.isSignedIn; this.isSignedIn = this.user.isSignedIn;
this.isGrafanaAdmin = this.user.isGrafanaAdmin; this.isGrafanaAdmin = this.user.isGrafanaAdmin;
this.isEditor = this.hasRole('Editor') || this.hasRole('Admin'); this.isEditor = this.hasRole("Editor") || this.hasRole("Admin");
} }
hasRole(role) { hasRole(role) {
@@ -51,18 +51,21 @@ export class ContextSrv {
} }
isGrafanaVisible() { isGrafanaVisible() {
return !!(document.visibilityState === undefined || document.visibilityState === 'visible'); return !!(
document.visibilityState === undefined ||
document.visibilityState === "visible"
);
} }
toggleSideMenu() { toggleSideMenu() {
this.sidemenu = !this.sidemenu; this.sidemenu = !this.sidemenu;
store.set('grafana.sidemenu', this.sidemenu); store.set("grafana.sidemenu", this.sidemenu);
} }
} }
var contextSrv = new ContextSrv(); var contextSrv = new ContextSrv();
export {contextSrv}; export { contextSrv };
coreModule.factory('contextSrv', function() { coreModule.factory("contextSrv", function() {
return contextSrv; return contextSrv;
}); });

View File

@@ -1,10 +1,9 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import angular from 'angular'; import angular from "angular";
import coreModule from '../core_module'; import coreModule from "../core_module";
class DynamicDirectiveSrv { class DynamicDirectiveSrv {
/** @ngInject */ /** @ngInject */
constructor(private $compile, private $rootScope) {} constructor(private $compile, private $rootScope) {}
@@ -17,27 +16,36 @@ class DynamicDirectiveSrv {
} }
link(scope, elem, attrs, options) { link(scope, elem, attrs, options) {
options.directive(scope).then(directiveInfo => { options
if (!directiveInfo || !directiveInfo.fn) { .directive(scope)
elem.empty(); .then(directiveInfo => {
return; if (!directiveInfo || !directiveInfo.fn) {
} elem.empty();
return;
}
if (!directiveInfo.fn.registered) { if (!directiveInfo.fn.registered) {
coreModule.directive(attrs.$normalize(directiveInfo.name), directiveInfo.fn); coreModule.directive(
directiveInfo.fn.registered = true; attrs.$normalize(directiveInfo.name),
} directiveInfo.fn
);
directiveInfo.fn.registered = true;
}
this.addDirective(elem, directiveInfo.name, scope); this.addDirective(elem, directiveInfo.name, scope);
}).catch(err => { })
console.log('Plugin load:', err); .catch(err => {
this.$rootScope.appEvent('alert-error', ['Plugin error', err.toString()]); console.log("Plugin load:", err);
}); this.$rootScope.appEvent("alert-error", [
"Plugin error",
err.toString()
]);
});
} }
create(options) { create(options) {
let directiveDef = { let directiveDef = {
restrict: 'E', restrict: "E",
scope: options.scope, scope: options.scope,
link: (scope, elem, attrs) => { link: (scope, elem, attrs) => {
if (options.watchPath) { if (options.watchPath) {
@@ -59,6 +67,4 @@ class DynamicDirectiveSrv {
} }
} }
coreModule.service('dynamicDirectiveSrv', DynamicDirectiveSrv); coreModule.service("dynamicDirectiveSrv", DynamicDirectiveSrv);

View File

@@ -1,6 +1,6 @@
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import config from 'app/core/config'; import config from "app/core/config";
import appEvents from 'app/core/app_events'; import appEvents from "app/core/app_events";
// This service is for registering global events. // This service is for registering global events.
// Good for communication react > angular and vice verse // Good for communication react > angular and vice verse
@@ -13,25 +13,27 @@ export class GlobalEventSrv {
} }
// Angular's $location does not like <base href...> and absolute urls // Angular's $location does not like <base href...> and absolute urls
stripBaseFromUrl (url = '') { stripBaseFromUrl(url = "") {
const appSubUrl = this.appSubUrl; const appSubUrl = this.appSubUrl;
const stripExtraChars = appSubUrl.endsWith('/') ? 1 : 0; const stripExtraChars = appSubUrl.endsWith("/") ? 1 : 0;
const urlWithoutBase = url.length > 0 && url.indexOf(appSubUrl) === 0 ? const urlWithoutBase =
url.slice(appSubUrl.length - stripExtraChars) url.length > 0 && url.indexOf(appSubUrl) === 0
: url; ? url.slice(appSubUrl.length - stripExtraChars)
: url;
return urlWithoutBase; return urlWithoutBase;
} }
init() { init() {
appEvents.on('location-change', payload => { appEvents.on("location-change", payload => {
const urlWithoutBase = this.stripBaseFromUrl(payload.href); const urlWithoutBase = this.stripBaseFromUrl(payload.href);
this.$timeout(() => { // A hack to use timeout when we're changing things (in this case the url) from outside of Angular. this.$timeout(() => {
this.$location.url(urlWithoutBase); // A hack to use timeout when we're changing things (in this case the url) from outside of Angular.
this.$location.url(urlWithoutBase);
}); });
}); });
} }
} }
coreModule.service('globalEventSrv', GlobalEventSrv); coreModule.service("globalEventSrv", GlobalEventSrv);

View File

@@ -1,6 +1,6 @@
import store from 'app/core/store'; import store from "app/core/store";
import _ from 'lodash'; import _ from "lodash";
import config from 'app/core/config'; import config from "app/core/config";
export class ImpressionSrv { export class ImpressionSrv {
constructor() {} constructor() {}
@@ -15,7 +15,7 @@ export class ImpressionSrv {
} }
} }
impressions = impressions.filter((imp) => { impressions = impressions.filter(imp => {
return dashboardId !== imp; return dashboardId !== imp;
}); });

View File

@@ -1,21 +1,18 @@
import $ from 'jquery'; import $ from "jquery";
import _ from 'lodash'; import _ from "lodash";
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import appEvents from 'app/core/app_events'; import appEvents from "app/core/app_events";
import Mousetrap from 'mousetrap'; import Mousetrap from "mousetrap";
export class KeybindingSrv { export class KeybindingSrv {
helpModal: boolean; helpModal: boolean;
/** @ngInject */ /** @ngInject */
constructor( constructor(private $rootScope, private $location) {
private $rootScope,
private $location) {
// clear out all shortcuts on route change // clear out all shortcuts on route change
$rootScope.$on('$routeChangeSuccess', () => { $rootScope.$on("$routeChangeSuccess", () => {
Mousetrap.reset(); Mousetrap.reset();
// rebind global shortcuts // rebind global shortcuts
this.setupGlobal(); this.setupGlobal();
@@ -25,26 +22,26 @@ export class KeybindingSrv {
} }
setupGlobal() { setupGlobal() {
this.bind(['?', 'h'], this.showHelpModal); this.bind(["?", "h"], this.showHelpModal);
this.bind("g h", this.goToHome); this.bind("g h", this.goToHome);
this.bind("g a", this.openAlerting); this.bind("g a", this.openAlerting);
this.bind("g p", this.goToProfile); this.bind("g p", this.goToProfile);
this.bind("s s", this.openSearchStarred); this.bind("s s", this.openSearchStarred);
this.bind('s o', this.openSearch); this.bind("s o", this.openSearch);
this.bind('s t', this.openSearchTags); this.bind("s t", this.openSearchTags);
this.bind('f', this.openSearch); this.bind("f", this.openSearch);
} }
openSearchStarred() { openSearchStarred() {
appEvents.emit('show-dash-search', {starred: true}); appEvents.emit("show-dash-search", { starred: true });
} }
openSearchTags() { openSearchTags() {
appEvents.emit('show-dash-search', {tagsMode: true}); appEvents.emit("show-dash-search", { tagsMode: true });
} }
openSearch() { openSearch() {
appEvents.emit('show-dash-search'); appEvents.emit("show-dash-search");
} }
openAlerting() { openAlerting() {
@@ -60,54 +57,58 @@ export class KeybindingSrv {
} }
showHelpModal() { showHelpModal() {
appEvents.emit('show-modal', {templateHtml: '<help-modal></help-modal>'}); appEvents.emit("show-modal", { templateHtml: "<help-modal></help-modal>" });
} }
bind(keyArg, fn) { bind(keyArg, fn) {
Mousetrap.bind(keyArg, evt => { Mousetrap.bind(
evt.preventDefault(); keyArg,
evt.stopPropagation(); evt => {
evt.returnValue = false; evt.preventDefault();
return this.$rootScope.$apply(fn.bind(this)); evt.stopPropagation();
}, 'keydown'); evt.returnValue = false;
return this.$rootScope.$apply(fn.bind(this));
},
"keydown"
);
} }
showDashEditView() { showDashEditView() {
var search = _.extend(this.$location.search(), {editview: 'settings'}); var search = _.extend(this.$location.search(), { editview: "settings" });
this.$location.search(search); this.$location.search(search);
} }
setupDashboardBindings(scope, dashboard) { setupDashboardBindings(scope, dashboard) {
this.bind('mod+o', () => { this.bind("mod+o", () => {
dashboard.graphTooltip = (dashboard.graphTooltip + 1) % 3; dashboard.graphTooltip = (dashboard.graphTooltip + 1) % 3;
appEvents.emit('graph-hover-clear'); appEvents.emit("graph-hover-clear");
this.$rootScope.$broadcast('refresh'); this.$rootScope.$broadcast("refresh");
}); });
this.bind('mod+s', e => { this.bind("mod+s", e => {
scope.appEvent('save-dashboard'); scope.appEvent("save-dashboard");
}); });
this.bind('t z', () => { this.bind("t z", () => {
scope.appEvent('zoom-out', 2); scope.appEvent("zoom-out", 2);
}); });
this.bind('ctrl+z', () => { this.bind("ctrl+z", () => {
scope.appEvent('zoom-out', 2); scope.appEvent("zoom-out", 2);
}); });
this.bind('t left', () => { this.bind("t left", () => {
scope.appEvent('shift-time-backward'); scope.appEvent("shift-time-backward");
}); });
this.bind('t right', () => { this.bind("t right", () => {
scope.appEvent('shift-time-forward'); scope.appEvent("shift-time-forward");
}); });
// edit panel // edit panel
this.bind('e', () => { this.bind("e", () => {
if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) { if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) {
this.$rootScope.appEvent('panel-change-view', { this.$rootScope.appEvent("panel-change-view", {
fullscreen: true, fullscreen: true,
edit: true, edit: true,
panelId: dashboard.meta.focusPanelId, panelId: dashboard.meta.focusPanelId,
@@ -117,19 +118,19 @@ export class KeybindingSrv {
}); });
// view panel // view panel
this.bind('v', () => { this.bind("v", () => {
if (dashboard.meta.focusPanelId) { if (dashboard.meta.focusPanelId) {
this.$rootScope.appEvent('panel-change-view', { this.$rootScope.appEvent("panel-change-view", {
fullscreen: true, fullscreen: true,
edit: null, edit: null,
panelId: dashboard.meta.focusPanelId, panelId: dashboard.meta.focusPanelId,
toggle: true, toggle: true
}); });
} }
}); });
// delete panel // delete panel
this.bind('p r', () => { this.bind("p r", () => {
if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) { if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) {
var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId); var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId);
panelInfo.row.removePanel(panelInfo.panel); panelInfo.row.removePanel(panelInfo.panel);
@@ -138,22 +139,22 @@ export class KeybindingSrv {
}); });
// share panel // share panel
this.bind('p s', () => { this.bind("p s", () => {
if (dashboard.meta.focusPanelId) { if (dashboard.meta.focusPanelId) {
var shareScope = scope.$new(); var shareScope = scope.$new();
var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId); var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId);
shareScope.panel = panelInfo.panel; shareScope.panel = panelInfo.panel;
shareScope.dashboard = dashboard; shareScope.dashboard = dashboard;
appEvents.emit('show-modal', { appEvents.emit("show-modal", {
src: 'public/app/features/dashboard/partials/shareModal.html', src: "public/app/features/dashboard/partials/shareModal.html",
scope: shareScope scope: shareScope
}); });
} }
}); });
// delete row // delete row
this.bind('r r', () => { this.bind("r r", () => {
if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) { if (dashboard.meta.focusPanelId && dashboard.meta.canEdit) {
var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId); var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId);
dashboard.removeRow(panelInfo.row); dashboard.removeRow(panelInfo.row);
@@ -162,7 +163,7 @@ export class KeybindingSrv {
}); });
// collapse row // collapse row
this.bind('r c', () => { this.bind("r c", () => {
if (dashboard.meta.focusPanelId) { if (dashboard.meta.focusPanelId) {
var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId); var panelInfo = dashboard.getPanelInfoById(dashboard.meta.focusPanelId);
panelInfo.row.toggleCollapse(); panelInfo.row.toggleCollapse();
@@ -171,47 +172,47 @@ export class KeybindingSrv {
}); });
// collapse all rows // collapse all rows
this.bind('d shift+c', () => { this.bind("d shift+c", () => {
for (let row of dashboard.rows) { for (let row of dashboard.rows) {
row.collapse = true; row.collapse = true;
} }
}); });
// expand all rows // expand all rows
this.bind('d shift+e', () => { this.bind("d shift+e", () => {
for (let row of dashboard.rows) { for (let row of dashboard.rows) {
row.collapse = false; row.collapse = false;
} }
}); });
this.bind('d n', e => { this.bind("d n", e => {
this.$location.url("/dashboard/new"); this.$location.url("/dashboard/new");
}); });
this.bind('d r', () => { this.bind("d r", () => {
this.$rootScope.$broadcast('refresh'); this.$rootScope.$broadcast("refresh");
}); });
this.bind('d s', () => { this.bind("d s", () => {
this.showDashEditView(); this.showDashEditView();
}); });
this.bind('d k', () => { this.bind("d k", () => {
appEvents.emit('toggle-kiosk-mode'); appEvents.emit("toggle-kiosk-mode");
}); });
this.bind('d v', () => { this.bind("d v", () => {
appEvents.emit('toggle-view-mode'); appEvents.emit("toggle-view-mode");
}); });
this.bind('esc', () => { this.bind("esc", () => {
var popups = $('.popover.in'); var popups = $(".popover.in");
if (popups.length > 0) { if (popups.length > 0) {
return; return;
} }
scope.appEvent('hide-modal'); scope.appEvent("hide-modal");
scope.appEvent('panel-change-view', {fullscreen: false, edit: false}); scope.appEvent("panel-change-view", { fullscreen: false, edit: false });
// close settings view // close settings view
var search = this.$location.search(); var search = this.$location.search();
@@ -223,4 +224,4 @@ export class KeybindingSrv {
} }
} }
coreModule.service('keybindingSrv', KeybindingSrv); coreModule.service("keybindingSrv", KeybindingSrv);

View File

@@ -2,7 +2,6 @@
// This is using ng-react with this PR applied https://github.com/ngReact/ngReact/pull/199 // This is using ng-react with this PR applied https://github.com/ngReact/ngReact/pull/199
// //
// # ngReact // # ngReact
// ### Use React Components inside of your Angular applications // ### Use React Components inside of your Angular applications
// //
@@ -10,9 +9,9 @@
// - reactComponent (generic directive for delegating off to React Components) // - reactComponent (generic directive for delegating off to React Components)
// - reactDirective (factory for creating specific directives that correspond to reactComponent directives) // - reactDirective (factory for creating specific directives that correspond to reactComponent directives)
import React from 'react'; import React from "react";
import ReactDOM from 'react-dom'; import ReactDOM from "react-dom";
import angular from 'angular'; import angular from "angular";
// get a react component from name (components can be an angular injectable e.g. value, factory or // get a react component from name (components can be an angular injectable e.g. value, factory or
// available on window // available on window
@@ -24,7 +23,7 @@ function getReactComponent(name, $injector) {
// a React component name must be specified // a React component name must be specified
if (!name) { if (!name) {
throw new Error('ReactComponent name attribute must be specified'); throw new Error("ReactComponent name attribute must be specified");
} }
// ensure the specified React component is accessible, and fail fast if it's not // ensure the specified React component is accessible, and fail fast if it's not
@@ -35,14 +34,14 @@ function getReactComponent(name, $injector) {
if (!reactComponent) { if (!reactComponent) {
try { try {
reactComponent = name.split('.').reduce(function(current, namePart) { reactComponent = name.split(".").reduce(function(current, namePart) {
return current[namePart]; return current[namePart];
}, window); }, window);
} catch (e) {} } catch (e) {}
} }
if (!reactComponent) { if (!reactComponent) {
throw Error('Cannot find react component ' + name); throw Error("Cannot find react component " + name);
} }
return reactComponent; return reactComponent;
@@ -56,7 +55,7 @@ function applied(fn, scope) {
var wrapped: any = function() { var wrapped: any = function() {
var args = arguments; var args = arguments;
var phase = scope.$root.$$phase; var phase = scope.$root.$$phase;
if (phase === '$apply' || phase === '$digest') { if (phase === "$apply" || phase === "$digest") {
return fn.apply(null, args); return fn.apply(null, args);
} else { } else {
return scope.$apply(function() { return scope.$apply(function() {
@@ -85,24 +84,27 @@ function applyFunctions(obj, scope, propsConfig?) {
var value = obj[key]; var value = obj[key];
var config = (propsConfig || {})[key] || {}; var config = (propsConfig || {})[key] || {};
/** /**
* wrap functions in a function that ensures they are scope.$applied * wrap functions in a function that ensures they are scope.$applied
* ensures that when function is called from a React component * ensures that when function is called from a React component
* the Angular digest cycle is run * the Angular digest cycle is run
*/ */
prev[key] = angular.isFunction(value) && config.wrapApply !== false ? applied(value, scope) : value; prev[key] =
angular.isFunction(value) && config.wrapApply !== false
? applied(value, scope)
: value;
return prev; return prev;
}, {}); }, {});
} }
/** /**
* *
* @param watchDepth (value of HTML watch-depth attribute) * @param watchDepth (value of HTML watch-depth attribute)
* @param scope (angular scope) * @param scope (angular scope)
* *
* Uses the watchDepth attribute to determine how to watch props on scope. * Uses the watchDepth attribute to determine how to watch props on scope.
* If watchDepth attribute is NOT reference or collection, watchDepth defaults to deep watching by value * If watchDepth attribute is NOT reference or collection, watchDepth defaults to deep watching by value
*/ */
function watchProps(watchDepth, scope, watchExpressions, listener) { function watchProps(watchDepth, scope, watchExpressions, listener) {
var supportsWatchCollection = angular.isFunction(scope.$watchCollection); var supportsWatchCollection = angular.isFunction(scope.$watchCollection);
var supportsWatchGroup = angular.isFunction(scope.$watchGroup); var supportsWatchGroup = angular.isFunction(scope.$watchGroup);
@@ -113,18 +115,18 @@ function watchProps(watchDepth, scope, watchExpressions, listener) {
var actualExpr = getPropExpression(expr); var actualExpr = getPropExpression(expr);
var exprWatchDepth = getPropWatchDepth(watchDepth, expr); var exprWatchDepth = getPropWatchDepth(watchDepth, expr);
if (exprWatchDepth === 'collection' && supportsWatchCollection) { if (exprWatchDepth === "collection" && supportsWatchCollection) {
scope.$watchCollection(actualExpr, listener); scope.$watchCollection(actualExpr, listener);
} else if (exprWatchDepth === 'reference' && supportsWatchGroup) { } else if (exprWatchDepth === "reference" && supportsWatchGroup) {
watchGroupExpressions.push(actualExpr); watchGroupExpressions.push(actualExpr);
} else if (exprWatchDepth === 'one-time') { } else if (exprWatchDepth === "one-time") {
//do nothing because we handle our one time bindings after this //do nothing because we handle our one time bindings after this
} else { } else {
scope.$watch(actualExpr, listener, exprWatchDepth !== 'reference'); scope.$watch(actualExpr, listener, exprWatchDepth !== "reference");
} }
}); });
if (watchDepth === 'one-time') { if (watchDepth === "one-time") {
listener(); listener();
} }
@@ -165,7 +167,8 @@ function findAttribute(attrs, propName) {
// get watch depth of prop (string or array) // get watch depth of prop (string or array)
function getPropWatchDepth(defaultWatch, prop) { function getPropWatchDepth(defaultWatch, prop) {
var customWatchDepth = Array.isArray(prop) && angular.isObject(prop[1]) && prop[1].watchDepth; var customWatchDepth =
Array.isArray(prop) && angular.isObject(prop[1]) && prop[1].watchDepth;
return customWatchDepth || defaultWatch; return customWatchDepth || defaultWatch;
} }
@@ -189,7 +192,7 @@ function getPropWatchDepth(defaultWatch, prop) {
// //
var reactComponent = function($injector) { var reactComponent = function($injector) {
return { return {
restrict: 'E', restrict: "E",
replace: true, replace: true,
link: function(scope, elem, attrs) { link: function(scope, elem, attrs) {
var reactComponent = getReactComponent(attrs.name, $injector); var reactComponent = getReactComponent(attrs.name, $injector);
@@ -202,19 +205,24 @@ var reactComponent = function($injector) {
}; };
// If there are props, re-render when they change // If there are props, re-render when they change
attrs.props ? watchProps(attrs.watchDepth, scope, [attrs.props], renderMyComponent) : renderMyComponent(); attrs.props
? watchProps(attrs.watchDepth, scope, [attrs.props], renderMyComponent)
: renderMyComponent();
// cleanup when scope is destroyed // cleanup when scope is destroyed
scope.$on('$destroy', function() { scope.$on("$destroy", function() {
if (!attrs.onScopeDestroy) { if (!attrs.onScopeDestroy) {
ReactDOM.unmountComponentAtNode(elem[0]); ReactDOM.unmountComponentAtNode(elem[0]);
} else { } else {
scope.$eval(attrs.onScopeDestroy, { scope.$eval(attrs.onScopeDestroy, {
unmountComponent: ReactDOM.unmountComponentAtNode.bind(this, elem[0]), unmountComponent: ReactDOM.unmountComponentAtNode.bind(
this,
elem[0]
)
}); });
} }
}); });
}, }
}; };
}; };
@@ -247,7 +255,7 @@ var reactComponent = function($injector) {
var reactDirective = function($injector) { var reactDirective = function($injector) {
return function(reactComponentName, props, conf, injectableProps) { return function(reactComponentName, props, conf, injectableProps) {
var directive = { var directive = {
restrict: 'E', restrict: "E",
replace: true, replace: true,
link: function(scope, elem, attrs) { link: function(scope, elem, attrs) {
var reactComponent = getReactComponent(reactComponentName, $injector); var reactComponent = getReactComponent(reactComponentName, $injector);
@@ -274,28 +282,40 @@ var reactDirective = function($injector) {
// watch each property name and trigger an update whenever something changes, // watch each property name and trigger an update whenever something changes,
// to update scope.props with new values // to update scope.props with new values
var propExpressions = props.map(function(prop) { var propExpressions = props.map(function(prop) {
return Array.isArray(prop) ? [attrs[getPropName(prop)], getPropConfig(prop)] : attrs[prop]; return Array.isArray(prop)
? [attrs[getPropName(prop)], getPropConfig(prop)]
: attrs[prop];
}); });
// If we don't have any props, then our watch statement won't fire. // If we don't have any props, then our watch statement won't fire.
props.length ? watchProps(attrs.watchDepth, scope, propExpressions, renderMyComponent) : renderMyComponent(); props.length
? watchProps(
attrs.watchDepth,
scope,
propExpressions,
renderMyComponent
)
: renderMyComponent();
// cleanup when scope is destroyed // cleanup when scope is destroyed
scope.$on('$destroy', function() { scope.$on("$destroy", function() {
if (!attrs.onScopeDestroy) { if (!attrs.onScopeDestroy) {
ReactDOM.unmountComponentAtNode(elem[0]); ReactDOM.unmountComponentAtNode(elem[0]);
} else { } else {
scope.$eval(attrs.onScopeDestroy, { scope.$eval(attrs.onScopeDestroy, {
unmountComponent: ReactDOM.unmountComponentAtNode.bind(this, elem[0]), unmountComponent: ReactDOM.unmountComponentAtNode.bind(
this,
elem[0]
)
}); });
} }
}); });
}, }
}; };
return angular.extend(directive, conf); return angular.extend(directive, conf);
}; };
}; };
let ngModule = angular.module('react', []); let ngModule = angular.module("react", []);
ngModule.directive('reactComponent', ['$injector', reactComponent]); ngModule.directive("reactComponent", ["$injector", reactComponent]);
ngModule.factory('reactDirective', ['$injector', reactDirective]); ngModule.factory("reactDirective", ["$injector", reactDirective]);

View File

@@ -1,8 +1,8 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import _ from 'lodash'; import _ from "lodash";
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import Drop from 'tether-drop'; import Drop from "tether-drop";
/** @ngInject **/ /** @ngInject **/
function popoverSrv($compile, $rootScope, $timeout) { function popoverSrv($compile, $rootScope, $timeout) {
@@ -43,7 +43,7 @@ function popoverSrv($compile, $rootScope, $timeout) {
drop.close(); drop.close();
}; };
var contentElement = document.createElement('div'); var contentElement = document.createElement("div");
contentElement.innerHTML = options.template; contentElement.innerHTML = options.template;
$compile(contentElement)(scope); $compile(contentElement)(scope);
@@ -53,15 +53,15 @@ function popoverSrv($compile, $rootScope, $timeout) {
target: options.element, target: options.element,
content: contentElement, content: contentElement,
position: options.position, position: options.position,
classes: options.classNames || 'drop-popover', classes: options.classNames || "drop-popover",
openOn: options.openOn, openOn: options.openOn,
hoverCloseDelay: 200, hoverCloseDelay: 200,
tetherOptions: { tetherOptions: {
constraints: [{to: 'scrollParent', attachment: 'together'}] constraints: [{ to: "scrollParent", attachment: "together" }]
} }
}); });
drop.on('close', () => { drop.on("close", () => {
cleanUp(); cleanUp();
}); });
@@ -78,5 +78,4 @@ function popoverSrv($compile, $rootScope, $timeout) {
}; };
} }
coreModule.service('popoverSrv', popoverSrv); coreModule.service("popoverSrv", popoverSrv);

View File

@@ -1,8 +1,8 @@
import _ from 'lodash'; import _ from "lodash";
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import impressionSrv from 'app/core/services/impression_srv'; import impressionSrv from "app/core/services/impression_srv";
import store from 'app/core/store'; import store from "app/core/store";
import { contextSrv } from 'app/core/services/context_srv'; import { contextSrv } from "app/core/services/context_srv";
export class SearchSrv { export class SearchSrv {
recentIsOpen: boolean; recentIsOpen: boolean;
@@ -10,21 +10,21 @@ export class SearchSrv {
/** @ngInject */ /** @ngInject */
constructor(private backendSrv, private $q) { constructor(private backendSrv, private $q) {
this.recentIsOpen = store.getBool('search.sections.recent', true); this.recentIsOpen = store.getBool("search.sections.recent", true);
this.starredIsOpen = store.getBool('search.sections.starred', true); this.starredIsOpen = store.getBool("search.sections.starred", true);
} }
private getRecentDashboards(sections) { private getRecentDashboards(sections) {
return this.queryForRecentDashboards().then(result => { return this.queryForRecentDashboards().then(result => {
if (result.length > 0) { if (result.length > 0) {
sections['recent'] = { sections["recent"] = {
title: 'Recent Boards', title: "Recent Boards",
icon: 'fa fa-clock-o', icon: "fa fa-clock-o",
score: -1, score: -1,
removable: true, removable: true,
expanded: this.recentIsOpen, expanded: this.recentIsOpen,
toggle: this.toggleRecent.bind(this), toggle: this.toggleRecent.bind(this),
items: result, items: result
}; };
} }
}); });
@@ -37,9 +37,11 @@ export class SearchSrv {
} }
return this.backendSrv.search({ dashboardIds: dashIds }).then(result => { return this.backendSrv.search({ dashboardIds: dashIds }).then(result => {
return dashIds.map(orderId => { return dashIds
return _.find(result, { id: orderId }); .map(orderId => {
}).filter(hit => hit && !hit.isStarred) return _.find(result, { id: orderId });
})
.filter(hit => hit && !hit.isStarred)
.map(hit => { .map(hit => {
return this.transformToViewModel(hit); return this.transformToViewModel(hit);
}); });
@@ -48,7 +50,7 @@ export class SearchSrv {
private toggleRecent(section) { private toggleRecent(section) {
this.recentIsOpen = section.expanded = !section.expanded; this.recentIsOpen = section.expanded = !section.expanded;
store.set('search.sections.recent', this.recentIsOpen); store.set("search.sections.recent", this.recentIsOpen);
if (!section.expanded || section.items.length) { if (!section.expanded || section.items.length) {
return Promise.resolve(section); return Promise.resolve(section);
@@ -62,7 +64,7 @@ export class SearchSrv {
private toggleStarred(section) { private toggleStarred(section) {
this.starredIsOpen = section.expanded = !section.expanded; this.starredIsOpen = section.expanded = !section.expanded;
store.set('search.sections.starred', this.starredIsOpen); store.set("search.sections.starred", this.starredIsOpen);
return Promise.resolve(section); return Promise.resolve(section);
} }
@@ -71,22 +73,22 @@ export class SearchSrv {
return Promise.resolve(); return Promise.resolve();
} }
return this.backendSrv.search({starred: true, limit: 5}).then(result => { return this.backendSrv.search({ starred: true, limit: 5 }).then(result => {
if (result.length > 0) { if (result.length > 0) {
sections['starred'] = { sections["starred"] = {
title: 'Starred Boards', title: "Starred Boards",
icon: 'fa fa-star-o', icon: "fa fa-star-o",
score: -2, score: -2,
expanded: this.starredIsOpen, expanded: this.starredIsOpen,
toggle: this.toggleStarred.bind(this), toggle: this.toggleStarred.bind(this),
items: result.map(this.transformToViewModel), items: result.map(this.transformToViewModel)
}; };
} }
}); });
} }
private transformToViewModel(hit) { private transformToViewModel(hit) {
hit.url = 'dashboard/db/' + hit.slug; hit.url = "dashboard/db/" + hit.slug;
return hit; return hit;
} }
@@ -94,8 +96,10 @@ export class SearchSrv {
let sections: any = {}; let sections: any = {};
let promises = []; let promises = [];
let query = _.clone(options); let query = _.clone(options);
let hasFilters = options.query || let hasFilters =
(options.tag && options.tag.length > 0) || options.starred || options.query ||
(options.tag && options.tag.length > 0) ||
options.starred ||
(options.folderIds && options.folderIds.length > 0); (options.folderIds && options.folderIds.length > 0);
if (!options.skipRecent && !hasFilters) { if (!options.skipRecent && !hasFilters) {
@@ -111,12 +115,14 @@ export class SearchSrv {
query.folderIds = [0]; query.folderIds = [0];
} }
promises.push(this.backendSrv.search(query).then(results => { promises.push(
return this.handleSearchResult(sections, results); this.backendSrv.search(query).then(results => {
})); return this.handleSearchResult(sections, results);
})
);
return this.$q.all(promises).then(() => { return this.$q.all(promises).then(() => {
return _.sortBy(_.values(sections), 'score'); return _.sortBy(_.values(sections), "score");
}); });
} }
@@ -127,7 +133,7 @@ export class SearchSrv {
// create folder index // create folder index
for (let hit of results) { for (let hit of results) {
if (hit.type === 'dash-folder') { if (hit.type === "dash-folder") {
sections[hit.id] = { sections[hit.id] = {
id: hit.id, id: hit.id,
title: hit.title, title: hit.title,
@@ -136,14 +142,14 @@ export class SearchSrv {
toggle: this.toggleFolder.bind(this), toggle: this.toggleFolder.bind(this),
url: `dashboards/folder/${hit.id}/${hit.slug}`, url: `dashboards/folder/${hit.id}/${hit.slug}`,
slug: hit.slug, slug: hit.slug,
icon: 'fa fa-folder', icon: "fa fa-folder",
score: _.keys(sections).length, score: _.keys(sections).length
}; };
} }
} }
for (let hit of results) { for (let hit of results) {
if (hit.type === 'dash-folder') { if (hit.type === "dash-folder") {
continue; continue;
} }
@@ -156,18 +162,18 @@ export class SearchSrv {
url: `dashboards/folder/${hit.folderId}/${hit.folderSlug}`, url: `dashboards/folder/${hit.folderId}/${hit.folderSlug}`,
slug: hit.slug, slug: hit.slug,
items: [], items: [],
icon: 'fa fa-folder-open', icon: "fa fa-folder-open",
toggle: this.toggleFolder.bind(this), toggle: this.toggleFolder.bind(this),
score: _.keys(sections).length, score: _.keys(sections).length
}; };
} else { } else {
section = { section = {
id: 0, id: 0,
title: 'Root', title: "Root",
items: [], items: [],
icon: 'fa fa-folder-open', icon: "fa fa-folder-open",
toggle: this.toggleFolder.bind(this), toggle: this.toggleFolder.bind(this),
score: _.keys(sections).length, score: _.keys(sections).length
}; };
} }
// add section // add section
@@ -181,14 +187,14 @@ export class SearchSrv {
private toggleFolder(section) { private toggleFolder(section) {
section.expanded = !section.expanded; section.expanded = !section.expanded;
section.icon = section.expanded ? 'fa fa-folder-open' : 'fa fa-folder'; section.icon = section.expanded ? "fa fa-folder-open" : "fa fa-folder";
if (section.items.length) { if (section.items.length) {
return Promise.resolve(section); return Promise.resolve(section);
} }
let query = { let query = {
folderIds: [section.id], folderIds: [section.id]
}; };
return this.backendSrv.search(query).then(results => { return this.backendSrv.search(query).then(results => {
@@ -198,8 +204,8 @@ export class SearchSrv {
} }
getDashboardTags() { getDashboardTags() {
return this.backendSrv.get('/api/dashboards/tags'); return this.backendSrv.get("/api/dashboards/tags");
} }
} }
coreModule.service('searchSrv', SearchSrv); coreModule.service("searchSrv", SearchSrv);

View File

@@ -1,5 +1,5 @@
import _ from 'lodash'; import _ from "lodash";
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
// This service really just tracks a list of $timeout promises to give us a // This service really just tracks a list of $timeout promises to give us a
// method for cancelling them all when we need to // method for cancelling them all when we need to
@@ -7,8 +7,7 @@ export class Timer {
timers = []; timers = [];
/** @ngInject */ /** @ngInject */
constructor(private $timeout) { constructor(private $timeout) {}
}
register(promise) { register(promise) {
this.timers.push(promise); this.timers.push(promise);
@@ -28,4 +27,4 @@ export class Timer {
} }
} }
coreModule.service('timer', Timer); coreModule.service("timer", Timer);

View File

@@ -1,18 +1,17 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
import appEvents from 'app/core/app_events'; import appEvents from "app/core/app_events";
export class UtilSrv { export class UtilSrv {
modalScope: any; modalScope: any;
/** @ngInject */ /** @ngInject */
constructor(private $rootScope, private $modal) { constructor(private $rootScope, private $modal) {}
}
init() { init() {
appEvents.on('show-modal', this.showModal.bind(this), this.$rootScope); appEvents.on("show-modal", this.showModal.bind(this), this.$rootScope);
appEvents.on('hide-modal', this.hideModal.bind(this), this.$rootScope); appEvents.on("hide-modal", this.hideModal.bind(this), this.$rootScope);
} }
hideModal() { hideModal() {
@@ -47,9 +46,9 @@ export class UtilSrv {
}); });
Promise.resolve(modal).then(function(modalEl) { Promise.resolve(modal).then(function(modalEl) {
modalEl.modal('show'); modalEl.modal("show");
}); });
} }
} }
coreModule.service('utilSrv', UtilSrv); coreModule.service("utilSrv", UtilSrv);

View File

@@ -1,26 +1,36 @@
import {describe, beforeEach, it, expect, angularMocks} from 'test/lib/common'; import {
import 'app/core/services/backend_srv'; describe,
beforeEach,
it,
expect,
angularMocks
} from "test/lib/common";
import "app/core/services/backend_srv";
describe('backend_srv', function() { describe("backend_srv", function() {
var _backendSrv; var _backendSrv;
var _httpBackend; var _httpBackend;
beforeEach(angularMocks.module('grafana.core')); beforeEach(angularMocks.module("grafana.core"));
beforeEach(angularMocks.module('grafana.services')); beforeEach(angularMocks.module("grafana.services"));
beforeEach(angularMocks.inject(function ($httpBackend, $http, backendSrv) { beforeEach(
_httpBackend = $httpBackend; angularMocks.inject(function($httpBackend, $http, backendSrv) {
_backendSrv = backendSrv; _httpBackend = $httpBackend;
})); _backendSrv = backendSrv;
})
);
describe('when handling errors', function() { describe("when handling errors", function() {
it('should return the http status code', function(done) { it("should return the http status code", function(done) {
_httpBackend.whenGET('gateway-error').respond(502); _httpBackend.whenGET("gateway-error").respond(502);
_backendSrv.datasourceRequest({ _backendSrv
url: 'gateway-error' .datasourceRequest({
}).catch(function(err) { url: "gateway-error"
expect(err.status).to.be(502); })
done(); .catch(function(err) {
}); expect(err.status).to.be(502);
done();
});
_httpBackend.flush(); _httpBackend.flush();
}); });
}); });

View File

@@ -1,37 +1,40 @@
import sinon from 'sinon'; import sinon from "sinon";
import * as dateMath from 'app/core/utils/datemath'; import * as dateMath from "app/core/utils/datemath";
import moment from 'moment'; import moment from "moment";
import _ from 'lodash'; import _ from "lodash";
describe("DateMath", () => { describe("DateMath", () => {
var spans = ['s', 'm', 'h', 'd', 'w', 'M', 'y']; var spans = ["s", "m", "h", "d", "w", "M", "y"];
var anchor = '2014-01-01T06:06:06.666Z'; var anchor = "2014-01-01T06:06:06.666Z";
var unix = moment(anchor).valueOf(); var unix = moment(anchor).valueOf();
var format = 'YYYY-MM-DDTHH:mm:ss.SSSZ'; var format = "YYYY-MM-DDTHH:mm:ss.SSSZ";
var clock; var clock;
describe('errors', () => { describe("errors", () => {
it('should return undefined if passed something falsy', () => { it("should return undefined if passed something falsy", () => {
expect(dateMath.parse(false)).toBe(undefined); expect(dateMath.parse(false)).toBe(undefined);
}); });
it('should return undefined if I pass an operator besides [+-/]', () => { it("should return undefined if I pass an operator besides [+-/]", () => {
expect(dateMath.parse('now&1d')).toBe(undefined); expect(dateMath.parse("now&1d")).toBe(undefined);
}); });
it('should return undefined if I pass a unit besides' + spans.toString(), () => { it(
expect(dateMath.parse('now+5f')).toBe(undefined); "should return undefined if I pass a unit besides" + spans.toString(),
() => {
expect(dateMath.parse("now+5f")).toBe(undefined);
}
);
it("should return undefined if rounding unit is not 1", () => {
expect(dateMath.parse("now/2y")).toBe(undefined);
expect(dateMath.parse("now/0.5y")).toBe(undefined);
}); });
it('should return undefined if rounding unit is not 1', () => { it("should not go into an infinite loop when missing a unit", () => {
expect(dateMath.parse('now/2y')).toBe(undefined); expect(dateMath.parse("now-0")).toBe(undefined);
expect(dateMath.parse('now/0.5y')).toBe(undefined); expect(dateMath.parse("now-00")).toBe(undefined);
});
it('should not go into an infinite loop when missing a unit', () => {
expect(dateMath.parse('now-0')).toBe(undefined);
expect(dateMath.parse('now-00')).toBe(undefined);
}); });
}); });
@@ -42,19 +45,29 @@ describe("DateMath", () => {
expected.setSeconds(0); expected.setSeconds(0);
expected.setMilliseconds(0); expected.setMilliseconds(0);
var startOfDay = dateMath.parse('now/d', false).valueOf(); var startOfDay = dateMath.parse("now/d", false).valueOf();
expect(startOfDay).toBe(expected.getTime()); expect(startOfDay).toBe(expected.getTime());
}); });
it("now/d on a utc dashboard should be start of the current day in UTC time", () => { it("now/d on a utc dashboard should be start of the current day in UTC time", () => {
var today = new Date(); var today = new Date();
var expected = new Date(Date.UTC(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate(), 0, 0, 0, 0)); var expected = new Date(
Date.UTC(
today.getUTCFullYear(),
today.getUTCMonth(),
today.getUTCDate(),
0,
0,
0,
0
)
);
var startOfDay = dateMath.parse('now/d', false, 'utc').valueOf(); var startOfDay = dateMath.parse("now/d", false, "utc").valueOf();
expect(startOfDay).toBe(expected.getTime()); expect(startOfDay).toBe(expected.getTime());
}); });
describe('subtraction', () => { describe("subtraction", () => {
var now; var now;
var anchored; var anchored;
@@ -64,16 +77,20 @@ describe("DateMath", () => {
anchored = moment(anchor); anchored = moment(anchor);
}); });
_.each(spans, (span) => { _.each(spans, span => {
var nowEx = 'now-5' + span; var nowEx = "now-5" + span;
var thenEx = anchor + '||-5' + span; var thenEx = anchor + "||-5" + span;
it('should return 5' + span + ' ago', () => { it("should return 5" + span + " ago", () => {
expect(dateMath.parse(nowEx).format(format)).toEqual(now.subtract(5, span).format(format)); expect(dateMath.parse(nowEx).format(format)).toEqual(
now.subtract(5, span).format(format)
);
}); });
it('should return 5' + span + ' before ' + anchor, () => { it("should return 5" + span + " before " + anchor, () => {
expect(dateMath.parse(thenEx).format(format)).toEqual(anchored.subtract(5, span).format(format)); expect(dateMath.parse(thenEx).format(format)).toEqual(
anchored.subtract(5, span).format(format)
);
}); });
}); });
@@ -82,7 +99,7 @@ describe("DateMath", () => {
}); });
}); });
describe('rounding', () => { describe("rounding", () => {
var now; var now;
beforeEach(() => { beforeEach(() => {
@@ -90,13 +107,17 @@ describe("DateMath", () => {
now = moment(); now = moment();
}); });
_.each(spans, (span) => { _.each(spans, span => {
it('should round now to the beginning of the ' + span, function () { it("should round now to the beginning of the " + span, function() {
expect(dateMath.parse('now/' + span).format(format)).toEqual(now.startOf(span).format(format)); expect(dateMath.parse("now/" + span).format(format)).toEqual(
now.startOf(span).format(format)
);
}); });
it('should round now to the end of the ' + span, function () { it("should round now to the end of the " + span, function() {
expect(dateMath.parse('now/' + span, true).format(format)).toEqual(now.endOf(span).format(format)); expect(dateMath.parse("now/" + span, true).format(format)).toEqual(
now.endOf(span).format(format)
);
}); });
}); });
@@ -105,32 +126,29 @@ describe("DateMath", () => {
}); });
}); });
describe('isValid', () => { describe("isValid", () => {
it('should return false when invalid date text', () => { it("should return false when invalid date text", () => {
expect(dateMath.isValid('asd')).toBe(false); expect(dateMath.isValid("asd")).toBe(false);
}); });
it('should return true when valid date text', () => { it("should return true when valid date text", () => {
expect(dateMath.isValid('now-1h')).toBe(true); expect(dateMath.isValid("now-1h")).toBe(true);
}); });
}); });
describe('relative time to date parsing', function() { describe("relative time to date parsing", function() {
it('should handle negative time', function() { it("should handle negative time", function() {
var date = dateMath.parseDateMath('-2d', moment([2014, 1, 5])); var date = dateMath.parseDateMath("-2d", moment([2014, 1, 5]));
expect(date.valueOf()).toEqual(moment([2014, 1, 3]).valueOf()); expect(date.valueOf()).toEqual(moment([2014, 1, 3]).valueOf());
}); });
it('should handle multiple math expressions', function() { it("should handle multiple math expressions", function() {
var date = dateMath.parseDateMath('-2d-6h', moment([2014, 1, 5])); var date = dateMath.parseDateMath("-2d-6h", moment([2014, 1, 5]));
expect(date.valueOf()).toEqual(moment([2014, 1, 2, 18]).valueOf()); expect(date.valueOf()).toEqual(moment([2014, 1, 2, 18]).valueOf());
}); });
it('should return false when invalid expression', function() { it("should return false when invalid expression", function() {
var date = dateMath.parseDateMath('2', moment([2014, 1, 5])); var date = dateMath.parseDateMath("2", moment([2014, 1, 5]));
expect(date).toEqual(undefined); expect(date).toEqual(undefined);
}); });
}); });
}); });

View File

@@ -1,28 +1,26 @@
import {Emitter} from '../utils/emitter'; import { Emitter } from "../utils/emitter";
describe("Emitter", () => { describe("Emitter", () => {
describe("given 2 subscribers", () => {
describe('given 2 subscribers', () => { it("should notfiy subscribers", () => {
it('should notfiy subscribers', () => {
var events = new Emitter(); var events = new Emitter();
var sub1Called = false; var sub1Called = false;
var sub2Called = false; var sub2Called = false;
events.on('test', () => { events.on("test", () => {
sub1Called = true; sub1Called = true;
}); });
events.on('test', () => { events.on("test", () => {
sub2Called = true; sub2Called = true;
}); });
events.emit('test', null); events.emit("test", null);
expect(sub1Called).toBe(true); expect(sub1Called).toBe(true);
expect(sub2Called).toBe(true); expect(sub2Called).toBe(true);
}); });
it('when subscribing twice', () => { it("when subscribing twice", () => {
var events = new Emitter(); var events = new Emitter();
var sub1Called = 0; var sub1Called = 0;
@@ -30,35 +28,37 @@ describe("Emitter", () => {
sub1Called += 1; sub1Called += 1;
} }
events.on('test', handler); events.on("test", handler);
events.on('test', handler); events.on("test", handler);
events.emit('test', null); events.emit("test", null);
expect(sub1Called).toBe(2); expect(sub1Called).toBe(2);
}); });
it('should handle errors', () => { it("should handle errors", () => {
var events = new Emitter(); var events = new Emitter();
var sub1Called = 0; var sub1Called = 0;
var sub2Called = 0; var sub2Called = 0;
events.on('test', () => { events.on("test", () => {
sub1Called++; sub1Called++;
throw {message: "hello"}; throw { message: "hello" };
}); });
events.on('test', () => { events.on("test", () => {
sub2Called++; sub2Called++;
}); });
try { events.emit('test', null); } catch (_) { } try {
try { events.emit('test', null); } catch (_) {} events.emit("test", null);
} catch (_) {}
try {
events.emit("test", null);
} catch (_) {}
expect(sub1Called).toBe(2); expect(sub1Called).toBe(2);
expect(sub2Called).toBe(0); expect(sub2Called).toBe(0);
}); });
}); });
}); });

View File

@@ -1,22 +1,22 @@
import flatten from 'app/core/utils/flatten'; import flatten from "app/core/utils/flatten";
describe("flatten", () => { describe("flatten", () => {
it("should return flatten object", () => {
it('should return flatten object', () => { var flattened = flatten(
var flattened = flatten({ {
level1: 'level1-value', level1: "level1-value",
deeper: {
level2: 'level2-value',
deeper: { deeper: {
level3: 'level3-value' level2: "level2-value",
deeper: {
level3: "level3-value"
}
} }
} },
}, null); null
);
expect(flattened['level1']).toBe('level1-value'); expect(flattened["level1"]).toBe("level1-value");
expect(flattened['deeper.level2']).toBe('level2-value'); expect(flattened["deeper.level2"]).toBe("level2-value");
expect(flattened['deeper.deeper.level3']).toBe('level3-value'); expect(flattened["deeper.deeper.level3"]).toBe("level3-value");
}); });
}); });

View File

@@ -1,23 +1,23 @@
import { GlobalEventSrv } from 'app/core/services/global_event_srv'; import { GlobalEventSrv } from "app/core/services/global_event_srv";
import { beforeEach } from 'test/lib/common'; import { beforeEach } from "test/lib/common";
jest.mock('app/core/config', () => { jest.mock("app/core/config", () => {
return { return {
appSubUrl: '/subUrl' appSubUrl: "/subUrl"
}; };
}); });
describe('GlobalEventSrv', () => { describe("GlobalEventSrv", () => {
let searchSrv; let searchSrv;
beforeEach(() => { beforeEach(() => {
searchSrv = new GlobalEventSrv(null, null); searchSrv = new GlobalEventSrv(null, null);
}); });
describe('With /subUrl as appSubUrl', () => { describe("With /subUrl as appSubUrl", () => {
it('/subUrl should be stripped', () => { it("/subUrl should be stripped", () => {
const urlWithoutMaster = searchSrv.stripBaseFromUrl('/subUrl/grafana/'); const urlWithoutMaster = searchSrv.stripBaseFromUrl("/subUrl/grafana/");
expect(urlWithoutMaster).toBe('/grafana/'); expect(urlWithoutMaster).toBe("/grafana/");
}); });
}); });
}); });

View File

@@ -1,27 +1,29 @@
import kbn from '../utils/kbn'; import kbn from "../utils/kbn";
import * as dateMath from '../utils/datemath'; import * as dateMath from "../utils/datemath";
import moment from 'moment'; import moment from "moment";
describe('unit format menu', function() { describe("unit format menu", function() {
var menu = kbn.getUnitFormats(); var menu = kbn.getUnitFormats();
menu.map(function(submenu) { menu.map(function(submenu) {
describe("submenu " + submenu.text, function() {
describe('submenu ' + submenu.text, function() { it("should have a title", function() {
expect(typeof submenu.text).toBe("string");
it('should have a title', function() {
expect(typeof submenu.text).toBe('string');
}); });
it('should have a submenu', function() { it("should have a submenu", function() {
expect(Array.isArray(submenu.submenu)).toBe(true); expect(Array.isArray(submenu.submenu)).toBe(true);
}); });
submenu.submenu.map(function(entry) { submenu.submenu.map(function(entry) {
describe('entry ' + entry.text, function() { describe("entry " + entry.text, function() {
it('should have a title', function() { expect(typeof entry.text).toBe('string'); }); it("should have a title", function() {
it('should have a format', function() { expect(typeof entry.value).toBe('string'); }); expect(typeof entry.text).toBe("string");
it('should have a valid format', function() { });
expect(typeof kbn.valueFormats[entry.value]).toBe('function'); it("should have a format", function() {
expect(typeof entry.value).toBe("string");
});
it("should have a valid format", function() {
expect(typeof kbn.valueFormats[entry.value]).toBe("function");
}); });
}); });
}); });
@@ -30,318 +32,324 @@ describe('unit format menu', function() {
}); });
function describeValueFormat(desc, value, tickSize, tickDecimals, result) { function describeValueFormat(desc, value, tickSize, tickDecimals, result) {
describe("value format: " + desc, function() {
describe('value format: ' + desc, function() { it("should translate " + value + " as " + result, function() {
it('should translate ' + value + ' as ' + result, function() { var scaledDecimals =
var scaledDecimals = tickDecimals - Math.floor(Math.log(tickSize) / Math.LN10); tickDecimals - Math.floor(Math.log(tickSize) / Math.LN10);
var str = kbn.valueFormats[desc](value, tickDecimals, scaledDecimals); var str = kbn.valueFormats[desc](value, tickDecimals, scaledDecimals);
expect(str).toBe(result); expect(str).toBe(result);
}); });
}); });
} }
describeValueFormat('ms', 0.0024, 0.0005, 4, '0.0024 ms'); describeValueFormat("ms", 0.0024, 0.0005, 4, "0.0024 ms");
describeValueFormat('ms', 100, 1, 0, '100 ms'); describeValueFormat("ms", 100, 1, 0, "100 ms");
describeValueFormat('ms', 1250, 10, 0, '1.25 s'); describeValueFormat("ms", 1250, 10, 0, "1.25 s");
describeValueFormat('ms', 1250, 300, 0, '1.3 s'); describeValueFormat("ms", 1250, 300, 0, "1.3 s");
describeValueFormat('ms', 65150, 10000, 0, '1.1 min'); describeValueFormat("ms", 65150, 10000, 0, "1.1 min");
describeValueFormat('ms', 6515000, 1500000, 0, '1.8 hour'); describeValueFormat("ms", 6515000, 1500000, 0, "1.8 hour");
describeValueFormat('ms', 651500000, 150000000, 0, '8 day'); describeValueFormat("ms", 651500000, 150000000, 0, "8 day");
describeValueFormat('none', 2.75e-10, 0, 10, '3e-10'); describeValueFormat("none", 2.75e-10, 0, 10, "3e-10");
describeValueFormat('none', 0, 0, 2, '0'); describeValueFormat("none", 0, 0, 2, "0");
describeValueFormat('dB', 10, 1000, 2, '10.00 dB'); describeValueFormat("dB", 10, 1000, 2, "10.00 dB");
describeValueFormat('percent', 0, 0, 0, '0%'); describeValueFormat("percent", 0, 0, 0, "0%");
describeValueFormat('percent', 53, 0, 1, '53.0%'); describeValueFormat("percent", 53, 0, 1, "53.0%");
describeValueFormat('percentunit', 0.0, 0, 0, '0%'); describeValueFormat("percentunit", 0.0, 0, 0, "0%");
describeValueFormat('percentunit', 0.278, 0, 1, '27.8%'); describeValueFormat("percentunit", 0.278, 0, 1, "27.8%");
describeValueFormat('percentunit', 1.0, 0, 0, '100%'); describeValueFormat("percentunit", 1.0, 0, 0, "100%");
describeValueFormat('currencyUSD', 7.42, 10000, 2, '$7.42'); describeValueFormat("currencyUSD", 7.42, 10000, 2, "$7.42");
describeValueFormat('currencyUSD', 1532.82, 1000, 1, '$1.53K'); describeValueFormat("currencyUSD", 1532.82, 1000, 1, "$1.53K");
describeValueFormat('currencyUSD', 18520408.7, 10000000, 0, '$19M'); describeValueFormat("currencyUSD", 18520408.7, 10000000, 0, "$19M");
describeValueFormat('bytes', -1.57e+308, -1.57e+308, 2, 'NA'); describeValueFormat("bytes", -1.57e308, -1.57e308, 2, "NA");
describeValueFormat('ns', 25, 1, 0, '25 ns'); describeValueFormat("ns", 25, 1, 0, "25 ns");
describeValueFormat('ns', 2558, 50, 0, '2.56 µs'); describeValueFormat("ns", 2558, 50, 0, "2.56 µs");
describeValueFormat('ops', 123, 1, 0, '123 ops'); describeValueFormat("ops", 123, 1, 0, "123 ops");
describeValueFormat('rps', 456000, 1000, -1, '456K rps'); describeValueFormat("rps", 456000, 1000, -1, "456K rps");
describeValueFormat('rps', 123456789, 1000000, 2, '123.457M rps'); describeValueFormat("rps", 123456789, 1000000, 2, "123.457M rps");
describeValueFormat('wps', 789000000, 1000000, -1, '789M wps'); describeValueFormat("wps", 789000000, 1000000, -1, "789M wps");
describeValueFormat('iops', 11000000000, 1000000000, -1, '11B iops'); describeValueFormat("iops", 11000000000, 1000000000, -1, "11B iops");
describeValueFormat('s', 1.23456789e-7, 1e-10, 8, '123.5 ns'); describeValueFormat("s", 1.23456789e-7, 1e-10, 8, "123.5 ns");
describeValueFormat('s', 1.23456789e-4, 1e-7, 5, '123.5 µs'); describeValueFormat("s", 1.23456789e-4, 1e-7, 5, "123.5 µs");
describeValueFormat('s', 1.23456789e-3, 1e-6, 4, '1.235 ms'); describeValueFormat("s", 1.23456789e-3, 1e-6, 4, "1.235 ms");
describeValueFormat('s', 1.23456789e-2, 1e-5, 3, '12.35 ms'); describeValueFormat("s", 1.23456789e-2, 1e-5, 3, "12.35 ms");
describeValueFormat('s', 1.23456789e-1, 1e-4, 2, '123.5 ms'); describeValueFormat("s", 1.23456789e-1, 1e-4, 2, "123.5 ms");
describeValueFormat('s', 24, 1, 0, '24 s'); describeValueFormat("s", 24, 1, 0, "24 s");
describeValueFormat('s', 246, 1, 0, '4.1 min'); describeValueFormat("s", 246, 1, 0, "4.1 min");
describeValueFormat('s', 24567, 100, 0, '6.82 hour'); describeValueFormat("s", 24567, 100, 0, "6.82 hour");
describeValueFormat('s', 24567890, 10000, 0, '40.62 week'); describeValueFormat("s", 24567890, 10000, 0, "40.62 week");
describeValueFormat('s', 24567890000, 1000000, 0, '778.53 year'); describeValueFormat("s", 24567890000, 1000000, 0, "778.53 year");
describeValueFormat('m', 24, 1, 0, '24 min'); describeValueFormat("m", 24, 1, 0, "24 min");
describeValueFormat('m', 246, 10, 0, '4.1 hour'); describeValueFormat("m", 246, 10, 0, "4.1 hour");
describeValueFormat('m', 6545, 10, 0, '4.55 day'); describeValueFormat("m", 6545, 10, 0, "4.55 day");
describeValueFormat('m', 24567, 100, 0, '2.44 week'); describeValueFormat("m", 24567, 100, 0, "2.44 week");
describeValueFormat('m', 24567892, 10000, 0, '46.7 year'); describeValueFormat("m", 24567892, 10000, 0, "46.7 year");
describeValueFormat('h', 21, 1, 0, '21 hour'); describeValueFormat("h", 21, 1, 0, "21 hour");
describeValueFormat('h', 145, 1, 0, '6.04 day'); describeValueFormat("h", 145, 1, 0, "6.04 day");
describeValueFormat('h', 1234, 100, 0, '7.3 week'); describeValueFormat("h", 1234, 100, 0, "7.3 week");
describeValueFormat('h', 9458, 1000, 0, '1.08 year'); describeValueFormat("h", 9458, 1000, 0, "1.08 year");
describeValueFormat('d', 3, 1, 0, '3 day'); describeValueFormat("d", 3, 1, 0, "3 day");
describeValueFormat('d', 245, 100, 0, '35 week'); describeValueFormat("d", 245, 100, 0, "35 week");
describeValueFormat('d', 2456, 10, 0, '6.73 year'); describeValueFormat("d", 2456, 10, 0, "6.73 year");
describe('date time formats', function() { describe("date time formats", function() {
it('should format as iso date', function() { it("should format as iso date", function() {
var str = kbn.valueFormats.dateTimeAsIso(1505634997920, 1); var str = kbn.valueFormats.dateTimeAsIso(1505634997920, 1);
expect(str).toBe(moment(1505634997920).format('YYYY-MM-DD HH:mm:ss')); expect(str).toBe(moment(1505634997920).format("YYYY-MM-DD HH:mm:ss"));
}); });
it('should format as iso date and skip date when today', function() { it("should format as iso date and skip date when today", function() {
var now = moment(); var now = moment();
var str = kbn.valueFormats.dateTimeAsIso(now.valueOf(), 1); var str = kbn.valueFormats.dateTimeAsIso(now.valueOf(), 1);
expect(str).toBe(now.format("HH:mm:ss")); expect(str).toBe(now.format("HH:mm:ss"));
}); });
it('should format as US date', function() { it("should format as US date", function() {
var str = kbn.valueFormats.dateTimeAsUS(1505634997920, 1); var str = kbn.valueFormats.dateTimeAsUS(1505634997920, 1);
expect(str).toBe(moment(1505634997920).format('MM/DD/YYYY h:mm:ss a')); expect(str).toBe(moment(1505634997920).format("MM/DD/YYYY h:mm:ss a"));
}); });
it('should format as US date and skip date when today', function() { it("should format as US date and skip date when today", function() {
var now = moment(); var now = moment();
var str = kbn.valueFormats.dateTimeAsUS(now.valueOf(), 1); var str = kbn.valueFormats.dateTimeAsUS(now.valueOf(), 1);
expect(str).toBe(now.format("h:mm:ss a")); expect(str).toBe(now.format("h:mm:ss a"));
}); });
it('should format as from now with days', function() { it("should format as from now with days", function() {
var daysAgo = moment().add(-7, 'd'); var daysAgo = moment().add(-7, "d");
var str = kbn.valueFormats.dateTimeFromNow(daysAgo.valueOf(), 1); var str = kbn.valueFormats.dateTimeFromNow(daysAgo.valueOf(), 1);
expect(str).toBe('7 days ago'); expect(str).toBe("7 days ago");
}); });
it('should format as from now with minutes', function() { it("should format as from now with minutes", function() {
var daysAgo = moment().add(-2, 'm'); var daysAgo = moment().add(-2, "m");
var str = kbn.valueFormats.dateTimeFromNow(daysAgo.valueOf(), 1); var str = kbn.valueFormats.dateTimeFromNow(daysAgo.valueOf(), 1);
expect(str).toBe('2 minutes ago'); expect(str).toBe("2 minutes ago");
}); });
}); });
describe('kbn.toFixed and negative decimals', function() { describe("kbn.toFixed and negative decimals", function() {
it('should treat as zero decimals', function() { it("should treat as zero decimals", function() {
var str = kbn.toFixed(186.123, -2); var str = kbn.toFixed(186.123, -2);
expect(str).toBe('186'); expect(str).toBe("186");
}); });
}); });
describe('kbn ms format when scaled decimals is null do not use it', function() { describe("kbn ms format when scaled decimals is null do not use it", function() {
it('should use specified decimals', function() { it("should use specified decimals", function() {
var str = kbn.valueFormats['ms'](10000086.123, 1, null); var str = kbn.valueFormats["ms"](10000086.123, 1, null);
expect(str).toBe('2.8 hour'); expect(str).toBe("2.8 hour");
}); });
}); });
describe('kbn kbytes format when scaled decimals is null do not use it', function() { describe("kbn kbytes format when scaled decimals is null do not use it", function() {
it('should use specified decimals', function() { it("should use specified decimals", function() {
var str = kbn.valueFormats['kbytes'](10000000, 3, null); var str = kbn.valueFormats["kbytes"](10000000, 3, null);
expect(str).toBe('9.537 GiB'); expect(str).toBe("9.537 GiB");
}); });
}); });
describe('kbn deckbytes format when scaled decimals is null do not use it', function() { describe("kbn deckbytes format when scaled decimals is null do not use it", function() {
it('should use specified decimals', function() { it("should use specified decimals", function() {
var str = kbn.valueFormats['deckbytes'](10000000, 3, null); var str = kbn.valueFormats["deckbytes"](10000000, 3, null);
expect(str).toBe('10.000 GB'); expect(str).toBe("10.000 GB");
}); });
}); });
describe('kbn roundValue', function() { describe("kbn roundValue", function() {
it('should should handle null value', function() { it("should should handle null value", function() {
var str = kbn.roundValue(null, 2); var str = kbn.roundValue(null, 2);
expect(str).toBe(null); expect(str).toBe(null);
}); });
it('should round value', function() { it("should round value", function() {
var str = kbn.roundValue(200.877, 2); var str = kbn.roundValue(200.877, 2);
expect(str).toBe(200.88); expect(str).toBe(200.88);
}); });
}); });
describe('calculateInterval', function() { describe("calculateInterval", function() {
it('1h 100 resultion', function() { it("1h 100 resultion", function() {
var range = { from: dateMath.parse('now-1h'), to: dateMath.parse('now') }; var range = { from: dateMath.parse("now-1h"), to: dateMath.parse("now") };
var res = kbn.calculateInterval(range, 100, null); var res = kbn.calculateInterval(range, 100, null);
expect(res.interval).toBe('30s'); expect(res.interval).toBe("30s");
}); });
it('10m 1600 resolution', function() { it("10m 1600 resolution", function() {
var range = { from: dateMath.parse('now-10m'), to: dateMath.parse('now') }; var range = { from: dateMath.parse("now-10m"), to: dateMath.parse("now") };
var res = kbn.calculateInterval(range, 1600, null); var res = kbn.calculateInterval(range, 1600, null);
expect(res.interval).toBe('500ms'); expect(res.interval).toBe("500ms");
expect(res.intervalMs).toBe(500); expect(res.intervalMs).toBe(500);
}); });
it('fixed user min interval', function() { it("fixed user min interval", function() {
var range = {from: dateMath.parse('now-10m'), to: dateMath.parse('now')}; var range = { from: dateMath.parse("now-10m"), to: dateMath.parse("now") };
var res = kbn.calculateInterval(range, 1600, '10s'); var res = kbn.calculateInterval(range, 1600, "10s");
expect(res.interval).toBe('10s'); expect(res.interval).toBe("10s");
expect(res.intervalMs).toBe(10000); expect(res.intervalMs).toBe(10000);
}); });
it('short time range and user low limit', function() { it("short time range and user low limit", function() {
var range = { from: dateMath.parse('now-10m'), to: dateMath.parse('now') }; var range = { from: dateMath.parse("now-10m"), to: dateMath.parse("now") };
var res = kbn.calculateInterval(range, 1600, '>10s'); var res = kbn.calculateInterval(range, 1600, ">10s");
expect(res.interval).toBe('10s'); expect(res.interval).toBe("10s");
}); });
it('large time range and user low limit', function() { it("large time range and user low limit", function() {
var range = {from: dateMath.parse('now-14d'), to: dateMath.parse('now')}; var range = { from: dateMath.parse("now-14d"), to: dateMath.parse("now") };
var res = kbn.calculateInterval(range, 1000, '>10s'); var res = kbn.calculateInterval(range, 1000, ">10s");
expect(res.interval).toBe('20m'); expect(res.interval).toBe("20m");
}); });
it('10s 900 resolution and user low limit in ms', function() { it("10s 900 resolution and user low limit in ms", function() {
var range = { from: dateMath.parse('now-10s'), to: dateMath.parse('now') }; var range = { from: dateMath.parse("now-10s"), to: dateMath.parse("now") };
var res = kbn.calculateInterval(range, 900, '>15ms'); var res = kbn.calculateInterval(range, 900, ">15ms");
expect(res.interval).toBe('15ms'); expect(res.interval).toBe("15ms");
}); });
it('1d 1 resolution', function() { it("1d 1 resolution", function() {
var range = { from: dateMath.parse('now-1d'), to: dateMath.parse('now') }; var range = { from: dateMath.parse("now-1d"), to: dateMath.parse("now") };
var res = kbn.calculateInterval(range, 1, null); var res = kbn.calculateInterval(range, 1, null);
expect(res.interval).toBe('1d'); expect(res.interval).toBe("1d");
expect(res.intervalMs).toBe(86400000); expect(res.intervalMs).toBe(86400000);
}); });
it('86399s 1 resolution', function() { it("86399s 1 resolution", function() {
var range = { from: dateMath.parse('now-86390s'), to: dateMath.parse('now') }; var range = {
from: dateMath.parse("now-86390s"),
to: dateMath.parse("now")
};
var res = kbn.calculateInterval(range, 1, null); var res = kbn.calculateInterval(range, 1, null);
expect(res.interval).toBe('12h'); expect(res.interval).toBe("12h");
expect(res.intervalMs).toBe(43200000); expect(res.intervalMs).toBe(43200000);
}); });
}); });
describe('hex', function() { describe("hex", function() {
it('positive integer', function() { it("positive integer", function() {
var str = kbn.valueFormats.hex(100, 0); var str = kbn.valueFormats.hex(100, 0);
expect(str).toBe('64'); expect(str).toBe("64");
}); });
it('negative integer', function() { it("negative integer", function() {
var str = kbn.valueFormats.hex(-100, 0); var str = kbn.valueFormats.hex(-100, 0);
expect(str).toBe('-64'); expect(str).toBe("-64");
}); });
it('null', function() { it("null", function() {
var str = kbn.valueFormats.hex(null, 0); var str = kbn.valueFormats.hex(null, 0);
expect(str).toBe(''); expect(str).toBe("");
}); });
it('positive float', function() { it("positive float", function() {
var str = kbn.valueFormats.hex(50.52, 1); var str = kbn.valueFormats.hex(50.52, 1);
expect(str).toBe('32.8'); expect(str).toBe("32.8");
}); });
it('negative float', function() { it("negative float", function() {
var str = kbn.valueFormats.hex(-50.333, 2); var str = kbn.valueFormats.hex(-50.333, 2);
expect(str).toBe('-32.547AE147AE14'); expect(str).toBe("-32.547AE147AE14");
}); });
}); });
describe('hex 0x', function() { describe("hex 0x", function() {
it('positive integeter', function() { it("positive integeter", function() {
var str = kbn.valueFormats.hex0x(7999,0); var str = kbn.valueFormats.hex0x(7999, 0);
expect(str).toBe('0x1F3F'); expect(str).toBe("0x1F3F");
}); });
it('negative integer', function() { it("negative integer", function() {
var str = kbn.valueFormats.hex0x(-584,0); var str = kbn.valueFormats.hex0x(-584, 0);
expect(str).toBe('-0x248'); expect(str).toBe("-0x248");
}); });
it('null', function() { it("null", function() {
var str = kbn.valueFormats.hex0x(null, 0); var str = kbn.valueFormats.hex0x(null, 0);
expect(str).toBe(''); expect(str).toBe("");
}); });
it('positive float', function() { it("positive float", function() {
var str = kbn.valueFormats.hex0x(74.443, 3); var str = kbn.valueFormats.hex0x(74.443, 3);
expect(str).toBe('0x4A.716872B020C4'); expect(str).toBe("0x4A.716872B020C4");
}); });
it('negative float', function() { it("negative float", function() {
var str = kbn.valueFormats.hex0x(-65.458, 1); var str = kbn.valueFormats.hex0x(-65.458, 1);
expect(str).toBe('-0x41.8'); expect(str).toBe("-0x41.8");
}); });
}); });
describe('duration', function() { describe("duration", function() {
it('null', function() { it("null", function() {
var str = kbn.toDuration(null, 0, "millisecond"); var str = kbn.toDuration(null, 0, "millisecond");
expect(str).toBe(''); expect(str).toBe("");
}); });
it('0 milliseconds', function() { it("0 milliseconds", function() {
var str = kbn.toDuration(0, 0, "millisecond"); var str = kbn.toDuration(0, 0, "millisecond");
expect(str).toBe('0 milliseconds'); expect(str).toBe("0 milliseconds");
}); });
it('1 millisecond', function() { it("1 millisecond", function() {
var str = kbn.toDuration(1, 0, "millisecond"); var str = kbn.toDuration(1, 0, "millisecond");
expect(str).toBe('1 millisecond'); expect(str).toBe("1 millisecond");
}); });
it('-1 millisecond', function() { it("-1 millisecond", function() {
var str = kbn.toDuration(-1, 0, "millisecond"); var str = kbn.toDuration(-1, 0, "millisecond");
expect(str).toBe('1 millisecond ago'); expect(str).toBe("1 millisecond ago");
}); });
it('seconds', function() { it("seconds", function() {
var str = kbn.toDuration(1, 0, "second"); var str = kbn.toDuration(1, 0, "second");
expect(str).toBe('1 second'); expect(str).toBe("1 second");
}); });
it('minutes', function() { it("minutes", function() {
var str = kbn.toDuration(1, 0, "minute"); var str = kbn.toDuration(1, 0, "minute");
expect(str).toBe('1 minute'); expect(str).toBe("1 minute");
}); });
it('hours', function() { it("hours", function() {
var str = kbn.toDuration(1, 0, "hour"); var str = kbn.toDuration(1, 0, "hour");
expect(str).toBe('1 hour'); expect(str).toBe("1 hour");
}); });
it('days', function() { it("days", function() {
var str = kbn.toDuration(1, 0, "day"); var str = kbn.toDuration(1, 0, "day");
expect(str).toBe('1 day'); expect(str).toBe("1 day");
}); });
it('weeks', function() { it("weeks", function() {
var str = kbn.toDuration(1, 0, "week"); var str = kbn.toDuration(1, 0, "week");
expect(str).toBe('1 week'); expect(str).toBe("1 week");
}); });
it('months', function() { it("months", function() {
var str = kbn.toDuration(1, 0, "month"); var str = kbn.toDuration(1, 0, "month");
expect(str).toBe('1 month'); expect(str).toBe("1 month");
}); });
it('years', function() { it("years", function() {
var str = kbn.toDuration(1, 0, "year"); var str = kbn.toDuration(1, 0, "year");
expect(str).toBe('1 year'); expect(str).toBe("1 year");
}); });
it('decimal days', function() { it("decimal days", function() {
var str = kbn.toDuration(1.5, 2, "day"); var str = kbn.toDuration(1.5, 2, "day");
expect(str).toBe('1 day, 12 hours, 0 minutes'); expect(str).toBe("1 day, 12 hours, 0 minutes");
}); });
it('decimal months', function() { it("decimal months", function() {
var str = kbn.toDuration(1.5, 3, "month"); var str = kbn.toDuration(1.5, 3, "month");
expect(str).toBe('1 month, 2 weeks, 1 day, 0 hours'); expect(str).toBe("1 month, 2 weeks, 1 day, 0 hours");
}); });
it('no decimals', function() { it("no decimals", function() {
var str = kbn.toDuration(38898367008, 0, "millisecond"); var str = kbn.toDuration(38898367008, 0, "millisecond");
expect(str).toBe('1 year'); expect(str).toBe("1 year");
}); });
it('1 decimal', function() { it("1 decimal", function() {
var str = kbn.toDuration(38898367008, 1, "millisecond"); var str = kbn.toDuration(38898367008, 1, "millisecond");
expect(str).toBe('1 year, 2 months'); expect(str).toBe("1 year, 2 months");
}); });
it('too many decimals', function() { it("too many decimals", function() {
var str = kbn.toDuration(38898367008, 20, "millisecond"); var str = kbn.toDuration(38898367008, 20, "millisecond");
expect(str).toBe('1 year, 2 months, 3 weeks, 4 days, 5 hours, 6 minutes, 7 seconds, 8 milliseconds'); expect(str).toBe(
"1 year, 2 months, 3 weeks, 4 days, 5 hours, 6 minutes, 7 seconds, 8 milliseconds"
);
}); });
it('floating point error', function() { it("floating point error", function() {
var str = kbn.toDuration(36993906007, 8, "millisecond"); var str = kbn.toDuration(36993906007, 8, "millisecond");
expect(str).toBe('1 year, 2 months, 0 weeks, 3 days, 4 hours, 5 minutes, 6 seconds, 7 milliseconds'); expect(str).toBe(
"1 year, 2 months, 0 weeks, 3 days, 4 hours, 5 minutes, 6 seconds, 7 milliseconds"
);
}); });
}); });

View File

@@ -1,11 +1,11 @@
import { ManageDashboardsCtrl } from 'app/core/components/manage_dashboards/manage_dashboards'; import { ManageDashboardsCtrl } from "app/core/components/manage_dashboards/manage_dashboards";
import { SearchSrv } from 'app/core/services/search_srv'; import { SearchSrv } from "app/core/services/search_srv";
import q from 'q'; import q from "q";
describe('ManageDashboards', () => { describe("ManageDashboards", () => {
let ctrl; let ctrl;
describe('when browsing dashboards', () => { describe("when browsing dashboards", () => {
beforeEach(() => { beforeEach(() => {
const response = [ const response = [
{ {
@@ -17,7 +17,7 @@ describe('ManageDashboards', () => {
id: 399, id: 399,
title: "Dashboard Test", title: "Dashboard Test",
url: "dashboard/db/dashboard-test", url: "dashboard/db/dashboard-test",
icon: 'fa fa-folder', icon: "fa fa-folder",
tags: [], tags: [],
isStarred: false, isStarred: false,
folderId: 410, folderId: 410,
@@ -31,7 +31,7 @@ describe('ManageDashboards', () => {
{ {
id: 0, id: 0,
title: "Root", title: "Root",
icon: 'fa fa-folder-open', icon: "fa fa-folder-open",
uri: "db/something-else", uri: "db/something-else",
type: "dash-db", type: "dash-db",
items: [ items: [
@@ -39,20 +39,20 @@ describe('ManageDashboards', () => {
id: 500, id: 500,
title: "Dashboard Test", title: "Dashboard Test",
url: "dashboard/db/dashboard-test", url: "dashboard/db/dashboard-test",
icon: 'fa fa-folder', icon: "fa fa-folder",
tags: [], tags: [],
isStarred: false isStarred: false
} }
], ],
tags: [], tags: [],
isStarred: false, isStarred: false
} }
]; ];
ctrl = createCtrlWithStubs(response); ctrl = createCtrlWithStubs(response);
return ctrl.getDashboards(); return ctrl.getDashboards();
}); });
it('should set checked to false on all sections and children', () => { it("should set checked to false on all sections and children", () => {
expect(ctrl.sections.length).toEqual(2); expect(ctrl.sections.length).toEqual(2);
expect(ctrl.sections[0].checked).toEqual(false); expect(ctrl.sections[0].checked).toEqual(false);
expect(ctrl.sections[0].items[0].checked).toEqual(false); expect(ctrl.sections[0].items[0].checked).toEqual(false);
@@ -62,7 +62,7 @@ describe('ManageDashboards', () => {
}); });
}); });
describe('when browsing dashboards for a folder', () => { describe("when browsing dashboards for a folder", () => {
beforeEach(() => { beforeEach(() => {
const response = [ const response = [
{ {
@@ -74,7 +74,7 @@ describe('ManageDashboards', () => {
id: 399, id: 399,
title: "Dashboard Test", title: "Dashboard Test",
url: "dashboard/db/dashboard-test", url: "dashboard/db/dashboard-test",
icon: 'fa fa-folder', icon: "fa fa-folder",
tags: [], tags: [],
isStarred: false, isStarred: false,
folderId: 410, folderId: 410,
@@ -91,12 +91,12 @@ describe('ManageDashboards', () => {
return ctrl.getDashboards(); return ctrl.getDashboards();
}); });
it('should set hide header to true on section', () => { it("should set hide header to true on section", () => {
expect(ctrl.sections[0].hideHeader).toBeTruthy(); expect(ctrl.sections[0].hideHeader).toBeTruthy();
}); });
}); });
describe('when searching dashboards', () => { describe("when searching dashboards", () => {
beforeEach(() => { beforeEach(() => {
const response = [ const response = [
{ {
@@ -108,7 +108,7 @@ describe('ManageDashboards', () => {
id: 399, id: 399,
title: "Dashboard Test", title: "Dashboard Test",
url: "dashboard/db/dashboard-test", url: "dashboard/db/dashboard-test",
icon: 'fa fa-folder', icon: "fa fa-folder",
tags: [], tags: [],
isStarred: false, isStarred: false,
folderId: 410, folderId: 410,
@@ -119,7 +119,7 @@ describe('ManageDashboards', () => {
id: 500, id: 500,
title: "Dashboard Test", title: "Dashboard Test",
url: "dashboard/db/dashboard-test", url: "dashboard/db/dashboard-test",
icon: 'fa fa-folder', icon: "fa fa-folder",
tags: [], tags: [],
folderId: 499, folderId: 499,
isStarred: false isStarred: false
@@ -131,96 +131,96 @@ describe('ManageDashboards', () => {
ctrl = createCtrlWithStubs(response); ctrl = createCtrlWithStubs(response);
}); });
describe('with query filter', () => { describe("with query filter", () => {
beforeEach(() => { beforeEach(() => {
ctrl.query.query = 'd'; ctrl.query.query = "d";
ctrl.canMove = true; ctrl.canMove = true;
ctrl.canDelete = true; ctrl.canDelete = true;
ctrl.selectAllChecked = true; ctrl.selectAllChecked = true;
return ctrl.getDashboards(); return ctrl.getDashboards();
}); });
it('should set checked to false on all sections and children', () => { it("should set checked to false on all sections and children", () => {
expect(ctrl.sections.length).toEqual(1); expect(ctrl.sections.length).toEqual(1);
expect(ctrl.sections[0].checked).toEqual(false); expect(ctrl.sections[0].checked).toEqual(false);
expect(ctrl.sections[0].items[0].checked).toEqual(false); expect(ctrl.sections[0].items[0].checked).toEqual(false);
expect(ctrl.sections[0].items[1].checked).toEqual(false); expect(ctrl.sections[0].items[1].checked).toEqual(false);
}); });
it('should uncheck select all', () => { it("should uncheck select all", () => {
expect(ctrl.selectAllChecked).toBeFalsy(); expect(ctrl.selectAllChecked).toBeFalsy();
}); });
it('should disable Move To button', () => { it("should disable Move To button", () => {
expect(ctrl.canMove).toBeFalsy(); expect(ctrl.canMove).toBeFalsy();
}); });
it('should disable delete button', () => { it("should disable delete button", () => {
expect(ctrl.canDelete).toBeFalsy(); expect(ctrl.canDelete).toBeFalsy();
}); });
it('should have active filters', () => { it("should have active filters", () => {
expect(ctrl.hasFilters).toBeTruthy(); expect(ctrl.hasFilters).toBeTruthy();
}); });
describe('when select all is checked', () => { describe("when select all is checked", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectAllChecked = true; ctrl.selectAllChecked = true;
ctrl.onSelectAllChanged(); ctrl.onSelectAllChanged();
}); });
it('should select all dashboards', () => { it("should select all dashboards", () => {
expect(ctrl.sections[0].checked).toBeFalsy(); expect(ctrl.sections[0].checked).toBeFalsy();
expect(ctrl.sections[0].items[0].checked).toBeTruthy(); expect(ctrl.sections[0].items[0].checked).toBeTruthy();
expect(ctrl.sections[0].items[1].checked).toBeTruthy(); expect(ctrl.sections[0].items[1].checked).toBeTruthy();
}); });
it('should enable Move To button', () => { it("should enable Move To button", () => {
expect(ctrl.canMove).toBeTruthy(); expect(ctrl.canMove).toBeTruthy();
}); });
it('should enable delete button', () => { it("should enable delete button", () => {
expect(ctrl.canDelete).toBeTruthy(); expect(ctrl.canDelete).toBeTruthy();
}); });
describe('when clearing filters', () => { describe("when clearing filters", () => {
beforeEach(() => { beforeEach(() => {
return ctrl.clearFilters(); return ctrl.clearFilters();
}); });
it('should reset query filter', () => { it("should reset query filter", () => {
expect(ctrl.query.query).toEqual(''); expect(ctrl.query.query).toEqual("");
}); });
}); });
}); });
}); });
describe('with tag filter', () => { describe("with tag filter", () => {
beforeEach(() => { beforeEach(() => {
return ctrl.filterByTag('test'); return ctrl.filterByTag("test");
}); });
it('should set tag filter', () => { it("should set tag filter", () => {
expect(ctrl.sections.length).toEqual(1); expect(ctrl.sections.length).toEqual(1);
expect(ctrl.query.tag[0]).toEqual('test'); expect(ctrl.query.tag[0]).toEqual("test");
}); });
it('should have active filters', () => { it("should have active filters", () => {
expect(ctrl.hasFilters).toBeTruthy(); expect(ctrl.hasFilters).toBeTruthy();
}); });
describe('when clearing filters', () => { describe("when clearing filters", () => {
beforeEach(() => { beforeEach(() => {
return ctrl.clearFilters(); return ctrl.clearFilters();
}); });
it('should reset tag filter', () => { it("should reset tag filter", () => {
expect(ctrl.query.tag.length).toEqual(0); expect(ctrl.query.tag.length).toEqual(0);
}); });
}); });
}); });
describe('with starred filter', () => { describe("with starred filter", () => {
beforeEach(() => { beforeEach(() => {
const yesOption: any = ctrl.starredFilterOptions[1]; const yesOption: any = ctrl.starredFilterOptions[1];
@@ -228,187 +228,171 @@ describe('ManageDashboards', () => {
return ctrl.onStarredFilterChange(); return ctrl.onStarredFilterChange();
}); });
it('should set starred filter', () => { it("should set starred filter", () => {
expect(ctrl.sections.length).toEqual(1); expect(ctrl.sections.length).toEqual(1);
expect(ctrl.query.starred).toEqual(true); expect(ctrl.query.starred).toEqual(true);
}); });
it('should have active filters', () => { it("should have active filters", () => {
expect(ctrl.hasFilters).toBeTruthy(); expect(ctrl.hasFilters).toBeTruthy();
}); });
describe('when clearing filters', () => { describe("when clearing filters", () => {
beforeEach(() => { beforeEach(() => {
return ctrl.clearFilters(); return ctrl.clearFilters();
}); });
it('should reset starred filter', () => { it("should reset starred filter", () => {
expect(ctrl.query.starred).toEqual(false); expect(ctrl.query.starred).toEqual(false);
}); });
}); });
}); });
}); });
describe('when selecting dashboards', () => { describe("when selecting dashboards", () => {
let ctrl; let ctrl;
beforeEach(() => { beforeEach(() => {
ctrl = createCtrlWithStubs([]); ctrl = createCtrlWithStubs([]);
}); });
describe('and no dashboards are selected', () => { describe("and no dashboards are selected", () => {
beforeEach(() => { beforeEach(() => {
ctrl.sections = [ ctrl.sections = [
{ {
id: 1, id: 1,
items: [ items: [{ id: 2, checked: false }],
{ id: 2, checked: false }
],
checked: false checked: false
}, },
{ {
id: 0, id: 0,
items: [ items: [{ id: 3, checked: false }],
{ id: 3, checked: false }
],
checked: false checked: false
} }
]; ];
ctrl.selectionChanged(); ctrl.selectionChanged();
}); });
it('should disable Move To button', () => { it("should disable Move To button", () => {
expect(ctrl.canMove).toBeFalsy(); expect(ctrl.canMove).toBeFalsy();
}); });
it('should disable delete button', () => { it("should disable delete button", () => {
expect(ctrl.canDelete).toBeFalsy(); expect(ctrl.canDelete).toBeFalsy();
}); });
describe('when select all is checked', () => { describe("when select all is checked", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectAllChecked = true; ctrl.selectAllChecked = true;
ctrl.onSelectAllChanged(); ctrl.onSelectAllChanged();
}); });
it('should select all folders and dashboards', () => { it("should select all folders and dashboards", () => {
expect(ctrl.sections[0].checked).toBeTruthy(); expect(ctrl.sections[0].checked).toBeTruthy();
expect(ctrl.sections[0].items[0].checked).toBeTruthy(); expect(ctrl.sections[0].items[0].checked).toBeTruthy();
expect(ctrl.sections[1].checked).toBeTruthy(); expect(ctrl.sections[1].checked).toBeTruthy();
expect(ctrl.sections[1].items[0].checked).toBeTruthy(); expect(ctrl.sections[1].items[0].checked).toBeTruthy();
}); });
it('should enable Move To button', () => { it("should enable Move To button", () => {
expect(ctrl.canMove).toBeTruthy(); expect(ctrl.canMove).toBeTruthy();
}); });
it('should enable delete button', () => { it("should enable delete button", () => {
expect(ctrl.canDelete).toBeTruthy(); expect(ctrl.canDelete).toBeTruthy();
}); });
}); });
}); });
describe('and all folders and dashboards are selected', () => { describe("and all folders and dashboards are selected", () => {
beforeEach(() => { beforeEach(() => {
ctrl.sections = [ ctrl.sections = [
{ {
id: 1, id: 1,
items: [ items: [{ id: 2, checked: true }],
{ id: 2, checked: true }
],
checked: true checked: true
}, },
{ {
id: 0, id: 0,
items: [ items: [{ id: 3, checked: true }],
{ id: 3, checked: true }
],
checked: true checked: true
} }
]; ];
ctrl.selectionChanged(); ctrl.selectionChanged();
}); });
it('should enable Move To button', () => { it("should enable Move To button", () => {
expect(ctrl.canMove).toBeTruthy(); expect(ctrl.canMove).toBeTruthy();
}); });
it('should enable delete button', () => { it("should enable delete button", () => {
expect(ctrl.canDelete).toBeTruthy(); expect(ctrl.canDelete).toBeTruthy();
}); });
describe('when select all is unchecked', () => { describe("when select all is unchecked", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectAllChecked = false; ctrl.selectAllChecked = false;
ctrl.onSelectAllChanged(); ctrl.onSelectAllChanged();
}); });
it('should uncheck all checked folders and dashboards', () => { it("should uncheck all checked folders and dashboards", () => {
expect(ctrl.sections[0].checked).toBeFalsy(); expect(ctrl.sections[0].checked).toBeFalsy();
expect(ctrl.sections[0].items[0].checked).toBeFalsy(); expect(ctrl.sections[0].items[0].checked).toBeFalsy();
expect(ctrl.sections[1].checked).toBeFalsy(); expect(ctrl.sections[1].checked).toBeFalsy();
expect(ctrl.sections[1].items[0].checked).toBeFalsy(); expect(ctrl.sections[1].items[0].checked).toBeFalsy();
}); });
it('should disable Move To button', () => { it("should disable Move To button", () => {
expect(ctrl.canMove).toBeFalsy(); expect(ctrl.canMove).toBeFalsy();
}); });
it('should disable delete button', () => { it("should disable delete button", () => {
expect(ctrl.canDelete).toBeFalsy(); expect(ctrl.canDelete).toBeFalsy();
}); });
}); });
}); });
describe('and one dashboard in root is selected', () => { describe("and one dashboard in root is selected", () => {
beforeEach(() => { beforeEach(() => {
ctrl.sections = [ ctrl.sections = [
{ {
id: 1, id: 1,
title: 'folder', title: "folder",
items: [ items: [{ id: 2, checked: false }],
{ id: 2, checked: false }
],
checked: false checked: false
}, },
{ {
id: 0, id: 0,
title: 'Root', title: "Root",
items: [ items: [{ id: 3, checked: true }],
{ id: 3, checked: true }
],
checked: false checked: false
} }
]; ];
ctrl.selectionChanged(); ctrl.selectionChanged();
}); });
it('should enable Move To button', () => { it("should enable Move To button", () => {
expect(ctrl.canMove).toBeTruthy(); expect(ctrl.canMove).toBeTruthy();
}); });
it('should enable delete button', () => { it("should enable delete button", () => {
expect(ctrl.canDelete).toBeTruthy(); expect(ctrl.canDelete).toBeTruthy();
}); });
}); });
describe('and one child dashboard is selected', () => { describe("and one child dashboard is selected", () => {
beforeEach(() => { beforeEach(() => {
ctrl.sections = [ ctrl.sections = [
{ {
id: 1, id: 1,
title: 'folder', title: "folder",
items: [ items: [{ id: 2, checked: true }],
{ id: 2, checked: true }
],
checked: false checked: false
}, },
{ {
id: 0, id: 0,
title: 'Root', title: "Root",
items: [ items: [{ id: 3, checked: false }],
{ id: 3, checked: false }
],
checked: false checked: false
} }
]; ];
@@ -416,32 +400,28 @@ describe('ManageDashboards', () => {
ctrl.selectionChanged(); ctrl.selectionChanged();
}); });
it('should enable Move To button', () => { it("should enable Move To button", () => {
expect(ctrl.canMove).toBeTruthy(); expect(ctrl.canMove).toBeTruthy();
}); });
it('should enable delete button', () => { it("should enable delete button", () => {
expect(ctrl.canDelete).toBeTruthy(); expect(ctrl.canDelete).toBeTruthy();
}); });
}); });
describe('and one child dashboard and one dashboard is selected', () => { describe("and one child dashboard and one dashboard is selected", () => {
beforeEach(() => { beforeEach(() => {
ctrl.sections = [ ctrl.sections = [
{ {
id: 1, id: 1,
title: 'folder', title: "folder",
items: [ items: [{ id: 2, checked: true }],
{ id: 2, checked: true }
],
checked: false checked: false
}, },
{ {
id: 0, id: 0,
title: 'Root', title: "Root",
items: [ items: [{ id: 3, checked: true }],
{ id: 3, checked: true }
],
checked: false checked: false
} }
]; ];
@@ -449,40 +429,34 @@ describe('ManageDashboards', () => {
ctrl.selectionChanged(); ctrl.selectionChanged();
}); });
it('should enable Move To button', () => { it("should enable Move To button", () => {
expect(ctrl.canMove).toBeTruthy(); expect(ctrl.canMove).toBeTruthy();
}); });
it('should enable delete button', () => { it("should enable delete button", () => {
expect(ctrl.canDelete).toBeTruthy(); expect(ctrl.canDelete).toBeTruthy();
}); });
}); });
describe('and one child dashboard and one folder is selected', () => { describe("and one child dashboard and one folder is selected", () => {
beforeEach(() => { beforeEach(() => {
ctrl.sections = [ ctrl.sections = [
{ {
id: 1, id: 1,
title: 'folder', title: "folder",
items: [ items: [{ id: 2, checked: false }],
{ id: 2, checked: false }
],
checked: true checked: true
}, },
{ {
id: 3, id: 3,
title: 'folder', title: "folder",
items: [ items: [{ id: 4, checked: true }],
{ id: 4, checked: true }
],
checked: false checked: false
}, },
{ {
id: 0, id: 0,
title: 'Root', title: "Root",
items: [ items: [{ id: 3, checked: false }],
{ id: 3, checked: false }
],
checked: false checked: false
} }
]; ];
@@ -490,17 +464,17 @@ describe('ManageDashboards', () => {
ctrl.selectionChanged(); ctrl.selectionChanged();
}); });
it('should enable Move To button', () => { it("should enable Move To button", () => {
expect(ctrl.canMove).toBeTruthy(); expect(ctrl.canMove).toBeTruthy();
}); });
it('should enable delete button', () => { it("should enable delete button", () => {
expect(ctrl.canDelete).toBeTruthy(); expect(ctrl.canDelete).toBeTruthy();
}); });
}); });
}); });
describe('when deleting dashboards', () => { describe("when deleting dashboards", () => {
let toBeDeleted: any; let toBeDeleted: any;
beforeEach(() => { beforeEach(() => {
@@ -509,28 +483,22 @@ describe('ManageDashboards', () => {
ctrl.sections = [ ctrl.sections = [
{ {
id: 1, id: 1,
title: 'folder', title: "folder",
items: [ items: [{ id: 2, checked: true, slug: "folder-dash" }],
{ id: 2, checked: true, slug: 'folder-dash' }
],
checked: true, checked: true,
slug: 'folder' slug: "folder"
}, },
{ {
id: 3, id: 3,
title: 'folder-2', title: "folder-2",
items: [ items: [{ id: 3, checked: true, slug: "folder-2-dash" }],
{ id: 3, checked: true, slug: 'folder-2-dash' }
],
checked: false, checked: false,
slug: 'folder-2' slug: "folder-2"
}, },
{ {
id: 0, id: 0,
title: 'Root', title: "Root",
items: [ items: [{ id: 3, checked: true, slug: "root-dash" }],
{ id: 3, checked: true, slug: 'root-dash' }
],
checked: true checked: true
} }
]; ];
@@ -538,57 +506,53 @@ describe('ManageDashboards', () => {
toBeDeleted = ctrl.getFoldersAndDashboardsToDelete(); toBeDeleted = ctrl.getFoldersAndDashboardsToDelete();
}); });
it('should return 1 folder', () => { it("should return 1 folder", () => {
expect(toBeDeleted.folders.length).toEqual(1); expect(toBeDeleted.folders.length).toEqual(1);
}); });
it('should return 2 dashboards', () => { it("should return 2 dashboards", () => {
expect(toBeDeleted.dashboards.length).toEqual(2); expect(toBeDeleted.dashboards.length).toEqual(2);
}); });
it('should filter out children if parent is checked', () => { it("should filter out children if parent is checked", () => {
expect(toBeDeleted.folders[0]).toEqual('folder'); expect(toBeDeleted.folders[0]).toEqual("folder");
}); });
it('should not filter out children if parent not is checked', () => { it("should not filter out children if parent not is checked", () => {
expect(toBeDeleted.dashboards[0]).toEqual('folder-2-dash'); expect(toBeDeleted.dashboards[0]).toEqual("folder-2-dash");
}); });
it('should not filter out children if parent is checked and root', () => { it("should not filter out children if parent is checked and root", () => {
expect(toBeDeleted.dashboards[1]).toEqual('root-dash'); expect(toBeDeleted.dashboards[1]).toEqual("root-dash");
}); });
}); });
describe('when moving dashboards', () => { describe("when moving dashboards", () => {
beforeEach(() => { beforeEach(() => {
ctrl = createCtrlWithStubs([]); ctrl = createCtrlWithStubs([]);
ctrl.sections = [ ctrl.sections = [
{ {
id: 1, id: 1,
title: 'folder', title: "folder",
items: [ items: [{ id: 2, checked: true, slug: "dash" }],
{ id: 2, checked: true, slug: 'dash' }
],
checked: false, checked: false,
slug: 'folder' slug: "folder"
}, },
{ {
id: 0, id: 0,
title: 'Root', title: "Root",
items: [ items: [{ id: 3, checked: true, slug: "dash-2" }],
{ id: 3, checked: true, slug: 'dash-2' }
],
checked: false checked: false
} }
]; ];
}); });
it('should get selected dashboards', () => { it("should get selected dashboards", () => {
const toBeMove = ctrl.getDashboardsToMove(); const toBeMove = ctrl.getDashboardsToMove();
expect(toBeMove.length).toEqual(2); expect(toBeMove.length).toEqual(2);
expect(toBeMove[0]).toEqual('dash'); expect(toBeMove[0]).toEqual("dash");
expect(toBeMove[1]).toEqual('dash-2'); expect(toBeMove[1]).toEqual("dash-2");
}); });
}); });
}); });
@@ -603,5 +567,9 @@ function createCtrlWithStubs(searchResponse: any, tags?: any) {
} }
}; };
return new ManageDashboardsCtrl({}, { getNav: () => { } }, <SearchSrv>searchSrvStub); return new ManageDashboardsCtrl(
{},
{ getNav: () => {} },
<SearchSrv>searchSrvStub
);
} }

View File

@@ -1,38 +1,45 @@
import {OrgSwitchCtrl} from '../components/org_switcher'; import { OrgSwitchCtrl } from "../components/org_switcher";
import q from 'q'; import q from "q";
jest.mock('app/core/services/context_srv', () => ({ jest.mock("app/core/services/context_srv", () => ({
contextSrv: { contextSrv: {
user: {orgId: 1} user: { orgId: 1 }
} }
})); }));
describe('OrgSwitcher', () => { describe("OrgSwitcher", () => {
describe('when switching org', () => { describe("when switching org", () => {
let expectedHref; let expectedHref;
let expectedUsingUrl; let expectedUsingUrl;
beforeEach(() => { beforeEach(() => {
const backendSrvStub: any = { const backendSrvStub: any = {
get: (url) => { return q.resolve([]); }, get: url => {
post: (url) => { expectedUsingUrl = url; return q.resolve({}); } return q.resolve([]);
},
post: url => {
expectedUsingUrl = url;
return q.resolve({});
}
}; };
const orgSwitcherCtrl = new OrgSwitchCtrl(backendSrvStub); const orgSwitcherCtrl = new OrgSwitchCtrl(backendSrvStub);
orgSwitcherCtrl.getWindowLocationHref = () => 'http://localhost:3000?orgId=1&from=now-3h&to=now'; orgSwitcherCtrl.getWindowLocationHref = () =>
orgSwitcherCtrl.setWindowLocationHref = (href) => expectedHref = href; "http://localhost:3000?orgId=1&from=now-3h&to=now";
orgSwitcherCtrl.setWindowLocationHref = href => (expectedHref = href);
return orgSwitcherCtrl.setUsingOrg({orgId: 2}); return orgSwitcherCtrl.setUsingOrg({ orgId: 2 });
}); });
it('should switch orgId in call to backend', () => { it("should switch orgId in call to backend", () => {
expect(expectedUsingUrl).toBe('/api/user/using/2'); expect(expectedUsingUrl).toBe("/api/user/using/2");
}); });
it('should switch orgId in url', () => { it("should switch orgId in url", () => {
expect(expectedHref).toBe('http://localhost:3000?orgId=2&from=now-3h&to=now'); expect(expectedHref).toBe(
"http://localhost:3000?orgId=2&from=now-3h&to=now"
);
}); });
}); });
}); });

View File

@@ -1,108 +1,120 @@
import * as rangeUtil from 'app/core/utils/rangeutil'; import * as rangeUtil from "app/core/utils/rangeutil";
import _ from 'lodash'; import _ from "lodash";
import moment from 'moment'; import moment from "moment";
describe("rangeUtil", () => { describe("rangeUtil", () => {
describe("Can get range grouped list of ranges", () => { describe("Can get range grouped list of ranges", () => {
it('when custom settings should return default range list', () => { it("when custom settings should return default range list", () => {
var groups = rangeUtil.getRelativeTimesList({time_options: []}, 'Last 5 minutes'); var groups = rangeUtil.getRelativeTimesList(
{ time_options: [] },
"Last 5 minutes"
);
expect(_.keys(groups).length).toBe(4); expect(_.keys(groups).length).toBe(4);
expect(groups[3][0].active).toBe(true); expect(groups[3][0].active).toBe(true);
}); });
}); });
describe("Can get range text described", () => { describe("Can get range text described", () => {
it('should handle simple old expression with only amount and unit', () => { it("should handle simple old expression with only amount and unit", () => {
var info = rangeUtil.describeTextRange('5m'); var info = rangeUtil.describeTextRange("5m");
expect(info.display).toBe('Last 5 minutes'); expect(info.display).toBe("Last 5 minutes");
}); });
it('should have singular when amount is 1', () => { it("should have singular when amount is 1", () => {
var info = rangeUtil.describeTextRange('1h'); var info = rangeUtil.describeTextRange("1h");
expect(info.display).toBe('Last 1 hour'); expect(info.display).toBe("Last 1 hour");
}); });
it('should handle non default amount', () => { it("should handle non default amount", () => {
var info = rangeUtil.describeTextRange('13h'); var info = rangeUtil.describeTextRange("13h");
expect(info.display).toBe('Last 13 hours'); expect(info.display).toBe("Last 13 hours");
expect(info.from).toBe('now-13h'); expect(info.from).toBe("now-13h");
}); });
it('should handle non default future amount', () => { it("should handle non default future amount", () => {
var info = rangeUtil.describeTextRange('+3h'); var info = rangeUtil.describeTextRange("+3h");
expect(info.display).toBe('Next 3 hours'); expect(info.display).toBe("Next 3 hours");
expect(info.from).toBe('now'); expect(info.from).toBe("now");
expect(info.to).toBe('now+3h'); expect(info.to).toBe("now+3h");
}); });
it('should handle now/d', () => { it("should handle now/d", () => {
var info = rangeUtil.describeTextRange('now/d'); var info = rangeUtil.describeTextRange("now/d");
expect(info.display).toBe('Today so far'); expect(info.display).toBe("Today so far");
}); });
it('should handle now/w', () => { it("should handle now/w", () => {
var info = rangeUtil.describeTextRange('now/w'); var info = rangeUtil.describeTextRange("now/w");
expect(info.display).toBe('This week so far'); expect(info.display).toBe("This week so far");
}); });
it('should handle now/M', () => { it("should handle now/M", () => {
var info = rangeUtil.describeTextRange('now/M'); var info = rangeUtil.describeTextRange("now/M");
expect(info.display).toBe('This month so far'); expect(info.display).toBe("This month so far");
}); });
it('should handle now/y', () => { it("should handle now/y", () => {
var info = rangeUtil.describeTextRange('now/y'); var info = rangeUtil.describeTextRange("now/y");
expect(info.display).toBe('This year so far'); expect(info.display).toBe("This year so far");
}); });
}); });
describe("Can get date range described", () => { describe("Can get date range described", () => {
it('Date range with simple ranges', () => { it("Date range with simple ranges", () => {
var text = rangeUtil.describeTimeRange({from: 'now-1h', to: 'now'}); var text = rangeUtil.describeTimeRange({ from: "now-1h", to: "now" });
expect(text).toBe('Last 1 hour'); expect(text).toBe("Last 1 hour");
}); });
it('Date range with rounding ranges', () => { it("Date range with rounding ranges", () => {
var text = rangeUtil.describeTimeRange({from: 'now/d+6h', to: 'now'}); var text = rangeUtil.describeTimeRange({ from: "now/d+6h", to: "now" });
expect(text).toBe('now/d+6h to now'); expect(text).toBe("now/d+6h to now");
}); });
it('Date range with absolute to now', () => { it("Date range with absolute to now", () => {
var text = rangeUtil.describeTimeRange({from: moment([2014,10,10,2,3,4]), to: 'now'}); var text = rangeUtil.describeTimeRange({
expect(text).toBe('Nov 10, 2014 02:03:04 to a few seconds ago'); from: moment([2014, 10, 10, 2, 3, 4]),
to: "now"
});
expect(text).toBe("Nov 10, 2014 02:03:04 to a few seconds ago");
}); });
it('Date range with absolute to relative', () => { it("Date range with absolute to relative", () => {
var text = rangeUtil.describeTimeRange({from: moment([2014,10,10,2,3,4]), to: 'now-1d'}); var text = rangeUtil.describeTimeRange({
expect(text).toBe('Nov 10, 2014 02:03:04 to a day ago'); from: moment([2014, 10, 10, 2, 3, 4]),
to: "now-1d"
});
expect(text).toBe("Nov 10, 2014 02:03:04 to a day ago");
}); });
it('Date range with relative to absolute', () => { it("Date range with relative to absolute", () => {
var text = rangeUtil.describeTimeRange({from: 'now-7d', to: moment([2014,10,10,2,3,4])}); var text = rangeUtil.describeTimeRange({
expect(text).toBe('7 days ago to Nov 10, 2014 02:03:04'); from: "now-7d",
to: moment([2014, 10, 10, 2, 3, 4])
});
expect(text).toBe("7 days ago to Nov 10, 2014 02:03:04");
}); });
it('Date range with non matching default ranges', () => { it("Date range with non matching default ranges", () => {
var text = rangeUtil.describeTimeRange({from: 'now-13h', to: 'now'}); var text = rangeUtil.describeTimeRange({ from: "now-13h", to: "now" });
expect(text).toBe('Last 13 hours'); expect(text).toBe("Last 13 hours");
}); });
it('Date range with from and to both are in now-* format', () => { it("Date range with from and to both are in now-* format", () => {
var text = rangeUtil.describeTimeRange({from: 'now-6h', to: 'now-3h'}); var text = rangeUtil.describeTimeRange({ from: "now-6h", to: "now-3h" });
expect(text).toBe('now-6h to now-3h'); expect(text).toBe("now-6h to now-3h");
}); });
it('Date range with from and to both are either in now-* or now/* format', () => { it("Date range with from and to both are either in now-* or now/* format", () => {
var text = rangeUtil.describeTimeRange({from: 'now/d+6h', to: 'now-3h'}); var text = rangeUtil.describeTimeRange({
expect(text).toBe('now/d+6h to now-3h'); from: "now/d+6h",
to: "now-3h"
});
expect(text).toBe("now/d+6h to now-3h");
}); });
it('Date range with from and to both are either in now-* or now+* format', () => { it("Date range with from and to both are either in now-* or now+* format", () => {
var text = rangeUtil.describeTimeRange({from: 'now-6h', to: 'now+1h'}); var text = rangeUtil.describeTimeRange({ from: "now-6h", to: "now+1h" });
expect(text).toBe('now-6h to now+1h'); expect(text).toBe("now-6h to now+1h");
}); });
}); });
}); });

View File

@@ -1,73 +1,75 @@
import { SearchCtrl } from '../components/search/search'; import { SearchCtrl } from "../components/search/search";
import { SearchSrv } from '../services/search_srv'; import { SearchSrv } from "../services/search_srv";
describe('SearchCtrl', () => { describe("SearchCtrl", () => {
const searchSrvStub = { const searchSrvStub = {
search: (options: any) => {}, search: (options: any) => {},
getDashboardTags: () => {} getDashboardTags: () => {}
}; };
let ctrl = new SearchCtrl({$on: () => {}}, {}, {}, <SearchSrv>searchSrvStub); let ctrl = new SearchCtrl(
{ $on: () => {} },
{},
{},
<SearchSrv>searchSrvStub
);
describe('Given an empty result', () => { describe("Given an empty result", () => {
beforeEach(() => { beforeEach(() => {
ctrl.results = []; ctrl.results = [];
}); });
describe('When navigating down one step', () => { describe("When navigating down one step", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 0; ctrl.selectedIndex = 0;
ctrl.moveSelection(1); ctrl.moveSelection(1);
}); });
it('should not navigate', () => { it("should not navigate", () => {
expect(ctrl.selectedIndex).toBe(0); expect(ctrl.selectedIndex).toBe(0);
}); });
}); });
describe('When navigating up one step', () => { describe("When navigating up one step", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 0; ctrl.selectedIndex = 0;
ctrl.moveSelection(-1); ctrl.moveSelection(-1);
}); });
it('should not navigate', () => { it("should not navigate", () => {
expect(ctrl.selectedIndex).toBe(0); expect(ctrl.selectedIndex).toBe(0);
}); });
}); });
}); });
describe('Given a result of one selected collapsed folder with no dashboards and a root folder with 2 dashboards', () => { describe("Given a result of one selected collapsed folder with no dashboards and a root folder with 2 dashboards", () => {
beforeEach(() => { beforeEach(() => {
ctrl.results = [ ctrl.results = [
{ {
id: 1, id: 1,
title: 'folder', title: "folder",
items: [], items: [],
selected: true, selected: true,
expanded: false, expanded: false,
toggle: (i) => i.expanded = !i.expanded toggle: i => (i.expanded = !i.expanded)
}, },
{ {
id: 0, id: 0,
title: 'Root', title: "Root",
items: [ items: [{ id: 3, selected: false }, { id: 5, selected: false }],
{ id: 3, selected: false },
{ id: 5, selected: false }
],
selected: false, selected: false,
expanded: true, expanded: true,
toggle: (i) => i.expanded = !i.expanded toggle: i => (i.expanded = !i.expanded)
} }
]; ];
}); });
describe('When navigating down one step', () => { describe("When navigating down one step", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 0; ctrl.selectedIndex = 0;
ctrl.moveSelection(1); ctrl.moveSelection(1);
}); });
it('should select first dashboard in root folder', () => { it("should select first dashboard in root folder", () => {
expect(ctrl.results[0].selected).toBeFalsy(); expect(ctrl.results[0].selected).toBeFalsy();
expect(ctrl.results[1].selected).toBeFalsy(); expect(ctrl.results[1].selected).toBeFalsy();
expect(ctrl.results[1].items[0].selected).toBeTruthy(); expect(ctrl.results[1].items[0].selected).toBeTruthy();
@@ -75,14 +77,14 @@ describe('SearchCtrl', () => {
}); });
}); });
describe('When navigating down two steps', () => { describe("When navigating down two steps", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 0; ctrl.selectedIndex = 0;
ctrl.moveSelection(1); ctrl.moveSelection(1);
ctrl.moveSelection(1); ctrl.moveSelection(1);
}); });
it('should select last dashboard in root folder', () => { it("should select last dashboard in root folder", () => {
expect(ctrl.results[0].selected).toBeFalsy(); expect(ctrl.results[0].selected).toBeFalsy();
expect(ctrl.results[1].selected).toBeFalsy(); expect(ctrl.results[1].selected).toBeFalsy();
expect(ctrl.results[1].items[0].selected).toBeFalsy(); expect(ctrl.results[1].items[0].selected).toBeFalsy();
@@ -90,7 +92,7 @@ describe('SearchCtrl', () => {
}); });
}); });
describe('When navigating down three steps', () => { describe("When navigating down three steps", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 0; ctrl.selectedIndex = 0;
ctrl.moveSelection(1); ctrl.moveSelection(1);
@@ -98,7 +100,7 @@ describe('SearchCtrl', () => {
ctrl.moveSelection(1); ctrl.moveSelection(1);
}); });
it('should select first folder', () => { it("should select first folder", () => {
expect(ctrl.results[0].selected).toBeTruthy(); expect(ctrl.results[0].selected).toBeTruthy();
expect(ctrl.results[1].selected).toBeFalsy(); expect(ctrl.results[1].selected).toBeFalsy();
expect(ctrl.results[1].items[0].selected).toBeFalsy(); expect(ctrl.results[1].items[0].selected).toBeFalsy();
@@ -106,13 +108,13 @@ describe('SearchCtrl', () => {
}); });
}); });
describe('When navigating up one step', () => { describe("When navigating up one step", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 0; ctrl.selectedIndex = 0;
ctrl.moveSelection(-1); ctrl.moveSelection(-1);
}); });
it('should select last dashboard in root folder', () => { it("should select last dashboard in root folder", () => {
expect(ctrl.results[0].selected).toBeFalsy(); expect(ctrl.results[0].selected).toBeFalsy();
expect(ctrl.results[1].selected).toBeFalsy(); expect(ctrl.results[1].selected).toBeFalsy();
expect(ctrl.results[1].items[0].selected).toBeFalsy(); expect(ctrl.results[1].items[0].selected).toBeFalsy();
@@ -120,14 +122,14 @@ describe('SearchCtrl', () => {
}); });
}); });
describe('When navigating up two steps', () => { describe("When navigating up two steps", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 0; ctrl.selectedIndex = 0;
ctrl.moveSelection(-1); ctrl.moveSelection(-1);
ctrl.moveSelection(-1); ctrl.moveSelection(-1);
}); });
it('should select first dashboard in root folder', () => { it("should select first dashboard in root folder", () => {
expect(ctrl.results[0].selected).toBeFalsy(); expect(ctrl.results[0].selected).toBeFalsy();
expect(ctrl.results[1].selected).toBeFalsy(); expect(ctrl.results[1].selected).toBeFalsy();
expect(ctrl.results[1].items[0].selected).toBeTruthy(); expect(ctrl.results[1].items[0].selected).toBeTruthy();
@@ -136,41 +138,35 @@ describe('SearchCtrl', () => {
}); });
}); });
describe('Given a result of one selected collapsed folder with 2 dashboards and a root folder with 2 dashboards', () => { describe("Given a result of one selected collapsed folder with 2 dashboards and a root folder with 2 dashboards", () => {
beforeEach(() => { beforeEach(() => {
ctrl.results = [ ctrl.results = [
{ {
id: 1, id: 1,
title: 'folder', title: "folder",
items: [ items: [{ id: 2, selected: false }, { id: 4, selected: false }],
{ id: 2, selected: false },
{ id: 4, selected: false }
],
selected: true, selected: true,
expanded: false, expanded: false,
toggle: (i) => i.expanded = !i.expanded toggle: i => (i.expanded = !i.expanded)
}, },
{ {
id: 0, id: 0,
title: 'Root', title: "Root",
items: [ items: [{ id: 3, selected: false }, { id: 5, selected: false }],
{ id: 3, selected: false },
{ id: 5, selected: false }
],
selected: false, selected: false,
expanded: true, expanded: true,
toggle: (i) => i.expanded = !i.expanded toggle: i => (i.expanded = !i.expanded)
} }
]; ];
}); });
describe('When navigating down one step', () => { describe("When navigating down one step", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 0; ctrl.selectedIndex = 0;
ctrl.moveSelection(1); ctrl.moveSelection(1);
}); });
it('should select first dashboard in root folder', () => { it("should select first dashboard in root folder", () => {
expect(ctrl.results[0].selected).toBeFalsy(); expect(ctrl.results[0].selected).toBeFalsy();
expect(ctrl.results[1].selected).toBeFalsy(); expect(ctrl.results[1].selected).toBeFalsy();
expect(ctrl.results[0].items[0].selected).toBeFalsy(); expect(ctrl.results[0].items[0].selected).toBeFalsy();
@@ -180,14 +176,14 @@ describe('SearchCtrl', () => {
}); });
}); });
describe('When navigating down two steps', () => { describe("When navigating down two steps", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 0; ctrl.selectedIndex = 0;
ctrl.moveSelection(1); ctrl.moveSelection(1);
ctrl.moveSelection(1); ctrl.moveSelection(1);
}); });
it('should select last dashboard in root folder', () => { it("should select last dashboard in root folder", () => {
expect(ctrl.results[0].selected).toBeFalsy(); expect(ctrl.results[0].selected).toBeFalsy();
expect(ctrl.results[1].selected).toBeFalsy(); expect(ctrl.results[1].selected).toBeFalsy();
expect(ctrl.results[0].items[0].selected).toBeFalsy(); expect(ctrl.results[0].items[0].selected).toBeFalsy();
@@ -197,7 +193,7 @@ describe('SearchCtrl', () => {
}); });
}); });
describe('When navigating down three steps', () => { describe("When navigating down three steps", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 0; ctrl.selectedIndex = 0;
ctrl.moveSelection(1); ctrl.moveSelection(1);
@@ -205,7 +201,7 @@ describe('SearchCtrl', () => {
ctrl.moveSelection(1); ctrl.moveSelection(1);
}); });
it('should select first folder', () => { it("should select first folder", () => {
expect(ctrl.results[0].selected).toBeTruthy(); expect(ctrl.results[0].selected).toBeTruthy();
expect(ctrl.results[1].selected).toBeFalsy(); expect(ctrl.results[1].selected).toBeFalsy();
expect(ctrl.results[0].items[0].selected).toBeFalsy(); expect(ctrl.results[0].items[0].selected).toBeFalsy();
@@ -215,13 +211,13 @@ describe('SearchCtrl', () => {
}); });
}); });
describe('When navigating up one step', () => { describe("When navigating up one step", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 0; ctrl.selectedIndex = 0;
ctrl.moveSelection(-1); ctrl.moveSelection(-1);
}); });
it('should select last dashboard in root folder', () => { it("should select last dashboard in root folder", () => {
expect(ctrl.results[0].selected).toBeFalsy(); expect(ctrl.results[0].selected).toBeFalsy();
expect(ctrl.results[1].selected).toBeFalsy(); expect(ctrl.results[1].selected).toBeFalsy();
expect(ctrl.results[0].items[0].selected).toBeFalsy(); expect(ctrl.results[0].items[0].selected).toBeFalsy();
@@ -231,14 +227,14 @@ describe('SearchCtrl', () => {
}); });
}); });
describe('When navigating up two steps', () => { describe("When navigating up two steps", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 0; ctrl.selectedIndex = 0;
ctrl.moveSelection(-1); ctrl.moveSelection(-1);
ctrl.moveSelection(-1); ctrl.moveSelection(-1);
}); });
it('should select first dashboard in root folder', () => { it("should select first dashboard in root folder", () => {
expect(ctrl.results[0].selected).toBeFalsy(); expect(ctrl.results[0].selected).toBeFalsy();
expect(ctrl.results[1].selected).toBeFalsy(); expect(ctrl.results[1].selected).toBeFalsy();
expect(ctrl.results[1].items[0].selected).toBeTruthy(); expect(ctrl.results[1].items[0].selected).toBeTruthy();
@@ -247,50 +243,47 @@ describe('SearchCtrl', () => {
}); });
}); });
describe('Given a result of a search with 2 dashboards where the first is selected', () => { describe("Given a result of a search with 2 dashboards where the first is selected", () => {
beforeEach(() => { beforeEach(() => {
ctrl.results = [ ctrl.results = [
{ {
hideHeader: true, hideHeader: true,
items: [ items: [{ id: 3, selected: true }, { id: 5, selected: false }],
{ id: 3, selected: true },
{ id: 5, selected: false }
],
selected: false, selected: false,
expanded: true, expanded: true,
toggle: (i) => i.expanded = !i.expanded toggle: i => (i.expanded = !i.expanded)
} }
]; ];
}); });
describe('When navigating down one step', () => { describe("When navigating down one step", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 1; ctrl.selectedIndex = 1;
ctrl.moveSelection(1); ctrl.moveSelection(1);
}); });
it('should select last dashboard', () => { it("should select last dashboard", () => {
expect(ctrl.results[0].selected).toBeFalsy(); expect(ctrl.results[0].selected).toBeFalsy();
expect(ctrl.results[0].items[0].selected).toBeFalsy(); expect(ctrl.results[0].items[0].selected).toBeFalsy();
expect(ctrl.results[0].items[1].selected).toBeTruthy(); expect(ctrl.results[0].items[1].selected).toBeTruthy();
}); });
}); });
describe('When navigating down two steps', () => { describe("When navigating down two steps", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 1; ctrl.selectedIndex = 1;
ctrl.moveSelection(1); ctrl.moveSelection(1);
ctrl.moveSelection(1); ctrl.moveSelection(1);
}); });
it('should select first dashboard', () => { it("should select first dashboard", () => {
expect(ctrl.results[0].selected).toBeFalsy(); expect(ctrl.results[0].selected).toBeFalsy();
expect(ctrl.results[0].items[0].selected).toBeTruthy(); expect(ctrl.results[0].items[0].selected).toBeTruthy();
expect(ctrl.results[0].items[1].selected).toBeFalsy(); expect(ctrl.results[0].items[1].selected).toBeFalsy();
}); });
}); });
describe('When navigating down three steps', () => { describe("When navigating down three steps", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 1; ctrl.selectedIndex = 1;
ctrl.moveSelection(1); ctrl.moveSelection(1);
@@ -298,34 +291,34 @@ describe('SearchCtrl', () => {
ctrl.moveSelection(1); ctrl.moveSelection(1);
}); });
it('should select last dashboard', () => { it("should select last dashboard", () => {
expect(ctrl.results[0].selected).toBeFalsy(); expect(ctrl.results[0].selected).toBeFalsy();
expect(ctrl.results[0].items[0].selected).toBeFalsy(); expect(ctrl.results[0].items[0].selected).toBeFalsy();
expect(ctrl.results[0].items[1].selected).toBeTruthy(); expect(ctrl.results[0].items[1].selected).toBeTruthy();
}); });
}); });
describe('When navigating up one step', () => { describe("When navigating up one step", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 1; ctrl.selectedIndex = 1;
ctrl.moveSelection(-1); ctrl.moveSelection(-1);
}); });
it('should select last dashboard', () => { it("should select last dashboard", () => {
expect(ctrl.results[0].selected).toBeFalsy(); expect(ctrl.results[0].selected).toBeFalsy();
expect(ctrl.results[0].items[0].selected).toBeFalsy(); expect(ctrl.results[0].items[0].selected).toBeFalsy();
expect(ctrl.results[0].items[1].selected).toBeTruthy(); expect(ctrl.results[0].items[1].selected).toBeTruthy();
}); });
}); });
describe('When navigating up two steps', () => { describe("When navigating up two steps", () => {
beforeEach(() => { beforeEach(() => {
ctrl.selectedIndex = 1; ctrl.selectedIndex = 1;
ctrl.moveSelection(-1); ctrl.moveSelection(-1);
ctrl.moveSelection(-1); ctrl.moveSelection(-1);
}); });
it('should select first dashboard', () => { it("should select first dashboard", () => {
expect(ctrl.results[0].selected).toBeFalsy(); expect(ctrl.results[0].selected).toBeFalsy();
expect(ctrl.results[0].items[0].selected).toBeTruthy(); expect(ctrl.results[0].items[0].selected).toBeTruthy();
expect(ctrl.results[0].items[1].selected).toBeFalsy(); expect(ctrl.results[0].items[1].selected).toBeFalsy();

View File

@@ -1,74 +1,76 @@
import { SearchResultsCtrl } from '../components/search/search_results'; import { SearchResultsCtrl } from "../components/search/search_results";
import { beforeEach, afterEach } from 'test/lib/common'; import { beforeEach, afterEach } from "test/lib/common";
import appEvents from 'app/core/app_events'; import appEvents from "app/core/app_events";
jest.mock('app/core/app_events', () => { jest.mock("app/core/app_events", () => {
return { return {
emit: jest.fn<any>() emit: jest.fn<any>()
}; };
}); });
describe('SearchResultsCtrl', () => { describe("SearchResultsCtrl", () => {
let ctrl; let ctrl;
describe('when checking an item that is not checked', () => { describe("when checking an item that is not checked", () => {
let item = {checked: false}; let item = { checked: false };
let selectionChanged = false; let selectionChanged = false;
beforeEach(() => { beforeEach(() => {
ctrl = new SearchResultsCtrl({}); ctrl = new SearchResultsCtrl({});
ctrl.onSelectionChanged = () => selectionChanged = true; ctrl.onSelectionChanged = () => (selectionChanged = true);
ctrl.toggleSelection(item); ctrl.toggleSelection(item);
}); });
it('should set checked to true', () => { it("should set checked to true", () => {
expect(item.checked).toBeTruthy(); expect(item.checked).toBeTruthy();
}); });
it('should trigger selection changed callback', () => { it("should trigger selection changed callback", () => {
expect(selectionChanged).toBeTruthy(); expect(selectionChanged).toBeTruthy();
}); });
}); });
describe('when checking an item that is checked', () => { describe("when checking an item that is checked", () => {
let item = {checked: true}; let item = { checked: true };
let selectionChanged = false; let selectionChanged = false;
beforeEach(() => { beforeEach(() => {
ctrl = new SearchResultsCtrl({}); ctrl = new SearchResultsCtrl({});
ctrl.onSelectionChanged = () => selectionChanged = true; ctrl.onSelectionChanged = () => (selectionChanged = true);
ctrl.toggleSelection(item); ctrl.toggleSelection(item);
}); });
it('should set checked to false', () => { it("should set checked to false", () => {
expect(item.checked).toBeFalsy(); expect(item.checked).toBeFalsy();
}); });
it('should trigger selection changed callback', () => { it("should trigger selection changed callback", () => {
expect(selectionChanged).toBeTruthy(); expect(selectionChanged).toBeTruthy();
}); });
}); });
describe('when selecting a tag', () => { describe("when selecting a tag", () => {
let selectedTag = null; let selectedTag = null;
beforeEach(() => { beforeEach(() => {
ctrl = new SearchResultsCtrl({}); ctrl = new SearchResultsCtrl({});
ctrl.onTagSelected = (tag) => selectedTag = tag; ctrl.onTagSelected = tag => (selectedTag = tag);
ctrl.selectTag('tag-test'); ctrl.selectTag("tag-test");
}); });
it('should trigger tag selected callback', () => { it("should trigger tag selected callback", () => {
expect(selectedTag["$tag"]).toBe('tag-test'); expect(selectedTag["$tag"]).toBe("tag-test");
}); });
}); });
describe('when toggle a collapsed folder', () => { describe("when toggle a collapsed folder", () => {
let folderExpanded = false; let folderExpanded = false;
beforeEach(() => { beforeEach(() => {
ctrl = new SearchResultsCtrl({}); ctrl = new SearchResultsCtrl({});
ctrl.onFolderExpanding = () => { folderExpanded = true; }; ctrl.onFolderExpanding = () => {
folderExpanded = true;
};
let folder = { let folder = {
expanded: false, expanded: false,
@@ -78,17 +80,19 @@ describe('SearchResultsCtrl', () => {
ctrl.toggleFolderExpand(folder); ctrl.toggleFolderExpand(folder);
}); });
it('should trigger folder expanding callback', () => { it("should trigger folder expanding callback", () => {
expect(folderExpanded).toBeTruthy(); expect(folderExpanded).toBeTruthy();
}); });
}); });
describe('when toggle an expanded folder', () => { describe("when toggle an expanded folder", () => {
let folderExpanded = false; let folderExpanded = false;
beforeEach(() => { beforeEach(() => {
ctrl = new SearchResultsCtrl({}); ctrl = new SearchResultsCtrl({});
ctrl.onFolderExpanding = () => { folderExpanded = true; }; ctrl.onFolderExpanding = () => {
folderExpanded = true;
};
let folder = { let folder = {
expanded: true, expanded: true,
@@ -98,37 +102,37 @@ describe('SearchResultsCtrl', () => {
ctrl.toggleFolderExpand(folder); ctrl.toggleFolderExpand(folder);
}); });
it('should not trigger folder expanding callback', () => { it("should not trigger folder expanding callback", () => {
expect(folderExpanded).toBeFalsy(); expect(folderExpanded).toBeFalsy();
}); });
}); });
describe('when clicking on a link in search result', () => { describe("when clicking on a link in search result", () => {
const dashPath = 'dashboard/path'; const dashPath = "dashboard/path";
const $location = { path: () => dashPath}; const $location = { path: () => dashPath };
const appEventsMock = appEvents as any; const appEventsMock = appEvents as any;
describe('with the same url as current path', () => { describe("with the same url as current path", () => {
beforeEach(() => { beforeEach(() => {
ctrl = new SearchResultsCtrl($location); ctrl = new SearchResultsCtrl($location);
const item = { url: dashPath}; const item = { url: dashPath };
ctrl.onItemClick(item); ctrl.onItemClick(item);
}); });
it('should close the search', () => { it("should close the search", () => {
expect(appEventsMock.emit.mock.calls.length).toBe(1); expect(appEventsMock.emit.mock.calls.length).toBe(1);
expect(appEventsMock.emit.mock.calls[0][0]).toBe('hide-dash-search'); expect(appEventsMock.emit.mock.calls[0][0]).toBe("hide-dash-search");
}); });
}); });
describe('with a different url than current path', () => { describe("with a different url than current path", () => {
beforeEach(() => { beforeEach(() => {
ctrl = new SearchResultsCtrl($location); ctrl = new SearchResultsCtrl($location);
const item = { url: 'another/path'}; const item = { url: "another/path" };
ctrl.onItemClick(item); ctrl.onItemClick(item);
}); });
it('should do nothing', () => { it("should do nothing", () => {
expect(appEventsMock.emit.mock.calls.length).toBe(0); expect(appEventsMock.emit.mock.calls.length).toBe(0);
}); });
}); });

View File

@@ -1,23 +1,23 @@
import { SearchSrv } from 'app/core/services/search_srv'; import { SearchSrv } from "app/core/services/search_srv";
import { BackendSrvMock } from 'test/mocks/backend_srv'; import { BackendSrvMock } from "test/mocks/backend_srv";
import impressionSrv from 'app/core/services/impression_srv'; import impressionSrv from "app/core/services/impression_srv";
import { contextSrv } from 'app/core/services/context_srv'; import { contextSrv } from "app/core/services/context_srv";
import { beforeEach } from 'test/lib/common'; import { beforeEach } from "test/lib/common";
jest.mock('app/core/store', () => { jest.mock("app/core/store", () => {
return { return {
getBool: jest.fn(), getBool: jest.fn(),
set: jest.fn(), set: jest.fn()
}; };
}); });
jest.mock('app/core/services/impression_srv', () => { jest.mock("app/core/services/impression_srv", () => {
return { return {
getDashboardOpened: jest.fn, getDashboardOpened: jest.fn
}; };
}); });
describe('SearchSrv', () => { describe("SearchSrv", () => {
let searchSrv, backendSrvMock; let searchSrv, backendSrvMock;
beforeEach(() => { beforeEach(() => {
@@ -28,52 +28,57 @@ describe('SearchSrv', () => {
impressionSrv.getDashboardOpened = jest.fn().mockReturnValue([]); impressionSrv.getDashboardOpened = jest.fn().mockReturnValue([]);
}); });
describe('With recent dashboards', () => { describe("With recent dashboards", () => {
let results; let results;
beforeEach(() => { beforeEach(() => {
backendSrvMock.search = jest backendSrvMock.search = jest
.fn() .fn()
.mockReturnValueOnce( .mockReturnValueOnce(
Promise.resolve([{ id: 2, title: 'second but first' }, { id: 1, title: 'first but second' }]), Promise.resolve([
{ id: 2, title: "second but first" },
{ id: 1, title: "first but second" }
])
) )
.mockReturnValue(Promise.resolve([])); .mockReturnValue(Promise.resolve([]));
impressionSrv.getDashboardOpened = jest.fn().mockReturnValue([1, 2]); impressionSrv.getDashboardOpened = jest.fn().mockReturnValue([1, 2]);
return searchSrv.search({ query: '' }).then(res => { return searchSrv.search({ query: "" }).then(res => {
results = res; results = res;
}); });
}); });
it('should include recent dashboards section', () => { it("should include recent dashboards section", () => {
expect(results[0].title).toBe('Recent Boards'); expect(results[0].title).toBe("Recent Boards");
}); });
it('should return order decided by impressions store not api', () => { it("should return order decided by impressions store not api", () => {
expect(results[0].items[0].title).toBe('first but second'); expect(results[0].items[0].title).toBe("first but second");
expect(results[0].items[1].title).toBe('second but first'); expect(results[0].items[1].title).toBe("second but first");
}); });
describe('and 3 recent dashboards removed in backend', () => { describe("and 3 recent dashboards removed in backend", () => {
let results; let results;
beforeEach(() => { beforeEach(() => {
backendSrvMock.search = jest backendSrvMock.search = jest
.fn() .fn()
.mockReturnValueOnce( .mockReturnValueOnce(
Promise.resolve([{ id: 2, title: 'two' }, { id: 1, title: 'one' }]), Promise.resolve([{ id: 2, title: "two" }, { id: 1, title: "one" }])
) )
.mockReturnValue(Promise.resolve([])); .mockReturnValue(Promise.resolve([]));
impressionSrv.getDashboardOpened = jest.fn().mockReturnValue([4, 5, 1, 2, 3]); impressionSrv.getDashboardOpened = jest
.fn()
.mockReturnValue([4, 5, 1, 2, 3]);
return searchSrv.search({ query: '' }).then(res => { return searchSrv.search({ query: "" }).then(res => {
results = res; results = res;
}); });
}); });
it('should return 2 dashboards', () => { it("should return 2 dashboards", () => {
expect(results[0].items.length).toBe(2); expect(results[0].items.length).toBe(2);
expect(results[0].items[0].id).toBe(1); expect(results[0].items[0].id).toBe(1);
expect(results[0].items[1].id).toBe(2); expect(results[0].items[1].id).toBe(2);
@@ -81,60 +86,59 @@ describe('SearchSrv', () => {
}); });
}); });
describe('With starred dashboards', () => { describe("With starred dashboards", () => {
let results; let results;
beforeEach(() => { beforeEach(() => {
backendSrvMock.search = jest backendSrvMock.search = jest
.fn() .fn()
.mockReturnValue(Promise.resolve([ .mockReturnValue(Promise.resolve([{ id: 1, title: "starred" }]));
{id: 1, title: 'starred'}
]));
return searchSrv.search({ query: '' }).then(res => { return searchSrv.search({ query: "" }).then(res => {
results = res; results = res;
}); });
}); });
it('should include starred dashboards section', () => { it("should include starred dashboards section", () => {
expect(results[0].title).toBe('Starred Boards'); expect(results[0].title).toBe("Starred Boards");
expect(results[0].items.length).toBe(1); expect(results[0].items.length).toBe(1);
}); });
}); });
describe('With starred dashboards and recent', () => { describe("With starred dashboards and recent", () => {
let results; let results;
beforeEach(() => { beforeEach(() => {
backendSrvMock.search = jest backendSrvMock.search = jest
.fn() .fn()
.mockReturnValueOnce(Promise.resolve([ .mockReturnValueOnce(
{id: 1, title: 'starred and recent', isStarred: true}, Promise.resolve([
{id: 2, title: 'recent'} { id: 1, title: "starred and recent", isStarred: true },
])) { id: 2, title: "recent" }
.mockReturnValue(Promise.resolve([ ])
{id: 1, title: 'starred and recent'} )
])); .mockReturnValue(
Promise.resolve([{ id: 1, title: "starred and recent" }])
);
impressionSrv.getDashboardOpened = jest.fn().mockReturnValue([1,2]); impressionSrv.getDashboardOpened = jest.fn().mockReturnValue([1, 2]);
return searchSrv.search({ query: '' }).then(res => { return searchSrv.search({ query: "" }).then(res => {
results = res; results = res;
}); });
}); });
it('should not show starred in recent', () => { it("should not show starred in recent", () => {
expect(results[1].title).toBe('Recent Boards'); expect(results[1].title).toBe("Recent Boards");
expect(results[1].items[0].title).toBe('recent'); expect(results[1].items[0].title).toBe("recent");
}); });
it('should show starred', () => { it("should show starred", () => {
expect(results[0].title).toBe('Starred Boards'); expect(results[0].title).toBe("Starred Boards");
expect(results[0].items[0].title).toBe('starred and recent'); expect(results[0].items[0].title).toBe("starred and recent");
}); });
}); });
describe('with no query string and dashboards with folders returned', () => { describe("with no query string and dashboards with folders returned", () => {
let results; let results;
beforeEach(() => { beforeEach(() => {
@@ -144,45 +148,45 @@ describe('SearchSrv', () => {
.mockReturnValue( .mockReturnValue(
Promise.resolve([ Promise.resolve([
{ {
title: 'folder1', title: "folder1",
type: 'dash-folder', type: "dash-folder",
id: 1, id: 1
}, },
{ {
title: 'dash with no folder', title: "dash with no folder",
type: 'dash-db', type: "dash-db",
id: 2, id: 2
}, },
{ {
title: 'dash in folder1 1', title: "dash in folder1 1",
type: 'dash-db', type: "dash-db",
id: 3, id: 3,
folderId: 1, folderId: 1
}, },
{ {
title: 'dash in folder1 2', title: "dash in folder1 2",
type: 'dash-db', type: "dash-db",
id: 4, id: 4,
folderId: 1, folderId: 1
}, }
]), ])
); );
return searchSrv.search({ query: '' }).then(res => { return searchSrv.search({ query: "" }).then(res => {
results = res; results = res;
}); });
}); });
it('should create sections for each folder and root', () => { it("should create sections for each folder and root", () => {
expect(results).toHaveLength(2); expect(results).toHaveLength(2);
}); });
it('should place folders first', () => { it("should place folders first", () => {
expect(results[0].title).toBe('folder1'); expect(results[0].title).toBe("folder1");
}); });
}); });
describe('with query string and dashboards with folders returned', () => { describe("with query string and dashboards with folders returned", () => {
let results; let results;
beforeEach(() => { beforeEach(() => {
@@ -192,47 +196,47 @@ describe('SearchSrv', () => {
Promise.resolve([ Promise.resolve([
{ {
id: 2, id: 2,
title: 'dash with no folder', title: "dash with no folder",
type: 'dash-db', type: "dash-db"
}, },
{ {
id: 3, id: 3,
title: 'dash in folder1 1', title: "dash in folder1 1",
type: 'dash-db', type: "dash-db",
folderId: 1, folderId: 1,
folderTitle: 'folder1', folderTitle: "folder1"
}, }
]), ])
); );
return searchSrv.search({ query: 'search' }).then(res => { return searchSrv.search({ query: "search" }).then(res => {
results = res; results = res;
}); });
}); });
it('should not specify folder ids', () => { it("should not specify folder ids", () => {
expect(backendSrvMock.search.mock.calls[0][0].folderIds).toHaveLength(0); expect(backendSrvMock.search.mock.calls[0][0].folderIds).toHaveLength(0);
}); });
it('should group results by folder', () => { it("should group results by folder", () => {
expect(results).toHaveLength(2); expect(results).toHaveLength(2);
}); });
}); });
describe('with tags', () => { describe("with tags", () => {
beforeEach(() => { beforeEach(() => {
backendSrvMock.search = jest.fn(); backendSrvMock.search = jest.fn();
backendSrvMock.search.mockReturnValue(Promise.resolve([])); backendSrvMock.search.mockReturnValue(Promise.resolve([]));
return searchSrv.search({ tag: ['atag'] }).then(() => {}); return searchSrv.search({ tag: ["atag"] }).then(() => {});
}); });
it('should send tags query to backend search', () => { it("should send tags query to backend search", () => {
expect(backendSrvMock.search.mock.calls[0][0].tag).toHaveLength(1); expect(backendSrvMock.search.mock.calls[0][0].tag).toHaveLength(1);
}); });
}); });
describe('with starred', () => { describe("with starred", () => {
beforeEach(() => { beforeEach(() => {
backendSrvMock.search = jest.fn(); backendSrvMock.search = jest.fn();
backendSrvMock.search.mockReturnValue(Promise.resolve([])); backendSrvMock.search.mockReturnValue(Promise.resolve([]));
@@ -240,12 +244,12 @@ describe('SearchSrv', () => {
return searchSrv.search({ starred: true }).then(() => {}); return searchSrv.search({ starred: true }).then(() => {});
}); });
it('should send starred query to backend search', () => { it("should send starred query to backend search", () => {
expect(backendSrvMock.search.mock.calls[0][0].starred).toEqual(true); expect(backendSrvMock.search.mock.calls[0][0].starred).toEqual(true);
}); });
}); });
describe('when skipping recent dashboards', () => { describe("when skipping recent dashboards", () => {
let getRecentDashboardsCalled = false; let getRecentDashboardsCalled = false;
beforeEach(() => { beforeEach(() => {
@@ -259,12 +263,12 @@ describe('SearchSrv', () => {
return searchSrv.search({ skipRecent: true }).then(() => {}); return searchSrv.search({ skipRecent: true }).then(() => {});
}); });
it('should not fetch recent dashboards', () => { it("should not fetch recent dashboards", () => {
expect(getRecentDashboardsCalled).toBeFalsy(); expect(getRecentDashboardsCalled).toBeFalsy();
}); });
}); });
describe('when skipping starred dashboards', () => { describe("when skipping starred dashboards", () => {
let getStarredCalled = false; let getStarredCalled = false;
beforeEach(() => { beforeEach(() => {
@@ -279,7 +283,7 @@ describe('SearchSrv', () => {
return searchSrv.search({ skipStarred: true }).then(() => {}); return searchSrv.search({ skipStarred: true }).then(() => {});
}); });
it('should not fetch starred dashboards', () => { it("should not fetch starred dashboards", () => {
expect(getStarredCalled).toBeFalsy(); expect(getStarredCalled).toBeFalsy();
}); });
}); });

View File

@@ -1,4 +1,4 @@
import store from '../store'; import store from "../store";
Object.assign(window, { Object.assign(window, {
localStorage: { localStorage: {
@@ -8,37 +8,33 @@ Object.assign(window, {
} }
}); });
describe('store', () => { describe("store", () => {
it("should store", () => {
it("should store", ()=> {
store.set("key1", "123"); store.set("key1", "123");
expect(store.get("key1")).toBe("123"); expect(store.get("key1")).toBe("123");
}); });
it("get key when undefined", ()=> { it("get key when undefined", () => {
expect(store.get("key2")).toBe(undefined); expect(store.get("key2")).toBe(undefined);
}); });
it("check if key exixts", ()=> { it("check if key exixts", () => {
store.set("key3", "123"); store.set("key3", "123");
expect(store.exists("key3")).toBe(true); expect(store.exists("key3")).toBe(true);
}); });
it("get boolean when no key", ()=> { it("get boolean when no key", () => {
expect(store.getBool("key4", false)).toBe(false); expect(store.getBool("key4", false)).toBe(false);
}); });
it("get boolean", ()=> { it("get boolean", () => {
store.set("key5", "true"); store.set("key5", "true");
expect(store.getBool("key5", false)).toBe(true); expect(store.getBool("key5", false)).toBe(true);
}); });
it("key should be deleted", ()=> { it("key should be deleted", () => {
store.set("key6", "123"); store.set("key6", "123");
store.delete("key6"); store.delete("key6");
expect(store.exists("key6")).toBe(false); expect(store.exists("key6")).toBe(false);
}); });
}); });

View File

@@ -1,9 +1,9 @@
import TableModel from 'app/core/table_model'; import TableModel from "app/core/table_model";
describe('when sorting table desc', () => { describe("when sorting table desc", () => {
var table; var table;
var panel = { var panel = {
sort: {col: 0, desc: true}, sort: { col: 0, desc: true }
}; };
beforeEach(() => { beforeEach(() => {
@@ -13,23 +13,22 @@ describe('when sorting table desc', () => {
table.sort(panel.sort); table.sort(panel.sort);
}); });
it('should sort by time', () => { it("should sort by time", () => {
expect(table.rows[0][0]).toBe(105); expect(table.rows[0][0]).toBe(105);
expect(table.rows[1][0]).toBe(103); expect(table.rows[1][0]).toBe(103);
expect(table.rows[2][0]).toBe(100); expect(table.rows[2][0]).toBe(100);
}); });
it ('should mark column being sorted', () => { it("should mark column being sorted", () => {
expect(table.columns[0].sort).toBe(true); expect(table.columns[0].sort).toBe(true);
expect(table.columns[0].desc).toBe(true); expect(table.columns[0].desc).toBe(true);
}); });
}); });
describe('when sorting table asc', () => { describe("when sorting table asc", () => {
var table; var table;
var panel = { var panel = {
sort: {col: 1, desc: false}, sort: { col: 1, desc: false }
}; };
beforeEach(() => { beforeEach(() => {
@@ -39,11 +38,9 @@ describe('when sorting table asc', () => {
table.sort(panel.sort); table.sort(panel.sort);
}); });
it('should sort by time', () => { it("should sort by time", () => {
expect(table.rows[0][1]).toBe(10); expect(table.rows[0][1]).toBe(10);
expect(table.rows[1][1]).toBe(11); expect(table.rows[1][1]).toBe(11);
expect(table.rows[2][1]).toBe(15); expect(table.rows[2][1]).toBe(15);
}); });
}); });

View File

@@ -1,292 +1,303 @@
import TimeSeries from 'app/core/time_series2'; import TimeSeries from "app/core/time_series2";
describe("TimeSeries", function() { describe("TimeSeries", function() {
var points, series; var points, series;
var yAxisFormats = ['short', 'ms']; var yAxisFormats = ["short", "ms"];
var testData; var testData;
beforeEach(function() { beforeEach(function() {
testData = { testData = {
alias: 'test', alias: "test",
datapoints: [ datapoints: [[1, 2], [null, 3], [10, 4], [8, 5]]
[1,2],[null,3],[10,4],[8,5]
]
}; };
}); });
describe('when getting flot pairs', function() { describe("when getting flot pairs", function() {
it('with connected style, should ignore nulls', function() { it("with connected style, should ignore nulls", function() {
series = new TimeSeries(testData); series = new TimeSeries(testData);
points = series.getFlotPairs('connected', yAxisFormats); points = series.getFlotPairs("connected", yAxisFormats);
expect(points.length).toBe(3); expect(points.length).toBe(3);
}); });
it('with null as zero style, should replace nulls with zero', function() { it("with null as zero style, should replace nulls with zero", function() {
series = new TimeSeries(testData); series = new TimeSeries(testData);
points = series.getFlotPairs('null as zero', yAxisFormats); points = series.getFlotPairs("null as zero", yAxisFormats);
expect(points.length).toBe(4); expect(points.length).toBe(4);
expect(points[1][1]).toBe(0); expect(points[1][1]).toBe(0);
}); });
it('if last is null current should pick next to last', function() { it("if last is null current should pick next to last", function() {
series = new TimeSeries({ series = new TimeSeries({
datapoints: [[10,1], [null, 2]] datapoints: [[10, 1], [null, 2]]
}); });
series.getFlotPairs('null', yAxisFormats); series.getFlotPairs("null", yAxisFormats);
expect(series.stats.current).toBe(10); expect(series.stats.current).toBe(10);
}); });
it('max value should work for negative values', function() { it("max value should work for negative values", function() {
series = new TimeSeries({ series = new TimeSeries({
datapoints: [[-10,1], [-4, 2]] datapoints: [[-10, 1], [-4, 2]]
}); });
series.getFlotPairs('null', yAxisFormats); series.getFlotPairs("null", yAxisFormats);
expect(series.stats.max).toBe(-4); expect(series.stats.max).toBe(-4);
}); });
it('average value should ignore nulls', function() { it("average value should ignore nulls", function() {
series = new TimeSeries(testData); series = new TimeSeries(testData);
series.getFlotPairs('null', yAxisFormats); series.getFlotPairs("null", yAxisFormats);
expect(series.stats.avg).toBe(6.333333333333333); expect(series.stats.avg).toBe(6.333333333333333);
}); });
it('the delta value should account for nulls', function() { it("the delta value should account for nulls", function() {
series = new TimeSeries({ series = new TimeSeries({
datapoints: [[1,2],[3,3],[null,4],[10,5],[15,6]] datapoints: [[1, 2], [3, 3], [null, 4], [10, 5], [15, 6]]
}); });
series.getFlotPairs('null', yAxisFormats); series.getFlotPairs("null", yAxisFormats);
expect(series.stats.delta).toBe(14); expect(series.stats.delta).toBe(14);
}); });
it('the delta value should account for nulls on first', function() { it("the delta value should account for nulls on first", function() {
series = new TimeSeries({ series = new TimeSeries({
datapoints: [[null,2],[1,3],[10,4],[15,5]] datapoints: [[null, 2], [1, 3], [10, 4], [15, 5]]
}); });
series.getFlotPairs('null', yAxisFormats); series.getFlotPairs("null", yAxisFormats);
expect(series.stats.delta).toBe(14); expect(series.stats.delta).toBe(14);
}); });
it('the delta value should account for nulls on last', function() { it("the delta value should account for nulls on last", function() {
series = new TimeSeries({ series = new TimeSeries({
datapoints: [[1,2],[5,3],[10,4],[null,5]] datapoints: [[1, 2], [5, 3], [10, 4], [null, 5]]
}); });
series.getFlotPairs('null', yAxisFormats); series.getFlotPairs("null", yAxisFormats);
expect(series.stats.delta).toBe(9); expect(series.stats.delta).toBe(9);
}); });
it('the delta value should account for resets', function() { it("the delta value should account for resets", function() {
series = new TimeSeries({ series = new TimeSeries({
datapoints: [[1,2],[5,3],[10,4],[0,5],[10,6]] datapoints: [[1, 2], [5, 3], [10, 4], [0, 5], [10, 6]]
}); });
series.getFlotPairs('null', yAxisFormats); series.getFlotPairs("null", yAxisFormats);
expect(series.stats.delta).toBe(19); expect(series.stats.delta).toBe(19);
}); });
it('the delta value should account for resets on last', function() { it("the delta value should account for resets on last", function() {
series = new TimeSeries({ series = new TimeSeries({
datapoints: [[1,2],[2,3],[10,4],[8,5]] datapoints: [[1, 2], [2, 3], [10, 4], [8, 5]]
}); });
series.getFlotPairs('null', yAxisFormats); series.getFlotPairs("null", yAxisFormats);
expect(series.stats.delta).toBe(17); expect(series.stats.delta).toBe(17);
}); });
it('the range value should be max - min', function() { it("the range value should be max - min", function() {
series = new TimeSeries(testData); series = new TimeSeries(testData);
series.getFlotPairs('null', yAxisFormats); series.getFlotPairs("null", yAxisFormats);
expect(series.stats.range).toBe(9); expect(series.stats.range).toBe(9);
}); });
it('first value should ingone nulls', function() { it("first value should ingone nulls", function() {
series = new TimeSeries(testData); series = new TimeSeries(testData);
series.getFlotPairs('null', yAxisFormats); series.getFlotPairs("null", yAxisFormats);
expect(series.stats.first).toBe(1); expect(series.stats.first).toBe(1);
series = new TimeSeries({ series = new TimeSeries({
datapoints: [[null,2],[1,3],[10,4],[8,5]] datapoints: [[null, 2], [1, 3], [10, 4], [8, 5]]
}); });
series.getFlotPairs('null', yAxisFormats); series.getFlotPairs("null", yAxisFormats);
expect(series.stats.first).toBe(1); expect(series.stats.first).toBe(1);
}); });
it('with null as zero style, average value should treat nulls as 0', function() { it("with null as zero style, average value should treat nulls as 0", function() {
series = new TimeSeries(testData); series = new TimeSeries(testData);
series.getFlotPairs('null as zero', yAxisFormats); series.getFlotPairs("null as zero", yAxisFormats);
expect(series.stats.avg).toBe(4.75); expect(series.stats.avg).toBe(4.75);
}); });
it('average value should be null if all values is null', function() { it("average value should be null if all values is null", function() {
series = new TimeSeries({ series = new TimeSeries({
datapoints: [[null,2],[null,3],[null,4],[null,5]] datapoints: [[null, 2], [null, 3], [null, 4], [null, 5]]
}); });
series.getFlotPairs('null'); series.getFlotPairs("null");
expect(series.stats.avg).toBe(null); expect(series.stats.avg).toBe(null);
}); });
}); });
describe('When checking if ms resolution is needed', function() { describe("When checking if ms resolution is needed", function() {
describe('msResolution with second resolution timestamps', function() { describe("msResolution with second resolution timestamps", function() {
beforeEach(function() { beforeEach(function() {
series = new TimeSeries({datapoints: [[45, 1234567890], [60, 1234567899]]}); series = new TimeSeries({
datapoints: [[45, 1234567890], [60, 1234567899]]
});
}); });
it('should set hasMsResolution to false', function() { it("should set hasMsResolution to false", function() {
expect(series.hasMsResolution).toBe(false); expect(series.hasMsResolution).toBe(false);
}); });
}); });
describe('msResolution with millisecond resolution timestamps', function() { describe("msResolution with millisecond resolution timestamps", function() {
beforeEach(function() { beforeEach(function() {
series = new TimeSeries({datapoints: [[55, 1236547890001], [90, 1234456709000]]}); series = new TimeSeries({
datapoints: [[55, 1236547890001], [90, 1234456709000]]
});
}); });
it('should show millisecond resolution tooltip', function() { it("should show millisecond resolution tooltip", function() {
expect(series.hasMsResolution).toBe(true); expect(series.hasMsResolution).toBe(true);
}); });
}); });
describe('msResolution with millisecond resolution timestamps but with trailing zeroes', function() { describe("msResolution with millisecond resolution timestamps but with trailing zeroes", function() {
beforeEach(function() { beforeEach(function() {
series = new TimeSeries({datapoints: [[45, 1234567890000], [60, 1234567899000]]}); series = new TimeSeries({
datapoints: [[45, 1234567890000], [60, 1234567899000]]
});
}); });
it('should not show millisecond resolution tooltip', function() { it("should not show millisecond resolution tooltip", function() {
expect(series.hasMsResolution).toBe(false); expect(series.hasMsResolution).toBe(false);
}); });
}); });
}); });
describe('can detect if series contains ms precision', function() { describe("can detect if series contains ms precision", function() {
var fakedata; var fakedata;
beforeEach(function() { beforeEach(function() {
fakedata = testData; fakedata = testData;
}); });
it('missing datapoint with ms precision', function() { it("missing datapoint with ms precision", function() {
fakedata.datapoints[0] = [1337, 1234567890000]; fakedata.datapoints[0] = [1337, 1234567890000];
series = new TimeSeries(fakedata); series = new TimeSeries(fakedata);
expect(series.isMsResolutionNeeded()).toBe(false); expect(series.isMsResolutionNeeded()).toBe(false);
}); });
it('contains datapoint with ms precision', function() { it("contains datapoint with ms precision", function() {
fakedata.datapoints[0] = [1337, 1236547890001]; fakedata.datapoints[0] = [1337, 1236547890001];
series = new TimeSeries(fakedata); series = new TimeSeries(fakedata);
expect(series.isMsResolutionNeeded()).toBe(true); expect(series.isMsResolutionNeeded()).toBe(true);
}); });
}); });
describe('series overrides', function() { describe("series overrides", function() {
var series; var series;
beforeEach(function() { beforeEach(function() {
series = new TimeSeries(testData); series = new TimeSeries(testData);
}); });
describe('fill & points', function() { describe("fill & points", function() {
beforeEach(function() { beforeEach(function() {
series.alias = 'test'; series.alias = "test";
series.applySeriesOverrides([{ alias: 'test', fill: 0, points: true }]); series.applySeriesOverrides([{ alias: "test", fill: 0, points: true }]);
}); });
it('should set fill zero, and enable points', function() { it("should set fill zero, and enable points", function() {
expect(series.lines.fill).toBe(0.001); expect(series.lines.fill).toBe(0.001);
expect(series.points.show).toBe(true); expect(series.points.show).toBe(true);
}); });
}); });
describe('series option overrides, bars, true & lines false', function() { describe("series option overrides, bars, true & lines false", function() {
beforeEach(function() { beforeEach(function() {
series.alias = 'test'; series.alias = "test";
series.applySeriesOverrides([{ alias: 'test', bars: true, lines: false }]); series.applySeriesOverrides([
{ alias: "test", bars: true, lines: false }
]);
}); });
it('should disable lines, and enable bars', function() { it("should disable lines, and enable bars", function() {
expect(series.lines.show).toBe(false); expect(series.lines.show).toBe(false);
expect(series.bars.show).toBe(true); expect(series.bars.show).toBe(true);
}); });
}); });
describe('series option overrides, linewidth, stack', function() { describe("series option overrides, linewidth, stack", function() {
beforeEach(function() { beforeEach(function() {
series.alias = 'test'; series.alias = "test";
series.applySeriesOverrides([{ alias: 'test', linewidth: 5, stack: false }]); series.applySeriesOverrides([
{ alias: "test", linewidth: 5, stack: false }
]);
}); });
it('should disable stack, and set lineWidth', function() { it("should disable stack, and set lineWidth", function() {
expect(series.stack).toBe(false); expect(series.stack).toBe(false);
expect(series.lines.lineWidth).toBe(5); expect(series.lines.lineWidth).toBe(5);
}); });
}); });
describe('series option overrides, dashes and lineWidth', function() { describe("series option overrides, dashes and lineWidth", function() {
beforeEach(function() { beforeEach(function() {
series.alias = 'test'; series.alias = "test";
series.applySeriesOverrides([{ alias: 'test', linewidth: 5, dashes: true }]); series.applySeriesOverrides([
{ alias: "test", linewidth: 5, dashes: true }
]);
}); });
it('should enable dashes, set dashes lineWidth to 5 and lines lineWidth to 0', function() { it("should enable dashes, set dashes lineWidth to 5 and lines lineWidth to 0", function() {
expect(series.dashes.show).toBe(true); expect(series.dashes.show).toBe(true);
expect(series.dashes.lineWidth).toBe(5); expect(series.dashes.lineWidth).toBe(5);
expect(series.lines.lineWidth).toBe(0); expect(series.lines.lineWidth).toBe(0);
}); });
}); });
describe('series option overrides, fill below to', function() { describe("series option overrides, fill below to", function() {
beforeEach(function() { beforeEach(function() {
series.alias = 'test'; series.alias = "test";
series.applySeriesOverrides([{ alias: 'test', fillBelowTo: 'min' }]); series.applySeriesOverrides([{ alias: "test", fillBelowTo: "min" }]);
}); });
it('should disable line fill and add fillBelowTo', function() { it("should disable line fill and add fillBelowTo", function() {
expect(series.fillBelowTo).toBe('min'); expect(series.fillBelowTo).toBe("min");
}); });
}); });
describe('series option overrides, pointradius, steppedLine', function() { describe("series option overrides, pointradius, steppedLine", function() {
beforeEach(function() { beforeEach(function() {
series.alias = 'test'; series.alias = "test";
series.applySeriesOverrides([{ alias: 'test', pointradius: 5, steppedLine: true }]); series.applySeriesOverrides([
{ alias: "test", pointradius: 5, steppedLine: true }
]);
}); });
it('should set pointradius, and set steppedLine', function() { it("should set pointradius, and set steppedLine", function() {
expect(series.points.radius).toBe(5); expect(series.points.radius).toBe(5);
expect(series.lines.steps).toBe(true); expect(series.lines.steps).toBe(true);
}); });
}); });
describe('override match on regex', function() { describe("override match on regex", function() {
beforeEach(function() { beforeEach(function() {
series.alias = 'test_01'; series.alias = "test_01";
series.applySeriesOverrides([{ alias: '/.*01/', lines: false }]); series.applySeriesOverrides([{ alias: "/.*01/", lines: false }]);
}); });
it('should match second series', function() { it("should match second series", function() {
expect(series.lines.show).toBe(false); expect(series.lines.show).toBe(false);
}); });
}); });
describe('override series y-axis, and z-index', function() { describe("override series y-axis, and z-index", function() {
beforeEach(function() { beforeEach(function() {
series.alias = 'test'; series.alias = "test";
series.applySeriesOverrides([{ alias: 'test', yaxis: 2, zindex: 2 }]); series.applySeriesOverrides([{ alias: "test", yaxis: 2, zindex: 2 }]);
}); });
it('should set yaxis', function() { it("should set yaxis", function() {
expect(series.yaxis).toBe(2); expect(series.yaxis).toBe(2);
}); });
it('should set zindex', function() { it("should set zindex", function() {
expect(series.zindex).toBe(2); expect(series.zindex).toBe(2);
}); });
}); });
}); });
describe('value formatter', function() { describe("value formatter", function() {
var series; var series;
beforeEach(function() { beforeEach(function() {
series = new TimeSeries(testData); series = new TimeSeries(testData);
}); });
it('should format non-numeric values as empty string', function() { it("should format non-numeric values as empty string", function() {
expect(series.formatValue(null)).toBe(""); expect(series.formatValue(null)).toBe("");
expect(series.formatValue(undefined)).toBe(""); expect(series.formatValue(undefined)).toBe("");
expect(series.formatValue(NaN)).toBe(""); expect(series.formatValue(NaN)).toBe("");
@@ -294,5 +305,4 @@ describe("TimeSeries", function() {
expect(series.formatValue(-Infinity)).toBe(""); expect(series.formatValue(-Infinity)).toBe("");
}); });
}); });
}); });

View File

@@ -1,5 +1,12 @@
import {describe, beforeEach, it, expect, angularMocks, sinon} from 'test/lib/common'; import {
import 'app/core/directives/value_select_dropdown'; describe,
beforeEach,
it,
expect,
angularMocks,
sinon
} from "test/lib/common";
import "app/core/directives/value_select_dropdown";
describe("SelectDropdownCtrl", function() { describe("SelectDropdownCtrl", function() {
var scope; var scope;
@@ -8,23 +15,25 @@ describe("SelectDropdownCtrl", function() {
var rootScope; var rootScope;
var q; var q;
beforeEach(angularMocks.module('grafana.core')); beforeEach(angularMocks.module("grafana.core"));
beforeEach(angularMocks.inject(function($controller, $rootScope, $q, $httpBackend) { beforeEach(
rootScope = $rootScope; angularMocks.inject(function($controller, $rootScope, $q, $httpBackend) {
q = $q; rootScope = $rootScope;
scope = $rootScope.$new(); q = $q;
ctrl = $controller('ValueSelectDropdownCtrl', {$scope: scope}); scope = $rootScope.$new();
ctrl.onUpdated = sinon.spy(); ctrl = $controller("ValueSelectDropdownCtrl", { $scope: scope });
$httpBackend.when('GET', /\.html$/).respond(''); ctrl.onUpdated = sinon.spy();
})); $httpBackend.when("GET", /\.html$/).respond("");
})
);
describe("Given simple variable", function() { describe("Given simple variable", function() {
beforeEach(function() { beforeEach(function() {
ctrl.variable = { ctrl.variable = {
current: {text: 'hej', value: 'hej' }, current: { text: "hej", value: "hej" },
getValuesForTag: function(key) { getValuesForTag: function(key) {
return q.when(tagValuesMap[key]); return q.when(tagValuesMap[key]);
}, }
}; };
ctrl.init(); ctrl.init();
}); });
@@ -37,11 +46,11 @@ describe("SelectDropdownCtrl", function() {
describe("Given variable with tags and dropdown is opened", function() { describe("Given variable with tags and dropdown is opened", function() {
beforeEach(function() { beforeEach(function() {
ctrl.variable = { ctrl.variable = {
current: {text: 'server-1', value: 'server-1'}, current: { text: "server-1", value: "server-1" },
options: [ options: [
{text: 'server-1', value: 'server-1', selected: true}, { text: "server-1", value: "server-1", selected: true },
{text: 'server-2', value: 'server-2'}, { text: "server-2", value: "server-2" },
{text: 'server-3', value: 'server-3'}, { text: "server-3", value: "server-3" }
], ],
tags: ["key1", "key2", "key3"], tags: ["key1", "key2", "key3"],
getValuesForTag: function(key) { getValuesForTag: function(key) {
@@ -49,9 +58,9 @@ describe("SelectDropdownCtrl", function() {
}, },
multi: true multi: true
}; };
tagValuesMap.key1 = ['server-1', 'server-3']; tagValuesMap.key1 = ["server-1", "server-3"];
tagValuesMap.key2 = ['server-2', 'server-3']; tagValuesMap.key2 = ["server-2", "server-3"];
tagValuesMap.key3 = ['server-1', 'server-2', 'server-3']; tagValuesMap.key3 = ["server-1", "server-2", "server-3"];
ctrl.init(); ctrl.init();
ctrl.show(); ctrl.show();
}); });
@@ -70,21 +79,21 @@ describe("SelectDropdownCtrl", function() {
}); });
it("should set linkText", function() { it("should set linkText", function() {
expect(ctrl.linkText).to.be('server-1'); expect(ctrl.linkText).to.be("server-1");
}); });
describe('after adititional value is selected', function() { describe("after adititional value is selected", function() {
beforeEach(function() { beforeEach(function() {
ctrl.selectValue(ctrl.options[2], {}); ctrl.selectValue(ctrl.options[2], {});
ctrl.commitChanges(); ctrl.commitChanges();
}); });
it('should update link text', function() { it("should update link text", function() {
expect(ctrl.linkText).to.be('server-1 + server-3'); expect(ctrl.linkText).to.be("server-1 + server-3");
}); });
}); });
describe('When tag is selected', function() { describe("When tag is selected", function() {
beforeEach(function() { beforeEach(function() {
ctrl.selectTag(ctrl.tags[0]); ctrl.selectTag(ctrl.tags[0]);
rootScope.$digest(); rootScope.$digest();
@@ -101,10 +110,10 @@ describe("SelectDropdownCtrl", function() {
}); });
it("link text should not include tag values", function() { it("link text should not include tag values", function() {
expect(ctrl.linkText).to.be(''); expect(ctrl.linkText).to.be("");
}); });
describe('and then dropdown is opened and closed without changes', function() { describe("and then dropdown is opened and closed without changes", function() {
beforeEach(function() { beforeEach(function() {
ctrl.show(); ctrl.show();
ctrl.commitChanges(); ctrl.commitChanges();
@@ -116,7 +125,7 @@ describe("SelectDropdownCtrl", function() {
}); });
}); });
describe('and then unselected', function() { describe("and then unselected", function() {
beforeEach(function() { beforeEach(function() {
ctrl.selectTag(ctrl.tags[0]); ctrl.selectTag(ctrl.tags[0]);
rootScope.$digest(); rootScope.$digest();
@@ -127,7 +136,7 @@ describe("SelectDropdownCtrl", function() {
}); });
}); });
describe('and then value is unselected', function() { describe("and then value is unselected", function() {
beforeEach(function() { beforeEach(function() {
ctrl.selectValue(ctrl.options[0], {}); ctrl.selectValue(ctrl.options[0], {});
}); });
@@ -142,11 +151,15 @@ describe("SelectDropdownCtrl", function() {
describe("Given variable with selected tags", function() { describe("Given variable with selected tags", function() {
beforeEach(function() { beforeEach(function() {
ctrl.variable = { ctrl.variable = {
current: {text: 'server-1', value: 'server-1', tags: [{text: 'key1', selected: true}] }, current: {
text: "server-1",
value: "server-1",
tags: [{ text: "key1", selected: true }]
},
options: [ options: [
{text: 'server-1', value: 'server-1'}, { text: "server-1", value: "server-1" },
{text: 'server-2', value: 'server-2'}, { text: "server-2", value: "server-2" },
{text: 'server-3', value: 'server-3'}, { text: "server-3", value: "server-3" }
], ],
tags: ["key1", "key2", "key3"], tags: ["key1", "key2", "key3"],
getValuesForTag: function(key) { getValuesForTag: function(key) {
@@ -161,7 +174,5 @@ describe("SelectDropdownCtrl", function() {
it("should set tag as selected", function() { it("should set tag as selected", function() {
expect(ctrl.tags[0].selected).to.be(true); expect(ctrl.tags[0].selected).to.be(true);
}); });
}); });
}); });

View File

@@ -1,5 +1,4 @@
export class Store { export class Store {
get(key) { get(key) {
return window.localStorage[key]; return window.localStorage[key];
} }
@@ -12,7 +11,7 @@ export class Store {
if (def !== void 0 && !this.exists(key)) { if (def !== void 0 && !this.exists(key)) {
return def; return def;
} }
return window.localStorage[key] === 'true'; return window.localStorage[key] === "true";
} }
exists(key) { exists(key) {
@@ -22,7 +21,6 @@ export class Store {
delete(key) { delete(key) {
window.localStorage.removeItem(key); window.localStorage.removeItem(key);
} }
} }
const store = new Store(); const store = new Store();

View File

@@ -1,4 +1,3 @@
export default class TableModel { export default class TableModel {
columns: any[]; columns: any[];
rows: any[]; rows: any[];
@@ -9,7 +8,7 @@ export default class TableModel {
this.columns = []; this.columns = [];
this.columnMap = {}; this.columnMap = {};
this.rows = []; this.rows = [];
this.type = 'table'; this.type = "table";
} }
sort(options) { sort(options) {

View File

@@ -1,11 +1,13 @@
import kbn from 'app/core/utils/kbn'; import kbn from "app/core/utils/kbn";
import {getFlotTickDecimals} from 'app/core/utils/ticks'; import { getFlotTickDecimals } from "app/core/utils/ticks";
import _ from 'lodash'; import _ from "lodash";
function matchSeriesOverride(aliasOrRegex, seriesAlias) { function matchSeriesOverride(aliasOrRegex, seriesAlias) {
if (!aliasOrRegex) { return false; } if (!aliasOrRegex) {
return false;
}
if (aliasOrRegex[0] === '/') { if (aliasOrRegex[0] === "/") {
var regex = kbn.stringToJsRegex(aliasOrRegex); var regex = kbn.stringToJsRegex(aliasOrRegex);
return seriesAlias.match(regex) != null; return seriesAlias.match(regex) != null;
} }
@@ -14,7 +16,7 @@ function matchSeriesOverride(aliasOrRegex, seriesAlias) {
} }
function translateFillOption(fill) { function translateFillOption(fill) {
return fill === 0 ? 0.001 : fill/10; return fill === 0 ? 0.001 : fill / 10;
} }
/** /**
@@ -27,7 +29,7 @@ export function updateLegendValues(data: TimeSeries[], panel) {
let series = data[i]; let series = data[i];
let yaxes = panel.yaxes; let yaxes = panel.yaxes;
let axis = yaxes[series.yaxis - 1]; let axis = yaxes[series.yaxis - 1];
let {tickDecimals, scaledDecimals} = getFlotTickDecimals(data, axis); let { tickDecimals, scaledDecimals } = getFlotTickDecimals(data, axis);
let formater = kbn.valueFormats[panel.yaxes[series.yaxis - 1].format]; let formater = kbn.valueFormats[panel.yaxes[series.yaxis - 1].format];
// decimal override // decimal override
@@ -56,7 +58,7 @@ export function getDataMinMax(data: TimeSeries[]) {
} }
} }
return {datamin, datamax}; return { datamin, datamax };
} }
export default class TimeSeries { export default class TimeSeries {
@@ -120,29 +122,59 @@ export default class TimeSeries {
if (!matchSeriesOverride(override.alias, this.alias)) { if (!matchSeriesOverride(override.alias, this.alias)) {
continue; continue;
} }
if (override.lines !== void 0) { this.lines.show = override.lines; } if (override.lines !== void 0) {
this.lines.show = override.lines;
}
if (override.dashes !== void 0) { if (override.dashes !== void 0) {
this.dashes.show = override.dashes; this.dashes.show = override.dashes;
this.lines.lineWidth = 0; this.lines.lineWidth = 0;
}
if (override.points !== void 0) {
this.points.show = override.points;
}
if (override.bars !== void 0) {
this.bars.show = override.bars;
}
if (override.fill !== void 0) {
this.lines.fill = translateFillOption(override.fill);
}
if (override.stack !== void 0) {
this.stack = override.stack;
} }
if (override.points !== void 0) { this.points.show = override.points; }
if (override.bars !== void 0) { this.bars.show = override.bars; }
if (override.fill !== void 0) { this.lines.fill = translateFillOption(override.fill); }
if (override.stack !== void 0) { this.stack = override.stack; }
if (override.linewidth !== void 0) { if (override.linewidth !== void 0) {
this.lines.lineWidth = this.dashes.show ? 0: override.linewidth; this.lines.lineWidth = this.dashes.show ? 0 : override.linewidth;
this.dashes.lineWidth = override.linewidth; this.dashes.lineWidth = override.linewidth;
}
if (override.dashLength !== void 0) {
this.dashes.dashLength[0] = override.dashLength;
}
if (override.spaceLength !== void 0) {
this.dashes.dashLength[1] = override.spaceLength;
}
if (override.nullPointMode !== void 0) {
this.nullPointMode = override.nullPointMode;
}
if (override.pointradius !== void 0) {
this.points.radius = override.pointradius;
}
if (override.steppedLine !== void 0) {
this.lines.steps = override.steppedLine;
}
if (override.zindex !== void 0) {
this.zindex = override.zindex;
}
if (override.fillBelowTo !== void 0) {
this.fillBelowTo = override.fillBelowTo;
}
if (override.color !== void 0) {
this.color = override.color;
}
if (override.transform !== void 0) {
this.transform = override.transform;
}
if (override.legend !== void 0) {
this.legend = override.legend;
} }
if (override.dashLength !== void 0) { this.dashes.dashLength[0] = override.dashLength; }
if (override.spaceLength !== void 0) { this.dashes.dashLength[1] = override.spaceLength; }
if (override.nullPointMode !== void 0) { this.nullPointMode = override.nullPointMode; }
if (override.pointradius !== void 0) { this.points.radius = override.pointradius; }
if (override.steppedLine !== void 0) { this.lines.steps = override.steppedLine; }
if (override.zindex !== void 0) { this.zindex = override.zindex; }
if (override.fillBelowTo !== void 0) { this.fillBelowTo = override.fillBelowTo; }
if (override.color !== void 0) { this.color = override.color; }
if (override.transform !== void 0) { this.transform = override.transform; }
if (override.legend !== void 0) { this.legend = override.legend; }
if (override.yaxis !== void 0) { if (override.yaxis !== void 0) {
this.yaxis = override.yaxis; this.yaxis = override.yaxis;
@@ -167,8 +199,8 @@ export default class TimeSeries {
this.allIsNull = true; this.allIsNull = true;
this.allIsZero = true; this.allIsZero = true;
var ignoreNulls = fillStyle === 'connected'; var ignoreNulls = fillStyle === "connected";
var nullAsZero = fillStyle === 'null as zero'; var nullAsZero = fillStyle === "null as zero";
var currentTime; var currentTime;
var currentValue; var currentValue;
var nonNulls = 0; var nonNulls = 0;
@@ -191,7 +223,9 @@ export default class TimeSeries {
previousTime = currentTime; previousTime = currentTime;
if (currentValue === null) { if (currentValue === null) {
if (ignoreNulls) { continue; } if (ignoreNulls) {
continue;
}
if (nullAsZero) { if (nullAsZero) {
currentValue = 0; currentValue = 0;
} }
@@ -215,16 +249,18 @@ export default class TimeSeries {
if (this.stats.first === null) { if (this.stats.first === null) {
this.stats.first = currentValue; this.stats.first = currentValue;
} else { } else {
if (previousValue > currentValue) { // counter reset if (previousValue > currentValue) {
// counter reset
previousDeltaUp = false; previousDeltaUp = false;
if (i === this.datapoints.length-1) { // reset on last if (i === this.datapoints.length - 1) {
this.stats.delta += currentValue; // reset on last
this.stats.delta += currentValue;
} }
} else { } else {
if (previousDeltaUp) { if (previousDeltaUp) {
this.stats.delta += currentValue - previousValue; // normal increment this.stats.delta += currentValue - previousValue; // normal increment
} else { } else {
this.stats.delta += currentValue; // account for counter reset this.stats.delta += currentValue; // account for counter reset
} }
previousDeltaUp = true; previousDeltaUp = true;
} }
@@ -243,14 +279,18 @@ export default class TimeSeries {
result.push([currentTime, currentValue]); result.push([currentTime, currentValue]);
} }
if (this.stats.max === -Number.MAX_VALUE) { this.stats.max = null; } if (this.stats.max === -Number.MAX_VALUE) {
if (this.stats.min === Number.MAX_VALUE) { this.stats.min = null; } this.stats.max = null;
}
if (this.stats.min === Number.MAX_VALUE) {
this.stats.min = null;
}
if (result.length && !this.allIsNull) { if (result.length && !this.allIsNull) {
this.stats.avg = (this.stats.total / nonNulls); this.stats.avg = this.stats.total / nonNulls;
this.stats.current = result[result.length-1][1]; this.stats.current = result[result.length - 1][1];
if (this.stats.current === null && result.length > 1) { if (this.stats.current === null && result.length > 1) {
this.stats.current = result[result.length-2][1]; this.stats.current = result[result.length - 2][1];
} }
} }
if (this.stats.max !== null && this.stats.min !== null) { if (this.stats.max !== null && this.stats.min !== null) {
@@ -281,7 +321,7 @@ export default class TimeSeries {
for (var i = 0; i < this.datapoints.length; i++) { for (var i = 0; i < this.datapoints.length; i++) {
if (this.datapoints[i][1] !== null) { if (this.datapoints[i][1] !== null) {
var timestamp = this.datapoints[i][1].toString(); var timestamp = this.datapoints[i][1].toString();
if (timestamp.length === 13 && (timestamp % 1000) !== 0) { if (timestamp.length === 13 && timestamp % 1000 !== 0) {
return true; return true;
} }
} }

View File

@@ -1,31 +1,80 @@
import _ from 'lodash'; import _ from "lodash";
import tinycolor from 'tinycolor2'; import tinycolor from "tinycolor2";
export const PALETTE_ROWS = 4; export const PALETTE_ROWS = 4;
export const PALETTE_COLUMNS = 14; export const PALETTE_COLUMNS = 14;
export const DEFAULT_ANNOTATION_COLOR = 'rgba(0, 211, 255, 1)'; export const DEFAULT_ANNOTATION_COLOR = "rgba(0, 211, 255, 1)";
export const OK_COLOR = "rgba(11, 237, 50, 1)"; export const OK_COLOR = "rgba(11, 237, 50, 1)";
export const ALERTING_COLOR = "rgba(237, 46, 24, 1)"; export const ALERTING_COLOR = "rgba(237, 46, 24, 1)";
export const NO_DATA_COLOR = "rgba(150, 150, 150, 1)"; export const NO_DATA_COLOR = "rgba(150, 150, 150, 1)";
export const REGION_FILL_ALPHA = 0.09; export const REGION_FILL_ALPHA = 0.09;
let colors = [ let colors = [
"#7EB26D","#EAB839","#6ED0E0","#EF843C","#E24D42","#1F78C1","#BA43A9","#705DA0", "#7EB26D",
"#508642","#CCA300","#447EBC","#C15C17","#890F02","#0A437C","#6D1F62","#584477", "#EAB839",
"#B7DBAB","#F4D598","#70DBED","#F9BA8F","#F29191","#82B5D8","#E5A8E2","#AEA2E0", "#6ED0E0",
"#629E51","#E5AC0E","#64B0C8","#E0752D","#BF1B00","#0A50A1","#962D82","#614D93", "#EF843C",
"#9AC48A","#F2C96D","#65C5DB","#F9934E","#EA6460","#5195CE","#D683CE","#806EB7", "#E24D42",
"#3F6833","#967302","#2F575E","#99440A","#58140C","#052B51","#511749","#3F2B5B", "#1F78C1",
"#E0F9D7","#FCEACA","#CFFAFF","#F9E2D2","#FCE2DE","#BADFF4","#F9D9F9","#DEDAF7" "#BA43A9",
"#705DA0",
"#508642",
"#CCA300",
"#447EBC",
"#C15C17",
"#890F02",
"#0A437C",
"#6D1F62",
"#584477",
"#B7DBAB",
"#F4D598",
"#70DBED",
"#F9BA8F",
"#F29191",
"#82B5D8",
"#E5A8E2",
"#AEA2E0",
"#629E51",
"#E5AC0E",
"#64B0C8",
"#E0752D",
"#BF1B00",
"#0A50A1",
"#962D82",
"#614D93",
"#9AC48A",
"#F2C96D",
"#65C5DB",
"#F9934E",
"#EA6460",
"#5195CE",
"#D683CE",
"#806EB7",
"#3F6833",
"#967302",
"#2F575E",
"#99440A",
"#58140C",
"#052B51",
"#511749",
"#3F2B5B",
"#E0F9D7",
"#FCEACA",
"#CFFAFF",
"#F9E2D2",
"#FCE2DE",
"#BADFF4",
"#F9D9F9",
"#DEDAF7"
]; ];
export function sortColorsByHue(hexColors) { export function sortColorsByHue(hexColors) {
let hslColors = _.map(hexColors, hexToHsl); let hslColors = _.map(hexColors, hexToHsl);
let sortedHSLColors = _.sortBy(hslColors, ['h']); let sortedHSLColors = _.sortBy(hslColors, ["h"]);
sortedHSLColors = _.chunk(sortedHSLColors, PALETTE_ROWS); sortedHSLColors = _.chunk(sortedHSLColors, PALETTE_ROWS);
sortedHSLColors = _.map(sortedHSLColors, chunk => { sortedHSLColors = _.map(sortedHSLColors, chunk => {
return _.sortBy(chunk, 'l'); return _.sortBy(chunk, "l");
}); });
sortedHSLColors = _.flattenDeep(_.zip(...sortedHSLColors)); sortedHSLColors = _.flattenDeep(_.zip(...sortedHSLColors));

View File

@@ -1,10 +1,10 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
var waitSeconds = 100; var waitSeconds = 100;
var head = document.getElementsByTagName('head')[0]; var head = document.getElementsByTagName("head")[0];
// get all link tags in the page // get all link tags in the page
var links = document.getElementsByTagName('link'); var links = document.getElementsByTagName("link");
var linkHrefs = []; var linkHrefs = [];
for (var i = 0; i < links.length; i++) { for (var i = 0; i < links.length; i++) {
linkHrefs.push(links[i].href); linkHrefs.push(links[i].href);
@@ -27,9 +27,9 @@ var noop = function() {};
var loadCSS = function(url) { var loadCSS = function(url) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
var link = document.createElement('link'); var link = document.createElement("link");
var timeout = setTimeout(function() { var timeout = setTimeout(function() {
reject('Unable to load CSS'); reject("Unable to load CSS");
}, waitSeconds * 1000); }, waitSeconds * 1000);
var _callback = function(error) { var _callback = function(error) {
@@ -39,23 +39,25 @@ var loadCSS = function(url) {
if (error) { if (error) {
reject(error); reject(error);
} else { } else {
resolve(''); resolve("");
} }
}, 7); }, 7);
}; };
link.type = 'text/css'; link.type = "text/css";
link.rel = 'stylesheet'; link.rel = "stylesheet";
link.href = url; link.href = url;
if (!isWebkit) { if (!isWebkit) {
link.onload = function() { _callback(undefined); }; link.onload = function() {
_callback(undefined);
};
} else { } else {
webkitLoadCheck(link, _callback); webkitLoadCheck(link, _callback);
} }
link.onerror = function(evt: any) { link.onerror = function(evt: any) {
_callback(evt.error || new Error('Error loading CSS file.')); _callback(evt.error || new Error("Error loading CSS file."));
}; };
head.appendChild(link); head.appendChild(link);
@@ -63,16 +65,15 @@ var loadCSS = function(url) {
}; };
export function fetch(load): any { export function fetch(load): any {
if (typeof window === 'undefined') { if (typeof window === "undefined") {
return ''; return "";
} }
// dont reload styles loaded in the head // dont reload styles loaded in the head
for (var i = 0; i < linkHrefs.length; i++) { for (var i = 0; i < linkHrefs.length; i++) {
if (load.address === linkHrefs[i]) { if (load.address === linkHrefs[i]) {
return ''; return "";
} }
} }
return loadCSS(load.address); return loadCSS(load.address);
} }

View File

@@ -1,32 +1,38 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import _ from 'lodash'; import _ from "lodash";
import moment from 'moment'; import moment from "moment";
var units = ['y', 'M', 'w', 'd', 'h', 'm', 's']; var units = ["y", "M", "w", "d", "h", "m", "s"];
export function parse(text, roundUp?, timezone?) { export function parse(text, roundUp?, timezone?) {
if (!text) { return undefined; } if (!text) {
if (moment.isMoment(text)) { return text; } return undefined;
if (_.isDate(text)) { return moment(text); } }
if (moment.isMoment(text)) {
return text;
}
if (_.isDate(text)) {
return moment(text);
}
var time; var time;
var mathString = ''; var mathString = "";
var index; var index;
var parseString; var parseString;
if (text.substring(0, 3) === 'now') { if (text.substring(0, 3) === "now") {
if (timezone === 'utc') { if (timezone === "utc") {
time = moment.utc(); time = moment.utc();
} else { } else {
time = moment(); time = moment();
} }
mathString = text.substring('now'.length); mathString = text.substring("now".length);
} else { } else {
index = text.indexOf('||'); index = text.indexOf("||");
if (index === -1) { if (index === -1) {
parseString = text; parseString = text;
mathString = ''; // nothing else mathString = ""; // nothing else
} else { } else {
parseString = text.substring(0, index); parseString = text.substring(0, index);
mathString = text.substring(index + 2); mathString = text.substring(index + 2);
@@ -66,11 +72,11 @@ export function parseDateMath(mathString, time, roundUp?) {
var num; var num;
var unit; var unit;
if (c === '/') { if (c === "/") {
type = 0; type = 0;
} else if (c === '+') { } else if (c === "+") {
type = 1; type = 1;
} else if (c === '-') { } else if (c === "-") {
type = 2; type = 2;
} else { } else {
return undefined; return undefined;
@@ -84,7 +90,9 @@ export function parseDateMath(mathString, time, roundUp?) {
var numFrom = i; var numFrom = i;
while (!isNaN(mathString.charAt(i))) { while (!isNaN(mathString.charAt(i))) {
i++; i++;
if (i > 10) { return undefined; } if (i > 10) {
return undefined;
}
} }
num = parseInt(mathString.substring(numFrom, i), 10); num = parseInt(mathString.substring(numFrom, i), 10);
} }
@@ -115,4 +123,3 @@ export function parseDateMath(mathString, time, roundUp?) {
} }
return dateTime; return dateTime;
} }

View File

@@ -1,72 +1,86 @@
import _ from 'lodash'; import _ from "lodash";
import moment from 'moment'; import moment from "moment";
import {saveAs} from 'file-saver'; import { saveAs } from "file-saver";
const DEFAULT_DATETIME_FORMAT = 'YYYY-MM-DDTHH:mm:ssZ'; const DEFAULT_DATETIME_FORMAT = "YYYY-MM-DDTHH:mm:ssZ";
export function exportSeriesListToCsv(seriesList, dateTimeFormat = DEFAULT_DATETIME_FORMAT, excel = false) { export function exportSeriesListToCsv(
var text = (excel ? 'sep=;\n' : '') + 'Series;Time;Value\n'; seriesList,
_.each(seriesList, function(series) { dateTimeFormat = DEFAULT_DATETIME_FORMAT,
_.each(series.datapoints, function(dp) { excel = false
text += series.alias + ';' + moment(dp[1]).format(dateTimeFormat) + ';' + dp[0] + '\n'; ) {
}); var text = (excel ? "sep=;\n" : "") + "Series;Time;Value\n";
_.each(seriesList, function(series) {
_.each(series.datapoints, function(dp) {
text +=
series.alias +
";" +
moment(dp[1]).format(dateTimeFormat) +
";" +
dp[0] +
"\n";
}); });
saveSaveBlob(text, 'grafana_data_export.csv'); });
saveSaveBlob(text, "grafana_data_export.csv");
} }
export function exportSeriesListToCsvColumns(seriesList, dateTimeFormat = DEFAULT_DATETIME_FORMAT, excel = false) { export function exportSeriesListToCsvColumns(
var text = (excel ? 'sep=;\n' : '') + 'Time;'; seriesList,
// add header dateTimeFormat = DEFAULT_DATETIME_FORMAT,
_.each(seriesList, function(series) { excel = false
text += series.alias + ';'; ) {
}); var text = (excel ? "sep=;\n" : "") + "Time;";
text = text.substring(0,text.length-1); // add header
text += '\n'; _.each(seriesList, function(series) {
text += series.alias + ";";
});
text = text.substring(0, text.length - 1);
text += "\n";
// process data // process data
var dataArr = [[]]; var dataArr = [[]];
var sIndex = 1; var sIndex = 1;
_.each(seriesList, function(series) { _.each(seriesList, function(series) {
var cIndex = 0; var cIndex = 0;
dataArr.push([]); dataArr.push([]);
_.each(series.datapoints, function(dp) { _.each(series.datapoints, function(dp) {
dataArr[0][cIndex] = moment(dp[1]).format(dateTimeFormat); dataArr[0][cIndex] = moment(dp[1]).format(dateTimeFormat);
dataArr[sIndex][cIndex] = dp[0]; dataArr[sIndex][cIndex] = dp[0];
cIndex++; cIndex++;
});
sIndex++;
}); });
sIndex++;
});
// make text // make text
for (var i = 0; i < dataArr[0].length; i++) { for (var i = 0; i < dataArr[0].length; i++) {
text += dataArr[0][i] + ';'; text += dataArr[0][i] + ";";
for (var j = 1; j < dataArr.length; j++) { for (var j = 1; j < dataArr.length; j++) {
text += dataArr[j][i] + ';'; text += dataArr[j][i] + ";";
}
text = text.substring(0,text.length-1);
text += '\n';
} }
saveSaveBlob(text, 'grafana_data_export.csv'); text = text.substring(0, text.length - 1);
text += "\n";
}
saveSaveBlob(text, "grafana_data_export.csv");
} }
export function exportTableDataToCsv(table, excel = false) { export function exportTableDataToCsv(table, excel = false) {
var text = excel ? 'sep=;\n' : ''; var text = excel ? "sep=;\n" : "";
// add header // add header
_.each(table.columns, function(column) { _.each(table.columns, function(column) {
text += (column.title || column.text) + ';'; text += (column.title || column.text) + ";";
});
text += "\n";
// process data
_.each(table.rows, function(row) {
_.each(row, function(value) {
text += value + ";";
}); });
text += '\n'; text += "\n";
// process data });
_.each(table.rows, function(row) { saveSaveBlob(text, "grafana_data_export.csv");
_.each(row, function(value) {
text += value + ';';
});
text += '\n';
});
saveSaveBlob(text, 'grafana_data_export.csv');
} }
export function saveSaveBlob(payload, fname) { export function saveSaveBlob(payload, fname) {
var blob = new Blob([payload], { type: "text/csv;charset=utf-8" }); var blob = new Blob([payload], { type: "text/csv;charset=utf-8" });
saveAs(blob, fname); saveAs(blob, fname);
} }

View File

@@ -4,7 +4,7 @@
export default function flatten(target, opts): any { export default function flatten(target, opts): any {
opts = opts || {}; opts = opts || {};
var delimiter = opts.delimiter || '.'; var delimiter = opts.delimiter || ".";
var maxDepth = opts.maxDepth || 3; var maxDepth = opts.maxDepth || 3;
var currentDepth = 1; var currentDepth = 1;
var output = {}; var output = {};
@@ -22,7 +22,12 @@ export default function flatten(target, opts): any {
maxDepth = currentDepth + 1; maxDepth = currentDepth + 1;
} }
if (!isarray && isobject && Object.keys(value).length && currentDepth < maxDepth) { if (
!isarray &&
isobject &&
Object.keys(value).length &&
currentDepth < maxDepth
) {
++currentDepth; ++currentDepth;
return step(value, newKey); return step(value, newKey);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,9 @@
export function assignModelProperties(target, source, defaults, removeDefaults?) { export function assignModelProperties(
target,
source,
defaults,
removeDefaults?
) {
for (var key in defaults) { for (var key in defaults) {
if (!defaults.hasOwnProperty(key)) { if (!defaults.hasOwnProperty(key)) {
continue; continue;
@@ -7,4 +12,3 @@ export function assignModelProperties(target, source, defaults, removeDefaults?)
target[key] = source[key] === undefined ? defaults[key] : source[key]; target[key] = source[key] === undefined ? defaults[key] : source[key];
} }
} }

View File

@@ -2,32 +2,34 @@
function outlineFixer() { function outlineFixer() {
let d: any = document; let d: any = document;
var style_element = d.createElement('STYLE'); var style_element = d.createElement("STYLE");
var dom_events = 'addEventListener' in d; var dom_events = "addEventListener" in d;
var add_event_listener = function (type, callback) { var add_event_listener = function(type, callback) {
// Basic cross-browser event handling // Basic cross-browser event handling
if (dom_events) { if (dom_events) {
d.addEventListener(type, callback); d.addEventListener(type, callback);
} else { } else {
d.attachEvent('on' + type, callback); d.attachEvent("on" + type, callback);
} }
}; };
var set_css = function (css_text) { var set_css = function(css_text) {
// Handle setting of <style> element contents in IE8 // Handle setting of <style> element contents in IE8
!!style_element.styleSheet ? style_element.styleSheet.cssText = css_text : style_element.innerHTML = css_text; !!style_element.styleSheet
? (style_element.styleSheet.cssText = css_text)
: (style_element.innerHTML = css_text);
}; };
d.getElementsByTagName('HEAD')[0].appendChild(style_element); d.getElementsByTagName("HEAD")[0].appendChild(style_element);
// Using mousedown instead of mouseover, so that previously focused elements don't lose focus ring on mouse move // Using mousedown instead of mouseover, so that previously focused elements don't lose focus ring on mouse move
add_event_listener('mousedown', function () { add_event_listener("mousedown", function() {
set_css(':focus{outline:0 !important}::-moz-focus-inner{border:0;}'); set_css(":focus{outline:0 !important}::-moz-focus-inner{border:0;}");
}); });
add_event_listener('keydown', function () { add_event_listener("keydown", function() {
set_css(''); set_css("");
}); });
} }

View File

@@ -1,63 +1,73 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import _ from 'lodash'; import _ from "lodash";
import moment from 'moment'; import moment from "moment";
import * as dateMath from './datemath'; import * as dateMath from "./datemath";
var spans = { var spans = {
's': {display: 'second'}, s: { display: "second" },
'm': {display: 'minute'}, m: { display: "minute" },
'h': {display: 'hour'}, h: { display: "hour" },
'd': {display: 'day'}, d: { display: "day" },
'w': {display: 'week'}, w: { display: "week" },
'M': {display: 'month'}, M: { display: "month" },
'y': {display: 'year'}, y: { display: "year" }
}; };
var rangeOptions = [ var rangeOptions = [
{ from: 'now/d', to: 'now/d', display: 'Today', section: 2 }, { from: "now/d", to: "now/d", display: "Today", section: 2 },
{ from: 'now/d', to: 'now', display: 'Today so far', section: 2 }, { from: "now/d", to: "now", display: "Today so far", section: 2 },
{ from: 'now/w', to: 'now/w', display: 'This week', section: 2 }, { from: "now/w", to: "now/w", display: "This week", section: 2 },
{ from: 'now/w', to: 'now', display: 'This week so far', section: 2 }, { from: "now/w", to: "now", display: "This week so far", section: 2 },
{ from: 'now/M', to: 'now/M', display: 'This month', section: 2 }, { from: "now/M", to: "now/M", display: "This month", section: 2 },
{ from: 'now/M', to: 'now', display: 'This month so far', section: 2 }, { from: "now/M", to: "now", display: "This month so far", section: 2 },
{ from: 'now/y', to: 'now/y', display: 'This year', section: 2 }, { from: "now/y", to: "now/y", display: "This year", section: 2 },
{ from: 'now/y', to: 'now', display: 'This year so far', section: 2 }, { from: "now/y", to: "now", display: "This year so far", section: 2 },
{ from: 'now-1d/d', to: 'now-1d/d', display: 'Yesterday', section: 1 }, { from: "now-1d/d", to: "now-1d/d", display: "Yesterday", section: 1 },
{ from: 'now-2d/d', to: 'now-2d/d', display: 'Day before yesterday', section: 1 }, {
{ from: 'now-7d/d', to: 'now-7d/d', display: 'This day last week', section: 1 }, from: "now-2d/d",
{ from: 'now-1w/w', to: 'now-1w/w', display: 'Previous week', section: 1 }, to: "now-2d/d",
{ from: 'now-1M/M', to: 'now-1M/M', display: 'Previous month', section: 1 }, display: "Day before yesterday",
{ from: 'now-1y/y', to: 'now-1y/y', display: 'Previous year', section: 1 }, section: 1
},
{
from: "now-7d/d",
to: "now-7d/d",
display: "This day last week",
section: 1
},
{ from: "now-1w/w", to: "now-1w/w", display: "Previous week", section: 1 },
{ from: "now-1M/M", to: "now-1M/M", display: "Previous month", section: 1 },
{ from: "now-1y/y", to: "now-1y/y", display: "Previous year", section: 1 },
{ from: 'now-5m', to: 'now', display: 'Last 5 minutes', section: 3 }, { from: "now-5m", to: "now", display: "Last 5 minutes", section: 3 },
{ from: 'now-15m', to: 'now', display: 'Last 15 minutes', section: 3 }, { from: "now-15m", to: "now", display: "Last 15 minutes", section: 3 },
{ from: 'now-30m', to: 'now', display: 'Last 30 minutes', section: 3 }, { from: "now-30m", to: "now", display: "Last 30 minutes", section: 3 },
{ from: 'now-1h', to: 'now', display: 'Last 1 hour', section: 3 }, { from: "now-1h", to: "now", display: "Last 1 hour", section: 3 },
{ from: 'now-3h', to: 'now', display: 'Last 3 hours', section: 3 }, { from: "now-3h", to: "now", display: "Last 3 hours", section: 3 },
{ from: 'now-6h', to: 'now', display: 'Last 6 hours', section: 3 }, { from: "now-6h", to: "now", display: "Last 6 hours", section: 3 },
{ from: 'now-12h', to: 'now', display: 'Last 12 hours', section: 3 }, { from: "now-12h", to: "now", display: "Last 12 hours", section: 3 },
{ from: 'now-24h', to: 'now', display: 'Last 24 hours', section: 3 }, { from: "now-24h", to: "now", display: "Last 24 hours", section: 3 },
{ from: 'now-2d', to: 'now', display: 'Last 2 days', section: 0 }, { from: "now-2d", to: "now", display: "Last 2 days", section: 0 },
{ from: 'now-7d', to: 'now', display: 'Last 7 days', section: 0 }, { from: "now-7d", to: "now", display: "Last 7 days", section: 0 },
{ from: 'now-30d', to: 'now', display: 'Last 30 days', section: 0 }, { from: "now-30d", to: "now", display: "Last 30 days", section: 0 },
{ from: 'now-90d', to: 'now', display: 'Last 90 days', section: 0 }, { from: "now-90d", to: "now", display: "Last 90 days", section: 0 },
{ from: 'now-6M', to: 'now', display: 'Last 6 months', section: 0 }, { from: "now-6M", to: "now", display: "Last 6 months", section: 0 },
{ from: 'now-1y', to: 'now', display: 'Last 1 year', section: 0 }, { from: "now-1y", to: "now", display: "Last 1 year", section: 0 },
{ from: 'now-2y', to: 'now', display: 'Last 2 years', section: 0 }, { from: "now-2y", to: "now", display: "Last 2 years", section: 0 },
{ from: 'now-5y', to: 'now', display: 'Last 5 years', section: 0 }, { from: "now-5y", to: "now", display: "Last 5 years", section: 0 }
]; ];
var absoluteFormat = 'MMM D, YYYY HH:mm:ss'; var absoluteFormat = "MMM D, YYYY HH:mm:ss";
var rangeIndex = {}; var rangeIndex = {};
_.each(rangeOptions, function (frame) { _.each(rangeOptions, function(frame) {
rangeIndex[frame.from + ' to ' + frame.to] = frame; rangeIndex[frame.from + " to " + frame.to] = frame;
}); });
export function getRelativeTimesList(timepickerSettings, currentDisplay) { export function getRelativeTimesList(timepickerSettings, currentDisplay) {
var groups = _.groupBy(rangeOptions, (option: any) => { var groups = _.groupBy(rangeOptions, (option: any) => {
option.active = option.display === currentDisplay; option.active = option.display === currentDisplay;
return option.section; return option.section;
@@ -84,20 +94,20 @@ function formatDate(date) {
// now/d // now/d
// if no to <expr> then to now is assumed // if no to <expr> then to now is assumed
export function describeTextRange(expr: any) { export function describeTextRange(expr: any) {
let isLast = (expr.indexOf('+') !== 0); let isLast = expr.indexOf("+") !== 0;
if (expr.indexOf('now') === -1) { if (expr.indexOf("now") === -1) {
expr = (isLast ? 'now-' : 'now') + expr; expr = (isLast ? "now-" : "now") + expr;
} }
let opt = rangeIndex[expr + ' to now']; let opt = rangeIndex[expr + " to now"];
if (opt) { if (opt) {
return opt; return opt;
} }
if (isLast) { if (isLast) {
opt = {from: expr, to: 'now'}; opt = { from: expr, to: "now" };
} else { } else {
opt = {from: 'now', to: expr}; opt = { from: "now", to: expr };
} }
let parts = /^now([-+])(\d+)(\w)/.exec(expr); let parts = /^now([-+])(\d+)(\w)/.exec(expr);
@@ -106,15 +116,15 @@ export function describeTextRange(expr: any) {
let amount = parseInt(parts[2]); let amount = parseInt(parts[2]);
let span = spans[unit]; let span = spans[unit];
if (span) { if (span) {
opt.display = isLast ? 'Last ' : 'Next '; opt.display = isLast ? "Last " : "Next ";
opt.display += amount + ' ' + span.display; opt.display += amount + " " + span.display;
opt.section = span.section; opt.section = span.section;
if (amount > 1) { if (amount > 1) {
opt.display += 's'; opt.display += "s";
} }
} }
} else { } else {
opt.display = opt.from + ' to ' + opt.to; opt.display = opt.from + " to " + opt.to;
opt.invalid = true; opt.invalid = true;
} }
@@ -122,29 +132,29 @@ export function describeTextRange(expr: any) {
} }
export function describeTimeRange(range) { export function describeTimeRange(range) {
var option = rangeIndex[range.from.toString() + ' to ' + range.to.toString()]; var option = rangeIndex[range.from.toString() + " to " + range.to.toString()];
if (option) { if (option) {
return option.display; return option.display;
} }
if (moment.isMoment(range.from) && moment.isMoment(range.to)) { if (moment.isMoment(range.from) && moment.isMoment(range.to)) {
return formatDate(range.from) + ' to ' + formatDate(range.to); return formatDate(range.from) + " to " + formatDate(range.to);
} }
if (moment.isMoment(range.from)) { if (moment.isMoment(range.from)) {
var toMoment = dateMath.parse(range.to, true); var toMoment = dateMath.parse(range.to, true);
return formatDate(range.from) + ' to ' + toMoment.fromNow(); return formatDate(range.from) + " to " + toMoment.fromNow();
} }
if (moment.isMoment(range.to)) { if (moment.isMoment(range.to)) {
var from = dateMath.parse(range.from, false); var from = dateMath.parse(range.from, false);
return from.fromNow() + ' to ' + formatDate(range.to); return from.fromNow() + " to " + formatDate(range.to);
} }
if (range.to.toString() === 'now') { if (range.to.toString() === "now") {
var res = describeTextRange(range.from); var res = describeTextRange(range.from);
return res.display; return res.display;
} }
return range.from.toString() + ' to ' + range.to.toString(); return range.from.toString() + " to " + range.to.toString();
} }

View File

@@ -1,7 +1,14 @@
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
export function react2AngularDirective(name: string, component: any, options: any) { export function react2AngularDirective(
coreModule.directive(name, ['reactDirective', reactDirective => { name: string,
return reactDirective(component, options); component: any,
}]); options: any
) {
coreModule.directive(name, [
"reactDirective",
reactDirective => {
return reactDirective(component, options);
}
]);
} }

View File

@@ -1,4 +1,4 @@
import {getDataMinMax} from 'app/core/time_series2'; import { getDataMinMax } from "app/core/time_series2";
/** /**
* Calculate tick step. * Calculate tick step.
@@ -40,7 +40,12 @@ export function getScaledDecimals(decimals, tick_size) {
* @param noTicks Number of ticks * @param noTicks Number of ticks
* @param tickDecimals Tick decimal precision * @param tickDecimals Tick decimal precision
*/ */
export function getFlotTickSize(min: number, max: number, noTicks: number, tickDecimals: number) { export function getFlotTickSize(
min: number,
max: number,
noTicks: number,
tickDecimals: number
) {
var delta = (max - min) / noTicks, var delta = (max - min) / noTicks,
dec = -Math.floor(Math.log(delta) / Math.LN10), dec = -Math.floor(Math.log(delta) / Math.LN10),
maxDec = tickDecimals; maxDec = tickDecimals;
@@ -81,19 +86,19 @@ export function getFlotRange(panelMin, panelMax, datamin, datamax) {
let delta = max - min; let delta = max - min;
if (delta === 0.0) { if (delta === 0.0) {
// Grafana fix: wide Y min and max using increased wideFactor // Grafana fix: wide Y min and max using increased wideFactor
// when all series values are the same // when all series values are the same
var wideFactor = 0.25; var wideFactor = 0.25;
var widen = Math.abs(max === 0 ? 1 : max * wideFactor); var widen = Math.abs(max === 0 ? 1 : max * wideFactor);
if (panelMin === null) { if (panelMin === null) {
min -= widen; min -= widen;
} }
// always widen max if we couldn't widen min to ensure we // always widen max if we couldn't widen min to ensure we
// don't fall into min == max which doesn't work // don't fall into min == max which doesn't work
if (panelMax == null || panelMin != null) { if (panelMax == null || panelMin != null) {
max += widen; max += widen;
} }
} else { } else {
// consider autoscaling // consider autoscaling
var margin = autoscaleMargin; var margin = autoscaleMargin;
@@ -114,7 +119,7 @@ export function getFlotRange(panelMin, panelMax, datamin, datamax) {
} }
} }
} }
return {min, max}; return { min, max };
} }
/** /**
@@ -122,8 +127,8 @@ export function getFlotRange(panelMin, panelMax, datamin, datamax) {
* Implementation from Flot. * Implementation from Flot.
*/ */
export function getFlotTickDecimals(data, axis) { export function getFlotTickDecimals(data, axis) {
let {datamin, datamax} = getDataMinMax(data); let { datamin, datamax } = getDataMinMax(data);
let {min, max} = getFlotRange(axis.min, axis.max, datamin, datamax); let { min, max } = getFlotRange(axis.min, axis.max, datamin, datamax);
let noTicks = 3; let noTicks = 3;
let tickDecimals, maxDec; let tickDecimals, maxDec;
let delta = (max - min) / noTicks; let delta = (max - min) / noTicks;
@@ -154,5 +159,5 @@ export function getFlotTickDecimals(data, axis) {
tickDecimals = Math.max(0, maxDec != null ? maxDec : dec); tickDecimals = Math.max(0, maxDec != null ? maxDec : dec);
// grafana addition // grafana addition
const scaledDecimals = tickDecimals - Math.floor(Math.log(size) / Math.LN10); const scaledDecimals = tickDecimals - Math.floor(Math.log(size) / Math.LN10);
return {tickDecimals, scaledDecimals}; return { tickDecimals, scaledDecimals };
} }

View File

@@ -1,4 +1,4 @@
import _ from 'lodash'; import _ from "lodash";
const versionPattern = /^(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-([0-9A-Za-z\.]+))?/; const versionPattern = /^(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-([0-9A-Za-z\.]+))?/;
@@ -20,7 +20,11 @@ export class SemVersion {
isGtOrEq(version: string): boolean { isGtOrEq(version: string): boolean {
let compared = new SemVersion(version); let compared = new SemVersion(version);
return !(this.major < compared.major || this.minor < compared.minor || this.patch < compared.patch); return !(
this.major < compared.major ||
this.minor < compared.minor ||
this.patch < compared.patch
);
} }
isValid(): boolean { isValid(): boolean {

View File

@@ -1,21 +1,20 @@
import AdminListUsersCtrl from './admin_list_users_ctrl'; import AdminListUsersCtrl from "./admin_list_users_ctrl";
import './admin_list_orgs_ctrl'; import "./admin_list_orgs_ctrl";
import './admin_edit_org_ctrl'; import "./admin_edit_org_ctrl";
import './admin_edit_user_ctrl'; import "./admin_edit_user_ctrl";
import coreModule from 'app/core/core_module'; import coreModule from "app/core/core_module";
class AdminSettingsCtrl { class AdminSettingsCtrl {
navModel: any; navModel: any;
/** @ngInject **/ /** @ngInject **/
constructor($scope, backendSrv, navModelSrv) { constructor($scope, backendSrv, navModelSrv) {
this.navModel = navModelSrv.getNav('cfg', 'admin', 'server-settings', 1); this.navModel = navModelSrv.getNav("cfg", "admin", "server-settings", 1);
backendSrv.get('/api/admin/settings').then(function(settings) { backendSrv.get("/api/admin/settings").then(function(settings) {
$scope.settings = settings; $scope.settings = settings;
}); });
} }
} }
@@ -24,7 +23,7 @@ class AdminHomeCtrl {
/** @ngInject **/ /** @ngInject **/
constructor(navModelSrv) { constructor(navModelSrv) {
this.navModel = navModelSrv.getNav('cfg', 'admin', 1); this.navModel = navModelSrv.getNav("cfg", "admin", 1);
} }
} }
@@ -34,15 +33,15 @@ export class AdminStatsCtrl {
/** @ngInject */ /** @ngInject */
constructor(backendSrv: any, navModelSrv) { constructor(backendSrv: any, navModelSrv) {
this.navModel = navModelSrv.getNav('cfg', 'admin', 'server-stats', 1); this.navModel = navModelSrv.getNav("cfg", "admin", "server-stats", 1);
backendSrv.get('/api/admin/stats').then(stats => { backendSrv.get("/api/admin/stats").then(stats => {
this.stats = stats; this.stats = stats;
}); });
} }
} }
coreModule.controller('AdminSettingsCtrl', AdminSettingsCtrl); coreModule.controller("AdminSettingsCtrl", AdminSettingsCtrl);
coreModule.controller('AdminHomeCtrl', AdminHomeCtrl); coreModule.controller("AdminHomeCtrl", AdminHomeCtrl);
coreModule.controller('AdminStatsCtrl', AdminStatsCtrl); coreModule.controller("AdminStatsCtrl", AdminStatsCtrl);
coreModule.controller('AdminListUsersCtrl', AdminListUsersCtrl); coreModule.controller("AdminListUsersCtrl", AdminListUsersCtrl);

View File

@@ -1,11 +1,10 @@
import angular from 'angular'; import angular from "angular";
export class AdminEditOrgCtrl { export class AdminEditOrgCtrl {
/** @ngInject */ /** @ngInject */
constructor($scope, $routeParams, backendSrv, $location, navModelSrv) { constructor($scope, $routeParams, backendSrv, $location, navModelSrv) {
$scope.init = function() { $scope.init = function() {
$scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs', 1); $scope.navModel = navModelSrv.getNav("cfg", "admin", "global-orgs", 1);
if ($routeParams.id) { if ($routeParams.id) {
$scope.getOrg($routeParams.id); $scope.getOrg($routeParams.id);
@@ -14,37 +13,46 @@ export class AdminEditOrgCtrl {
}; };
$scope.getOrg = function(id) { $scope.getOrg = function(id) {
backendSrv.get('/api/orgs/' + id).then(function(org) { backendSrv.get("/api/orgs/" + id).then(function(org) {
$scope.org = org; $scope.org = org;
}); });
}; };
$scope.getOrgUsers = function(id) { $scope.getOrgUsers = function(id) {
backendSrv.get('/api/orgs/' + id + '/users').then(function(orgUsers) { backendSrv.get("/api/orgs/" + id + "/users").then(function(orgUsers) {
$scope.orgUsers = orgUsers; $scope.orgUsers = orgUsers;
}); });
}; };
$scope.update = function() { $scope.update = function() {
if (!$scope.orgDetailsForm.$valid) { return; } if (!$scope.orgDetailsForm.$valid) {
return;
}
backendSrv.put('/api/orgs/' + $scope.org.id, $scope.org).then(function() { backendSrv.put("/api/orgs/" + $scope.org.id, $scope.org).then(function() {
$location.path('/admin/orgs'); $location.path("/admin/orgs");
}); });
}; };
$scope.updateOrgUser= function(orgUser) { $scope.updateOrgUser = function(orgUser) {
backendSrv.patch('/api/orgs/' + orgUser.orgId + '/users/' + orgUser.userId, orgUser); backendSrv.patch(
"/api/orgs/" + orgUser.orgId + "/users/" + orgUser.userId,
orgUser
);
}; };
$scope.removeOrgUser = function(orgUser) { $scope.removeOrgUser = function(orgUser) {
backendSrv.delete('/api/orgs/' + orgUser.orgId + '/users/' + orgUser.userId).then(function() { backendSrv
$scope.getOrgUsers($scope.org.id); .delete("/api/orgs/" + orgUser.orgId + "/users/" + orgUser.userId)
}); .then(function() {
$scope.getOrgUsers($scope.org.id);
});
}; };
$scope.init(); $scope.init();
} }
} }
angular.module('grafana.controllers').controller('AdminEditOrgCtrl', AdminEditOrgCtrl); angular
.module("grafana.controllers")
.controller("AdminEditOrgCtrl", AdminEditOrgCtrl);

View File

@@ -1,14 +1,13 @@
import angular from 'angular'; import angular from "angular";
import _ from 'lodash'; import _ from "lodash";
export class AdminEditUserCtrl { export class AdminEditUserCtrl {
/** @ngInject */ /** @ngInject */
constructor($scope, $routeParams, backendSrv, $location, navModelSrv) { constructor($scope, $routeParams, backendSrv, $location, navModelSrv) {
$scope.user = {}; $scope.user = {};
$scope.newOrg = { name: '', role: 'Editor' }; $scope.newOrg = { name: "", role: "Editor" };
$scope.permissions = {}; $scope.permissions = {};
$scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-users', 1); $scope.navModel = navModelSrv.getNav("cfg", "admin", "global-users", 1);
$scope.init = function() { $scope.init = function() {
if ($routeParams.id) { if ($routeParams.id) {
@@ -18,61 +17,79 @@ export class AdminEditUserCtrl {
}; };
$scope.getUser = function(id) { $scope.getUser = function(id) {
backendSrv.get('/api/users/' + id).then(function(user) { backendSrv.get("/api/users/" + id).then(function(user) {
$scope.user = user; $scope.user = user;
$scope.user_id = id; $scope.user_id = id;
$scope.permissions.isGrafanaAdmin = user.isGrafanaAdmin; $scope.permissions.isGrafanaAdmin = user.isGrafanaAdmin;
}); });
}; };
$scope.setPassword = function () { $scope.setPassword = function() {
if (!$scope.passwordForm.$valid) { return; } if (!$scope.passwordForm.$valid) {
return;
}
var payload = { password: $scope.password }; var payload = { password: $scope.password };
backendSrv.put('/api/admin/users/' + $scope.user_id + '/password', payload).then(function() { backendSrv
$location.path('/admin/users'); .put("/api/admin/users/" + $scope.user_id + "/password", payload)
}); .then(function() {
$location.path("/admin/users");
});
}; };
$scope.updatePermissions = function() { $scope.updatePermissions = function() {
var payload = $scope.permissions; var payload = $scope.permissions;
backendSrv.put('/api/admin/users/' + $scope.user_id + '/permissions', payload).then(function() { backendSrv
$location.path('/admin/users'); .put("/api/admin/users/" + $scope.user_id + "/permissions", payload)
}); .then(function() {
$location.path("/admin/users");
});
}; };
$scope.create = function() { $scope.create = function() {
if (!$scope.userForm.$valid) { return; } if (!$scope.userForm.$valid) {
return;
}
backendSrv.post('/api/admin/users', $scope.user).then(function() { backendSrv.post("/api/admin/users", $scope.user).then(function() {
$location.path('/admin/users'); $location.path("/admin/users");
}); });
}; };
$scope.getUserOrgs = function(id) { $scope.getUserOrgs = function(id) {
backendSrv.get('/api/users/' + id + '/orgs').then(function(orgs) { backendSrv.get("/api/users/" + id + "/orgs").then(function(orgs) {
$scope.orgs = orgs; $scope.orgs = orgs;
}); });
}; };
$scope.update = function() { $scope.update = function() {
if (!$scope.userForm.$valid) { return; } if (!$scope.userForm.$valid) {
return;
}
backendSrv.put('/api/users/' + $scope.user_id, $scope.user).then(function() { backendSrv
$location.path('/admin/users'); .put("/api/users/" + $scope.user_id, $scope.user)
}); .then(function() {
$location.path("/admin/users");
});
}; };
$scope.updateOrgUser= function(orgUser) { $scope.updateOrgUser = function(orgUser) {
backendSrv.patch('/api/orgs/' + orgUser.orgId + '/users/' + $scope.user_id, orgUser).then(function() { backendSrv
}); .patch(
"/api/orgs/" + orgUser.orgId + "/users/" + $scope.user_id,
orgUser
)
.then(function() {});
}; };
$scope.removeOrgUser = function(orgUser) { $scope.removeOrgUser = function(orgUser) {
backendSrv.delete('/api/orgs/' + orgUser.orgId + '/users/' + $scope.user_id).then(function() { backendSrv
$scope.getUserOrgs($scope.user_id); .delete("/api/orgs/" + orgUser.orgId + "/users/" + $scope.user_id)
}); .then(function() {
$scope.getUserOrgs($scope.user_id);
});
}; };
$scope.orgsSearchCache = []; $scope.orgsSearchCache = [];
@@ -83,27 +100,37 @@ export class AdminEditUserCtrl {
return; return;
} }
backendSrv.get('/api/orgs', {query: ''}).then(function(result) { backendSrv.get("/api/orgs", { query: "" }).then(function(result) {
$scope.orgsSearchCache = result; $scope.orgsSearchCache = result;
callback(_.map(result, "name")); callback(_.map(result, "name"));
}); });
}; };
$scope.addOrgUser = function() { $scope.addOrgUser = function() {
if (!$scope.addOrgForm.$valid) { return; } if (!$scope.addOrgForm.$valid) {
return;
}
var orgInfo = _.find($scope.orgsSearchCache, {name: $scope.newOrg.name}); var orgInfo = _.find($scope.orgsSearchCache, {
if (!orgInfo) { return; } name: $scope.newOrg.name
});
if (!orgInfo) {
return;
}
$scope.newOrg.loginOrEmail = $scope.user.login; $scope.newOrg.loginOrEmail = $scope.user.login;
backendSrv.post('/api/orgs/' + orgInfo.id + '/users/', $scope.newOrg).then(function() { backendSrv
$scope.getUserOrgs($scope.user_id); .post("/api/orgs/" + orgInfo.id + "/users/", $scope.newOrg)
}); .then(function() {
$scope.getUserOrgs($scope.user_id);
});
}; };
$scope.init(); $scope.init();
} }
} }
angular.module('grafana.controllers').controller('AdminEditUserCtrl', AdminEditUserCtrl); angular
.module("grafana.controllers")
.controller("AdminEditUserCtrl", AdminEditUserCtrl);

View File

@@ -1,29 +1,28 @@
import angular from 'angular'; import angular from "angular";
export class AdminListOrgsCtrl { export class AdminListOrgsCtrl {
/** @ngInject */ /** @ngInject */
constructor($scope, backendSrv, navModelSrv) { constructor($scope, backendSrv, navModelSrv) {
$scope.init = function() { $scope.init = function() {
$scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs', 1); $scope.navModel = navModelSrv.getNav("cfg", "admin", "global-orgs", 1);
$scope.getOrgs(); $scope.getOrgs();
}; };
$scope.getOrgs = function() { $scope.getOrgs = function() {
backendSrv.get('/api/orgs').then(function(orgs) { backendSrv.get("/api/orgs").then(function(orgs) {
$scope.orgs = orgs; $scope.orgs = orgs;
}); });
}; };
$scope.deleteOrg = function(org) { $scope.deleteOrg = function(org) {
$scope.appEvent('confirm-modal', { $scope.appEvent("confirm-modal", {
title: 'Delete', title: "Delete",
text: 'Do you want to delete organization ' + org.name + '?', text: "Do you want to delete organization " + org.name + "?",
text2: 'All dashboards for this organization will be removed!', text2: "All dashboards for this organization will be removed!",
icon: 'fa-trash', icon: "fa-trash",
yesText: 'Delete', yesText: "Delete",
onConfirm: function() { onConfirm: function() {
backendSrv.delete('/api/orgs/' + org.id).then(function() { backendSrv.delete("/api/orgs/" + org.id).then(function() {
$scope.getOrgs(); $scope.getOrgs();
}); });
} }
@@ -34,4 +33,6 @@ export class AdminListOrgsCtrl {
} }
} }
angular.module('grafana.controllers').controller('AdminListOrgsCtrl', AdminListOrgsCtrl); angular
.module("grafana.controllers")
.controller("AdminListOrgsCtrl", AdminListOrgsCtrl);

View File

@@ -10,24 +10,30 @@ export default class AdminListUsersCtrl {
/** @ngInject */ /** @ngInject */
constructor(private $scope, private backendSrv, navModelSrv) { constructor(private $scope, private backendSrv, navModelSrv) {
this.navModel = navModelSrv.getNav('cfg', 'admin', 'global-users', 1); this.navModel = navModelSrv.getNav("cfg", "admin", "global-users", 1);
this.query = ''; this.query = "";
this.getUsers(); this.getUsers();
} }
getUsers() { getUsers() {
this.backendSrv.get(`/api/users/search?perpage=${this.perPage}&page=${this.page}&query=${this.query}`).then((result) => { this.backendSrv
this.users = result.users; .get(
this.page = result.page; `/api/users/search?perpage=${this.perPage}&page=${this.page}&query=${
this.perPage = result.perPage; this.query
this.totalPages = Math.ceil(result.totalCount / result.perPage); }`
this.showPaging = this.totalPages > 1; )
this.pages = []; .then(result => {
this.users = result.users;
this.page = result.page;
this.perPage = result.perPage;
this.totalPages = Math.ceil(result.totalCount / result.perPage);
this.showPaging = this.totalPages > 1;
this.pages = [];
for (var i = 1; i < this.totalPages+1; i++) { for (var i = 1; i < this.totalPages + 1; i++) {
this.pages.push({ page: i, current: i === this.page}); this.pages.push({ page: i, current: i === this.page });
} }
}); });
} }
navigateToPage(page) { navigateToPage(page) {
@@ -36,13 +42,13 @@ export default class AdminListUsersCtrl {
} }
deleteUser(user) { deleteUser(user) {
this.$scope.appEvent('confirm-modal', { this.$scope.appEvent("confirm-modal", {
title: 'Delete', title: "Delete",
text: 'Do you want to delete ' + user.login + '?', text: "Do you want to delete " + user.login + "?",
icon: 'fa-trash', icon: "fa-trash",
yesText: 'Delete', yesText: "Delete",
onConfirm: () => { onConfirm: () => {
this.backendSrv.delete('/api/admin/users/' + user.id).then(() => { this.backendSrv.delete("/api/admin/users/" + user.id).then(() => {
this.getUsers(); this.getUsers();
}); });
} }

View File

@@ -1,131 +1,137 @@
///<reference path="../../headers/common.d.ts" /> ///<reference path="../../headers/common.d.ts" />
import _ from 'lodash'; import _ from "lodash";
import { import {
QueryPartDef, QueryPartDef,
QueryPart, QueryPart
} from 'app/core/components/query_part/query_part'; } from "app/core/components/query_part/query_part";
var alertQueryDef = new QueryPartDef({ var alertQueryDef = new QueryPartDef({
type: 'query', type: "query",
params: [ params: [
{name: "queryRefId", type: 'string', dynamicLookup: true}, { name: "queryRefId", type: "string", dynamicLookup: true },
{name: "from", type: "string", options: ['1s', '10s', '1m', '5m', '10m', '15m', '1h', '24h', '48h']}, {
{name: "to", type: "string", options: ['now']}, name: "from",
type: "string",
options: ["1s", "10s", "1m", "5m", "10m", "15m", "1h", "24h", "48h"]
},
{ name: "to", type: "string", options: ["now"] }
], ],
defaultParams: ['#A', '15m', 'now', 'avg'] defaultParams: ["#A", "15m", "now", "avg"]
}); });
var conditionTypes = [ var conditionTypes = [{ text: "Query", value: "query" }];
{text: 'Query', value: 'query'},
];
var alertStateSortScore = { var alertStateSortScore = {
alerting: 1, alerting: 1,
no_data: 2, no_data: 2,
pending: 3, pending: 3,
ok: 4, ok: 4,
paused: 5, paused: 5
}; };
var evalFunctions = [ var evalFunctions = [
{text: 'IS ABOVE', value: 'gt'}, { text: "IS ABOVE", value: "gt" },
{text: 'IS BELOW', value: 'lt'}, { text: "IS BELOW", value: "lt" },
{text: 'IS OUTSIDE RANGE', value: 'outside_range'}, { text: "IS OUTSIDE RANGE", value: "outside_range" },
{text: 'IS WITHIN RANGE', value: 'within_range'}, { text: "IS WITHIN RANGE", value: "within_range" },
{text: 'HAS NO VALUE' , value: 'no_value'} { text: "HAS NO VALUE", value: "no_value" }
]; ];
var evalOperators = [ var evalOperators = [
{text: 'OR', value: 'or'}, { text: "OR", value: "or" },
{text: 'AND', value: 'and'}, { text: "AND", value: "and" }
]; ];
var reducerTypes = [ var reducerTypes = [
{text: 'avg()', value: 'avg'}, { text: "avg()", value: "avg" },
{text: 'min()', value: 'min'}, { text: "min()", value: "min" },
{text: 'max()', value: 'max'}, { text: "max()", value: "max" },
{text: 'sum()' , value: 'sum'}, { text: "sum()", value: "sum" },
{text: 'count()', value: 'count'}, { text: "count()", value: "count" },
{text: 'last()', value: 'last'}, { text: "last()", value: "last" },
{text: 'median()', value: 'median'}, { text: "median()", value: "median" },
{text: 'diff()', value: 'diff'}, { text: "diff()", value: "diff" },
{text: 'percent_diff()', value: 'percent_diff'}, { text: "percent_diff()", value: "percent_diff" },
{text: 'count_non_null()', value: 'count_non_null'}, { text: "count_non_null()", value: "count_non_null" }
]; ];
var noDataModes = [ var noDataModes = [
{text: 'Alerting', value: 'alerting'}, { text: "Alerting", value: "alerting" },
{text: 'No Data', value: 'no_data'}, { text: "No Data", value: "no_data" },
{text: 'Keep Last State', value: 'keep_state'}, { text: "Keep Last State", value: "keep_state" },
{text: 'Ok', value: 'ok'}, { text: "Ok", value: "ok" }
]; ];
var executionErrorModes = [ var executionErrorModes = [
{text: 'Alerting', value: 'alerting'}, { text: "Alerting", value: "alerting" },
{text: 'Keep Last State', value: 'keep_state'}, { text: "Keep Last State", value: "keep_state" }
]; ];
function createReducerPart(model) { function createReducerPart(model) {
var def = new QueryPartDef({type: model.type, defaultParams: []}); var def = new QueryPartDef({ type: model.type, defaultParams: [] });
return new QueryPart(model, def); return new QueryPart(model, def);
} }
function getStateDisplayModel(state) { function getStateDisplayModel(state) {
switch (state) { switch (state) {
case 'ok': { case "ok": {
return { return {
text: 'OK', text: "OK",
iconClass: 'icon-gf icon-gf-online', iconClass: "icon-gf icon-gf-online",
stateClass: 'alert-state-ok' stateClass: "alert-state-ok"
}; };
} }
case 'alerting': { case "alerting": {
return { return {
text: 'ALERTING', text: "ALERTING",
iconClass: 'icon-gf icon-gf-critical', iconClass: "icon-gf icon-gf-critical",
stateClass: 'alert-state-critical' stateClass: "alert-state-critical"
}; };
} }
case 'no_data': { case "no_data": {
return { return {
text: 'NO DATA', text: "NO DATA",
iconClass: "fa fa-question", iconClass: "fa fa-question",
stateClass: 'alert-state-warning' stateClass: "alert-state-warning"
}; };
} }
case 'paused': { case "paused": {
return { return {
text: 'PAUSED', text: "PAUSED",
iconClass: "fa fa-pause", iconClass: "fa fa-pause",
stateClass: 'alert-state-paused' stateClass: "alert-state-paused"
}; };
} }
case 'pending': { case "pending": {
return { return {
text: 'PENDING', text: "PENDING",
iconClass: "fa fa-exclamation", iconClass: "fa fa-exclamation",
stateClass: 'alert-state-warning' stateClass: "alert-state-warning"
}; };
} }
} }
throw {message: 'Unknown alert state'}; throw { message: "Unknown alert state" };
} }
function joinEvalMatches(matches, separator: string) { function joinEvalMatches(matches, separator: string) {
return _.reduce(matches, (res, ev)=> { return _.reduce(
if (ev.metric !== undefined && ev.value !== undefined) { matches,
res.push(ev.metric + '=' + ev.value); (res, ev) => {
} if (ev.metric !== undefined && ev.value !== undefined) {
res.push(ev.metric + "=" + ev.value);
}
// For backwards compatibility . Should be be able to remove this after ~2017-06-01 // For backwards compatibility . Should be be able to remove this after ~2017-06-01
if (ev.Metric !== undefined && ev.Value !== undefined) { if (ev.Metric !== undefined && ev.Value !== undefined) {
res.push(ev.Metric + '=' + ev.Value); res.push(ev.Metric + "=" + ev.Value);
} }
return res; return res;
}, []).join(separator); },
[]
).join(separator);
} }
function getAlertAnnotationInfo(ah) { function getAlertAnnotationInfo(ah) {
@@ -134,9 +140,9 @@ function getAlertAnnotationInfo(ah) {
// new way stores it in evalMatches property on new data object // new way stores it in evalMatches property on new data object
if (_.isArray(ah.data)) { if (_.isArray(ah.data)) {
return joinEvalMatches(ah.data, ', '); return joinEvalMatches(ah.data, ", ");
} else if (_.isArray(ah.data.evalMatches)) { } else if (_.isArray(ah.data.evalMatches)) {
return joinEvalMatches(ah.data.evalMatches, ', '); return joinEvalMatches(ah.data.evalMatches, ", ");
} }
if (ah.data.error) { if (ah.data.error) {
@@ -161,5 +167,5 @@ export default {
reducerTypes: reducerTypes, reducerTypes: reducerTypes,
createReducerPart: createReducerPart, createReducerPart: createReducerPart,
getAlertAnnotationInfo: getAlertAnnotationInfo, getAlertAnnotationInfo: getAlertAnnotationInfo,
alertStateSortScore: alertStateSortScore, alertStateSortScore: alertStateSortScore
}; };

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