mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'master' into develop
This commit is contained in:
commit
93d21bec75
109
Dockerfile
109
Dockerfile
@ -1,109 +0,0 @@
|
||||
FROM phusion/baseimage:0.9.22
|
||||
MAINTAINER Denys Zhdanov <denis.zhdanov@gmail.com>
|
||||
|
||||
RUN apt-get -y update \
|
||||
&& apt-get -y upgrade \
|
||||
&& apt-get -y install vim \
|
||||
nginx \
|
||||
python-dev \
|
||||
python-flup \
|
||||
python-pip \
|
||||
python-ldap \
|
||||
expect \
|
||||
git \
|
||||
memcached \
|
||||
sqlite3 \
|
||||
libffi-dev \
|
||||
libcairo2 \
|
||||
libcairo2-dev \
|
||||
python-cairo \
|
||||
python-rrdtool \
|
||||
pkg-config \
|
||||
nodejs \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# choose a timezone at build-time
|
||||
# use `--build-arg CONTAINER_TIMEZONE=Europe/Brussels` in `docker build`
|
||||
ARG CONTAINER_TIMEZONE
|
||||
ENV DEBIAN_FRONTEND noninteractive
|
||||
|
||||
RUN if [ ! -z "${CONTAINER_TIMEZONE}" ]; \
|
||||
then ln -sf /usr/share/zoneinfo/$CONTAINER_TIMEZONE /etc/localtime && \
|
||||
dpkg-reconfigure -f noninteractive tzdata; \
|
||||
fi
|
||||
|
||||
# fix python dependencies (LTS Django and newer memcached/txAMQP)
|
||||
RUN pip install --upgrade pip && \
|
||||
pip install django==1.8.18 \
|
||||
python-memcached==1.53 \
|
||||
txAMQP==0.6.2
|
||||
|
||||
ARG version=1.0.2
|
||||
ARG whisper_version=${version}
|
||||
ARG carbon_version=${version}
|
||||
ARG graphite_version=${version}
|
||||
|
||||
ARG statsd_version=v0.7.2
|
||||
|
||||
# install whisper
|
||||
RUN git clone -b ${whisper_version} --depth 1 https://github.com/graphite-project/whisper.git /usr/local/src/whisper
|
||||
WORKDIR /usr/local/src/whisper
|
||||
RUN python ./setup.py install
|
||||
|
||||
# install carbon
|
||||
RUN git clone -b ${carbon_version} --depth 1 https://github.com/graphite-project/carbon.git /usr/local/src/carbon
|
||||
WORKDIR /usr/local/src/carbon
|
||||
RUN pip install -r requirements.txt \
|
||||
&& python ./setup.py install
|
||||
|
||||
# install graphite
|
||||
RUN git clone -b ${graphite_version} --depth 1 https://github.com/graphite-project/graphite-web.git /usr/local/src/graphite-web
|
||||
WORKDIR /usr/local/src/graphite-web
|
||||
RUN pip install -r requirements.txt \
|
||||
&& python ./setup.py install
|
||||
ADD conf/opt/graphite/conf/*.conf /opt/graphite/conf/
|
||||
ADD conf/opt/graphite/webapp/graphite/local_settings.py /opt/graphite/webapp/graphite/local_settings.py
|
||||
# ADD conf/opt/graphite/webapp/graphite/app_settings.py /opt/graphite/webapp/graphite/app_settings.py
|
||||
WORKDIR /opt/graphite/webapp
|
||||
RUN mkdir -p /var/log/graphite/ \
|
||||
&& PYTHONPATH=/opt/graphite/webapp django-admin.py collectstatic --noinput --settings=graphite.settings
|
||||
|
||||
# install statsd
|
||||
RUN git clone -b ${statsd_version} https://github.com/etsy/statsd.git /opt/statsd
|
||||
ADD conf/opt/statsd/config.js /opt/statsd/config.js
|
||||
|
||||
# config nginx
|
||||
RUN rm /etc/nginx/sites-enabled/default
|
||||
ADD conf/etc/nginx/nginx.conf /etc/nginx/nginx.conf
|
||||
ADD conf/etc/nginx/sites-enabled/graphite-statsd.conf /etc/nginx/sites-enabled/graphite-statsd.conf
|
||||
|
||||
# init django admin
|
||||
ADD conf/usr/local/bin/django_admin_init.exp /usr/local/bin/django_admin_init.exp
|
||||
ADD conf/usr/local/bin/manage.sh /usr/local/bin/manage.sh
|
||||
RUN chmod +x /usr/local/bin/manage.sh && /usr/local/bin/django_admin_init.exp
|
||||
|
||||
# logging support
|
||||
RUN mkdir -p /var/log/carbon /var/log/graphite /var/log/nginx
|
||||
ADD conf/etc/logrotate.d/graphite-statsd /etc/logrotate.d/graphite-statsd
|
||||
|
||||
# daemons
|
||||
ADD conf/etc/service/carbon/run /etc/service/carbon/run
|
||||
ADD conf/etc/service/carbon-aggregator/run /etc/service/carbon-aggregator/run
|
||||
ADD conf/etc/service/graphite/run /etc/service/graphite/run
|
||||
ADD conf/etc/service/statsd/run /etc/service/statsd/run
|
||||
ADD conf/etc/service/nginx/run /etc/service/nginx/run
|
||||
|
||||
# default conf setup
|
||||
ADD conf /etc/graphite-statsd/conf
|
||||
ADD conf/etc/my_init.d/01_conf_init.sh /etc/my_init.d/01_conf_init.sh
|
||||
|
||||
# cleanup
|
||||
RUN apt-get clean\
|
||||
&& rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
# defaults
|
||||
EXPOSE 80 2003-2004 2023-2024 8125/udp 8126
|
||||
VOLUME ["/opt/graphite/conf", "/opt/graphite/storage", "/etc/nginx", "/opt/statsd", "/etc/logrotate.d", "/var/log"]
|
||||
WORKDIR /
|
||||
ENV HOME /root
|
||||
CMD ["/sbin/my_init"]
|
22
LICENSE.txt
22
LICENSE.txt
@ -1,22 +0,0 @@
|
||||
Copyright (c) 2013-2016 Nathan Hopkins
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@ -495,3 +495,4 @@ public_url =
|
||||
[external_image_storage.gcs]
|
||||
key_file =
|
||||
bucket =
|
||||
path =
|
@ -438,3 +438,4 @@ log_queries =
|
||||
[external_image_storage.gcs]
|
||||
;key_file =
|
||||
;bucket =
|
||||
;path =
|
@ -133,6 +133,37 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
## Pause all alerts
|
||||
|
||||
`POST /api/admin/pause-all-alerts`
|
||||
|
||||
```http
|
||||
POST /api/admin/pause-all-alerts HTTP/1.1
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
|
||||
{
|
||||
"paused": true
|
||||
}
|
||||
```
|
||||
|
||||
JSON Body Schema:
|
||||
|
||||
- **paused** – Can be `true` or `false`. True to pause an alert. False to unpause an alert.
|
||||
|
||||
**Example Response**:
|
||||
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
Content-Type: application/json
|
||||
{
|
||||
"state": "Paused",
|
||||
"message": "alert paused",
|
||||
"alertsAffected": 1
|
||||
}
|
||||
```
|
||||
|
||||
## Get alert notifications
|
||||
|
||||
`GET /api/alert-notifications`
|
||||
|
@ -140,9 +140,9 @@ Content-Type: application/json
|
||||
}
|
||||
```
|
||||
|
||||
## Delete Snapshot by Id
|
||||
## Delete Snapshot by deleteKey
|
||||
|
||||
`GET /api/snapshots-delete/:key`
|
||||
`GET /api/snapshots-delete/:deleteKey`
|
||||
|
||||
**Example Request**:
|
||||
|
||||
|
@ -778,6 +778,9 @@ Service Account should have "Storage Object Writer" role.
|
||||
### bucket name
|
||||
Bucket Name on Google Cloud Storage.
|
||||
|
||||
### path
|
||||
Optional extra path inside bucket
|
||||
|
||||
## [alerting]
|
||||
|
||||
### enabled
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"stable": "4.5.2",
|
||||
"testing": "4.5.2"
|
||||
"stable": "4.6.2",
|
||||
"testing": "4.6.2"
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/grafana/grafana/pkg/log"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
@ -20,19 +21,22 @@ const (
|
||||
type GCSUploader struct {
|
||||
keyFile string
|
||||
bucket string
|
||||
path string
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
func NewGCSUploader(keyFile, bucket string) *GCSUploader {
|
||||
func NewGCSUploader(keyFile, bucket, path string) *GCSUploader {
|
||||
return &GCSUploader{
|
||||
keyFile: keyFile,
|
||||
bucket: bucket,
|
||||
path: path,
|
||||
log: log.New("gcsuploader"),
|
||||
}
|
||||
}
|
||||
|
||||
func (u *GCSUploader) Upload(ctx context.Context, imageDiskPath string) (string, error) {
|
||||
key := util.GetRandomString(20) + ".png"
|
||||
fileName := util.GetRandomString(20) + ".png"
|
||||
key := path.Join(u.path, fileName)
|
||||
|
||||
u.log.Debug("Opening key file ", u.keyFile)
|
||||
data, err := ioutil.ReadFile(u.keyFile)
|
||||
|
@ -73,8 +73,9 @@ func NewImageUploader() (ImageUploader, error) {
|
||||
|
||||
keyFile := gcssec.Key("key_file").MustString("")
|
||||
bucketName := gcssec.Key("bucket").MustString("")
|
||||
path := gcssec.Key("path").MustString("")
|
||||
|
||||
return NewGCSUploader(keyFile, bucketName), nil
|
||||
return NewGCSUploader(keyFile, bucketName, path), nil
|
||||
}
|
||||
|
||||
return NopImageUploader{}, nil
|
||||
|
@ -5,9 +5,10 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@ -124,6 +125,30 @@ func (w *FileLogWriter) createLogFile() (*os.File, error) {
|
||||
return os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644)
|
||||
}
|
||||
|
||||
func (w *FileLogWriter) lineCounter() (int, error) {
|
||||
r, err := os.OpenFile(w.Filename, os.O_RDONLY, 0644)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("lineCounter Open File : %s", err)
|
||||
}
|
||||
buf := make([]byte, 32*1024)
|
||||
count := 0
|
||||
|
||||
for {
|
||||
c, err := r.Read(buf)
|
||||
count += bytes.Count(buf[:c], []byte{'\n'})
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
if err := r.Close(); err != nil {
|
||||
return count, err
|
||||
}
|
||||
return count, nil
|
||||
|
||||
case err != nil:
|
||||
return count, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *FileLogWriter) initFd() error {
|
||||
fd := w.mw.fd
|
||||
finfo, err := fd.Stat()
|
||||
@ -133,11 +158,11 @@ func (w *FileLogWriter) initFd() error {
|
||||
w.maxsize_cursize = int(finfo.Size())
|
||||
w.daily_opendate = time.Now().Day()
|
||||
if finfo.Size() > 0 {
|
||||
content, err := ioutil.ReadFile(w.Filename)
|
||||
count, err := w.lineCounter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.maxlines_curlines = len(strings.Split(string(content), "\n"))
|
||||
w.maxlines_curlines = count
|
||||
} else {
|
||||
w.maxlines_curlines = 0
|
||||
}
|
||||
|
44
pkg/log/file_test.go
Normal file
44
pkg/log/file_test.go
Normal file
@ -0,0 +1,44 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func (w *FileLogWriter) WriteLine(line string) error {
|
||||
n, err := w.mw.Write([]byte(line))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
w.docheck(n)
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestLogFile(t *testing.T) {
|
||||
|
||||
Convey("When logging to file", t, func() {
|
||||
fileLogWrite := NewFileWriter()
|
||||
So(fileLogWrite, ShouldNotBeNil)
|
||||
|
||||
fileLogWrite.Filename = "grafana_test.log"
|
||||
err := fileLogWrite.Init()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
Convey("Log file is empty", func() {
|
||||
So(fileLogWrite.maxlines_curlines, ShouldEqual, 0)
|
||||
})
|
||||
|
||||
Convey("Logging should add lines", func() {
|
||||
err := fileLogWrite.WriteLine("test1\n")
|
||||
err = fileLogWrite.WriteLine("test2\n")
|
||||
err = fileLogWrite.WriteLine("test3\n")
|
||||
So(err, ShouldBeNil)
|
||||
So(fileLogWrite.maxlines_curlines, ShouldEqual, 3)
|
||||
})
|
||||
|
||||
err = os.Remove(fileLogWrite.Filename)
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
}
|
@ -15,6 +15,8 @@ class Settings {
|
||||
disableLoginForm: boolean;
|
||||
defaultDatasource: string;
|
||||
alertingEnabled: boolean;
|
||||
authProxyEnabled: boolean;
|
||||
ldapEnabled: boolean;
|
||||
|
||||
constructor(options) {
|
||||
var defaults = {
|
||||
|
@ -1,163 +0,0 @@
|
||||
define([
|
||||
'angular',
|
||||
'require',
|
||||
'../core_module',
|
||||
'app/core/utils/kbn',
|
||||
],
|
||||
function (angular, require, coreModule, kbn) {
|
||||
'use strict';
|
||||
|
||||
kbn = kbn.default;
|
||||
|
||||
coreModule.default.directive('tip', function($compile) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function(scope, elem, attrs) {
|
||||
var _t = '<i class="grafana-tip fa fa-'+(attrs.icon||'question-circle')+'" bs-tooltip="\''+
|
||||
kbn.addslashes(elem.text())+'\'"></i>';
|
||||
_t = _t.replace(/{/g, '\\{').replace(/}/g, '\\}');
|
||||
elem.replaceWith($compile(angular.element(_t))(scope));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
coreModule.default.directive('clipboardButton', function() {
|
||||
return {
|
||||
scope: {
|
||||
getText: '&clipboardButton'
|
||||
},
|
||||
link: function(scope, elem) {
|
||||
require(['clipboard'], function(Clipboard) {
|
||||
scope.clipboard = new Clipboard(elem[0], {
|
||||
text: function() {
|
||||
return scope.getText();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
scope.$on('$destroy', function() {
|
||||
if (scope.clipboard) {
|
||||
scope.clipboard.destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
coreModule.default.directive('compile', function($compile) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
link: function(scope, element, attrs) {
|
||||
scope.$watch(function(scope) {
|
||||
return scope.$eval(attrs.compile);
|
||||
}, function(value) {
|
||||
element.html(value);
|
||||
$compile(element.contents())(scope);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
coreModule.default.directive('watchChange', function() {
|
||||
return {
|
||||
scope: { onchange: '&watchChange' },
|
||||
link: function(scope, element) {
|
||||
element.on('input', function() {
|
||||
scope.$apply(function () {
|
||||
scope.onchange({ inputValue: element.val() });
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
coreModule.default.directive('editorOptBool', function($compile) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function(scope, elem, attrs) {
|
||||
var ngchange = attrs.change ? (' ng-change="' + attrs.change + '"') : '';
|
||||
var tip = attrs.tip ? (' <tip>' + attrs.tip + '</tip>') : '';
|
||||
var showIf = attrs.showIf ? (' ng-show="' + attrs.showIf + '" ') : '';
|
||||
|
||||
var template = '<div class="editor-option gf-form-checkbox text-center"' + showIf + '>' +
|
||||
' <label for="' + attrs.model + '" class="small">' +
|
||||
attrs.text + tip + '</label>' +
|
||||
'<input class="cr1" id="' + attrs.model + '" type="checkbox" ' +
|
||||
' ng-model="' + attrs.model + '"' + ngchange +
|
||||
' ng-checked="' + attrs.model + '"></input>' +
|
||||
' <label for="' + attrs.model + '" class="cr1"></label>';
|
||||
elem.replaceWith($compile(angular.element(template))(scope));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
coreModule.default.directive('editorCheckbox', function($compile, $interpolate) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function(scope, elem, attrs) {
|
||||
var text = $interpolate(attrs.text)(scope);
|
||||
var model = $interpolate(attrs.model)(scope);
|
||||
var ngchange = attrs.change ? (' ng-change="' + attrs.change + '"') : '';
|
||||
var tip = attrs.tip ? (' <tip>' + attrs.tip + '</tip>') : '';
|
||||
var label = '<label for="' + scope.$id + model + '" class="checkbox-label">' +
|
||||
text + tip + '</label>';
|
||||
|
||||
var template =
|
||||
'<input class="cr1" id="' + scope.$id + model + '" type="checkbox" ' +
|
||||
' ng-model="' + model + '"' + ngchange +
|
||||
' ng-checked="' + model + '"></input>' +
|
||||
' <label for="' + scope.$id + model + '" class="cr1"></label>';
|
||||
|
||||
template = template + label;
|
||||
elem.addClass('gf-form-checkbox');
|
||||
elem.html($compile(angular.element(template))(scope));
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
coreModule.default.directive('gfDropdown', function ($parse, $compile, $timeout) {
|
||||
function buildTemplate(items, placement) {
|
||||
var upclass = placement === 'top' ? 'dropup' : '';
|
||||
var ul = [
|
||||
'<ul class="dropdown-menu ' + upclass + '" role="menu" aria-labelledby="drop1">',
|
||||
'</ul>'
|
||||
];
|
||||
|
||||
angular.forEach(items, function (item, index) {
|
||||
if (item.divider) {
|
||||
return ul.splice(index + 1, 0, '<li class="divider"></li>');
|
||||
}
|
||||
|
||||
var li = '<li' + (item.submenu && item.submenu.length ? ' class="dropdown-submenu"' : '') + '>' +
|
||||
'<a tabindex="-1" ng-href="' + (item.href || '') + '"' + (item.click ? ' ng-click="' + item.click + '"' : '') +
|
||||
(item.target ? ' target="' + item.target + '"' : '') + (item.method ? ' data-method="' + item.method + '"' : '') +
|
||||
'>' + (item.text || '') + '</a>';
|
||||
|
||||
if (item.submenu && item.submenu.length) {
|
||||
li += buildTemplate(item.submenu).join('\n');
|
||||
}
|
||||
|
||||
li += '</li>';
|
||||
ul.splice(index + 1, 0, li);
|
||||
});
|
||||
return ul;
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'EA',
|
||||
scope: true,
|
||||
link: function postLink(scope, iElement, iAttrs) {
|
||||
var getter = $parse(iAttrs.gfDropdown), items = getter(scope);
|
||||
$timeout(function () {
|
||||
var placement = iElement.data('placement');
|
||||
var dropdown = angular.element(buildTemplate(items, placement).join(''));
|
||||
dropdown.insertAfter(iElement);
|
||||
$compile(iElement.next('ul.dropdown-menu'))(scope);
|
||||
});
|
||||
|
||||
iElement.addClass('dropdown-toggle').attr('data-toggle', 'dropdown');
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
});
|
226
public/app/core/directives/misc.ts
Normal file
226
public/app/core/directives/misc.ts
Normal file
@ -0,0 +1,226 @@
|
||||
import angular from "angular";
|
||||
import Clipboard from "clipboard";
|
||||
import coreModule from "../core_module";
|
||||
import kbn from "app/core/utils/kbn";
|
||||
|
||||
/** @ngInject */
|
||||
function tip($compile) {
|
||||
return {
|
||||
restrict: "E",
|
||||
link: function(scope, elem, attrs) {
|
||||
var _t =
|
||||
'<i class="grafana-tip fa fa-' +
|
||||
(attrs.icon || "question-circle") +
|
||||
'" bs-tooltip="\'' +
|
||||
kbn.addslashes(elem.text()) +
|
||||
"'\"></i>";
|
||||
_t = _t.replace(/{/g, "\\{").replace(/}/g, "\\}");
|
||||
elem.replaceWith($compile(angular.element(_t))(scope));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function clipboardButton() {
|
||||
return {
|
||||
scope: {
|
||||
getText: "&clipboardButton"
|
||||
},
|
||||
link: function(scope, elem) {
|
||||
scope.clipboard = new Clipboard(elem[0], {
|
||||
text: function() {
|
||||
return scope.getText();
|
||||
}
|
||||
});
|
||||
|
||||
scope.$on("$destroy", function() {
|
||||
if (scope.clipboard) {
|
||||
scope.clipboard.destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** @ngInject */
|
||||
function compile($compile) {
|
||||
return {
|
||||
restrict: "A",
|
||||
link: function(scope, element, attrs) {
|
||||
scope.$watch(
|
||||
function(scope) {
|
||||
return scope.$eval(attrs.compile);
|
||||
},
|
||||
function(value) {
|
||||
element.html(value);
|
||||
$compile(element.contents())(scope);
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function watchChange() {
|
||||
return {
|
||||
scope: { onchange: "&watchChange" },
|
||||
link: function(scope, element) {
|
||||
element.on("input", function() {
|
||||
scope.$apply(function() {
|
||||
scope.onchange({ inputValue: element.val() });
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** @ngInject */
|
||||
function editorOptBool($compile) {
|
||||
return {
|
||||
restrict: "E",
|
||||
link: function(scope, elem, attrs) {
|
||||
var ngchange = attrs.change ? ' ng-change="' + attrs.change + '"' : "";
|
||||
var tip = attrs.tip ? " <tip>" + attrs.tip + "</tip>" : "";
|
||||
var showIf = attrs.showIf ? ' ng-show="' + attrs.showIf + '" ' : "";
|
||||
|
||||
var template =
|
||||
'<div class="editor-option gf-form-checkbox text-center"' +
|
||||
showIf +
|
||||
">" +
|
||||
' <label for="' +
|
||||
attrs.model +
|
||||
'" class="small">' +
|
||||
attrs.text +
|
||||
tip +
|
||||
"</label>" +
|
||||
'<input class="cr1" id="' +
|
||||
attrs.model +
|
||||
'" type="checkbox" ' +
|
||||
' ng-model="' +
|
||||
attrs.model +
|
||||
'"' +
|
||||
ngchange +
|
||||
' ng-checked="' +
|
||||
attrs.model +
|
||||
'"></input>' +
|
||||
' <label for="' +
|
||||
attrs.model +
|
||||
'" class="cr1"></label>';
|
||||
elem.replaceWith($compile(angular.element(template))(scope));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** @ngInject */
|
||||
function editorCheckbox($compile, $interpolate) {
|
||||
return {
|
||||
restrict: "E",
|
||||
link: function(scope, elem, attrs) {
|
||||
var text = $interpolate(attrs.text)(scope);
|
||||
var model = $interpolate(attrs.model)(scope);
|
||||
var ngchange = attrs.change ? ' ng-change="' + attrs.change + '"' : "";
|
||||
var tip = attrs.tip ? " <tip>" + attrs.tip + "</tip>" : "";
|
||||
var label =
|
||||
'<label for="' +
|
||||
scope.$id +
|
||||
model +
|
||||
'" class="checkbox-label">' +
|
||||
text +
|
||||
tip +
|
||||
"</label>";
|
||||
|
||||
var template =
|
||||
'<input class="cr1" id="' +
|
||||
scope.$id +
|
||||
model +
|
||||
'" type="checkbox" ' +
|
||||
' ng-model="' +
|
||||
model +
|
||||
'"' +
|
||||
ngchange +
|
||||
' ng-checked="' +
|
||||
model +
|
||||
'"></input>' +
|
||||
' <label for="' +
|
||||
scope.$id +
|
||||
model +
|
||||
'" class="cr1"></label>';
|
||||
|
||||
template = template + label;
|
||||
elem.addClass("gf-form-checkbox");
|
||||
elem.html($compile(angular.element(template))(scope));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** @ngInject */
|
||||
function gfDropdown($parse, $compile, $timeout) {
|
||||
function buildTemplate(items, placement?) {
|
||||
var upclass = placement === "top" ? "dropup" : "";
|
||||
var ul = [
|
||||
'<ul class="dropdown-menu ' +
|
||||
upclass +
|
||||
'" role="menu" aria-labelledby="drop1">',
|
||||
"</ul>"
|
||||
];
|
||||
|
||||
for (let index = 0; index < items.length; index++) {
|
||||
let item = items[index];
|
||||
|
||||
if (item.divider) {
|
||||
ul.splice(index + 1, 0, '<li class="divider"></li>');
|
||||
continue;
|
||||
}
|
||||
|
||||
var li =
|
||||
"<li" +
|
||||
(item.submenu && item.submenu.length
|
||||
? ' class="dropdown-submenu"'
|
||||
: "") +
|
||||
">" +
|
||||
'<a tabindex="-1" ng-href="' +
|
||||
(item.href || "") +
|
||||
'"' +
|
||||
(item.click ? ' ng-click="' + item.click + '"' : "") +
|
||||
(item.target ? ' target="' + item.target + '"' : "") +
|
||||
(item.method ? ' data-method="' + item.method + '"' : "") +
|
||||
">" +
|
||||
(item.text || "") +
|
||||
"</a>";
|
||||
|
||||
if (item.submenu && item.submenu.length) {
|
||||
li += buildTemplate(item.submenu).join("\n");
|
||||
}
|
||||
|
||||
li += "</li>";
|
||||
ul.splice(index + 1, 0, li);
|
||||
}
|
||||
|
||||
return ul;
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: "EA",
|
||||
scope: true,
|
||||
link: function postLink(scope, iElement, iAttrs) {
|
||||
var getter = $parse(iAttrs.gfDropdown),
|
||||
items = getter(scope);
|
||||
$timeout(function() {
|
||||
var placement = iElement.data("placement");
|
||||
var dropdown = angular.element(
|
||||
buildTemplate(items, placement).join("")
|
||||
);
|
||||
dropdown.insertAfter(iElement);
|
||||
$compile(iElement.next("ul.dropdown-menu"))(scope);
|
||||
});
|
||||
|
||||
iElement.addClass("dropdown-toggle").attr("data-toggle", "dropdown");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
coreModule.directive("tip", tip);
|
||||
coreModule.directive("clipboardButton", clipboardButton);
|
||||
coreModule.directive("compile", compile);
|
||||
coreModule.directive("watchChange", watchChange);
|
||||
coreModule.directive("editorOptBool", editorOptBool);
|
||||
coreModule.directive("editorCheckbox", editorCheckbox);
|
||||
coreModule.directive("gfDropdown", gfDropdown);
|
@ -1,8 +1,7 @@
|
||||
import coreModule from '../core_module';
|
||||
import * as rangeUtil from 'app/core/utils/rangeutil';
|
||||
|
||||
export class NgModelOnBlur {
|
||||
constructor() {
|
||||
function ngModelOnBlur() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
priority: 1,
|
||||
@ -20,12 +19,9 @@ export class NgModelOnBlur {
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class EmptyToNull {
|
||||
constructor() {
|
||||
function emptyToNull() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: 'ngModel',
|
||||
@ -36,11 +32,9 @@ export class EmptyToNull {
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class ValidTimeSpan {
|
||||
constructor() {
|
||||
function validTimeSpan() {
|
||||
return {
|
||||
require: 'ngModel',
|
||||
link: function(scope, elm, attrs, ctrl) {
|
||||
@ -56,9 +50,8 @@ export class ValidTimeSpan {
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
coreModule.directive('ngModelOnblur', NgModelOnBlur);
|
||||
coreModule.directive('emptyToNull', EmptyToNull);
|
||||
coreModule.directive('validTimeSpan', ValidTimeSpan);
|
||||
coreModule.directive('ngModelOnblur', ngModelOnBlur);
|
||||
coreModule.directive('emptyToNull', emptyToNull);
|
||||
coreModule.directive('validTimeSpan', validTimeSpan);
|
||||
|
@ -1,135 +0,0 @@
|
||||
define([
|
||||
'angular',
|
||||
'jquery',
|
||||
'../core_module',
|
||||
'vendor/tagsinput/bootstrap-tagsinput.js',
|
||||
],
|
||||
function (angular, $, coreModule) {
|
||||
'use strict';
|
||||
|
||||
function djb2(str) {
|
||||
var hash = 5381;
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
hash = ((hash << 5) + hash) + str.charCodeAt(i); /* hash * 33 + c */
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
function setColor(name, element) {
|
||||
var hash = djb2(name.toLowerCase());
|
||||
var colors = [
|
||||
"#E24D42","#1F78C1","#BA43A9","#705DA0","#466803",
|
||||
"#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 = [
|
||||
"#FF7368","#459EE7","#E069CF","#9683C6","#6C8E29",
|
||||
"#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 borderColor = borderColors[Math.abs(hash % borderColors.length)];
|
||||
element.css("background-color", color);
|
||||
element.css("border-color", borderColor);
|
||||
}
|
||||
|
||||
coreModule.default.directive('tagColorFromName', function() {
|
||||
return {
|
||||
scope: { tagColorFromName: "=" },
|
||||
link: function (scope, element) {
|
||||
setColor(scope.tagColorFromName, element);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
coreModule.default.directive('bootstrapTagsinput', function() {
|
||||
|
||||
function getItemProperty(scope, property) {
|
||||
if (!property) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (angular.isFunction(scope.$parent[property])) {
|
||||
return scope.$parent[property];
|
||||
}
|
||||
|
||||
return function(item) {
|
||||
return item[property];
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'EA',
|
||||
scope: {
|
||||
model: '=ngModel',
|
||||
onTagsUpdated: "&",
|
||||
},
|
||||
template: '<select multiple></select>',
|
||||
replace: false,
|
||||
link: function(scope, element, attrs) {
|
||||
|
||||
if (!angular.isArray(scope.model)) {
|
||||
scope.model = [];
|
||||
}
|
||||
|
||||
var select = $('select', element);
|
||||
|
||||
if (attrs.placeholder) {
|
||||
select.attr('placeholder', attrs.placeholder);
|
||||
}
|
||||
|
||||
select.tagsinput({
|
||||
typeahead: {
|
||||
source: angular.isFunction(scope.$parent[attrs.typeaheadSource]) ? scope.$parent[attrs.typeaheadSource] : null
|
||||
},
|
||||
widthClass: attrs.widthClass,
|
||||
itemValue: getItemProperty(scope, attrs.itemvalue),
|
||||
itemText : getItemProperty(scope, attrs.itemtext),
|
||||
tagClass : angular.isFunction(scope.$parent[attrs.tagclass]) ?
|
||||
scope.$parent[attrs.tagclass] : function() { return attrs.tagclass; }
|
||||
});
|
||||
|
||||
select.on('itemAdded', function(event) {
|
||||
if (scope.model.indexOf(event.item) === -1) {
|
||||
scope.model.push(event.item);
|
||||
if (scope.onTagsUpdated) {
|
||||
scope.onTagsUpdated();
|
||||
}
|
||||
}
|
||||
var tagElement = select.next().children("span").filter(function() { return $(this).text() === event.item; });
|
||||
setColor(event.item, tagElement);
|
||||
});
|
||||
|
||||
select.on('itemRemoved', function(event) {
|
||||
var idx = scope.model.indexOf(event.item);
|
||||
if (idx !== -1) {
|
||||
scope.model.splice(idx, 1);
|
||||
if (scope.onTagsUpdated) {
|
||||
scope.onTagsUpdated();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
scope.$watch("model", function() {
|
||||
if (!angular.isArray(scope.model)) {
|
||||
scope.model = [];
|
||||
}
|
||||
|
||||
select.tagsinput('removeAll');
|
||||
|
||||
for (var i = 0; i < scope.model.length; i++) {
|
||||
select.tagsinput('add', scope.model[i]);
|
||||
}
|
||||
|
||||
}, true);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
});
|
131
public/app/core/directives/tags.ts
Normal file
131
public/app/core/directives/tags.ts
Normal file
@ -0,0 +1,131 @@
|
||||
import angular from 'angular';
|
||||
import $ from 'jquery';
|
||||
import coreModule from '../core_module';
|
||||
import 'vendor/tagsinput/bootstrap-tagsinput.js';
|
||||
|
||||
function djb2(str) {
|
||||
var hash = 5381;
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
hash = ((hash << 5) + hash) + str.charCodeAt(i); /* hash * 33 + c */
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
function setColor(name, element) {
|
||||
var hash = djb2(name.toLowerCase());
|
||||
var colors = [
|
||||
"#E24D42","#1F78C1","#BA43A9","#705DA0","#466803",
|
||||
"#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 = [
|
||||
"#FF7368","#459EE7","#E069CF","#9683C6","#6C8E29",
|
||||
"#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 borderColor = borderColors[Math.abs(hash % borderColors.length)];
|
||||
element.css("background-color", color);
|
||||
element.css("border-color", borderColor);
|
||||
}
|
||||
|
||||
function tagColorFromName() {
|
||||
return {
|
||||
scope: { tagColorFromName: "=" },
|
||||
link: function (scope, element) {
|
||||
setColor(scope.tagColorFromName, element);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function bootstrapTagsinput() {
|
||||
function getItemProperty(scope, property) {
|
||||
if (!property) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (angular.isFunction(scope.$parent[property])) {
|
||||
return scope.$parent[property];
|
||||
}
|
||||
|
||||
return function(item) {
|
||||
return item[property];
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'EA',
|
||||
scope: {
|
||||
model: '=ngModel',
|
||||
onTagsUpdated: "&",
|
||||
},
|
||||
template: '<select multiple></select>',
|
||||
replace: false,
|
||||
link: function(scope, element, attrs) {
|
||||
|
||||
if (!angular.isArray(scope.model)) {
|
||||
scope.model = [];
|
||||
}
|
||||
|
||||
var select = $('select', element);
|
||||
|
||||
if (attrs.placeholder) {
|
||||
select.attr('placeholder', attrs.placeholder);
|
||||
}
|
||||
|
||||
select.tagsinput({
|
||||
typeahead: {
|
||||
source: angular.isFunction(scope.$parent[attrs.typeaheadSource]) ? scope.$parent[attrs.typeaheadSource] : null
|
||||
},
|
||||
widthClass: attrs.widthClass,
|
||||
itemValue: getItemProperty(scope, attrs.itemvalue),
|
||||
itemText : getItemProperty(scope, attrs.itemtext),
|
||||
tagClass : angular.isFunction(scope.$parent[attrs.tagclass]) ?
|
||||
scope.$parent[attrs.tagclass] : function() { return attrs.tagclass; }
|
||||
});
|
||||
|
||||
select.on('itemAdded', function(event) {
|
||||
if (scope.model.indexOf(event.item) === -1) {
|
||||
scope.model.push(event.item);
|
||||
if (scope.onTagsUpdated) {
|
||||
scope.onTagsUpdated();
|
||||
}
|
||||
}
|
||||
var tagElement = select.next().children("span").filter(function() { return $(this).text() === event.item; });
|
||||
setColor(event.item, tagElement);
|
||||
});
|
||||
|
||||
select.on('itemRemoved', function(event) {
|
||||
var idx = scope.model.indexOf(event.item);
|
||||
if (idx !== -1) {
|
||||
scope.model.splice(idx, 1);
|
||||
if (scope.onTagsUpdated) {
|
||||
scope.onTagsUpdated();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
scope.$watch("model", function() {
|
||||
if (!angular.isArray(scope.model)) {
|
||||
scope.model = [];
|
||||
}
|
||||
|
||||
select.tagsinput('removeAll');
|
||||
|
||||
for (var i = 0; i < scope.model.length; i++) {
|
||||
select.tagsinput('add', scope.model[i]);
|
||||
}
|
||||
|
||||
}, true);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
coreModule.directive('tagColorFromName', tagColorFromName);
|
||||
coreModule.directive('bootstrapTagsinput', bootstrapTagsinput);
|
@ -1,7 +1,7 @@
|
||||
import AdminListUsersCtrl from './admin_list_users_ctrl';
|
||||
import './adminListOrgsCtrl';
|
||||
import './adminEditOrgCtrl';
|
||||
import './adminEditUserCtrl';
|
||||
import './admin_list_orgs_ctrl';
|
||||
import './admin_edit_org_ctrl';
|
||||
import './admin_edit_user_ctrl';
|
||||
|
||||
import coreModule from 'app/core/core_module';
|
||||
|
||||
|
@ -1,13 +1,9 @@
|
||||
define([
|
||||
'angular',
|
||||
],
|
||||
function (angular) {
|
||||
'use strict';
|
||||
import angular from 'angular';
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
|
||||
module.controller('AdminEditOrgCtrl', function($scope, $routeParams, backendSrv, $location, navModelSrv) {
|
||||
export class AdminEditOrgCtrl {
|
||||
|
||||
/** @ngInject */
|
||||
constructor($scope, $routeParams, backendSrv, $location, navModelSrv) {
|
||||
$scope.init = function() {
|
||||
$scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs');
|
||||
|
||||
@ -48,7 +44,7 @@ function (angular) {
|
||||
};
|
||||
|
||||
$scope.init();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
angular.module('grafana.controllers').controller('AdminEditOrgCtrl', AdminEditOrgCtrl);
|
@ -1,13 +1,10 @@
|
||||
define([
|
||||
'angular',
|
||||
'lodash',
|
||||
],
|
||||
function (angular, _) {
|
||||
'use strict';
|
||||
import angular from 'angular';
|
||||
import _ from 'lodash';
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
export class AdminEditUserCtrl {
|
||||
|
||||
module.controller('AdminEditUserCtrl', function($scope, $routeParams, backendSrv, $location, navModelSrv) {
|
||||
/** @ngInject */
|
||||
constructor($scope, $routeParams, backendSrv, $location, navModelSrv) {
|
||||
$scope.user = {};
|
||||
$scope.newOrg = { name: '', role: 'Editor' };
|
||||
$scope.permissions = {};
|
||||
@ -106,6 +103,7 @@ function (angular, _) {
|
||||
};
|
||||
|
||||
$scope.init();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
angular.module('grafana.controllers').controller('AdminEditUserCtrl', AdminEditUserCtrl);
|
@ -1,13 +1,9 @@
|
||||
define([
|
||||
'angular',
|
||||
],
|
||||
function (angular) {
|
||||
'use strict';
|
||||
import angular from 'angular';
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
|
||||
module.controller('AdminListOrgsCtrl', function($scope, backendSrv, navModelSrv) {
|
||||
export class AdminListOrgsCtrl {
|
||||
|
||||
/** @ngInject */
|
||||
constructor($scope, backendSrv, navModelSrv) {
|
||||
$scope.init = function() {
|
||||
$scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs');
|
||||
$scope.getOrgs();
|
||||
@ -35,7 +31,7 @@ function (angular) {
|
||||
};
|
||||
|
||||
$scope.init();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
angular.module('grafana.controllers').controller('AdminListOrgsCtrl', AdminListOrgsCtrl);
|
@ -1,13 +1,7 @@
|
||||
define([
|
||||
'angular',
|
||||
'lodash',
|
||||
],
|
||||
function (angular, _) {
|
||||
'use strict';
|
||||
import angular from 'angular';
|
||||
import _ from 'lodash';
|
||||
|
||||
var module = angular.module('grafana.directives');
|
||||
|
||||
var iconMap = {
|
||||
var iconMap = {
|
||||
"external link": "fa-external-link",
|
||||
"dashboard": "fa-th-large",
|
||||
"question": "fa-question",
|
||||
@ -15,9 +9,9 @@ function (angular, _) {
|
||||
"bolt": "fa-bolt",
|
||||
"doc": "fa-file-text-o",
|
||||
"cloud": "fa-cloud",
|
||||
};
|
||||
};
|
||||
|
||||
module.directive('dashLinksEditor', function() {
|
||||
function dashLinksEditor() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
controller: 'DashLinkEditorCtrl',
|
||||
@ -25,9 +19,9 @@ function (angular, _) {
|
||||
link: function() {
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
module.directive('dashLinksContainer', function() {
|
||||
function dashLinksContainer() {
|
||||
return {
|
||||
scope: {
|
||||
links: "="
|
||||
@ -37,9 +31,10 @@ function (angular, _) {
|
||||
template: '<dash-link ng-repeat="link in generatedLinks" link="link"></dash-link>',
|
||||
link: function() { }
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
module.directive('dashLink', function($compile, linkSrv) {
|
||||
/** @ngInject */
|
||||
function dashLink($compile, linkSrv) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function(scope, elem) {
|
||||
@ -84,9 +79,11 @@ function (angular, _) {
|
||||
scope.$on('refresh', update);
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
module.controller("DashLinksContainerCtrl", function($scope, $rootScope, $q, backendSrv, dashboardSrv, linkSrv) {
|
||||
export class DashLinksContainerCtrl {
|
||||
/** @ngInject */
|
||||
constructor($scope, $rootScope, $q, backendSrv, dashboardSrv, linkSrv) {
|
||||
var currentDashId = dashboardSrv.getCurrent().id;
|
||||
|
||||
function buildLinks(linkDef) {
|
||||
@ -162,10 +159,12 @@ function (angular, _) {
|
||||
|
||||
updateDashLinks();
|
||||
$rootScope.onAppEvent('dash-links-updated', updateDashLinks, $scope);
|
||||
});
|
||||
|
||||
module.controller('DashLinkEditorCtrl', function($scope, $rootScope) {
|
||||
}
|
||||
}
|
||||
|
||||
export class DashLinkEditorCtrl {
|
||||
/** @ngInject */
|
||||
constructor($scope, $rootScope) {
|
||||
$scope.iconMap = iconMap;
|
||||
$scope.dashboard.links = $scope.dashboard.links || [];
|
||||
|
||||
@ -189,6 +188,11 @@ function (angular, _) {
|
||||
$scope.dashboard.updateSubmenuVisibility();
|
||||
$scope.updated();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
angular.module('grafana.directives').directive('dashLinksEditor', dashLinksEditor);
|
||||
angular.module('grafana.directives').directive('dashLinksContainer', dashLinksContainer);
|
||||
angular.module('grafana.directives').directive('dashLink', dashLink);
|
||||
angular.module('grafana.directives').controller("DashLinksContainerCtrl", DashLinksContainerCtrl);
|
||||
angular.module('grafana.directives').controller('DashLinkEditorCtrl', DashLinkEditorCtrl);
|
@ -1,14 +0,0 @@
|
||||
define([
|
||||
'./org_users_ctrl',
|
||||
'./profile_ctrl',
|
||||
'./select_org_ctrl',
|
||||
'./change_password_ctrl',
|
||||
'./newOrgCtrl',
|
||||
'./userInviteCtrl',
|
||||
'./orgApiKeysCtrl',
|
||||
'./orgDetailsCtrl',
|
||||
'./prefs_control',
|
||||
'./user_groups_ctrl',
|
||||
'./user_group_details_ctrl',
|
||||
'./create_user_group_modal',
|
||||
], function () {});
|
10
public/app/features/org/all.ts
Normal file
10
public/app/features/org/all.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import './org_users_ctrl';
|
||||
import './profile_ctrl';
|
||||
import './org_users_ctrl';
|
||||
import './select_org_ctrl';
|
||||
import './change_password_ctrl';
|
||||
import './new_org_ctrl';
|
||||
import './user_invite_ctrl';
|
||||
import './org_api_keys_ctrl';
|
||||
import './org_details_ctrl';
|
||||
import './prefs_control';
|
@ -1,16 +1,10 @@
|
||||
define([
|
||||
'angular',
|
||||
'app/core/config',
|
||||
],
|
||||
function (angular, config) {
|
||||
'use strict';
|
||||
import angular from 'angular';
|
||||
import config from 'app/core/config';
|
||||
|
||||
config = config.default;
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
|
||||
module.controller('ChangePasswordCtrl', function($scope, backendSrv, $location, navModelSrv) {
|
||||
export class ChangePasswordCtrl {
|
||||
|
||||
/** @ngInject **/
|
||||
constructor($scope, backendSrv, $location, navModelSrv) {
|
||||
$scope.command = {};
|
||||
$scope.authProxyEnabled = config.authProxyEnabled;
|
||||
$scope.ldapEnabled = config.ldapEnabled;
|
||||
@ -28,6 +22,7 @@ function (angular, config) {
|
||||
$location.path("profile");
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
angular.module('grafana.controllers').controller('ChangePasswordCtrl', ChangePasswordCtrl);
|
@ -1,16 +1,10 @@
|
||||
define([
|
||||
'angular',
|
||||
'app/core/config',
|
||||
],
|
||||
function (angular, config) {
|
||||
'use strict';
|
||||
import angular from 'angular';
|
||||
import config from 'app/core/config';
|
||||
|
||||
config = config.default;
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
|
||||
module.controller('NewOrgCtrl', function($scope, $http, backendSrv, navModelSrv) {
|
||||
export class NewOrgCtrl {
|
||||
|
||||
/** @ngInject **/
|
||||
constructor($scope, $http, backendSrv, navModelSrv) {
|
||||
$scope.navModel = navModelSrv.getOrgNav(0);
|
||||
$scope.newOrg = {name: ''};
|
||||
|
||||
@ -21,6 +15,7 @@ function (angular, config) {
|
||||
});
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
angular.module('grafana.controllers').controller('NewOrgCtrl', NewOrgCtrl);
|
@ -1,14 +1,11 @@
|
||||
define([
|
||||
'angular',
|
||||
],
|
||||
function (angular) {
|
||||
'use strict';
|
||||
import angular from 'angular';
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
|
||||
module.controller('OrgApiKeysCtrl', function($scope, $http, backendSrv, navModelSrv) {
|
||||
export class OrgApiKeysCtrl {
|
||||
|
||||
/** @ngInject **/
|
||||
constructor ($scope, $http, backendSrv, navModelSrv) {
|
||||
$scope.navModel = navModelSrv.getNav('cfg', 'apikeys');
|
||||
|
||||
$scope.roleTypes = ['Viewer', 'Editor', 'Admin'];
|
||||
$scope.token = { role: 'Viewer' };
|
||||
|
||||
@ -43,6 +40,7 @@ function (angular) {
|
||||
};
|
||||
|
||||
$scope.init();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
angular.module('grafana.controllers').controller('OrgApiKeysCtrl', OrgApiKeysCtrl);
|
@ -1,13 +1,9 @@
|
||||
define([
|
||||
'angular',
|
||||
],
|
||||
function (angular) {
|
||||
'use strict';
|
||||
import angular from 'angular';
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
|
||||
module.controller('OrgDetailsCtrl', function($scope, $http, backendSrv, contextSrv, navModelSrv) {
|
||||
export class OrgDetailsCtrl {
|
||||
|
||||
/** @ngInject **/
|
||||
constructor($scope, $http, backendSrv, contextSrv, navModelSrv) {
|
||||
$scope.init = function() {
|
||||
$scope.getOrgInfo();
|
||||
$scope.navModel = navModelSrv.getNav('cfg', 'org');
|
||||
@ -33,6 +29,7 @@ function (angular) {
|
||||
};
|
||||
|
||||
$scope.init();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
angular.module('grafana.controllers').controller('OrgDetailsCtrl', OrgDetailsCtrl);
|
@ -1,16 +1,10 @@
|
||||
define([
|
||||
'angular',
|
||||
'app/core/config',
|
||||
],
|
||||
function (angular, config) {
|
||||
'use strict';
|
||||
import angular from 'angular';
|
||||
import config from 'app/core/config';
|
||||
|
||||
config = config.default;
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
|
||||
module.controller('SelectOrgCtrl', function($scope, backendSrv, contextSrv) {
|
||||
export class SelectOrgCtrl {
|
||||
|
||||
/** @ngInject **/
|
||||
constructor($scope, backendSrv, contextSrv) {
|
||||
contextSrv.sidemenu = false;
|
||||
|
||||
$scope.init = function() {
|
||||
@ -30,6 +24,7 @@ function (angular, config) {
|
||||
};
|
||||
|
||||
$scope.init();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
angular.module('grafana.controllers').controller('SelectOrgCtrl', SelectOrgCtrl);
|
@ -1,14 +1,10 @@
|
||||
define([
|
||||
'angular',
|
||||
'lodash',
|
||||
],
|
||||
function (angular, _) {
|
||||
'use strict';
|
||||
import angular from 'angular';
|
||||
import _ from 'lodash';
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
|
||||
module.controller('UserInviteCtrl', function($scope, backendSrv) {
|
||||
export class UserInviteCtrl {
|
||||
|
||||
/** @ngInject **/
|
||||
constructor($scope, backendSrv) {
|
||||
$scope.invites = [
|
||||
{name: '', email: '', role: 'Editor'},
|
||||
];
|
||||
@ -44,5 +40,7 @@ function (angular, _) {
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('grafana.controllers').controller('UserInviteCtrl', UserInviteCtrl);
|
@ -1,56 +0,0 @@
|
||||
define([
|
||||
'angular',
|
||||
'lodash',
|
||||
'./link_srv',
|
||||
],
|
||||
function (angular, _) {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('grafana.directives')
|
||||
.directive('panelLinksEditor', function() {
|
||||
return {
|
||||
scope: {
|
||||
panel: "="
|
||||
},
|
||||
restrict: 'E',
|
||||
controller: 'PanelLinksEditorCtrl',
|
||||
templateUrl: 'public/app/features/panellinks/module.html',
|
||||
link: function() {
|
||||
}
|
||||
};
|
||||
}).controller('PanelLinksEditorCtrl', function($scope, backendSrv) {
|
||||
|
||||
$scope.panel.links = $scope.panel.links || [];
|
||||
|
||||
$scope.addLink = function() {
|
||||
$scope.panel.links.push({
|
||||
type: 'dashboard',
|
||||
});
|
||||
};
|
||||
|
||||
$scope.searchDashboards = function(queryStr, callback) {
|
||||
backendSrv.search({query: queryStr}).then(function(hits) {
|
||||
var dashboards = _.map(hits, function(dash) {
|
||||
return dash.title;
|
||||
});
|
||||
|
||||
callback(dashboards);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.dashboardChanged = function(link) {
|
||||
backendSrv.search({query: link.dashboard}).then(function(hits) {
|
||||
var dashboard = _.find(hits, {title: link.dashboard});
|
||||
if (dashboard) {
|
||||
link.dashUri = dashboard.uri;
|
||||
link.title = dashboard.title;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.deleteLink = function(link) {
|
||||
$scope.panel.links = _.without($scope.panel.links, link);
|
||||
};
|
||||
});
|
||||
});
|
57
public/app/features/panellinks/module.ts
Normal file
57
public/app/features/panellinks/module.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import angular from 'angular';
|
||||
import _ from 'lodash';
|
||||
import './link_srv';
|
||||
|
||||
function panelLinksEditor() {
|
||||
return {
|
||||
scope: {
|
||||
panel: "="
|
||||
},
|
||||
restrict: 'E',
|
||||
controller: 'PanelLinksEditorCtrl',
|
||||
templateUrl: 'public/app/features/panellinks/module.html',
|
||||
link: function() {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export class PanelLinksEditorCtrl {
|
||||
/** @ngInject */
|
||||
constructor($scope, backendSrv) {
|
||||
$scope.panel.links = $scope.panel.links || [];
|
||||
|
||||
$scope.addLink = function() {
|
||||
$scope.panel.links.push({
|
||||
type: 'dashboard',
|
||||
});
|
||||
};
|
||||
|
||||
$scope.searchDashboards = function(queryStr, callback) {
|
||||
backendSrv.search({query: queryStr}).then(function(hits) {
|
||||
var dashboards = _.map(hits, function(dash) {
|
||||
return dash.title;
|
||||
});
|
||||
|
||||
callback(dashboards);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.dashboardChanged = function(link) {
|
||||
backendSrv.search({query: link.dashboard}).then(function(hits) {
|
||||
var dashboard = _.find(hits, {title: link.dashboard});
|
||||
if (dashboard) {
|
||||
link.dashUri = dashboard.uri;
|
||||
link.title = dashboard.title;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.deleteLink = function(link) {
|
||||
$scope.panel.links = _.without($scope.panel.links, link);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('grafana.directives').directive('panelLinksEditor', panelLinksEditor)
|
||||
.controller('PanelLinksEditorCtrl', PanelLinksEditorCtrl);
|
||||
|
@ -1,13 +1,9 @@
|
||||
define([
|
||||
'angular',
|
||||
'lodash',
|
||||
],
|
||||
function (angular, _) {
|
||||
'use strict';
|
||||
import angular from 'angular';
|
||||
import _ from 'lodash';
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
export class CloudWatchQueryParameter {
|
||||
|
||||
module.directive('cloudwatchQueryParameter', function() {
|
||||
constructor() {
|
||||
return {
|
||||
templateUrl: 'public/app/plugins/datasource/cloudwatch/partials/query.parameter.html',
|
||||
controller: 'CloudWatchQueryParameterCtrl',
|
||||
@ -18,9 +14,12 @@ function (angular, _) {
|
||||
onChange: "&",
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.controller('CloudWatchQueryParameterCtrl', function($scope, templateSrv, uiSegmentSrv, datasourceSrv, $q) {
|
||||
export class CloudWatchQueryParameterCtrl {
|
||||
|
||||
constructor($scope, templateSrv, uiSegmentSrv, datasourceSrv, $q) {
|
||||
|
||||
$scope.init = function() {
|
||||
var target = $scope.target;
|
||||
@ -120,8 +119,7 @@ function (angular, _) {
|
||||
|
||||
if (segment.value === $scope.removeDimSegment.value) {
|
||||
$scope.dimSegments.splice(index, 3);
|
||||
}
|
||||
else if (segment.type === 'plus-button') {
|
||||
} else if (segment.type === 'plus-button') {
|
||||
$scope.dimSegments.push(uiSegmentSrv.newOperator('='));
|
||||
$scope.dimSegments.push(uiSegmentSrv.newFake('select dimension value', 'value', 'query-segment-value'));
|
||||
segment.type = 'key';
|
||||
@ -195,7 +193,8 @@ function (angular, _) {
|
||||
};
|
||||
|
||||
$scope.init();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
angular.module('grafana.controllers').directive('cloudwatchQueryParameter', CloudWatchQueryParameter);
|
||||
angular.module('grafana.controllers').controller('CloudWatchQueryParameterCtrl', CloudWatchQueryParameterCtrl);
|
@ -8,6 +8,7 @@ export class ElasticConfigCtrl {
|
||||
constructor($scope) {
|
||||
this.current.jsonData.timeField = this.current.jsonData.timeField || '@timestamp';
|
||||
this.current.jsonData.esVersion = this.current.jsonData.esVersion || 5;
|
||||
this.current.jsonData.maxConcurrentShardRequests = this.current.jsonData.maxConcurrentShardRequests || 256;
|
||||
}
|
||||
|
||||
indexPatternTypes = [
|
||||
@ -22,6 +23,7 @@ export class ElasticConfigCtrl {
|
||||
esVersions = [
|
||||
{name: '2.x', value: 2},
|
||||
{name: '5.x', value: 5},
|
||||
{name: '5.6+', value: 56},
|
||||
];
|
||||
|
||||
indexPatternTypeChanged() {
|
||||
|
@ -16,6 +16,7 @@ export class ElasticDatasource {
|
||||
timeField: string;
|
||||
esVersion: number;
|
||||
interval: string;
|
||||
maxConcurrentShardRequests: number;
|
||||
queryBuilder: ElasticQueryBuilder;
|
||||
indexPattern: IndexPattern;
|
||||
|
||||
@ -30,6 +31,7 @@ export class ElasticDatasource {
|
||||
this.esVersion = instanceSettings.jsonData.esVersion;
|
||||
this.indexPattern = new IndexPattern(instanceSettings.index, instanceSettings.jsonData.interval);
|
||||
this.interval = instanceSettings.jsonData.timeInterval;
|
||||
this.maxConcurrentShardRequests = instanceSettings.jsonData.maxConcurrentShardRequests;
|
||||
this.queryBuilder = new ElasticQueryBuilder({
|
||||
timeField: this.timeField,
|
||||
esVersion: this.esVersion,
|
||||
@ -213,11 +215,15 @@ export class ElasticDatasource {
|
||||
}
|
||||
|
||||
getQueryHeader(searchType, timeFrom, timeTo) {
|
||||
return angular.toJson({
|
||||
var query_header: any = {
|
||||
search_type: searchType,
|
||||
"ignore_unavailable": true,
|
||||
index: this.indexPattern.getIndexList(timeFrom, timeTo),
|
||||
});
|
||||
};
|
||||
if (this.esVersion >= 56) {
|
||||
query_header["max_concurrent_shard_requests"] = this.maxConcurrentShardRequests;
|
||||
}
|
||||
return angular.toJson(query_header);
|
||||
}
|
||||
|
||||
query(options) {
|
||||
|
@ -25,6 +25,10 @@
|
||||
<span class="gf-form-label width-9">Version</span>
|
||||
<select class="gf-form-input gf-size-auto" ng-model="ctrl.current.jsonData.esVersion" ng-options="f.value as f.name for f in ctrl.esVersions"></select>
|
||||
</div>
|
||||
<div class="gf-form max-width-30" ng-if="ctrl.current.jsonData.esVersion>=56">
|
||||
<span class="gf-form-label width-15">Max concurrent Shard Requests</span>
|
||||
<input class="gf-form-input" type="text" ng-model='ctrl.current.jsonData.maxConcurrentShardRequests' placeholder="" required></input>
|
||||
</div>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-9">Min interval</span>
|
||||
|
@ -1,981 +0,0 @@
|
||||
define([
|
||||
'lodash',
|
||||
'jquery',
|
||||
'app/core/utils/version'
|
||||
],
|
||||
function (_, $, version) {
|
||||
'use strict';
|
||||
|
||||
var index = [];
|
||||
var categories = {
|
||||
Combine: [],
|
||||
Transform: [],
|
||||
Calculate: [],
|
||||
Filter: [],
|
||||
Special: []
|
||||
};
|
||||
|
||||
function addFuncDef(funcDef) {
|
||||
funcDef.params = funcDef.params || [];
|
||||
funcDef.defaultParams = funcDef.defaultParams || [];
|
||||
|
||||
if (funcDef.category) {
|
||||
funcDef.category.push(funcDef);
|
||||
}
|
||||
index[funcDef.name] = funcDef;
|
||||
index[funcDef.shortName || funcDef.name] = funcDef;
|
||||
}
|
||||
|
||||
var optionalSeriesRefArgs = [
|
||||
{ name: 'other', type: 'value_or_series', optional: true },
|
||||
{ name: 'other', type: 'value_or_series', optional: true },
|
||||
{ name: 'other', type: 'value_or_series', optional: true },
|
||||
{ name: 'other', type: 'value_or_series', optional: true },
|
||||
{ name: 'other', type: 'value_or_series', optional: true }
|
||||
];
|
||||
|
||||
addFuncDef({
|
||||
name: 'scaleToSeconds',
|
||||
category: categories.Transform,
|
||||
params: [{ name: 'seconds', type: 'int' }],
|
||||
defaultParams: [1],
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'perSecond',
|
||||
category: categories.Transform,
|
||||
params: [{ name: "max value", type: "int", optional: true }],
|
||||
defaultParams: [],
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "holtWintersForecast",
|
||||
category: categories.Calculate,
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "holtWintersConfidenceBands",
|
||||
category: categories.Calculate,
|
||||
params: [{ name: "delta", type: 'int' }],
|
||||
defaultParams: [3]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "holtWintersAberration",
|
||||
category: categories.Calculate,
|
||||
params: [{ name: "delta", type: 'int' }],
|
||||
defaultParams: [3]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "nPercentile",
|
||||
category: categories.Calculate,
|
||||
params: [{ name: "Nth percentile", type: 'int' }],
|
||||
defaultParams: [95]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'diffSeries',
|
||||
params: optionalSeriesRefArgs,
|
||||
defaultParams: ['#A'],
|
||||
category: categories.Calculate,
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'stddevSeries',
|
||||
params: optionalSeriesRefArgs,
|
||||
defaultParams: [''],
|
||||
category: categories.Calculate,
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'divideSeries',
|
||||
params: optionalSeriesRefArgs,
|
||||
defaultParams: ['#A'],
|
||||
category: categories.Calculate,
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'multiplySeries',
|
||||
params: optionalSeriesRefArgs,
|
||||
defaultParams: ['#A'],
|
||||
category: categories.Calculate,
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'asPercent',
|
||||
params: optionalSeriesRefArgs,
|
||||
defaultParams: ['#A'],
|
||||
category: categories.Calculate,
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'group',
|
||||
params: optionalSeriesRefArgs,
|
||||
defaultParams: ['#A', '#B'],
|
||||
category: categories.Combine,
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'sumSeries',
|
||||
shortName: 'sum',
|
||||
category: categories.Combine,
|
||||
params: optionalSeriesRefArgs,
|
||||
defaultParams: [''],
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'averageSeries',
|
||||
shortName: 'avg',
|
||||
category: categories.Combine,
|
||||
params: optionalSeriesRefArgs,
|
||||
defaultParams: [''],
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'rangeOfSeries',
|
||||
category: categories.Combine
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'percentileOfSeries',
|
||||
category: categories.Combine,
|
||||
params: [{ name: 'n', type: 'int' }, { name: 'interpolate', type: 'boolean', options: ['true', 'false'] }],
|
||||
defaultParams: [95, 'false']
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'sumSeriesWithWildcards',
|
||||
category: categories.Combine,
|
||||
params: [
|
||||
{ name: "node", type: "int" },
|
||||
{ name: "node", type: "int", optional: true },
|
||||
{ name: "node", type: "int", optional: true },
|
||||
{ name: "node", type: "int", optional: true }
|
||||
],
|
||||
defaultParams: [3]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'maxSeries',
|
||||
shortName: 'max',
|
||||
category: categories.Combine,
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'minSeries',
|
||||
shortName: 'min',
|
||||
category: categories.Combine,
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'averageSeriesWithWildcards',
|
||||
category: categories.Combine,
|
||||
params: [
|
||||
{ name: "node", type: "int" },
|
||||
{ name: "node", type: "int", optional: true },
|
||||
],
|
||||
defaultParams: [3]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "alias",
|
||||
category: categories.Special,
|
||||
params: [{ name: "alias", type: 'string' }],
|
||||
defaultParams: ['alias']
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "aliasSub",
|
||||
category: categories.Special,
|
||||
params: [{ name: "search", type: 'string' }, { name: "replace", type: 'string' }],
|
||||
defaultParams: ['', '\\1']
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "stacked",
|
||||
category: categories.Special,
|
||||
params: [{ name: "stack", type: 'string' }],
|
||||
defaultParams: ['stacked']
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "consolidateBy",
|
||||
category: categories.Special,
|
||||
params: [
|
||||
{
|
||||
name: 'function',
|
||||
type: 'string',
|
||||
options: ['sum', 'average', 'min', 'max']
|
||||
}
|
||||
],
|
||||
defaultParams: ['max']
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "cumulative",
|
||||
category: categories.Special,
|
||||
params: [],
|
||||
defaultParams: []
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "groupByNode",
|
||||
category: categories.Special,
|
||||
params: [
|
||||
{
|
||||
name: "node",
|
||||
type: "int",
|
||||
options: [0,1,2,3,4,5,6,7,8,9,10,12]
|
||||
},
|
||||
{
|
||||
name: "function",
|
||||
type: "string",
|
||||
options: ['sum', 'avg', 'maxSeries']
|
||||
}
|
||||
],
|
||||
defaultParams: [3, "sum"]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'aliasByNode',
|
||||
category: categories.Special,
|
||||
params: [
|
||||
{ name: "node", type: "int", options: [0,1,2,3,4,5,6,7,8,9,10,12] },
|
||||
{ name: "node", type: "int", options: [0,-1,-2,-3,-4,-5,-6,-7], optional: true },
|
||||
{ name: "node", type: "int", options: [0,-1,-2,-3,-4,-5,-6,-7], optional: true },
|
||||
{ name: "node", type: "int", options: [0,-1,-2,-3,-4,-5,-6,-7], optional: true },
|
||||
],
|
||||
defaultParams: [3]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'substr',
|
||||
category: categories.Special,
|
||||
params: [
|
||||
{ name: "start", type: "int", options: [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,12] },
|
||||
{ name: "stop", type: "int", options: [-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,12] },
|
||||
],
|
||||
defaultParams: [0, 0]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'sortByName',
|
||||
category: categories.Special,
|
||||
params: [{ name: 'natural', type: 'boolean', options: ['true', 'false'], optional: true }],
|
||||
defaultParams: ['false']
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'sortByMaxima',
|
||||
category: categories.Special
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'sortByMinima',
|
||||
category: categories.Special
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'sortByTotal',
|
||||
category: categories.Special
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'aliasByMetric',
|
||||
category: categories.Special,
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'randomWalk',
|
||||
fake: true,
|
||||
category: categories.Special,
|
||||
params: [{ name: "name", type: "string", }],
|
||||
defaultParams: ['randomWalk']
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'countSeries',
|
||||
category: categories.Special
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'constantLine',
|
||||
category: categories.Special,
|
||||
params: [{ name: "value", type: "int", }],
|
||||
defaultParams: [10]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'cactiStyle',
|
||||
category: categories.Special,
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'keepLastValue',
|
||||
category: categories.Special,
|
||||
params: [{ name: "n", type: "int", }],
|
||||
defaultParams: [100]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "changed",
|
||||
category: categories.Special,
|
||||
params: [],
|
||||
defaultParams: []
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'scale',
|
||||
category: categories.Transform,
|
||||
params: [{ name: "factor", type: "int", }],
|
||||
defaultParams: [1]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'offset',
|
||||
category: categories.Transform,
|
||||
params: [{ name: "amount", type: "int", }],
|
||||
defaultParams: [10]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'transformNull',
|
||||
category: categories.Transform,
|
||||
params: [{ name: "amount", type: "int", }],
|
||||
defaultParams: [0]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'integral',
|
||||
category: categories.Transform,
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'derivative',
|
||||
category: categories.Transform,
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'nonNegativeDerivative',
|
||||
category: categories.Transform,
|
||||
params: [{ name: "max value or 0", type: "int", optional: true }],
|
||||
defaultParams: ['']
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'timeShift',
|
||||
category: categories.Transform,
|
||||
params: [{ name: "amount", type: "select", options: ['1h', '6h', '12h', '1d', '2d', '7d', '14d', '30d'] }],
|
||||
defaultParams: ['1d']
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'timeStack',
|
||||
category: categories.Transform,
|
||||
params: [
|
||||
{ name: "timeShiftUnit", type: "select", options: ['1h', '6h', '12h', '1d', '2d', '7d', '14d', '30d'] },
|
||||
{ name: "timeShiftStart", type: "int" },
|
||||
{ name: "timeShiftEnd", type: "int" }
|
||||
],
|
||||
defaultParams: ['1d', 0, 7]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'summarize',
|
||||
category: categories.Transform,
|
||||
params: [
|
||||
{ name: "interval", type: "string" },
|
||||
{ name: "func", type: "select", options: ['sum', 'avg', 'min', 'max', 'last'] },
|
||||
{ name: "alignToFrom", type: "boolean", optional: true, options: ['false', 'true'] },
|
||||
],
|
||||
defaultParams: ['1h', 'sum', 'false']
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'smartSummarize',
|
||||
category: categories.Transform,
|
||||
params: [{ name: "interval", type: "string" }, { name: "func", type: "select", options: ['sum', 'avg', 'min', 'max', 'last'] }],
|
||||
defaultParams: ['1h', 'sum']
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'absolute',
|
||||
category: categories.Transform,
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'hitcount',
|
||||
category: categories.Transform,
|
||||
params: [{ name: "interval", type: "string" }],
|
||||
defaultParams: ['10s']
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'log',
|
||||
category: categories.Transform,
|
||||
params: [{ name: "base", type: "int" }],
|
||||
defaultParams: ['10']
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'averageAbove',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "n", type: "int", }],
|
||||
defaultParams: [25]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'averageBelow',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "n", type: "int", }],
|
||||
defaultParams: [25]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'currentAbove',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "n", type: "int", }],
|
||||
defaultParams: [25]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'currentBelow',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "n", type: "int", }],
|
||||
defaultParams: [25]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'maximumAbove',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "value", type: "int" }],
|
||||
defaultParams: [0]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'maximumBelow',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "value", type: "int" }],
|
||||
defaultParams: [0]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'minimumAbove',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "value", type: "int" }],
|
||||
defaultParams: [0]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'minimumBelow',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "value", type: "int" }],
|
||||
defaultParams: [0]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'limit',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "n", type: "int" }],
|
||||
defaultParams: [5]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'mostDeviant',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "n", type: "int" }],
|
||||
defaultParams: [10]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "exclude",
|
||||
category: categories.Filter,
|
||||
params: [{ name: "exclude", type: 'string' }],
|
||||
defaultParams: ['exclude']
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'highestCurrent',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "count", type: "int" }],
|
||||
defaultParams: [5]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'highestMax',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "count", type: "int" }],
|
||||
defaultParams: [5]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'lowestCurrent',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "count", type: "int" }],
|
||||
defaultParams: [5]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'movingAverage',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "windowSize", type: "int_or_interval", options: ['5', '7', '10', '5min', '10min', '30min', '1hour'] }],
|
||||
defaultParams: [10]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'movingMedian',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "windowSize", type: "int_or_interval", options: ['5', '7', '10', '5min', '10min', '30min', '1hour'] }],
|
||||
defaultParams: ['5']
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'stdev',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "n", type: "int" }, { name: "tolerance", type: "int" }],
|
||||
defaultParams: [5,0.1]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'highestAverage',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "count", type: "int" }],
|
||||
defaultParams: [5]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'lowestAverage',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "count", type: "int" }],
|
||||
defaultParams: [5]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'removeAbovePercentile',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "n", type: "int" }],
|
||||
defaultParams: [5]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'removeAboveValue',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "n", type: "int" }],
|
||||
defaultParams: [5]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'removeBelowPercentile',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "n", type: "int" }],
|
||||
defaultParams: [5]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'removeBelowValue',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "n", type: "int" }],
|
||||
defaultParams: [5]
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'useSeriesAbove',
|
||||
category: categories.Filter,
|
||||
params: [
|
||||
{ name: "value", type: "int" },
|
||||
{ name: "search", type: "string" },
|
||||
{ name: "replace", type: "string" }
|
||||
],
|
||||
defaultParams: [0, 'search', 'replace']
|
||||
});
|
||||
|
||||
////////////////////
|
||||
// Graphite 1.0.x //
|
||||
////////////////////
|
||||
|
||||
addFuncDef({
|
||||
name: 'aggregateLine',
|
||||
category: categories.Combine,
|
||||
params: [{ name: "func", type: "select", options: ['sum', 'avg', 'min', 'max', 'last']}],
|
||||
defaultParams: ['avg'],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'averageOutsidePercentile',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "n", type: "int", }],
|
||||
defaultParams: [95],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'delay',
|
||||
category: categories.Transform,
|
||||
params: [{ name: 'steps', type: 'int', }],
|
||||
defaultParams: [1],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'exponentialMovingAverage',
|
||||
category: categories.Calculate,
|
||||
params: [{ name: 'windowSize', type: 'int_or_interval', options: ['5', '7', '10', '5min', '10min', '30min', '1hour'] }],
|
||||
defaultParams: [10],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'fallbackSeries',
|
||||
category: categories.Special,
|
||||
params: [{ name: 'fallback', type: 'string' }],
|
||||
defaultParams: ['constantLine(0)'],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "grep",
|
||||
category: categories.Filter,
|
||||
params: [{ name: "grep", type: 'string' }],
|
||||
defaultParams: ['grep'],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "groupByNodes",
|
||||
category: categories.Special,
|
||||
params: [
|
||||
{
|
||||
name: "function",
|
||||
type: "string",
|
||||
options: ['sum', 'avg', 'maxSeries']
|
||||
},
|
||||
{ name: "node", type: "int", options: [0,1,2,3,4,5,6,7,8,9,10,12] },
|
||||
{ name: "node", type: "int", options: [0,-1,-2,-3,-4,-5,-6,-7], optional: true },
|
||||
{ name: "node", type: "int", options: [0,-1,-2,-3,-4,-5,-6,-7], optional: true },
|
||||
{ name: "node", type: "int", options: [0,-1,-2,-3,-4,-5,-6,-7], optional: true },
|
||||
],
|
||||
defaultParams: ["sum", 3],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'integralByInterval',
|
||||
category: categories.Transform,
|
||||
params: [{ name: "intervalUnit", type: "select", options: ['1h', '6h', '12h', '1d', '2d', '7d', '14d', '30d'] }],
|
||||
defaultParams: ['1d'],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'interpolate',
|
||||
category: categories.Transform,
|
||||
params: [{ name: 'limit', type: 'int', optional: true}],
|
||||
defaultParams: [],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'invert',
|
||||
category: categories.Transform,
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'isNonNull',
|
||||
category: categories.Combine,
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'linearRegression',
|
||||
category: categories.Calculate,
|
||||
params: [
|
||||
{ name: "startSourceAt", type: "select", options: ['-1h', '-6h', '-12h', '-1d', '-2d', '-7d', '-14d', '-30d'], optional: true },
|
||||
{ name: "endSourceAt", type: "select", options: ['-1h', '-6h', '-12h', '-1d', '-2d', '-7d', '-14d', '-30d'], optional: true }
|
||||
],
|
||||
defaultParams: [],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'mapSeries',
|
||||
shortName: 'map',
|
||||
params: [{ name: "node", type: 'int' }],
|
||||
defaultParams: [3],
|
||||
category: categories.Combine,
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'movingMin',
|
||||
category: categories.Calculate,
|
||||
params: [{ name: 'windowSize', type: 'int_or_interval', options: ['5', '7', '10', '5min', '10min', '30min', '1hour'] }],
|
||||
defaultParams: [10],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'movingMax',
|
||||
category: categories.Calculate,
|
||||
params: [{ name: 'windowSize', type: 'int_or_interval', options: ['5', '7', '10', '5min', '10min', '30min', '1hour'] }],
|
||||
defaultParams: [10],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'movingSum',
|
||||
category: categories.Calculate,
|
||||
params: [{ name: 'windowSize', type: 'int_or_interval', options: ['5', '7', '10', '5min', '10min', '30min', '1hour'] }],
|
||||
defaultParams: [10],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "multiplySeriesWithWildcards",
|
||||
category: categories.Calculate,
|
||||
params: [
|
||||
{ name: "position", type: "int", options: [0,1,2,3,4,5,6,7,8,9,10,12] },
|
||||
{ name: "position", type: "int", options: [0,-1,-2,-3,-4,-5,-6,-7], optional: true },
|
||||
{ name: "position", type: "int", options: [0,-1,-2,-3,-4,-5,-6,-7], optional: true },
|
||||
{ name: "position", type: "int", options: [0,-1,-2,-3,-4,-5,-6,-7], optional: true },
|
||||
],
|
||||
defaultParams: [2],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'offsetToZero',
|
||||
category: categories.Transform,
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'pow',
|
||||
category: categories.Transform,
|
||||
params: [{ name: 'factor', type: 'int' }],
|
||||
defaultParams: [10],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'powSeries',
|
||||
category: categories.Transform,
|
||||
params: optionalSeriesRefArgs,
|
||||
defaultParams: [''],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'reduceSeries',
|
||||
shortName: 'reduce',
|
||||
params: [
|
||||
{ name: "function", type: 'string', options: ['asPercent', 'diffSeries', 'divideSeries'] },
|
||||
{ name: "reduceNode", type: 'int', options: [0,1,2,3,4,5,6,7,8,9,10,11,12,13] },
|
||||
{ name: "reduceMatchers", type: 'string' },
|
||||
{ name: "reduceMatchers", type: 'string' },
|
||||
],
|
||||
defaultParams: ['asPercent', 2, 'used_bytes', 'total_bytes'],
|
||||
category: categories.Combine,
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'removeBetweenPercentile',
|
||||
category: categories.Filter,
|
||||
params: [{ name: "n", type: "int", }],
|
||||
defaultParams: [95],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'removeEmptySeries',
|
||||
category: categories.Filter,
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'squareRoot',
|
||||
category: categories.Transform,
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'timeSlice',
|
||||
category: categories.Transform,
|
||||
params: [
|
||||
{ name: "startSliceAt", type: "select", options: ['-1h', '-6h', '-12h', '-1d', '-2d', '-7d', '-14d', '-30d']},
|
||||
{ name: "endSliceAt", type: "select", options: ['-1h', '-6h', '-12h', '-1d', '-2d', '-7d', '-14d', '-30d'], optional: true }
|
||||
],
|
||||
defaultParams: ['-1h'],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'weightedAverage',
|
||||
category: categories.Filter,
|
||||
params: [
|
||||
{ name: 'other', type: 'value_or_series', optional: true },
|
||||
{ name: "node", type: "int", options: [0,1,2,3,4,5,6,7,8,9,10,12] },
|
||||
],
|
||||
defaultParams: ['#A', 4],
|
||||
version: '1.0'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: 'seriesByTag',
|
||||
category: categories.Special,
|
||||
params: [
|
||||
{ name: "tagExpression", type: "string" },
|
||||
{ name: "tagExpression", type: "string", optional: true },
|
||||
{ name: "tagExpression", type: "string", optional: true },
|
||||
{ name: "tagExpression", type: "string", optional: true },
|
||||
],
|
||||
version: '1.1'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "groupByTags",
|
||||
category: categories.Special,
|
||||
params: [
|
||||
{
|
||||
name: "function",
|
||||
type: "string",
|
||||
options: ['sum', 'avg', 'maxSeries']
|
||||
},
|
||||
{ name: "tag", type: "string" },
|
||||
{ name: "tag", type: "string", optional: true },
|
||||
{ name: "tag", type: "string", optional: true },
|
||||
{ name: "tag", type: "string", optional: true },
|
||||
],
|
||||
defaultParams: ["sum", "tag"],
|
||||
version: '1.1'
|
||||
});
|
||||
|
||||
addFuncDef({
|
||||
name: "aliasByTags",
|
||||
category: categories.Special,
|
||||
params: [
|
||||
{ name: "tag", type: "string" },
|
||||
{ name: "tag", type: "string", optional: true },
|
||||
{ name: "tag", type: "string", optional: true },
|
||||
{ name: "tag", type: "string", optional: true },
|
||||
],
|
||||
defaultParams: ["tag"],
|
||||
version: '1.1'
|
||||
});
|
||||
|
||||
_.each(categories, function(funcList, catName) {
|
||||
categories[catName] = _.sortBy(funcList, 'name');
|
||||
});
|
||||
|
||||
function FuncInstance(funcDef, options) {
|
||||
this.def = funcDef;
|
||||
this.params = [];
|
||||
|
||||
if (options && options.withDefaultParams) {
|
||||
this.params = funcDef.defaultParams.slice(0);
|
||||
}
|
||||
|
||||
this.updateText();
|
||||
}
|
||||
|
||||
FuncInstance.prototype.render = function(metricExp) {
|
||||
var str = this.def.name + '(';
|
||||
var parameters = _.map(this.params, function(value, index) {
|
||||
|
||||
var paramType = this.def.params[index].type;
|
||||
if (paramType === 'int' || paramType === 'value_or_series' || paramType === 'boolean') {
|
||||
return value;
|
||||
}
|
||||
else if (paramType === 'int_or_interval' && $.isNumeric(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return "'" + value + "'";
|
||||
|
||||
}.bind(this));
|
||||
|
||||
if (metricExp) {
|
||||
parameters.unshift(metricExp);
|
||||
}
|
||||
|
||||
return str + parameters.join(', ') + ')';
|
||||
};
|
||||
|
||||
FuncInstance.prototype._hasMultipleParamsInString = function(strValue, index) {
|
||||
if (strValue.indexOf(',') === -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.def.params[index + 1] && this.def.params[index + 1].optional;
|
||||
};
|
||||
|
||||
FuncInstance.prototype.updateParam = function(strValue, index) {
|
||||
// handle optional parameters
|
||||
// if string contains ',' and next param is optional, split and update both
|
||||
if (this._hasMultipleParamsInString(strValue, index)) {
|
||||
_.each(strValue.split(','), function(partVal, idx) {
|
||||
this.updateParam(partVal.trim(), index + idx);
|
||||
}.bind(this));
|
||||
return;
|
||||
}
|
||||
|
||||
if (strValue === '' && this.def.params[index].optional) {
|
||||
this.params.splice(index, 1);
|
||||
}
|
||||
else {
|
||||
this.params[index] = strValue;
|
||||
}
|
||||
|
||||
this.updateText();
|
||||
};
|
||||
|
||||
FuncInstance.prototype.updateText = function () {
|
||||
if (this.params.length === 0) {
|
||||
this.text = this.def.name + '()';
|
||||
return;
|
||||
}
|
||||
|
||||
var text = this.def.name + '(';
|
||||
text += this.params.join(', ');
|
||||
text += ')';
|
||||
this.text = text;
|
||||
};
|
||||
|
||||
function isVersionRelatedFunction(func, graphiteVersion) {
|
||||
return version.isVersionGtOrEq(graphiteVersion, func.version) || !func.version;
|
||||
}
|
||||
|
||||
return {
|
||||
createFuncInstance: function(funcDef, options) {
|
||||
if (_.isString(funcDef)) {
|
||||
if (!index[funcDef]) {
|
||||
throw { message: 'Method not found ' + name };
|
||||
}
|
||||
funcDef = index[funcDef];
|
||||
}
|
||||
return new FuncInstance(funcDef, options);
|
||||
},
|
||||
|
||||
getFuncDef: function(name) {
|
||||
return index[name];
|
||||
},
|
||||
|
||||
getCategories: function(graphiteVersion) {
|
||||
var filteredCategories = {};
|
||||
_.each(categories, function(functions, category) {
|
||||
var filteredFuncs = _.filter(functions, function(func) {
|
||||
return isVersionRelatedFunction(func, graphiteVersion);
|
||||
});
|
||||
if (filteredFuncs.length) {
|
||||
filteredCategories[category] = filteredFuncs;
|
||||
}
|
||||
});
|
||||
|
||||
return filteredCategories;
|
||||
}
|
||||
};
|
||||
|
||||
});
|
File diff suppressed because it is too large
Load Diff
@ -1,136 +0,0 @@
|
||||
define([
|
||||
'lodash'
|
||||
],
|
||||
function (_) {
|
||||
'use strict';
|
||||
|
||||
function PrometheusMetricFindQuery(datasource, query, timeSrv) {
|
||||
this.datasource = datasource;
|
||||
this.query = query;
|
||||
this.range = timeSrv.timeRange();
|
||||
}
|
||||
|
||||
PrometheusMetricFindQuery.prototype.process = function() {
|
||||
var label_values_regex = /^label_values\((?:(.+),\s*)?([a-zA-Z_][a-zA-Z0-9_]+)\)$/;
|
||||
var metric_names_regex = /^metrics\((.+)\)$/;
|
||||
var query_result_regex = /^query_result\((.+)\)$/;
|
||||
|
||||
var label_values_query = this.query.match(label_values_regex);
|
||||
if (label_values_query) {
|
||||
if (label_values_query[1]) {
|
||||
return this.labelValuesQuery(label_values_query[2], label_values_query[1]);
|
||||
} else {
|
||||
return this.labelValuesQuery(label_values_query[2], null);
|
||||
}
|
||||
}
|
||||
|
||||
var metric_names_query = this.query.match(metric_names_regex);
|
||||
if (metric_names_query) {
|
||||
return this.metricNameQuery(metric_names_query[1]);
|
||||
}
|
||||
|
||||
var query_result_query = this.query.match(query_result_regex);
|
||||
if (query_result_query) {
|
||||
return this.queryResultQuery(query_result_query[1]);
|
||||
}
|
||||
|
||||
// if query contains full metric name, return metric name and label list
|
||||
return this.metricNameAndLabelsQuery(this.query);
|
||||
};
|
||||
|
||||
PrometheusMetricFindQuery.prototype.labelValuesQuery = function(label, metric) {
|
||||
var url;
|
||||
|
||||
if (!metric) {
|
||||
// return label values globally
|
||||
url = '/api/v1/label/' + label + '/values';
|
||||
|
||||
return this.datasource._request('GET', url).then(function(result) {
|
||||
return _.map(result.data.data, function(value) {
|
||||
return {text: value};
|
||||
});
|
||||
});
|
||||
} else {
|
||||
var start = this.datasource.getPrometheusTime(this.range.from, false);
|
||||
var end = this.datasource.getPrometheusTime(this.range.to, true);
|
||||
url = '/api/v1/series?match[]=' + encodeURIComponent(metric)
|
||||
+ '&start=' + start
|
||||
+ '&end=' + end;
|
||||
|
||||
return this.datasource._request('GET', url)
|
||||
.then(function(result) {
|
||||
var _labels = _.map(result.data.data, function(metric) {
|
||||
return metric[label];
|
||||
});
|
||||
|
||||
return _.uniq(_labels).map(function(metric) {
|
||||
return {
|
||||
text: metric,
|
||||
expandable: true
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
PrometheusMetricFindQuery.prototype.metricNameQuery = function(metricFilterPattern) {
|
||||
var url = '/api/v1/label/__name__/values';
|
||||
|
||||
return this.datasource._request('GET', url)
|
||||
.then(function(result) {
|
||||
return _.chain(result.data.data)
|
||||
.filter(function(metricName) {
|
||||
var r = new RegExp(metricFilterPattern);
|
||||
return r.test(metricName);
|
||||
})
|
||||
.map(function(matchedMetricName) {
|
||||
return {
|
||||
text: matchedMetricName,
|
||||
expandable: true
|
||||
};
|
||||
})
|
||||
.value();
|
||||
});
|
||||
};
|
||||
|
||||
PrometheusMetricFindQuery.prototype.queryResultQuery = function(query) {
|
||||
var end = this.datasource.getPrometheusTime(this.range.to, true);
|
||||
return this.datasource.performInstantQuery({ expr: query }, end)
|
||||
.then(function(result) {
|
||||
return _.map(result.data.data.result, function(metricData) {
|
||||
var text = metricData.metric.__name__ || '';
|
||||
delete metricData.metric.__name__;
|
||||
text += '{' +
|
||||
_.map(metricData.metric, function(v, k) { return k + '="' + v + '"'; }).join(',') +
|
||||
'}';
|
||||
text += ' ' + metricData.value[1] + ' ' + metricData.value[0] * 1000;
|
||||
|
||||
return {
|
||||
text: text,
|
||||
expandable: true
|
||||
};
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
PrometheusMetricFindQuery.prototype.metricNameAndLabelsQuery = function(query) {
|
||||
var start = this.datasource.getPrometheusTime(this.range.from, false);
|
||||
var end = this.datasource.getPrometheusTime(this.range.to, true);
|
||||
var url = '/api/v1/series?match[]=' + encodeURIComponent(query)
|
||||
+ '&start=' + start
|
||||
+ '&end=' + end;
|
||||
|
||||
var self = this;
|
||||
return this.datasource._request('GET', url)
|
||||
.then(function(result) {
|
||||
return _.map(result.data.data, function(metric) {
|
||||
return {
|
||||
text: self.datasource.getOriginalMetricName(metric),
|
||||
expandable: true
|
||||
};
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return PrometheusMetricFindQuery;
|
||||
});
|
147
public/app/plugins/datasource/prometheus/metric_find_query.ts
Normal file
147
public/app/plugins/datasource/prometheus/metric_find_query.ts
Normal file
@ -0,0 +1,147 @@
|
||||
import _ from "lodash";
|
||||
|
||||
export default class PrometheusMetricFindQuery {
|
||||
datasource: any;
|
||||
query: any;
|
||||
range: any;
|
||||
|
||||
constructor(datasource, query, timeSrv) {
|
||||
this.datasource = datasource;
|
||||
this.query = query;
|
||||
this.range = timeSrv.timeRange();
|
||||
}
|
||||
|
||||
process() {
|
||||
var label_values_regex = /^label_values\((?:(.+),\s*)?([a-zA-Z_][a-zA-Z0-9_]+)\)$/;
|
||||
var metric_names_regex = /^metrics\((.+)\)$/;
|
||||
var query_result_regex = /^query_result\((.+)\)$/;
|
||||
|
||||
var label_values_query = this.query.match(label_values_regex);
|
||||
if (label_values_query) {
|
||||
if (label_values_query[1]) {
|
||||
return this.labelValuesQuery(
|
||||
label_values_query[2],
|
||||
label_values_query[1]
|
||||
);
|
||||
} else {
|
||||
return this.labelValuesQuery(label_values_query[2], null);
|
||||
}
|
||||
}
|
||||
|
||||
var metric_names_query = this.query.match(metric_names_regex);
|
||||
if (metric_names_query) {
|
||||
return this.metricNameQuery(metric_names_query[1]);
|
||||
}
|
||||
|
||||
var query_result_query = this.query.match(query_result_regex);
|
||||
if (query_result_query) {
|
||||
return this.queryResultQuery(query_result_query[1]);
|
||||
}
|
||||
|
||||
// if query contains full metric name, return metric name and label list
|
||||
return this.metricNameAndLabelsQuery(this.query);
|
||||
}
|
||||
|
||||
labelValuesQuery(label, metric) {
|
||||
var url;
|
||||
|
||||
if (!metric) {
|
||||
// return label values globally
|
||||
url = "/api/v1/label/" + label + "/values";
|
||||
|
||||
return this.datasource._request("GET", url).then(function(result) {
|
||||
return _.map(result.data.data, function(value) {
|
||||
return { text: value };
|
||||
});
|
||||
});
|
||||
} else {
|
||||
var start = this.datasource.getPrometheusTime(this.range.from, false);
|
||||
var end = this.datasource.getPrometheusTime(this.range.to, true);
|
||||
url =
|
||||
"/api/v1/series?match[]=" +
|
||||
encodeURIComponent(metric) +
|
||||
"&start=" +
|
||||
start +
|
||||
"&end=" +
|
||||
end;
|
||||
|
||||
return this.datasource._request("GET", url).then(function(result) {
|
||||
var _labels = _.map(result.data.data, function(metric) {
|
||||
return metric[label];
|
||||
});
|
||||
|
||||
return _.uniq(_labels).map(function(metric) {
|
||||
return {
|
||||
text: metric,
|
||||
expandable: true
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
metricNameQuery(metricFilterPattern) {
|
||||
var url = "/api/v1/label/__name__/values";
|
||||
|
||||
return this.datasource._request("GET", url).then(function(result) {
|
||||
return _.chain(result.data.data)
|
||||
.filter(function(metricName) {
|
||||
var r = new RegExp(metricFilterPattern);
|
||||
return r.test(metricName);
|
||||
})
|
||||
.map(function(matchedMetricName) {
|
||||
return {
|
||||
text: matchedMetricName,
|
||||
expandable: true
|
||||
};
|
||||
})
|
||||
.value();
|
||||
});
|
||||
}
|
||||
|
||||
queryResultQuery(query) {
|
||||
var end = this.datasource.getPrometheusTime(this.range.to, true);
|
||||
return this.datasource
|
||||
.performInstantQuery({ expr: query }, end)
|
||||
.then(function(result) {
|
||||
return _.map(result.data.data.result, function(metricData) {
|
||||
var text = metricData.metric.__name__ || "";
|
||||
delete metricData.metric.__name__;
|
||||
text +=
|
||||
"{" +
|
||||
_.map(metricData.metric, function(v, k) {
|
||||
return k + '="' + v + '"';
|
||||
}).join(",") +
|
||||
"}";
|
||||
text += " " + metricData.value[1] + " " + metricData.value[0] * 1000;
|
||||
|
||||
return {
|
||||
text: text,
|
||||
expandable: true
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
metricNameAndLabelsQuery(query) {
|
||||
var start = this.datasource.getPrometheusTime(this.range.from, false);
|
||||
var end = this.datasource.getPrometheusTime(this.range.to, true);
|
||||
var url =
|
||||
"/api/v1/series?match[]=" +
|
||||
encodeURIComponent(query) +
|
||||
"&start=" +
|
||||
start +
|
||||
"&end=" +
|
||||
end;
|
||||
|
||||
var self = this;
|
||||
return this.datasource._request("GET", url).then(function(result) {
|
||||
return _.map(result.data.data, function(metric) {
|
||||
return {
|
||||
text: self.datasource.getOriginalMetricName(metric),
|
||||
expandable: true
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
@ -1,27 +1,24 @@
|
||||
define([
|
||||
'angular',
|
||||
'jquery',
|
||||
'lodash',
|
||||
], function(angular, jquery, _) {
|
||||
'use strict';
|
||||
import _ from 'lodash';
|
||||
import angular from 'angular';
|
||||
|
||||
var module = angular.module('grafana.controllers');
|
||||
export class SeriesOverridesCtrl {
|
||||
|
||||
module.controller('SeriesOverridesCtrl', function($scope, $element, popoverSrv) {
|
||||
/** @ngInject */
|
||||
constructor($scope, $element, popoverSrv) {
|
||||
$scope.overrideMenu = [];
|
||||
$scope.currentOverrides = [];
|
||||
$scope.override = $scope.override || {};
|
||||
|
||||
$scope.addOverrideOption = function(name, propertyName, values) {
|
||||
var option = {};
|
||||
option.text = name;
|
||||
option.propertyName = propertyName;
|
||||
option.index = $scope.overrideMenu.length;
|
||||
option.values = values;
|
||||
|
||||
option.submenu = _.map(values, function(value) {
|
||||
var option = {
|
||||
text: name,
|
||||
propertyName: propertyName,
|
||||
index: $scope.overrideMenu.lenght,
|
||||
values: values,
|
||||
submenu: _.map(values, function(value) {
|
||||
return { text: String(value), value: value };
|
||||
});
|
||||
})
|
||||
};
|
||||
|
||||
$scope.overrideMenu.push(option);
|
||||
};
|
||||
@ -97,22 +94,24 @@ define([
|
||||
|
||||
$scope.addOverrideOption('Bars', 'bars', [true, false]);
|
||||
$scope.addOverrideOption('Lines', 'lines', [true, false]);
|
||||
$scope.addOverrideOption('Line fill', 'fill', [0,1,2,3,4,5,6,7,8,9,10]);
|
||||
$scope.addOverrideOption('Line width', 'linewidth', [0,1,2,3,4,5,6,7,8,9,10]);
|
||||
$scope.addOverrideOption('Line fill', 'fill', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
|
||||
$scope.addOverrideOption('Line width', 'linewidth', [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
|
||||
$scope.addOverrideOption('Null point mode', 'nullPointMode', ['connected', 'null', 'null as zero']);
|
||||
$scope.addOverrideOption('Fill below to', 'fillBelowTo', $scope.getSeriesNames());
|
||||
$scope.addOverrideOption('Staircase line', 'steppedLine', [true, false]);
|
||||
$scope.addOverrideOption('Dashes', 'dashes', [true, false]);
|
||||
$scope.addOverrideOption('Dash Length', 'dashLength', [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]);
|
||||
$scope.addOverrideOption('Dash Space', 'spaceLength', [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]);
|
||||
$scope.addOverrideOption('Dash Length', 'dashLength', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]);
|
||||
$scope.addOverrideOption('Dash Space', 'spaceLength', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]);
|
||||
$scope.addOverrideOption('Points', 'points', [true, false]);
|
||||
$scope.addOverrideOption('Points Radius', 'pointradius', [1,2,3,4,5]);
|
||||
$scope.addOverrideOption('Points Radius', 'pointradius', [1, 2, 3, 4, 5]);
|
||||
$scope.addOverrideOption('Stack', 'stack', [true, false, 'A', 'B', 'C', 'D']);
|
||||
$scope.addOverrideOption('Color', 'color', ['change']);
|
||||
$scope.addOverrideOption('Y-axis', 'yaxis', [1, 2]);
|
||||
$scope.addOverrideOption('Z-index', 'zindex', [-3,-2,-1,0,1,2,3]);
|
||||
$scope.addOverrideOption('Z-index', 'zindex', [-3, -2, -1, 0, 1, 2, 3]);
|
||||
$scope.addOverrideOption('Transform', 'transform', ['negative-Y']);
|
||||
$scope.addOverrideOption('Legend', 'legend', [true, false]);
|
||||
$scope.updateCurrentOverrides();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('grafana.controllers').controller('SeriesOverridesCtrl', SeriesOverridesCtrl);
|
@ -17,7 +17,7 @@
|
||||
"max-line-length": [true, 150],
|
||||
"member-access": false,
|
||||
"no-arg": true,
|
||||
"no-bitwise": true,
|
||||
"no-bitwise": false,
|
||||
"no-console": [true,
|
||||
"debug",
|
||||
"info",
|
||||
|
Loading…
Reference in New Issue
Block a user