mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge remote-tracking branch 'origin/graphite-query-editor-enhancements'
This commit is contained in:
@@ -8,7 +8,6 @@ charset = utf-8
|
|||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
max_line_length = 120
|
max_line_length = 120
|
||||||
insert_final_newline = true
|
|
||||||
|
|
||||||
[*.go]
|
[*.go]
|
||||||
indent_style = tab
|
indent_style = tab
|
||||||
|
|||||||
@@ -134,7 +134,7 @@
|
|||||||
"clipboard": "^1.7.1",
|
"clipboard": "^1.7.1",
|
||||||
"d3": "^4.11.0",
|
"d3": "^4.11.0",
|
||||||
"d3-scale-chromatic": "^1.1.1",
|
"d3-scale-chromatic": "^1.1.1",
|
||||||
"eventemitter3": "^2.0.2",
|
"eventemitter3": "^2.0.3",
|
||||||
"file-saver": "^1.3.3",
|
"file-saver": "^1.3.3",
|
||||||
"jquery": "^3.2.1",
|
"jquery": "^3.2.1",
|
||||||
"lodash": "^4.17.4",
|
"lodash": "^4.17.4",
|
||||||
@@ -153,6 +153,7 @@
|
|||||||
"react-select": "^1.1.0",
|
"react-select": "^1.1.0",
|
||||||
"react-sizeme": "^2.3.6",
|
"react-sizeme": "^2.3.6",
|
||||||
"remarkable": "^1.7.1",
|
"remarkable": "^1.7.1",
|
||||||
|
"rst2html": "github:thoward/rst2html#990cb89",
|
||||||
"rxjs": "^5.4.3",
|
"rxjs": "^5.4.3",
|
||||||
"tether": "^1.4.0",
|
"tether": "^1.4.0",
|
||||||
"tether-drop": "https://github.com/torkelo/drop",
|
"tether-drop": "https://github.com/torkelo/drop",
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
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 === '') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (str[0] === '/') {
|
if (str[0] === '/') {
|
||||||
str = str.substring(1);
|
str = str.substring(1);
|
||||||
}
|
}
|
||||||
@@ -30,6 +32,8 @@ export class FormDropdownCtrl {
|
|||||||
getOptions: any;
|
getOptions: any;
|
||||||
optionCache: any;
|
optionCache: any;
|
||||||
lookupText: boolean;
|
lookupText: boolean;
|
||||||
|
placeholder: any;
|
||||||
|
startOpen: any;
|
||||||
|
|
||||||
/** @ngInject **/
|
/** @ngInject **/
|
||||||
constructor(private $scope, $element, private $sce, private templateSrv, private $q) {
|
constructor(private $scope, $element, private $sce, private templateSrv, private $q) {
|
||||||
@@ -47,6 +51,10 @@ export class FormDropdownCtrl {
|
|||||||
this.cssClasses = 'gf-form-input gf-form-input--dropdown ' + this.cssClass;
|
this.cssClasses = 'gf-form-input gf-form-input--dropdown ' + this.cssClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.placeholder) {
|
||||||
|
this.inputElement.attr('placeholder', this.placeholder);
|
||||||
|
}
|
||||||
|
|
||||||
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),
|
||||||
@@ -61,8 +69,7 @@ export class FormDropdownCtrl {
|
|||||||
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));
|
this.source(this.query, this.process.bind(this));
|
||||||
return items ? this.process(items) : items;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.linkElement.keydown(evt => {
|
this.linkElement.keydown(evt => {
|
||||||
@@ -81,6 +88,10 @@ export class FormDropdownCtrl {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.inputElement.blur(this.inputBlur.bind(this));
|
this.inputElement.blur(this.inputBlur.bind(this));
|
||||||
|
|
||||||
|
if (this.startOpen) {
|
||||||
|
setTimeout(this.open.bind(this), 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getOptionsInternal(query) {
|
getOptionsInternal(query) {
|
||||||
@@ -121,9 +132,9 @@ export class FormDropdownCtrl {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// add custom values
|
// add custom values
|
||||||
if (this.allowCustom) {
|
if (this.allowCustom && this.text !== '') {
|
||||||
if (_.indexOf(optionTexts, this.text) === -1) {
|
if (_.indexOf(optionTexts, this.text) === -1) {
|
||||||
options.unshift(this.text);
|
optionTexts.unshift(this.text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,10 +239,10 @@ const template = `
|
|||||||
style="display:none">
|
style="display:none">
|
||||||
</input>
|
</input>
|
||||||
<a ng-class="ctrl.cssClasses"
|
<a ng-class="ctrl.cssClasses"
|
||||||
tabindex="1"
|
tabindex="1"
|
||||||
ng-click="ctrl.open()"
|
ng-click="ctrl.open()"
|
||||||
give-focus="ctrl.focus"
|
give-focus="ctrl.focus"
|
||||||
ng-bind-html="ctrl.display">
|
ng-bind-html="ctrl.display || ' '">
|
||||||
</a>
|
</a>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -250,6 +261,8 @@ export function formDropdownDirective() {
|
|||||||
allowCustom: '@',
|
allowCustom: '@',
|
||||||
labelMode: '@',
|
labelMode: '@',
|
||||||
lookupText: '@',
|
lookupText: '@',
|
||||||
|
placeholder: '@',
|
||||||
|
startOpen: '@',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ function (_, $, coreModule) {
|
|||||||
' class="gf-form-input input-medium tight-form-input"' +
|
' class="gf-form-input input-medium tight-form-input"' +
|
||||||
' spellcheck="false" style="display:none"></input>';
|
' spellcheck="false" style="display:none"></input>';
|
||||||
|
|
||||||
var buttonTemplate = '<a class="gf-form-label tight-form-func dropdown-toggle"' +
|
var buttonTemplate = '<a class="gf-form-label tight-form-func dropdown-toggle"' +
|
||||||
' tabindex="1" gf-dropdown="menuItems" data-toggle="dropdown"' +
|
' tabindex="1" gf-dropdown="menuItems" data-toggle="dropdown"' +
|
||||||
' data-placement="top"><i class="fa fa-plus"></i></a>';
|
' data-placement="top"><i class="fa fa-plus"></i></a>';
|
||||||
|
|
||||||
|
|||||||
@@ -106,10 +106,6 @@ function (angular, _, coreModule) {
|
|||||||
return new MetricSegment({fake: true, html: '<i class="fa fa-plus "></i>', type: 'plus-button', cssClass: 'query-part' });
|
return new MetricSegment({fake: true, html: '<i class="fa fa-plus "></i>', type: 'plus-button', cssClass: 'query-part' });
|
||||||
};
|
};
|
||||||
|
|
||||||
this.newSelectTagValue = function() {
|
|
||||||
return new MetricSegment({value: 'select tag value', fake: true});
|
|
||||||
};
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,12 +16,12 @@
|
|||||||
Add variable
|
Add variable
|
||||||
</a>
|
</a>
|
||||||
<div class="grafana-info-box">
|
<div class="grafana-info-box">
|
||||||
<h5>What does variables do?</h5>
|
<h5>What do variables do?</h5>
|
||||||
<p>Variables enables more interactive and dynamic dashboards. Instead of hard-coding things like server or sensor names
|
<p>Variables enable more interactive and dynamic dashboards. Instead of hard-coding things like server or sensor names
|
||||||
in your metric queries you can use variables in their place. Variables are shown as dropdown select boxes at the top of
|
in your metric queries you can use variables in their place. Variables are shown as dropdown select boxes at the top of
|
||||||
the dashboard. These dropdowns make it easy to change the data being displayed in your dashboard.
|
the dashboard. These dropdowns make it easy to change the data being displayed in your dashboard.
|
||||||
|
|
||||||
Checkout the
|
Check out the
|
||||||
<a class="external-link" href="http://docs.grafana.org/reference/templating/" target="_blank">
|
<a class="external-link" href="http://docs.grafana.org/reference/templating/" target="_blank">
|
||||||
Templating documentation
|
Templating documentation
|
||||||
</a> for more information.
|
</a> for more information.
|
||||||
@@ -93,7 +93,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gf-form" ng-show="ctrl.form.name.$error.pattern">
|
<div class="gf-form" ng-show="ctrl.form.name.$error.pattern">
|
||||||
<span class="gf-form-label gf-form-label--error">Template names cannot begin with '__' that's reserved for Grafanas global variables</span>
|
<span class="gf-form-label gf-form-label--error">Template names cannot begin with '__', that's reserved for Grafana's global variables</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gf-form-inline">
|
<div class="gf-form-inline">
|
||||||
|
|||||||
@@ -1,46 +1,37 @@
|
|||||||
define([
|
define(['angular', 'lodash', 'jquery', 'rst2html', 'tether-drop'], function(angular, _, $, rst2html, Drop) {
|
||||||
'angular',
|
|
||||||
'lodash',
|
|
||||||
'jquery',
|
|
||||||
'./gfunc',
|
|
||||||
],
|
|
||||||
function (angular, _, $, gfunc) {
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
gfunc = gfunc.default;
|
angular.module('grafana.directives').directive('graphiteAddFunc', function($compile) {
|
||||||
|
var inputTemplate =
|
||||||
|
'<input type="text"' + ' class="gf-form-input"' + ' spellcheck="false" style="display:none"></input>';
|
||||||
|
|
||||||
angular
|
var buttonTemplate =
|
||||||
.module('grafana.directives')
|
'<a class="gf-form-label query-part dropdown-toggle"' +
|
||||||
.directive('graphiteAddFunc', function($compile) {
|
' tabindex="1" gf-dropdown="functionMenu" data-toggle="dropdown">' +
|
||||||
var inputTemplate = '<input type="text"'+
|
'<i class="fa fa-plus"></i></a>';
|
||||||
' class="gf-form-input"' +
|
|
||||||
' spellcheck="false" style="display:none"></input>';
|
|
||||||
|
|
||||||
var buttonTemplate = '<a class="gf-form-label query-part dropdown-toggle"' +
|
return {
|
||||||
' tabindex="1" gf-dropdown="functionMenu" data-toggle="dropdown">' +
|
link: function($scope, elem) {
|
||||||
'<i class="fa fa-plus"></i></a>';
|
var ctrl = $scope.ctrl;
|
||||||
|
|
||||||
return {
|
var $input = $(inputTemplate);
|
||||||
link: function($scope, elem) {
|
var $button = $(buttonTemplate);
|
||||||
var ctrl = $scope.ctrl;
|
|
||||||
var graphiteVersion = ctrl.datasource.graphiteVersion;
|
|
||||||
var categories = gfunc.getCategories(graphiteVersion);
|
|
||||||
var allFunctions = getAllFunctionNames(categories);
|
|
||||||
|
|
||||||
$scope.functionMenu = createFunctionDropDownMenu(categories);
|
$input.appendTo(elem);
|
||||||
|
$button.appendTo(elem);
|
||||||
|
|
||||||
var $input = $(inputTemplate);
|
ctrl.datasource.getFuncDefs().then(function(funcDefs) {
|
||||||
var $button = $(buttonTemplate);
|
var allFunctions = _.map(funcDefs, 'name').sort();
|
||||||
$input.appendTo(elem);
|
|
||||||
$button.appendTo(elem);
|
$scope.functionMenu = createFunctionDropDownMenu(funcDefs);
|
||||||
|
|
||||||
$input.attr('data-provide', 'typeahead');
|
$input.attr('data-provide', 'typeahead');
|
||||||
$input.typeahead({
|
$input.typeahead({
|
||||||
source: allFunctions,
|
source: allFunctions,
|
||||||
minLength: 1,
|
minLength: 1,
|
||||||
items: 10,
|
items: 10,
|
||||||
updater: function (value) {
|
updater: function(value) {
|
||||||
var funcDef = gfunc.getFuncDef(value);
|
var funcDef = ctrl.datasource.getFuncDef(value);
|
||||||
if (!funcDef) {
|
if (!funcDef) {
|
||||||
// try find close match
|
// try find close match
|
||||||
value = value.toLowerCase();
|
value = value.toLowerCase();
|
||||||
@@ -48,7 +39,9 @@ function (angular, _, $, gfunc) {
|
|||||||
return funcName.toLowerCase().indexOf(value) === 0;
|
return funcName.toLowerCase().indexOf(value) === 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!funcDef) { return; }
|
if (!funcDef) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.$apply(function() {
|
$scope.$apply(function() {
|
||||||
@@ -57,7 +50,7 @@ function (angular, _, $, gfunc) {
|
|||||||
|
|
||||||
$input.trigger('blur');
|
$input.trigger('blur');
|
||||||
return '';
|
return '';
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
$button.click(function() {
|
$button.click(function() {
|
||||||
@@ -82,32 +75,81 @@ function (angular, _, $, gfunc) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$compile(elem.contents())($scope);
|
$compile(elem.contents())($scope);
|
||||||
}
|
});
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
function getAllFunctionNames(categories) {
|
var drop;
|
||||||
return _.reduce(categories, function(list, category) {
|
var cleanUpDrop = function() {
|
||||||
_.each(category, function(func) {
|
if (drop) {
|
||||||
list.push(func.name);
|
drop.destroy();
|
||||||
});
|
drop = null;
|
||||||
return list;
|
}
|
||||||
}, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createFunctionDropDownMenu(categories) {
|
|
||||||
return _.map(categories, function(list, category) {
|
|
||||||
var submenu = _.map(list, function(value) {
|
|
||||||
return {
|
|
||||||
text: value.name,
|
|
||||||
click: "ctrl.addFunction('" + value.name + "')",
|
|
||||||
};
|
};
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
$(elem)
|
||||||
text: category,
|
.on('mouseenter', 'ul.dropdown-menu li', function() {
|
||||||
submenu: submenu
|
cleanUpDrop();
|
||||||
};
|
|
||||||
|
var funcDef;
|
||||||
|
try {
|
||||||
|
funcDef = ctrl.datasource.getFuncDef($('a', this).text());
|
||||||
|
} catch (e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
if (funcDef && funcDef.description) {
|
||||||
|
var shortDesc = funcDef.description;
|
||||||
|
if (shortDesc.length > 500) {
|
||||||
|
shortDesc = shortDesc.substring(0, 497) + '...';
|
||||||
|
}
|
||||||
|
|
||||||
|
var contentElement = document.createElement('div');
|
||||||
|
contentElement.innerHTML = '<h4>' + funcDef.name + '</h4>' + rst2html(shortDesc);
|
||||||
|
|
||||||
|
drop = new Drop({
|
||||||
|
target: this,
|
||||||
|
content: contentElement,
|
||||||
|
classes: 'drop-popover',
|
||||||
|
openOn: 'always',
|
||||||
|
tetherOptions: {
|
||||||
|
attachment: 'bottom left',
|
||||||
|
targetAttachment: 'bottom right',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on('mouseout', 'ul.dropdown-menu li', function() {
|
||||||
|
cleanUpDrop();
|
||||||
|
});
|
||||||
|
|
||||||
|
$scope.$on('$destroy', cleanUpDrop);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
function createFunctionDropDownMenu(funcDefs) {
|
||||||
|
var categories = {};
|
||||||
|
|
||||||
|
_.forEach(funcDefs, function(funcDef) {
|
||||||
|
if (!funcDef.category) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!categories[funcDef.category]) {
|
||||||
|
categories[funcDef.category] = [];
|
||||||
|
}
|
||||||
|
categories[funcDef.category].push({
|
||||||
|
text: funcDef.name,
|
||||||
|
click: "ctrl.addFunction('" + funcDef.name + "')",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return _.sortBy(
|
||||||
|
_.map(categories, function(submenu, category) {
|
||||||
|
return {
|
||||||
|
text: category,
|
||||||
|
submenu: _.sortBy(submenu, 'text'),
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
'text'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ export class GraphiteConfigCtrl {
|
|||||||
this.datasourceSrv = datasourceSrv;
|
this.datasourceSrv = datasourceSrv;
|
||||||
this.current.jsonData = this.current.jsonData || {};
|
this.current.jsonData = this.current.jsonData || {};
|
||||||
this.current.jsonData.graphiteVersion = this.current.jsonData.graphiteVersion || '0.9';
|
this.current.jsonData.graphiteVersion = this.current.jsonData.graphiteVersion || '0.9';
|
||||||
|
|
||||||
this.autoDetectGraphiteVersion();
|
this.autoDetectGraphiteVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import * as dateMath from 'app/core/utils/datemath';
|
import * as dateMath from 'app/core/utils/datemath';
|
||||||
import { isVersionGtOrEq, SemVersion } from 'app/core/utils/version';
|
import { isVersionGtOrEq, SemVersion } from 'app/core/utils/version';
|
||||||
|
import gfunc from './gfunc';
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv) {
|
export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv) {
|
||||||
@@ -12,6 +13,8 @@ export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv
|
|||||||
this.cacheTimeout = instanceSettings.cacheTimeout;
|
this.cacheTimeout = instanceSettings.cacheTimeout;
|
||||||
this.withCredentials = instanceSettings.withCredentials;
|
this.withCredentials = instanceSettings.withCredentials;
|
||||||
this.render_method = instanceSettings.render_method || 'POST';
|
this.render_method = instanceSettings.render_method || 'POST';
|
||||||
|
this.funcDefs = null;
|
||||||
|
this.funcDefsPromise = null;
|
||||||
|
|
||||||
this.getQueryOptionsInfo = function() {
|
this.getQueryOptionsInfo = function() {
|
||||||
return {
|
return {
|
||||||
@@ -200,6 +203,35 @@ export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv
|
|||||||
let options = optionalOptions || {};
|
let options = optionalOptions || {};
|
||||||
let interpolatedQuery = templateSrv.replace(query);
|
let interpolatedQuery = templateSrv.replace(query);
|
||||||
|
|
||||||
|
// special handling for tag_values(<tag>[,<expression>]*), this is used for template variables
|
||||||
|
let matches = interpolatedQuery.match(/^tag_values\(([^,]+)((, *[^,]+)*)\)$/);
|
||||||
|
if (matches) {
|
||||||
|
const expressions = [];
|
||||||
|
const exprRegex = /, *([^,]+)/g;
|
||||||
|
let match;
|
||||||
|
while ((match = exprRegex.exec(matches[2])) !== null) {
|
||||||
|
expressions.push(match[1]);
|
||||||
|
}
|
||||||
|
options.limit = 10000;
|
||||||
|
return this.getTagValuesAutoComplete(expressions, matches[1], undefined, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
// special handling for tags(<expression>[,<expression>]*), this is used for template variables
|
||||||
|
matches = interpolatedQuery.match(/^tags\(([^,]*)((, *[^,]+)*)\)$/);
|
||||||
|
if (matches) {
|
||||||
|
const expressions = [];
|
||||||
|
if (matches[1]) {
|
||||||
|
expressions.push(matches[1]);
|
||||||
|
const exprRegex = /, *([^,]+)/g;
|
||||||
|
let match;
|
||||||
|
while ((match = exprRegex.exec(matches[2])) !== null) {
|
||||||
|
expressions.push(match[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
options.limit = 10000;
|
||||||
|
return this.getTagsAutoComplete(expressions, undefined, options);
|
||||||
|
}
|
||||||
|
|
||||||
let httpOptions: any = {
|
let httpOptions: any = {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/metrics/find',
|
url: '/metrics/find',
|
||||||
@@ -210,7 +242,7 @@ export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv
|
|||||||
requestId: options.requestId,
|
requestId: options.requestId,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (options && options.range) {
|
if (options.range) {
|
||||||
httpOptions.params.from = this.translateTime(options.range.from, false);
|
httpOptions.params.from = this.translateTime(options.range.from, false);
|
||||||
httpOptions.params.until = this.translateTime(options.range.to, true);
|
httpOptions.params.until = this.translateTime(options.range.to, true);
|
||||||
}
|
}
|
||||||
@@ -235,7 +267,7 @@ export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv
|
|||||||
requestId: options.requestId,
|
requestId: options.requestId,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (options && options.range) {
|
if (options.range) {
|
||||||
httpOptions.params.from = this.translateTime(options.range.from, false);
|
httpOptions.params.from = this.translateTime(options.range.from, false);
|
||||||
httpOptions.params.until = this.translateTime(options.range.to, true);
|
httpOptions.params.until = this.translateTime(options.range.to, true);
|
||||||
}
|
}
|
||||||
@@ -255,12 +287,12 @@ export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv
|
|||||||
|
|
||||||
let httpOptions: any = {
|
let httpOptions: any = {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/tags/' + tag,
|
url: '/tags/' + templateSrv.replace(tag),
|
||||||
// for cancellations
|
// for cancellations
|
||||||
requestId: options.requestId,
|
requestId: options.requestId,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (options && options.range) {
|
if (options.range) {
|
||||||
httpOptions.params.from = this.translateTime(options.range.from, false);
|
httpOptions.params.from = this.translateTime(options.range.from, false);
|
||||||
httpOptions.params.until = this.translateTime(options.range.to, true);
|
httpOptions.params.until = this.translateTime(options.range.to, true);
|
||||||
}
|
}
|
||||||
@@ -279,18 +311,29 @@ export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getTagsAutoComplete = (expression, tagPrefix) => {
|
this.getTagsAutoComplete = (expressions, tagPrefix, optionalOptions) => {
|
||||||
|
let options = optionalOptions || {};
|
||||||
|
|
||||||
let httpOptions: any = {
|
let httpOptions: any = {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/tags/autoComplete/tags',
|
url: '/tags/autoComplete/tags',
|
||||||
params: {
|
params: {
|
||||||
expr: expression,
|
expr: _.map(expressions, expression => templateSrv.replace(expression)),
|
||||||
},
|
},
|
||||||
|
// for cancellations
|
||||||
|
requestId: options.requestId,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (tagPrefix) {
|
if (tagPrefix) {
|
||||||
httpOptions.params.tagPrefix = tagPrefix;
|
httpOptions.params.tagPrefix = tagPrefix;
|
||||||
}
|
}
|
||||||
|
if (options.limit) {
|
||||||
|
httpOptions.params.limit = options.limit;
|
||||||
|
}
|
||||||
|
if (options.range) {
|
||||||
|
httpOptions.params.from = this.translateTime(options.range.from, false);
|
||||||
|
httpOptions.params.until = this.translateTime(options.range.to, true);
|
||||||
|
}
|
||||||
|
|
||||||
return this.doGraphiteRequest(httpOptions).then(results => {
|
return this.doGraphiteRequest(httpOptions).then(results => {
|
||||||
if (results.data) {
|
if (results.data) {
|
||||||
@@ -303,19 +346,30 @@ export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getTagValuesAutoComplete = (expression, tag, valuePrefix) => {
|
this.getTagValuesAutoComplete = (expressions, tag, valuePrefix, optionalOptions) => {
|
||||||
|
let options = optionalOptions || {};
|
||||||
|
|
||||||
let httpOptions: any = {
|
let httpOptions: any = {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/tags/autoComplete/values',
|
url: '/tags/autoComplete/values',
|
||||||
params: {
|
params: {
|
||||||
expr: expression,
|
expr: _.map(expressions, expression => templateSrv.replace(expression)),
|
||||||
tag: tag,
|
tag: templateSrv.replace(tag),
|
||||||
},
|
},
|
||||||
|
// for cancellations
|
||||||
|
requestId: options.requestId,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (valuePrefix) {
|
if (valuePrefix) {
|
||||||
httpOptions.params.valuePrefix = valuePrefix;
|
httpOptions.params.valuePrefix = valuePrefix;
|
||||||
}
|
}
|
||||||
|
if (options.limit) {
|
||||||
|
httpOptions.params.limit = options.limit;
|
||||||
|
}
|
||||||
|
if (options.range) {
|
||||||
|
httpOptions.params.from = this.translateTime(options.range.from, false);
|
||||||
|
httpOptions.params.until = this.translateTime(options.range.to, true);
|
||||||
|
}
|
||||||
|
|
||||||
return this.doGraphiteRequest(httpOptions).then(results => {
|
return this.doGraphiteRequest(httpOptions).then(results => {
|
||||||
if (results.data) {
|
if (results.data) {
|
||||||
@@ -328,10 +382,13 @@ export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getVersion = function() {
|
this.getVersion = function(optionalOptions) {
|
||||||
|
let options = optionalOptions || {};
|
||||||
|
|
||||||
let httpOptions = {
|
let httpOptions = {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: '/version/_', // Prevent last / trimming
|
url: '/version',
|
||||||
|
requestId: options.requestId,
|
||||||
};
|
};
|
||||||
|
|
||||||
return this.doGraphiteRequest(httpOptions)
|
return this.doGraphiteRequest(httpOptions)
|
||||||
@@ -347,6 +404,52 @@ export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.createFuncInstance = function(funcDef, options?) {
|
||||||
|
return gfunc.createFuncInstance(funcDef, options, this.funcDefs);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getFuncDef = function(name) {
|
||||||
|
return gfunc.getFuncDef(name, this.funcDefs);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.waitForFuncDefsLoaded = function() {
|
||||||
|
return this.getFuncDefs();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getFuncDefs = function() {
|
||||||
|
if (this.funcDefsPromise !== null) {
|
||||||
|
return this.funcDefsPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!supportsFunctionIndex(this.graphiteVersion)) {
|
||||||
|
this.funcDefs = gfunc.getFuncDefs(this.graphiteVersion);
|
||||||
|
this.funcDefsPromise = Promise.resolve(this.funcDefs);
|
||||||
|
return this.funcDefsPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
let httpOptions = {
|
||||||
|
method: 'GET',
|
||||||
|
url: '/functions',
|
||||||
|
};
|
||||||
|
|
||||||
|
this.funcDefsPromise = this.doGraphiteRequest(httpOptions)
|
||||||
|
.then(results => {
|
||||||
|
if (results.status !== 200 || typeof results.data !== 'object') {
|
||||||
|
this.funcDefs = gfunc.getFuncDefs(this.graphiteVersion);
|
||||||
|
} else {
|
||||||
|
this.funcDefs = gfunc.parseFuncDefs(results.data);
|
||||||
|
}
|
||||||
|
return this.funcDefs;
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.log('Fetching graphite functions error', err);
|
||||||
|
this.funcDefs = gfunc.getFuncDefs(this.graphiteVersion);
|
||||||
|
return this.funcDefs;
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.funcDefsPromise;
|
||||||
|
};
|
||||||
|
|
||||||
this.testDatasource = function() {
|
this.testDatasource = function() {
|
||||||
return this.metricFindQuery('*').then(function() {
|
return this.metricFindQuery('*').then(function() {
|
||||||
return { status: 'success', message: 'Data source is working' };
|
return { status: 'success', message: 'Data source is working' };
|
||||||
@@ -440,3 +543,7 @@ export function GraphiteDatasource(instanceSettings, $q, backendSrv, templateSrv
|
|||||||
function supportsTags(version: string): boolean {
|
function supportsTags(version: string): boolean {
|
||||||
return isVersionGtOrEq(version, '1.1');
|
return isVersionGtOrEq(version, '1.1');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function supportsFunctionIndex(version: string): boolean {
|
||||||
|
return isVersionGtOrEq(version, '1.1');
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,17 +2,18 @@ define([
|
|||||||
'angular',
|
'angular',
|
||||||
'lodash',
|
'lodash',
|
||||||
'jquery',
|
'jquery',
|
||||||
|
'rst2html',
|
||||||
],
|
],
|
||||||
function (angular, _, $) {
|
function (angular, _, $, rst2html) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular
|
angular
|
||||||
.module('grafana.directives')
|
.module('grafana.directives')
|
||||||
.directive('graphiteFuncEditor', function($compile, templateSrv) {
|
.directive('graphiteFuncEditor', function($compile, templateSrv, popoverSrv) {
|
||||||
|
|
||||||
var funcSpanTemplate = '<a ng-click="">{{func.def.name}}</a><span>(</span>';
|
var funcSpanTemplate = '<a ng-click="">{{func.def.name}}</a><span>(</span>';
|
||||||
var paramTemplate = '<input type="text" style="display:none"' +
|
var paramTemplate = '<input type="text" style="display:none"' +
|
||||||
' class="input-mini tight-form-func-param"></input>';
|
' class="input-small tight-form-func-param"></input>';
|
||||||
|
|
||||||
var funcControlsTemplate =
|
var funcControlsTemplate =
|
||||||
'<div class="tight-form-func-controls">' +
|
'<div class="tight-form-func-controls">' +
|
||||||
@@ -29,19 +30,20 @@ function (angular, _, $) {
|
|||||||
var $funcControls = $(funcControlsTemplate);
|
var $funcControls = $(funcControlsTemplate);
|
||||||
var ctrl = $scope.ctrl;
|
var ctrl = $scope.ctrl;
|
||||||
var func = $scope.func;
|
var func = $scope.func;
|
||||||
var funcDef = func.def;
|
|
||||||
var scheduledRelink = false;
|
var scheduledRelink = false;
|
||||||
var paramCountAtLink = 0;
|
var paramCountAtLink = 0;
|
||||||
|
var cancelBlur = null;
|
||||||
|
|
||||||
function clickFuncParam(paramIndex) {
|
function clickFuncParam(paramIndex) {
|
||||||
/*jshint validthis:true */
|
/*jshint validthis:true */
|
||||||
|
|
||||||
var $link = $(this);
|
var $link = $(this);
|
||||||
|
var $comma = $link.prev('.comma');
|
||||||
var $input = $link.next();
|
var $input = $link.next();
|
||||||
|
|
||||||
$input.val(func.params[paramIndex]);
|
$input.val(func.params[paramIndex]);
|
||||||
$input.css('width', ($link.width() + 16) + 'px');
|
|
||||||
|
|
||||||
|
$comma.removeClass('last');
|
||||||
$link.hide();
|
$link.hide();
|
||||||
$input.show();
|
$input.show();
|
||||||
$input.focus();
|
$input.focus();
|
||||||
@@ -68,31 +70,64 @@ function (angular, _, $) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function inputBlur(paramIndex) {
|
function paramDef(index) {
|
||||||
|
if (index < func.def.params.length) {
|
||||||
|
return func.def.params[index];
|
||||||
|
}
|
||||||
|
if (_.last(func.def.params).multiple) {
|
||||||
|
return _.assign({}, _.last(func.def.params), {optional: true});
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function switchToLink(inputElem, paramIndex) {
|
||||||
/*jshint validthis:true */
|
/*jshint validthis:true */
|
||||||
var $input = $(this);
|
var $input = $(inputElem);
|
||||||
|
|
||||||
|
clearTimeout(cancelBlur);
|
||||||
|
cancelBlur = null;
|
||||||
|
|
||||||
var $link = $input.prev();
|
var $link = $input.prev();
|
||||||
|
var $comma = $link.prev('.comma');
|
||||||
var newValue = $input.val();
|
var newValue = $input.val();
|
||||||
|
|
||||||
if (newValue !== '' || func.def.params[paramIndex].optional) {
|
// remove optional empty params
|
||||||
$link.html(templateSrv.highlightVariablesAsHtml(newValue));
|
if (newValue !== '' || paramDef(paramIndex).optional) {
|
||||||
|
func.updateParam(newValue, paramIndex);
|
||||||
func.updateParam($input.val(), paramIndex);
|
$link.html(newValue ? templateSrv.highlightVariablesAsHtml(newValue) : ' ');
|
||||||
scheduledRelinkIfNeeded();
|
|
||||||
|
|
||||||
$scope.$apply(function() {
|
|
||||||
ctrl.targetChanged();
|
|
||||||
});
|
|
||||||
|
|
||||||
$input.hide();
|
|
||||||
$link.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
scheduledRelinkIfNeeded();
|
||||||
|
|
||||||
|
$scope.$apply(function() {
|
||||||
|
ctrl.targetChanged();
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($link.hasClass('last') && newValue === '') {
|
||||||
|
$comma.addClass('last');
|
||||||
|
} else {
|
||||||
|
$link.removeClass('last');
|
||||||
|
}
|
||||||
|
|
||||||
|
$input.hide();
|
||||||
|
$link.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// this = input element
|
||||||
|
function inputBlur(paramIndex) {
|
||||||
|
/*jshint validthis:true */
|
||||||
|
var inputElem = this;
|
||||||
|
// happens long before the click event on the typeahead options
|
||||||
|
// need to have long delay because the blur
|
||||||
|
cancelBlur = setTimeout(function() {
|
||||||
|
switchToLink(inputElem, paramIndex);
|
||||||
|
}, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
function inputKeyPress(paramIndex, e) {
|
function inputKeyPress(paramIndex, e) {
|
||||||
/*jshint validthis:true */
|
/*jshint validthis:true */
|
||||||
if(e.which === 13) {
|
if(e.which === 13) {
|
||||||
inputBlur.call(this, paramIndex);
|
$(this).blur();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,8 +139,8 @@ function (angular, _, $) {
|
|||||||
function addTypeahead($input, paramIndex) {
|
function addTypeahead($input, paramIndex) {
|
||||||
$input.attr('data-provide', 'typeahead');
|
$input.attr('data-provide', 'typeahead');
|
||||||
|
|
||||||
var options = funcDef.params[paramIndex].options;
|
var options = paramDef(paramIndex).options;
|
||||||
if (funcDef.params[paramIndex].type === 'int') {
|
if (paramDef(paramIndex).type === 'int') {
|
||||||
options = _.map(options, function(val) { return val.toString(); });
|
options = _.map(options, function(val) { return val.toString(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,9 +149,8 @@ function (angular, _, $) {
|
|||||||
minLength: 0,
|
minLength: 0,
|
||||||
items: 20,
|
items: 20,
|
||||||
updater: function (value) {
|
updater: function (value) {
|
||||||
setTimeout(function() {
|
$input.val(value);
|
||||||
inputBlur.call($input[0], paramIndex);
|
switchToLink($input[0], paramIndex);
|
||||||
}, 0);
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -148,18 +182,34 @@ function (angular, _, $) {
|
|||||||
$funcControls.appendTo(elem);
|
$funcControls.appendTo(elem);
|
||||||
$funcLink.appendTo(elem);
|
$funcLink.appendTo(elem);
|
||||||
|
|
||||||
_.each(funcDef.params, function(param, index) {
|
var defParams = _.clone(func.def.params);
|
||||||
if (param.optional && func.params.length <= index) {
|
var lastParam = _.last(func.def.params);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index > 0) {
|
while (func.params.length >= defParams.length && lastParam && lastParam.multiple) {
|
||||||
$('<span>, </span>').appendTo(elem);
|
defParams.push(_.assign({}, lastParam, {optional: true}));
|
||||||
|
}
|
||||||
|
|
||||||
|
_.each(defParams, function(param, index) {
|
||||||
|
if (param.optional && func.params.length < index) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var paramValue = templateSrv.highlightVariablesAsHtml(func.params[index]);
|
var paramValue = templateSrv.highlightVariablesAsHtml(func.params[index]);
|
||||||
var $paramLink = $('<a ng-click="" class="graphite-func-param-link">' + paramValue + '</a>');
|
|
||||||
|
var last = (index >= func.params.length - 1) && param.optional && !paramValue;
|
||||||
|
if (last && param.multiple) {
|
||||||
|
paramValue = '+';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index > 0) {
|
||||||
|
$('<span class="comma' + (last ? ' last' : '') + '">, </span>').appendTo(elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
var $paramLink = $(
|
||||||
|
'<a ng-click="" class="graphite-func-param-link' + (last ? ' last' : '') + '">'
|
||||||
|
+ (paramValue || ' ') + '</a>');
|
||||||
var $input = $(paramTemplate);
|
var $input = $(paramTemplate);
|
||||||
|
$input.attr('placeholder', param.name);
|
||||||
|
|
||||||
paramCountAtLink++;
|
paramCountAtLink++;
|
||||||
|
|
||||||
@@ -171,10 +221,9 @@ function (angular, _, $) {
|
|||||||
$input.keypress(_.partial(inputKeyPress, index));
|
$input.keypress(_.partial(inputKeyPress, index));
|
||||||
$paramLink.click(_.partial(clickFuncParam, index));
|
$paramLink.click(_.partial(clickFuncParam, index));
|
||||||
|
|
||||||
if (funcDef.params[index].options) {
|
if (param.options) {
|
||||||
addTypeahead($input, index);
|
addTypeahead($input, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$('<span>)</span>').appendTo(elem);
|
$('<span>)</span>').appendTo(elem);
|
||||||
@@ -182,7 +231,7 @@ function (angular, _, $) {
|
|||||||
$compile(elem.contents())($scope);
|
$compile(elem.contents())($scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ifJustAddedFocusFistParam() {
|
function ifJustAddedFocusFirstParam() {
|
||||||
if ($scope.func.added) {
|
if ($scope.func.added) {
|
||||||
$scope.func.added = false;
|
$scope.func.added = false;
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
@@ -223,7 +272,20 @@ function (angular, _, $) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($target.hasClass('fa-question-circle')) {
|
if ($target.hasClass('fa-question-circle')) {
|
||||||
window.open("http://graphite.readthedocs.org/en/latest/functions.html#graphite.render.functions." + funcDef.name,'_blank');
|
var funcDef = ctrl.datasource.getFuncDef(func.def.name);
|
||||||
|
if (funcDef && funcDef.description) {
|
||||||
|
popoverSrv.show({
|
||||||
|
element: e.target,
|
||||||
|
position: 'bottom left',
|
||||||
|
classNames: 'drop-popover drop-function-def',
|
||||||
|
template: '<div style="overflow:auto;max-height:30rem;">'
|
||||||
|
+ '<h4>' + funcDef.name + '</h4>' + rst2html(funcDef.description) + '</div>',
|
||||||
|
openOn: 'click',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
window.open(
|
||||||
|
"http://graphite.readthedocs.org/en/latest/functions.html#graphite.render.functions." + func.def.name,'_blank');
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -233,7 +295,7 @@ function (angular, _, $) {
|
|||||||
elem.children().remove();
|
elem.children().remove();
|
||||||
|
|
||||||
addElementsAndCompile();
|
addElementsAndCompile();
|
||||||
ifJustAddedFocusFistParam();
|
ifJustAddedFocusFirstParam();
|
||||||
registerFuncControlsToggle();
|
registerFuncControlsToggle();
|
||||||
registerFuncControlsActions();
|
registerFuncControlsActions();
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,8 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import gfunc from './gfunc';
|
|
||||||
import { Parser } from './parser';
|
import { Parser } from './parser';
|
||||||
|
|
||||||
export default class GraphiteQuery {
|
export default class GraphiteQuery {
|
||||||
|
datasource: any;
|
||||||
target: any;
|
target: any;
|
||||||
functions: any[];
|
functions: any[];
|
||||||
segments: any[];
|
segments: any[];
|
||||||
@@ -15,7 +15,8 @@ export default class GraphiteQuery {
|
|||||||
scopedVars: any;
|
scopedVars: any;
|
||||||
|
|
||||||
/** @ngInject */
|
/** @ngInject */
|
||||||
constructor(target, templateSrv?, scopedVars?) {
|
constructor(datasource, target, templateSrv?, scopedVars?) {
|
||||||
|
this.datasource = datasource;
|
||||||
this.target = target;
|
this.target = target;
|
||||||
this.parseTarget();
|
this.parseTarget();
|
||||||
|
|
||||||
@@ -86,7 +87,7 @@ export default class GraphiteQuery {
|
|||||||
|
|
||||||
switch (astNode.type) {
|
switch (astNode.type) {
|
||||||
case 'function':
|
case 'function':
|
||||||
var innerFunc = gfunc.createFuncInstance(astNode.name, {
|
var innerFunc = this.datasource.createFuncInstance(astNode.name, {
|
||||||
withDefaultParams: false,
|
withDefaultParams: false,
|
||||||
});
|
});
|
||||||
_.each(astNode.params, param => {
|
_.each(astNode.params, param => {
|
||||||
@@ -133,7 +134,7 @@ export default class GraphiteQuery {
|
|||||||
|
|
||||||
moveAliasFuncLast() {
|
moveAliasFuncLast() {
|
||||||
var aliasFunc = _.find(this.functions, function(func) {
|
var aliasFunc = _.find(this.functions, function(func) {
|
||||||
return func.def.name === 'alias' || func.def.name === 'aliasByNode' || func.def.name === 'aliasByMetric';
|
return func.def.name.startsWith('alias');
|
||||||
});
|
});
|
||||||
|
|
||||||
if (aliasFunc) {
|
if (aliasFunc) {
|
||||||
@@ -143,7 +144,7 @@ export default class GraphiteQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addFunctionParameter(func, value) {
|
addFunctionParameter(func, value) {
|
||||||
if (func.params.length >= func.def.params.length) {
|
if (func.params.length >= func.def.params.length && !_.get(_.last(func.def.params), 'multiple', false)) {
|
||||||
throw { message: 'too many parameters for function ' + func.def.name };
|
throw { message: 'too many parameters for function ' + func.def.name };
|
||||||
}
|
}
|
||||||
func.params.push(value);
|
func.params.push(value);
|
||||||
@@ -208,7 +209,7 @@ export default class GraphiteQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
splitSeriesByTagParams(func) {
|
splitSeriesByTagParams(func) {
|
||||||
const tagPattern = /([^\!=~]+)([\!=~]+)([^\!=~]+)/;
|
const tagPattern = /([^\!=~]+)(\!?=~?)(.*)/;
|
||||||
return _.flatten(
|
return _.flatten(
|
||||||
_.map(func.params, (param: string) => {
|
_.map(func.params, (param: string) => {
|
||||||
let matches = tagPattern.exec(param);
|
let matches = tagPattern.exec(param);
|
||||||
|
|||||||
@@ -10,30 +10,50 @@
|
|||||||
<label class="gf-form-label width-6 query-keyword">Series</label>
|
<label class="gf-form-label width-6 query-keyword">Series</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-repeat="tag in ctrl.queryModel.tags" class="gf-form">
|
<div ng-if="ctrl.queryModel.seriesByTagUsed" ng-repeat="tag in ctrl.queryModel.tags" class="gf-form">
|
||||||
<gf-form-dropdown model="tag.key" lookup-text="false" allow-custom="false" label-mode="true" css-class="query-segment-key"
|
<gf-form-dropdown
|
||||||
|
model="tag.key"
|
||||||
|
lookup-text="false"
|
||||||
|
allow-custom="true"
|
||||||
|
label-mode="true"
|
||||||
|
placeholder="Tag key"
|
||||||
|
css-class="query-segment-key"
|
||||||
get-options="ctrl.getTags($index, $query)"
|
get-options="ctrl.getTags($index, $query)"
|
||||||
on-change="ctrl.tagChanged(tag, $index)">
|
on-change="ctrl.tagChanged(tag, $index)"
|
||||||
</gf-form-dropdown>
|
/>
|
||||||
<gf-form-dropdown model="tag.operator" lookup-text="false" allow-custom="false" label-mode="true" css-class="query-segment-operator"
|
<gf-form-dropdown
|
||||||
|
model="tag.operator"
|
||||||
|
lookup-text="false"
|
||||||
|
allow-custom="false"
|
||||||
|
label-mode="true"
|
||||||
|
css-class="query-segment-operator"
|
||||||
get-options="ctrl.getTagOperators()"
|
get-options="ctrl.getTagOperators()"
|
||||||
on-change="ctrl.tagChanged(tag, $index)"
|
on-change="ctrl.tagChanged(tag, $index)"
|
||||||
min-input-width="30">
|
min-input-width="30"
|
||||||
</gf-form-dropdown>
|
/>
|
||||||
<gf-form-dropdown model="tag.value" lookup-text="false" allow-custom="false" label-mode="true" css-class="query-segment-value"
|
<gf-form-dropdown
|
||||||
|
model="tag.value"
|
||||||
|
lookup-text="false"
|
||||||
|
allow-custom="true"
|
||||||
|
label-mode="true"
|
||||||
|
css-class="query-segment-value"
|
||||||
|
placeholder="Tag value"
|
||||||
get-options="ctrl.getTagValues(tag, $index, $query)"
|
get-options="ctrl.getTagValues(tag, $index, $query)"
|
||||||
on-change="ctrl.tagChanged(tag, $index)">
|
on-change="ctrl.tagChanged(tag, $index)"
|
||||||
</gf-form-dropdown>
|
/>
|
||||||
<label class="gf-form-label query-keyword" ng-if="ctrl.showDelimiter($index)">AND</label>
|
<label class="gf-form-label query-keyword" ng-if="ctrl.showDelimiter($index)">AND</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-repeat="segment in ctrl.segments" role="menuitem" class="gf-form">
|
<div ng-if="ctrl.queryModel.seriesByTagUsed" ng-repeat="segment in ctrl.addTagSegments" role="menuitem" class="gf-form">
|
||||||
<metric-segment segment="segment" get-options="ctrl.getAltSegments($index)" on-change="ctrl.segmentValueChanged(segment, $index)"></metric-segment>
|
<metric-segment segment="segment" get-options="ctrl.getTagsAsSegments($query)" on-change="ctrl.addNewTag(segment)" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div ng-if="ctrl.queryModel.seriesByTagUsed" ng-repeat="segment in ctrl.addTagSegments" role="menuitem" class="gf-form">
|
<div ng-if="!ctrl.queryModel.seriesByTagUsed" ng-repeat="segment in ctrl.segments" role="menuitem" class="gf-form">
|
||||||
<metric-segment segment="segment" get-options="ctrl.getTagsAsSegments()" on-change="ctrl.addNewTag(segment)">
|
<metric-segment segment="segment" get-options="ctrl.getAltSegments($index, $query)" on-change="ctrl.segmentValueChanged(segment, $index)" />
|
||||||
</metric-segment>
|
</div>
|
||||||
|
|
||||||
|
<div ng-if="ctrl.paused" class="gf-form">
|
||||||
|
<a ng-click="ctrl.unpause()" class="gf-form-label query-part"><i class="fa fa-play"></i></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="gf-form gf-form--grow">
|
<div class="gf-form gf-form--grow">
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import './add_graphite_func';
|
|||||||
import './func_editor';
|
import './func_editor';
|
||||||
|
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import gfunc from './gfunc';
|
|
||||||
import GraphiteQuery from './graphite_query';
|
import GraphiteQuery from './graphite_query';
|
||||||
import { QueryCtrl } from 'app/plugins/sdk';
|
import { QueryCtrl } from 'app/plugins/sdk';
|
||||||
import appEvents from 'app/core/app_events';
|
import appEvents from 'app/core/app_events';
|
||||||
@@ -18,17 +17,19 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|||||||
addTagSegments: any[];
|
addTagSegments: any[];
|
||||||
removeTagValue: string;
|
removeTagValue: string;
|
||||||
supportsTags: boolean;
|
supportsTags: boolean;
|
||||||
|
paused: boolean;
|
||||||
|
|
||||||
/** @ngInject **/
|
/** @ngInject **/
|
||||||
constructor($scope, $injector, private uiSegmentSrv, private templateSrv) {
|
constructor($scope, $injector, private uiSegmentSrv, private templateSrv, $timeout) {
|
||||||
super($scope, $injector);
|
super($scope, $injector);
|
||||||
this.supportsTags = this.datasource.supportsTags;
|
this.supportsTags = this.datasource.supportsTags;
|
||||||
|
this.paused = false;
|
||||||
|
this.target.target = this.target.target || '';
|
||||||
|
|
||||||
if (this.target) {
|
this.datasource.waitForFuncDefsLoaded().then(() => {
|
||||||
this.target.target = this.target.target || '';
|
this.queryModel = new GraphiteQuery(this.datasource, this.target, templateSrv);
|
||||||
this.queryModel = new GraphiteQuery(this.target, templateSrv);
|
|
||||||
this.buildSegments();
|
this.buildSegments();
|
||||||
}
|
});
|
||||||
|
|
||||||
this.removeTagValue = '-- remove tag --';
|
this.removeTagValue = '-- remove tag --';
|
||||||
}
|
}
|
||||||
@@ -104,8 +105,11 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getAltSegments(index) {
|
getAltSegments(index, prefix) {
|
||||||
var query = index === 0 ? '*' : this.queryModel.getSegmentPathUpTo(index) + '.*';
|
var query = prefix && prefix.length > 0 ? '*' + prefix + '*' : '*';
|
||||||
|
if (index > 0) {
|
||||||
|
query = this.queryModel.getSegmentPathUpTo(index) + '.' + query;
|
||||||
|
}
|
||||||
var options = {
|
var options = {
|
||||||
range: this.panelCtrl.range,
|
range: this.panelCtrl.range,
|
||||||
requestId: 'get-alt-segments',
|
requestId: 'get-alt-segments',
|
||||||
@@ -121,7 +125,7 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (altSegments.length === 0) {
|
if (index > 0 && altSegments.length === 0) {
|
||||||
return altSegments;
|
return altSegments;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +162,7 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|||||||
|
|
||||||
if (this.supportsTags && index === 0) {
|
if (this.supportsTags && index === 0) {
|
||||||
this.removeTaggedEntry(altSegments);
|
this.removeTaggedEntry(altSegments);
|
||||||
return this.addAltTagSegments(index, altSegments);
|
return this.addAltTagSegments(prefix, altSegments);
|
||||||
} else {
|
} else {
|
||||||
return altSegments;
|
return altSegments;
|
||||||
}
|
}
|
||||||
@@ -168,8 +172,8 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
addAltTagSegments(index, altSegments) {
|
addAltTagSegments(prefix, altSegments) {
|
||||||
return this.getTagsAsSegments().then(tagSegments => {
|
return this.getTagsAsSegments(prefix).then(tagSegments => {
|
||||||
tagSegments = _.map(tagSegments, segment => {
|
tagSegments = _.map(tagSegments, segment => {
|
||||||
segment.value = TAG_PREFIX + segment.value;
|
segment.value = TAG_PREFIX + segment.value;
|
||||||
return segment;
|
return segment;
|
||||||
@@ -192,6 +196,7 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|||||||
|
|
||||||
if (segment.type === 'tag') {
|
if (segment.type === 'tag') {
|
||||||
let tag = removeTagPrefix(segment.value);
|
let tag = removeTagPrefix(segment.value);
|
||||||
|
this.pause();
|
||||||
this.addSeriesByTagFunc(tag);
|
this.addSeriesByTagFunc(tag);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -236,13 +241,13 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|||||||
var oldTarget = this.queryModel.target.target;
|
var oldTarget = this.queryModel.target.target;
|
||||||
this.updateModelTarget();
|
this.updateModelTarget();
|
||||||
|
|
||||||
if (this.queryModel.target !== oldTarget) {
|
if (this.queryModel.target !== oldTarget && !this.paused) {
|
||||||
this.panelCtrl.refresh();
|
this.panelCtrl.refresh();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addFunction(funcDef) {
|
addFunction(funcDef) {
|
||||||
var newFunc = gfunc.createFuncInstance(funcDef, {
|
var newFunc = this.datasource.createFuncInstance(funcDef, {
|
||||||
withDefaultParams: true,
|
withDefaultParams: true,
|
||||||
});
|
});
|
||||||
newFunc.added = true;
|
newFunc.added = true;
|
||||||
@@ -268,11 +273,10 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addSeriesByTagFunc(tag) {
|
addSeriesByTagFunc(tag) {
|
||||||
let funcDef = gfunc.getFuncDef('seriesByTag');
|
let newFunc = this.datasource.createFuncInstance('seriesByTag', {
|
||||||
let newFunc = gfunc.createFuncInstance(funcDef, {
|
|
||||||
withDefaultParams: false,
|
withDefaultParams: false,
|
||||||
});
|
});
|
||||||
let tagParam = `${tag}=select tag value`;
|
let tagParam = `${tag}=`;
|
||||||
newFunc.params = [tagParam];
|
newFunc.params = [tagParam];
|
||||||
this.queryModel.addFunction(newFunc);
|
this.queryModel.addFunction(newFunc);
|
||||||
newFunc.added = true;
|
newFunc.added = true;
|
||||||
@@ -314,9 +318,9 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getTagsAsSegments() {
|
getTagsAsSegments(tagPrefix) {
|
||||||
let tagExpressions = this.queryModel.renderTagExpressions();
|
let tagExpressions = this.queryModel.renderTagExpressions();
|
||||||
return this.datasource.getTagsAutoComplete(tagExpressions).then(values => {
|
return this.datasource.getTagsAutoComplete(tagExpressions, tagPrefix).then(values => {
|
||||||
return _.map(values, val => {
|
return _.map(values, val => {
|
||||||
return this.uiSegmentSrv.newSegment({
|
return this.uiSegmentSrv.newSegment({
|
||||||
value: val.text,
|
value: val.text,
|
||||||
@@ -355,7 +359,7 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|||||||
|
|
||||||
addNewTag(segment) {
|
addNewTag(segment) {
|
||||||
let newTagKey = segment.value;
|
let newTagKey = segment.value;
|
||||||
let newTag = { key: newTagKey, operator: '=', value: 'select tag value' };
|
let newTag = { key: newTagKey, operator: '=', value: '' };
|
||||||
this.queryModel.addTag(newTag);
|
this.queryModel.addTag(newTag);
|
||||||
this.targetChanged();
|
this.targetChanged();
|
||||||
this.fixTagSegments();
|
this.fixTagSegments();
|
||||||
@@ -374,6 +378,15 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
|||||||
showDelimiter(index) {
|
showDelimiter(index) {
|
||||||
return index !== this.queryModel.tags.length - 1;
|
return index !== this.queryModel.tags.length - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pause() {
|
||||||
|
this.paused = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unpause() {
|
||||||
|
this.paused = false;
|
||||||
|
this.panelCtrl.refresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapToDropdownOptions(results) {
|
function mapToDropdownOptions(results) {
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ describe('when creating func instance from func names', function() {
|
|||||||
var func = gfunc.createFuncInstance('sumSeries');
|
var func = gfunc.createFuncInstance('sumSeries');
|
||||||
expect(func).toBeTruthy();
|
expect(func).toBeTruthy();
|
||||||
expect(func.def.name).toEqual('sumSeries');
|
expect(func.def.name).toEqual('sumSeries');
|
||||||
expect(func.def.params.length).toEqual(5);
|
expect(func.def.params.length).toEqual(1);
|
||||||
|
expect(func.def.params[0].multiple).toEqual(true);
|
||||||
expect(func.def.defaultParams.length).toEqual(1);
|
expect(func.def.defaultParams.length).toEqual(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -74,10 +75,10 @@ describe('when rendering func instance', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when requesting function categories', function() {
|
describe('when requesting function definitions', function() {
|
||||||
it('should return function categories', function() {
|
it('should return function definitions', function() {
|
||||||
var catIndex = gfunc.getCategories('1.0');
|
var funcIndex = gfunc.getFuncDefs('1.0');
|
||||||
expect(catIndex.Special.length).toBeGreaterThan(8);
|
expect(Object.keys(funcIndex).length).toBeGreaterThan(8);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,10 @@ describe('GraphiteQueryCtrl', function() {
|
|||||||
ctx.scope = $rootScope.$new();
|
ctx.scope = $rootScope.$new();
|
||||||
ctx.target = { target: 'aliasByNode(scaleToSeconds(test.prod.*,1),2)' };
|
ctx.target = { target: 'aliasByNode(scaleToSeconds(test.prod.*,1),2)' };
|
||||||
ctx.datasource.metricFindQuery = sinon.stub().returns(ctx.$q.when([]));
|
ctx.datasource.metricFindQuery = sinon.stub().returns(ctx.$q.when([]));
|
||||||
|
ctx.datasource.getFuncDefs = sinon.stub().returns(ctx.$q.when(gfunc.getFuncDefs('1.0')));
|
||||||
|
ctx.datasource.getFuncDef = gfunc.getFuncDef;
|
||||||
|
ctx.datasource.waitForFuncDefsLoaded = sinon.stub().returns(ctx.$q.when(null));
|
||||||
|
ctx.datasource.createFuncInstance = gfunc.createFuncInstance;
|
||||||
ctx.panelCtrl = { panel: {} };
|
ctx.panelCtrl = { panel: {} };
|
||||||
ctx.panelCtrl = {
|
ctx.panelCtrl = {
|
||||||
panel: {
|
panel: {
|
||||||
@@ -180,7 +184,21 @@ describe('GraphiteQueryCtrl', function() {
|
|||||||
ctx.ctrl.target.target = 'scaleToSeconds(#A, 60)';
|
ctx.ctrl.target.target = 'scaleToSeconds(#A, 60)';
|
||||||
ctx.ctrl.datasource.metricFindQuery = sinon.stub().returns(ctx.$q.when([{ expandable: false }]));
|
ctx.ctrl.datasource.metricFindQuery = sinon.stub().returns(ctx.$q.when([{ expandable: false }]));
|
||||||
ctx.ctrl.parseTarget();
|
ctx.ctrl.parseTarget();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add function params', function() {
|
||||||
|
expect(ctx.ctrl.queryModel.segments.length).to.be(1);
|
||||||
|
expect(ctx.ctrl.queryModel.segments[0].value).to.be('#A');
|
||||||
|
|
||||||
|
expect(ctx.ctrl.queryModel.functions[0].params.length).to.be(1);
|
||||||
|
expect(ctx.ctrl.queryModel.functions[0].params[0]).to.be(60);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('target should remain the same', function() {
|
||||||
|
expect(ctx.ctrl.target.target).to.be('scaleToSeconds(#A, 60)');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('targetFull should include nested queries', function() {
|
||||||
ctx.ctrl.panelCtrl.panel.targets = [
|
ctx.ctrl.panelCtrl.panel.targets = [
|
||||||
{
|
{
|
||||||
target: 'nested.query.count',
|
target: 'nested.query.count',
|
||||||
@@ -189,13 +207,9 @@ describe('GraphiteQueryCtrl', function() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
ctx.ctrl.updateModelTarget();
|
ctx.ctrl.updateModelTarget();
|
||||||
});
|
|
||||||
|
|
||||||
it('target should remain the same', function() {
|
|
||||||
expect(ctx.ctrl.target.target).to.be('scaleToSeconds(#A, 60)');
|
expect(ctx.ctrl.target.target).to.be('scaleToSeconds(#A, 60)');
|
||||||
});
|
|
||||||
|
|
||||||
it('targetFull should include nexted queries', function() {
|
|
||||||
expect(ctx.ctrl.target.targetFull).to.be('scaleToSeconds(nested.query.count, 60)');
|
expect(ctx.ctrl.target.targetFull).to.be('scaleToSeconds(nested.query.count, 60)');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -271,12 +285,12 @@ describe('GraphiteQueryCtrl', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should update tags with default value', function() {
|
it('should update tags with default value', function() {
|
||||||
const expected = [{ key: 'tag1', operator: '=', value: 'select tag value' }];
|
const expected = [{ key: 'tag1', operator: '=', value: '' }];
|
||||||
expect(ctx.ctrl.queryModel.tags).to.eql(expected);
|
expect(ctx.ctrl.queryModel.tags).to.eql(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update target', function() {
|
it('should update target', function() {
|
||||||
const expected = "seriesByTag('tag1=select tag value')";
|
const expected = "seriesByTag('tag1=')";
|
||||||
expect(ctx.ctrl.target.target).to.eql(expected);
|
expect(ctx.ctrl.target.target).to.eql(expected);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -89,7 +89,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"].tight-form-func-param {
|
input[type='text'].tight-form-func-param {
|
||||||
|
font-size: 0.875rem;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -129,32 +130,6 @@ input[type="text"].tight-form-func-param {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"].tight-form-func-param {
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tight-form-func-controls {
|
|
||||||
display: none;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
.fa-arrow-left {
|
|
||||||
float: left;
|
|
||||||
position: relative;
|
|
||||||
top: 2px;
|
|
||||||
}
|
|
||||||
.fa-arrow-right {
|
|
||||||
float: right;
|
|
||||||
position: relative;
|
|
||||||
top: 2px;
|
|
||||||
}
|
|
||||||
.fa-remove {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.query-troubleshooter {
|
.query-troubleshooter {
|
||||||
font-size: $font-size-sm;
|
font-size: $font-size-sm;
|
||||||
margin: $gf-form-margin;
|
margin: $gf-form-margin;
|
||||||
@@ -176,3 +151,34 @@ input[type="text"].tight-form-func-param {
|
|||||||
.query-troubleshooter__body {
|
.query-troubleshooter__body {
|
||||||
padding: $spacer 0;
|
padding: $spacer 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.rst-text::before {
|
||||||
|
content: ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-unknown.rst-directive {
|
||||||
|
font-family: monospace;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-interpreted_text {
|
||||||
|
font-family: monospace;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-bullet-list {
|
||||||
|
padding-left: 1.5rem;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-paragraph:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drop-element.drop-popover.drop-function-def .drop-content {
|
||||||
|
max-width: 30rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rst-literal-block .rst-text {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,4 +6,12 @@
|
|||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.last {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .last {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ module.exports = function(grunt) {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
grunt.registerTask('precommit', [
|
grunt.registerTask('precommit', [
|
||||||
|
'jscs',
|
||||||
|
'jshint',
|
||||||
'sasslint',
|
'sasslint',
|
||||||
'exec:tslint',
|
'exec:tslint',
|
||||||
'no-only-tests'
|
'no-only-tests'
|
||||||
|
|||||||
183
yarn.lock
183
yarn.lock
@@ -263,6 +263,10 @@ acorn-dynamic-import@^2.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
acorn "^4.0.3"
|
acorn "^4.0.3"
|
||||||
|
|
||||||
|
acorn-es7-plugin@^1.0.12:
|
||||||
|
version "1.1.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/acorn-es7-plugin/-/acorn-es7-plugin-1.1.7.tgz#f2ee1f3228a90eead1245f9ab1922eb2e71d336b"
|
||||||
|
|
||||||
acorn-globals@^4.0.0:
|
acorn-globals@^4.0.0:
|
||||||
version "4.1.0"
|
version "4.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.1.0.tgz#ab716025dbe17c54d3ef81d32ece2b2d99fe2538"
|
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.1.0.tgz#ab716025dbe17c54d3ef81d32ece2b2d99fe2538"
|
||||||
@@ -279,7 +283,7 @@ acorn@^3.0.4:
|
|||||||
version "3.3.0"
|
version "3.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
|
||||||
|
|
||||||
acorn@^4.0.3:
|
acorn@^4.0.0, acorn@^4.0.3:
|
||||||
version "4.0.13"
|
version "4.0.13"
|
||||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
|
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
|
||||||
|
|
||||||
@@ -525,6 +529,10 @@ array-equal@^1.0.0:
|
|||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
|
resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
|
||||||
|
|
||||||
|
array-filter@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-1.0.0.tgz#baf79e62e6ef4c2a4c0b831232daffec251f9d83"
|
||||||
|
|
||||||
array-filter@~0.0.0:
|
array-filter@~0.0.0:
|
||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec"
|
resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec"
|
||||||
@@ -1512,6 +1520,10 @@ call-limit@~1.1.0:
|
|||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/call-limit/-/call-limit-1.1.0.tgz#6fd61b03f3da42a2cd0ec2b60f02bd0e71991fea"
|
resolved "https://registry.yarnpkg.com/call-limit/-/call-limit-1.1.0.tgz#6fd61b03f3da42a2cd0ec2b60f02bd0e71991fea"
|
||||||
|
|
||||||
|
call-signature@0.0.2:
|
||||||
|
version "0.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/call-signature/-/call-signature-0.0.2.tgz#a84abc825a55ef4cb2b028bd74e205a65b9a4996"
|
||||||
|
|
||||||
caller-path@^0.1.0:
|
caller-path@^0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
|
resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
|
||||||
@@ -2072,6 +2084,10 @@ core-js@^1.0.0:
|
|||||||
version "1.2.7"
|
version "1.2.7"
|
||||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
|
resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
|
||||||
|
|
||||||
|
core-js@^2.0.0:
|
||||||
|
version "2.5.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.3.tgz#8acc38345824f16d8365b7c9b4259168e8ed603e"
|
||||||
|
|
||||||
core-js@^2.2.0, core-js@^2.4.0, core-js@^2.5.0:
|
core-js@^2.2.0, core-js@^2.4.0, core-js@^2.5.0:
|
||||||
version "2.5.1"
|
version "2.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b"
|
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.1.tgz#ae6874dc66937789b80754ff5428df66819ca50b"
|
||||||
@@ -2744,6 +2760,10 @@ di@^0.0.1:
|
|||||||
version "0.0.1"
|
version "0.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c"
|
resolved "https://registry.yarnpkg.com/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c"
|
||||||
|
|
||||||
|
diff-match-patch@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.0.tgz#1cc3c83a490d67f95d91e39f6ad1f2e086b63048"
|
||||||
|
|
||||||
diff@3.3.1:
|
diff@3.3.1:
|
||||||
version "3.3.1"
|
version "3.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75"
|
resolved "https://registry.yarnpkg.com/diff/-/diff-3.3.1.tgz#aa8567a6eed03c531fc89d3f711cd0e5259dec75"
|
||||||
@@ -2891,6 +2911,10 @@ each-async@^1.0.0:
|
|||||||
onetime "^1.0.0"
|
onetime "^1.0.0"
|
||||||
set-immediate-shim "^1.0.0"
|
set-immediate-shim "^1.0.0"
|
||||||
|
|
||||||
|
eastasianwidth@^0.1.1:
|
||||||
|
version "0.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.1.1.tgz#44d656de9da415694467335365fb3147b8572b7c"
|
||||||
|
|
||||||
ecc-jsbn@~0.1.1:
|
ecc-jsbn@~0.1.1:
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
|
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
|
||||||
@@ -2939,6 +2963,20 @@ emojis-list@^2.0.0:
|
|||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
|
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
|
||||||
|
|
||||||
|
empower-core@^0.6.2:
|
||||||
|
version "0.6.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/empower-core/-/empower-core-0.6.2.tgz#5adef566088e31fba80ba0a36df47d7094169144"
|
||||||
|
dependencies:
|
||||||
|
call-signature "0.0.2"
|
||||||
|
core-js "^2.0.0"
|
||||||
|
|
||||||
|
empower@^1.2.3:
|
||||||
|
version "1.2.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/empower/-/empower-1.2.3.tgz#6f0da73447f4edd838fec5c60313a88ba5cb852b"
|
||||||
|
dependencies:
|
||||||
|
core-js "^2.0.0"
|
||||||
|
empower-core "^0.6.2"
|
||||||
|
|
||||||
encodeurl@~1.0.1:
|
encodeurl@~1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20"
|
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20"
|
||||||
@@ -3266,6 +3304,12 @@ esprima@^4.0.0:
|
|||||||
version "4.0.0"
|
version "4.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
|
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
|
||||||
|
|
||||||
|
espurify@^1.6.0:
|
||||||
|
version "1.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/espurify/-/espurify-1.7.0.tgz#1c5cf6cbccc32e6f639380bd4f991fab9ba9d226"
|
||||||
|
dependencies:
|
||||||
|
core-js "^2.0.0"
|
||||||
|
|
||||||
esrecurse@^4.1.0:
|
esrecurse@^4.1.0:
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163"
|
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163"
|
||||||
@@ -3300,7 +3344,7 @@ eventemitter3@1.x.x:
|
|||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508"
|
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508"
|
||||||
|
|
||||||
eventemitter3@^2.0.2:
|
eventemitter3@^2.0.3:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba"
|
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba"
|
||||||
|
|
||||||
@@ -7058,7 +7102,7 @@ object-is@^1.0.1:
|
|||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6"
|
resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6"
|
||||||
|
|
||||||
object-keys@^1.0.11, object-keys@^1.0.8:
|
object-keys@^1.0.0, object-keys@^1.0.11, object-keys@^1.0.8:
|
||||||
version "1.0.11"
|
version "1.0.11"
|
||||||
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
|
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
|
||||||
|
|
||||||
@@ -7809,6 +7853,94 @@ postcss@^6.0.0, postcss@^6.0.1, postcss@^6.0.8:
|
|||||||
source-map "^0.6.1"
|
source-map "^0.6.1"
|
||||||
supports-color "^4.4.0"
|
supports-color "^4.4.0"
|
||||||
|
|
||||||
|
power-assert-context-formatter@^1.0.7:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/power-assert-context-formatter/-/power-assert-context-formatter-1.1.1.tgz#edba352d3ed8a603114d667265acce60d689ccdf"
|
||||||
|
dependencies:
|
||||||
|
core-js "^2.0.0"
|
||||||
|
power-assert-context-traversal "^1.1.1"
|
||||||
|
|
||||||
|
power-assert-context-reducer-ast@^1.0.7:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/power-assert-context-reducer-ast/-/power-assert-context-reducer-ast-1.1.2.tgz#484a99e26f4973ff8832e5c5cc756702e6094174"
|
||||||
|
dependencies:
|
||||||
|
acorn "^4.0.0"
|
||||||
|
acorn-es7-plugin "^1.0.12"
|
||||||
|
core-js "^2.0.0"
|
||||||
|
espurify "^1.6.0"
|
||||||
|
estraverse "^4.2.0"
|
||||||
|
|
||||||
|
power-assert-context-traversal@^1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/power-assert-context-traversal/-/power-assert-context-traversal-1.1.1.tgz#88cabca0d13b6359f07d3d3e8afa699264577ed9"
|
||||||
|
dependencies:
|
||||||
|
core-js "^2.0.0"
|
||||||
|
estraverse "^4.1.0"
|
||||||
|
|
||||||
|
power-assert-formatter@^1.3.1:
|
||||||
|
version "1.4.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/power-assert-formatter/-/power-assert-formatter-1.4.1.tgz#5dc125ed50a3dfb1dda26c19347f3bf58ec2884a"
|
||||||
|
dependencies:
|
||||||
|
core-js "^2.0.0"
|
||||||
|
power-assert-context-formatter "^1.0.7"
|
||||||
|
power-assert-context-reducer-ast "^1.0.7"
|
||||||
|
power-assert-renderer-assertion "^1.0.7"
|
||||||
|
power-assert-renderer-comparison "^1.0.7"
|
||||||
|
power-assert-renderer-diagram "^1.0.7"
|
||||||
|
power-assert-renderer-file "^1.0.7"
|
||||||
|
|
||||||
|
power-assert-renderer-assertion@^1.0.7:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/power-assert-renderer-assertion/-/power-assert-renderer-assertion-1.1.1.tgz#cbfc0e77e0086a8f96af3f1d8e67b9ee7e28ce98"
|
||||||
|
dependencies:
|
||||||
|
power-assert-renderer-base "^1.1.1"
|
||||||
|
power-assert-util-string-width "^1.1.1"
|
||||||
|
|
||||||
|
power-assert-renderer-base@^1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/power-assert-renderer-base/-/power-assert-renderer-base-1.1.1.tgz#96a650c6fd05ee1bc1f66b54ad61442c8b3f63eb"
|
||||||
|
|
||||||
|
power-assert-renderer-comparison@^1.0.7:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/power-assert-renderer-comparison/-/power-assert-renderer-comparison-1.1.1.tgz#d7439d97d85156be4e30a00f2fb5a72514ce3c08"
|
||||||
|
dependencies:
|
||||||
|
core-js "^2.0.0"
|
||||||
|
diff-match-patch "^1.0.0"
|
||||||
|
power-assert-renderer-base "^1.1.1"
|
||||||
|
stringifier "^1.3.0"
|
||||||
|
type-name "^2.0.1"
|
||||||
|
|
||||||
|
power-assert-renderer-diagram@^1.0.7:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/power-assert-renderer-diagram/-/power-assert-renderer-diagram-1.1.2.tgz#655f8f711935a9b6d541b86327654717c637a986"
|
||||||
|
dependencies:
|
||||||
|
core-js "^2.0.0"
|
||||||
|
power-assert-renderer-base "^1.1.1"
|
||||||
|
power-assert-util-string-width "^1.1.1"
|
||||||
|
stringifier "^1.3.0"
|
||||||
|
|
||||||
|
power-assert-renderer-file@^1.0.7:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/power-assert-renderer-file/-/power-assert-renderer-file-1.1.1.tgz#a37e2bbd178ccacd04e78dbb79c92fe34933c5e7"
|
||||||
|
dependencies:
|
||||||
|
power-assert-renderer-base "^1.1.1"
|
||||||
|
|
||||||
|
power-assert-util-string-width@^1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/power-assert-util-string-width/-/power-assert-util-string-width-1.1.1.tgz#be659eb7937fdd2e6c9a77268daaf64bd5b7c592"
|
||||||
|
dependencies:
|
||||||
|
eastasianwidth "^0.1.1"
|
||||||
|
|
||||||
|
power-assert@^1.2.0:
|
||||||
|
version "1.4.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/power-assert/-/power-assert-1.4.4.tgz#9295ea7437196f5a601fde420f042631186d7517"
|
||||||
|
dependencies:
|
||||||
|
define-properties "^1.1.2"
|
||||||
|
empower "^1.2.3"
|
||||||
|
power-assert-formatter "^1.3.1"
|
||||||
|
universal-deep-strict-equal "^1.2.1"
|
||||||
|
xtend "^4.0.0"
|
||||||
|
|
||||||
prebuild-install@^2.3.0:
|
prebuild-install@^2.3.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-2.3.0.tgz#19481247df728b854ab57b187ce234211311b485"
|
resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-2.3.0.tgz#19481247df728b854ab57b187ce234211311b485"
|
||||||
@@ -8651,6 +8783,15 @@ restore-cursor@^1.0.1:
|
|||||||
exit-hook "^1.0.0"
|
exit-hook "^1.0.0"
|
||||||
onetime "^1.0.0"
|
onetime "^1.0.0"
|
||||||
|
|
||||||
|
restructured@0.0.11:
|
||||||
|
version "0.0.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/restructured/-/restructured-0.0.11.tgz#f914f6b6f358b8e45d6d8ee268926cf1a783f710"
|
||||||
|
dependencies:
|
||||||
|
commander "^2.9.0"
|
||||||
|
lodash "^4.0.0"
|
||||||
|
power-assert "^1.2.0"
|
||||||
|
unist-util-map "^1.0.2"
|
||||||
|
|
||||||
ret@~0.1.10:
|
ret@~0.1.10:
|
||||||
version "0.1.15"
|
version "0.1.15"
|
||||||
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
|
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
|
||||||
@@ -8693,6 +8834,12 @@ rst-selector-parser@^2.2.3:
|
|||||||
lodash.flattendeep "^4.4.0"
|
lodash.flattendeep "^4.4.0"
|
||||||
nearley "^2.7.10"
|
nearley "^2.7.10"
|
||||||
|
|
||||||
|
"rst2html@github:thoward/rst2html#990cb89":
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://codeload.github.com/thoward/rst2html/tar.gz/990cb89f2a300cdd9151790be377c4c0840df809"
|
||||||
|
dependencies:
|
||||||
|
restructured "0.0.11"
|
||||||
|
|
||||||
run-async@^0.1.0:
|
run-async@^0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389"
|
resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389"
|
||||||
@@ -9359,6 +9506,14 @@ string_decoder@~0.10.x:
|
|||||||
version "0.10.31"
|
version "0.10.31"
|
||||||
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
|
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
|
||||||
|
|
||||||
|
stringifier@^1.3.0:
|
||||||
|
version "1.3.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/stringifier/-/stringifier-1.3.0.tgz#def18342f6933db0f2dbfc9aa02175b448c17959"
|
||||||
|
dependencies:
|
||||||
|
core-js "^2.0.0"
|
||||||
|
traverse "^0.6.6"
|
||||||
|
type-name "^2.0.1"
|
||||||
|
|
||||||
stringify-object@^3.2.0:
|
stringify-object@^3.2.0:
|
||||||
version "3.2.1"
|
version "3.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.2.1.tgz#2720c2eff940854c819f6ee252aaeb581f30624d"
|
resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.2.1.tgz#2720c2eff940854c819f6ee252aaeb581f30624d"
|
||||||
@@ -9713,6 +9868,10 @@ tr46@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
punycode "^2.1.0"
|
punycode "^2.1.0"
|
||||||
|
|
||||||
|
traverse@^0.6.6:
|
||||||
|
version "0.6.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137"
|
||||||
|
|
||||||
trim-newlines@^1.0.0:
|
trim-newlines@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
|
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
|
||||||
@@ -9826,6 +9985,10 @@ type-is@~1.6.15:
|
|||||||
media-typer "0.3.0"
|
media-typer "0.3.0"
|
||||||
mime-types "~2.1.15"
|
mime-types "~2.1.15"
|
||||||
|
|
||||||
|
type-name@^2.0.1:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/type-name/-/type-name-2.0.2.tgz#efe7d4123d8ac52afff7f40c7e4dec5266008fb4"
|
||||||
|
|
||||||
typedarray@^0.0.6:
|
typedarray@^0.0.6:
|
||||||
version "0.0.6"
|
version "0.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||||
@@ -9952,6 +10115,20 @@ unique-string@^1.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
crypto-random-string "^1.0.0"
|
crypto-random-string "^1.0.0"
|
||||||
|
|
||||||
|
unist-util-map@^1.0.2:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/unist-util-map/-/unist-util-map-1.0.3.tgz#26a913d7cddb3cd3e9a886d135d37a3d1f54e514"
|
||||||
|
dependencies:
|
||||||
|
object-assign "^4.0.1"
|
||||||
|
|
||||||
|
universal-deep-strict-equal@^1.2.1:
|
||||||
|
version "1.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/universal-deep-strict-equal/-/universal-deep-strict-equal-1.2.2.tgz#0da4ac2f73cff7924c81fa4de018ca562ca2b0a7"
|
||||||
|
dependencies:
|
||||||
|
array-filter "^1.0.0"
|
||||||
|
indexof "0.0.1"
|
||||||
|
object-keys "^1.0.0"
|
||||||
|
|
||||||
universalify@^0.1.0:
|
universalify@^0.1.0:
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7"
|
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7"
|
||||||
|
|||||||
Reference in New Issue
Block a user