mirror of
https://github.com/grafana/grafana.git
synced 2024-12-02 05:29:42 -06:00
Merge branch 'master' into create-annotations
This commit is contained in:
commit
809467955a
@ -76,7 +76,7 @@
|
||||
"systemjs-builder": "^0.15.34",
|
||||
"tether": "^1.4.0",
|
||||
"tether-drop": "https://github.com/torkelo/drop",
|
||||
"tslint": "^4.0.2",
|
||||
"tslint": "^4.5.1",
|
||||
"typescript": "^2.1.4",
|
||||
"virtual-scroll": "^1.1.1"
|
||||
}
|
||||
|
@ -37,14 +37,8 @@ MAX_OPEN_FILES=10000
|
||||
PID_FILE=/var/run/$NAME.pid
|
||||
DAEMON=/usr/sbin/$NAME
|
||||
|
||||
|
||||
umask 0027
|
||||
|
||||
if [ `id -u` -ne 0 ]; then
|
||||
echo "You need root privileges to run this script"
|
||||
exit 4
|
||||
fi
|
||||
|
||||
if [ ! -x $DAEMON ]; then
|
||||
echo "Program not installed or not executable"
|
||||
exit 5
|
||||
@ -63,9 +57,16 @@ fi
|
||||
|
||||
DAEMON_OPTS="--pidfile=${PID_FILE} --config=${CONF_FILE} cfg:default.paths.data=${DATA_DIR} cfg:default.paths.logs=${LOG_DIR} cfg:default.paths.plugins=${PLUGINS_DIR}"
|
||||
|
||||
function checkUser() {
|
||||
if [ `id -u` -ne 0 ]; then
|
||||
echo "You need root privileges to run this script"
|
||||
exit 4
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
|
||||
checkUser
|
||||
log_daemon_msg "Starting $DESC"
|
||||
|
||||
pid=`pidofproc -p $PID_FILE grafana`
|
||||
@ -112,6 +113,7 @@ case "$1" in
|
||||
log_end_msg $return
|
||||
;;
|
||||
stop)
|
||||
checkUser
|
||||
log_daemon_msg "Stopping $DESC"
|
||||
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
|
@ -36,11 +36,6 @@ MAX_OPEN_FILES=10000
|
||||
PID_FILE=/var/run/$NAME.pid
|
||||
DAEMON=/usr/sbin/$NAME
|
||||
|
||||
if [ `id -u` -ne 0 ]; then
|
||||
echo "You need root privileges to run this script"
|
||||
exit 4
|
||||
fi
|
||||
|
||||
if [ ! -x $DAEMON ]; then
|
||||
echo "Program not installed or not executable"
|
||||
exit 5
|
||||
@ -70,8 +65,16 @@ function isRunning() {
|
||||
status -p $PID_FILE $NAME > /dev/null 2>&1
|
||||
}
|
||||
|
||||
function checkUser() {
|
||||
if [ `id -u` -ne 0 ]; then
|
||||
echo "You need root privileges to run this script"
|
||||
exit 4
|
||||
fi
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
checkUser
|
||||
isRunning
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Already running."
|
||||
@ -115,6 +118,7 @@ case "$1" in
|
||||
exit $return
|
||||
;;
|
||||
stop)
|
||||
checkUser
|
||||
echo -n "Stopping $DESC: ..."
|
||||
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
|
@ -1,4 +1,4 @@
|
||||
<div class="submenu-controls gf-form-query">
|
||||
<div class="submenu-controls">
|
||||
|
||||
<div ng-repeat="variable in ctrl.variables" ng-hide="variable.hide === 2" class="submenu-item gf-form-inline">
|
||||
<div class="gf-form">
|
||||
|
@ -1,7 +1,7 @@
|
||||
<query-editor-row query-ctrl="ctrl" has-text-edit-mode="true">
|
||||
|
||||
<div class="gf-form" ng-show="ctrl.target.textEditor">
|
||||
<input type="text" class="gf-form-input" ng-model="ctrl.target.target" spellcheck="false" ng-blur="ctrl.refresh()"></input>
|
||||
<input type="text" class="gf-form-input" ng-model="ctrl.target.target" spellcheck="false" ng-blur="ctrl.targetTextChanged()"></input>
|
||||
</div>
|
||||
|
||||
<div ng-hide="ctrl.target.textEditor">
|
||||
|
@ -28,7 +28,6 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
||||
}
|
||||
|
||||
toggleEditorMode() {
|
||||
this.target.textEditor = !this.target.textEditor;
|
||||
this.parseTarget();
|
||||
}
|
||||
|
||||
@ -55,7 +54,7 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
||||
}
|
||||
|
||||
try {
|
||||
this.parseTargeRecursive(astNode, null, 0);
|
||||
this.parseTargetRecursive(astNode, null, 0);
|
||||
} catch (err) {
|
||||
console.log('error parsing target:', err.message);
|
||||
this.error = err.message;
|
||||
@ -72,7 +71,7 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
||||
func.params[index] = value;
|
||||
}
|
||||
|
||||
parseTargeRecursive(astNode, func, index) {
|
||||
parseTargetRecursive(astNode, func, index) {
|
||||
if (astNode === null) {
|
||||
return null;
|
||||
}
|
||||
@ -81,7 +80,7 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
||||
case 'function':
|
||||
var innerFunc = gfunc.createFuncInstance(astNode.name, { withDefaultParams: false });
|
||||
_.each(astNode.params, (param, index) => {
|
||||
this.parseTargeRecursive(param, innerFunc, index);
|
||||
this.parseTargetRecursive(param, innerFunc, index);
|
||||
});
|
||||
|
||||
innerFunc.updateText();
|
||||
@ -209,30 +208,61 @@ export class GraphiteQueryCtrl extends QueryCtrl {
|
||||
}
|
||||
|
||||
targetTextChanged() {
|
||||
this.parseTarget();
|
||||
this.panelCtrl.refresh();
|
||||
this.updateModelTarget();
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
updateModelTarget() {
|
||||
// render query
|
||||
if (!this.target.textEditor) {
|
||||
var metricPath = this.getSegmentPathUpTo(this.segments.length);
|
||||
this.target.target = _.reduce(this.functions, this.wrapFunction, metricPath);
|
||||
}
|
||||
|
||||
this.updateRenderedTarget(this.target);
|
||||
|
||||
// loop through other queries and update targetFull as needed
|
||||
for (const target of this.panelCtrl.panel.targets || []) {
|
||||
if (target.refId !== this.target.refId) {
|
||||
this.updateRenderedTarget(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateRenderedTarget(target) {
|
||||
// render nested query
|
||||
var targetsByRefId = _.keyBy(this.panelCtrl.panel.targets, 'refId');
|
||||
|
||||
// no references to self
|
||||
delete targetsByRefId[target.refId];
|
||||
|
||||
var nestedSeriesRefRegex = /\#([A-Z])/g;
|
||||
var targetWithNestedQueries = this.target.target.replace(nestedSeriesRefRegex, (match, g1) => {
|
||||
var target = targetsByRefId[g1];
|
||||
if (!target) {
|
||||
var targetWithNestedQueries = target.target;
|
||||
|
||||
// Keep interpolating until there are no query references
|
||||
// The reason for the loop is that the referenced query might contain another reference to another query
|
||||
while (targetWithNestedQueries.match(nestedSeriesRefRegex)) {
|
||||
var updated = targetWithNestedQueries.replace(nestedSeriesRefRegex, (match, g1) => {
|
||||
var t = targetsByRefId[g1];
|
||||
if (!t) {
|
||||
return match;
|
||||
}
|
||||
|
||||
return target.targetFull || target.target;
|
||||
// no circular references
|
||||
delete targetsByRefId[g1];
|
||||
return t.target;
|
||||
});
|
||||
|
||||
delete this.target.targetFull;
|
||||
if (this.target.target !== targetWithNestedQueries) {
|
||||
this.target.targetFull = targetWithNestedQueries;
|
||||
if (updated === targetWithNestedQueries) {
|
||||
break;
|
||||
}
|
||||
|
||||
targetWithNestedQueries = updated;
|
||||
}
|
||||
|
||||
delete target.targetFull;
|
||||
if (target.target !== targetWithNestedQueries) {
|
||||
target.targetFull = targetWithNestedQueries;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,4 +186,24 @@ describe('GraphiteQueryCtrl', function() {
|
||||
expect(ctx.ctrl.target.targetFull).to.be('scaleToSeconds(nested.query.count)');
|
||||
});
|
||||
});
|
||||
|
||||
describe('when updating target used in other query', function() {
|
||||
beforeEach(function() {
|
||||
ctx.ctrl.target.target = 'metrics.a.count';
|
||||
ctx.ctrl.target.refId = 'A';
|
||||
ctx.ctrl.datasource.metricFindQuery = sinon.stub().returns(ctx.$q.when([{expandable: false}]));
|
||||
ctx.ctrl.parseTarget();
|
||||
|
||||
ctx.ctrl.panelCtrl.panel.targets = [
|
||||
ctx.ctrl.target, {target: 'sumSeries(#A)', refId: 'B'}
|
||||
];
|
||||
|
||||
ctx.ctrl.updateModelTarget();
|
||||
});
|
||||
|
||||
it('targetFull of other query should update', function() {
|
||||
expect(ctx.ctrl.panel.targets[1].targetFull).to.be('sumSeries(metrics.a.count)');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -54,7 +54,7 @@
|
||||
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 2">
|
||||
<h5>Stacking and fill</h5>
|
||||
<ul>
|
||||
<li>When stacking is enabled it important that points align</li>
|
||||
<li>When stacking is enabled it is important that points align</li>
|
||||
<li>If there are missing points for one series it can cause gaps or missing bars</li>
|
||||
<li>You must use fill(0), and select a group by time low limit</li>
|
||||
<li>Use the group by time option below your queries and specify for example >10s if your metrics are written every 10 seconds</li>
|
||||
|
@ -1,4 +1,10 @@
|
||||
.submenu-controls {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
align-content: flex-start;
|
||||
align-items: flex-start;
|
||||
|
||||
margin: 0 $panel-margin ($panel-margin*2) $panel-margin;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
module.exports = function(config) {
|
||||
module.exports = function(config, grunt) {
|
||||
'use strict'
|
||||
return {
|
||||
tslint : "node ./node_modules/tslint/lib/tslint-cli.js -c tslint.json --project ./tsconfig.json",
|
||||
tslintfile : "node ./node_modules/tslint/lib/tslint-cli.js -c tslint.json --project ./tsconfig.json <%= tslint.source.files.src %>",
|
||||
tscompile: "node ./node_modules/typescript/lib/tsc.js -p tsconfig.json --diagnostics",
|
||||
tswatch: "node ./node_modules/typescript/lib/tsc.js -p tsconfig.json --diagnostics --watch",
|
||||
};
|
||||
|
11
tasks/options/tslint.js
Normal file
11
tasks/options/tslint.js
Normal file
@ -0,0 +1,11 @@
|
||||
module.exports = function(config, grunt) {
|
||||
'use strict'
|
||||
// dummy to avoid template compile error
|
||||
return {
|
||||
source: {
|
||||
files: {
|
||||
src: ""
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
@ -8,6 +8,10 @@ module.exports = function(config, grunt) {
|
||||
var lastTime;
|
||||
|
||||
grunt.registerTask('watch', function() {
|
||||
if (!grunt.option('skip-ts-compile')) {
|
||||
grunt.log.writeln('We recommoned starting with: grunt watch --force --skip-ts-compile')
|
||||
grunt.log.writeln('Then do incremental typescript builds with: grunt exec:tswatch')
|
||||
}
|
||||
|
||||
done = this.async();
|
||||
lastTime = new Date().getTime();
|
||||
@ -58,7 +62,15 @@ module.exports = function(config, grunt) {
|
||||
newPath = filepath.replace(/^public/, 'public_gen');
|
||||
grunt.log.writeln('Copying to ' + newPath);
|
||||
grunt.file.copy(filepath, newPath);
|
||||
grunt.task.run('exec:tslint');
|
||||
|
||||
if (grunt.option('skip-ts-compile')) {
|
||||
grunt.log.writeln('Skipping ts compile, run grunt exec:tswatch to start typescript watcher')
|
||||
} else {
|
||||
grunt.task.run('exec:tscompile');
|
||||
}
|
||||
|
||||
grunt.config('tslint.source.files.src', filepath);
|
||||
grunt.task.run('exec:tslintfile');
|
||||
}
|
||||
|
||||
done();
|
||||
|
0
tasks/tslint.js
Normal file
0
tasks/tslint.js
Normal file
Loading…
Reference in New Issue
Block a user