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:
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]
|
[external_image_storage.gcs]
|
||||||
key_file =
|
key_file =
|
||||||
bucket =
|
bucket =
|
||||||
|
path =
|
||||||
@@ -438,3 +438,4 @@ log_queries =
|
|||||||
[external_image_storage.gcs]
|
[external_image_storage.gcs]
|
||||||
;key_file =
|
;key_file =
|
||||||
;bucket =
|
;bucket =
|
||||||
|
;path =
|
||||||
@@ -133,6 +133,37 @@ Content-Type: application/json
|
|||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
**Example Response**:
|
||||||
|
|
||||||
|
```http
|
||||||
|
HTTP/1.1 200
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Create alert notification
|
||||||
|
|
||||||
|
`POST /api/alert-notifications`
|
||||||
|
|
||||||
|
**Example Request**:
|
||||||
|
|
||||||
|
```http
|
||||||
|
POST /api/alert-notifications HTTP/1.1
|
||||||
|
Accept: application/json
|
||||||
|
Content-Type: application/json
|
||||||
|
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example Response**:
|
||||||
|
|
||||||
|
```http
|
||||||
|
HTTP/1.1 200
|
||||||
|
Content-Type: application/json
|
||||||
|
{
|
||||||
|
```
|
||||||
|
|
||||||
## Update alert notification
|
## Update alert notification
|
||||||
|
|
||||||
|
|||||||
@@ -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**:
|
**Example Request**:
|
||||||
|
|
||||||
|
|||||||
@@ -778,6 +778,9 @@ Service Account should have "Storage Object Writer" role.
|
|||||||
### bucket name
|
### bucket name
|
||||||
Bucket Name on Google Cloud Storage.
|
Bucket Name on Google Cloud Storage.
|
||||||
|
|
||||||
|
### path
|
||||||
|
Optional extra path inside bucket
|
||||||
|
|
||||||
## [alerting]
|
## [alerting]
|
||||||
|
|
||||||
### enabled
|
### enabled
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"stable": "4.5.2",
|
"stable": "4.6.2",
|
||||||
"testing": "4.5.2"
|
"testing": "4.6.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
|
|
||||||
"github.com/grafana/grafana/pkg/log"
|
"github.com/grafana/grafana/pkg/log"
|
||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
@@ -20,19 +21,22 @@ const (
|
|||||||
type GCSUploader struct {
|
type GCSUploader struct {
|
||||||
keyFile string
|
keyFile string
|
||||||
bucket string
|
bucket string
|
||||||
|
path string
|
||||||
log log.Logger
|
log log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGCSUploader(keyFile, bucket string) *GCSUploader {
|
func NewGCSUploader(keyFile, bucket, path string) *GCSUploader {
|
||||||
return &GCSUploader{
|
return &GCSUploader{
|
||||||
keyFile: keyFile,
|
keyFile: keyFile,
|
||||||
bucket: bucket,
|
bucket: bucket,
|
||||||
|
path: path,
|
||||||
log: log.New("gcsuploader"),
|
log: log.New("gcsuploader"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *GCSUploader) Upload(ctx context.Context, imageDiskPath string) (string, error) {
|
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)
|
u.log.Debug("Opening key file ", u.keyFile)
|
||||||
data, err := ioutil.ReadFile(u.keyFile)
|
data, err := ioutil.ReadFile(u.keyFile)
|
||||||
|
|||||||
@@ -73,8 +73,9 @@ func NewImageUploader() (ImageUploader, error) {
|
|||||||
|
|
||||||
keyFile := gcssec.Key("key_file").MustString("")
|
keyFile := gcssec.Key("key_file").MustString("")
|
||||||
bucketName := gcssec.Key("bucket").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
|
return NopImageUploader{}, nil
|
||||||
|
|||||||
@@ -5,9 +5,10 @@
|
|||||||
package log
|
package log
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"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)
|
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 {
|
func (w *FileLogWriter) initFd() error {
|
||||||
fd := w.mw.fd
|
fd := w.mw.fd
|
||||||
finfo, err := fd.Stat()
|
finfo, err := fd.Stat()
|
||||||
@@ -133,11 +158,11 @@ func (w *FileLogWriter) initFd() error {
|
|||||||
w.maxsize_cursize = int(finfo.Size())
|
w.maxsize_cursize = int(finfo.Size())
|
||||||
w.daily_opendate = time.Now().Day()
|
w.daily_opendate = time.Now().Day()
|
||||||
if finfo.Size() > 0 {
|
if finfo.Size() > 0 {
|
||||||
content, err := ioutil.ReadFile(w.Filename)
|
count, err := w.lineCounter()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
w.maxlines_curlines = len(strings.Split(string(content), "\n"))
|
w.maxlines_curlines = count
|
||||||
} else {
|
} else {
|
||||||
w.maxlines_curlines = 0
|
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;
|
disableLoginForm: boolean;
|
||||||
defaultDatasource: string;
|
defaultDatasource: string;
|
||||||
alertingEnabled: boolean;
|
alertingEnabled: boolean;
|
||||||
|
authProxyEnabled: boolean;
|
||||||
|
ldapEnabled: boolean;
|
||||||
|
|
||||||
constructor(options) {
|
constructor(options) {
|
||||||
var defaults = {
|
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,64 +1,57 @@
|
|||||||
import coreModule from '../core_module';
|
import coreModule from '../core_module';
|
||||||
import * as rangeUtil from 'app/core/utils/rangeutil';
|
import * as rangeUtil from 'app/core/utils/rangeutil';
|
||||||
|
|
||||||
export class NgModelOnBlur {
|
function ngModelOnBlur() {
|
||||||
constructor() {
|
return {
|
||||||
return {
|
restrict: 'A',
|
||||||
restrict: 'A',
|
priority: 1,
|
||||||
priority: 1,
|
require: 'ngModel',
|
||||||
require: 'ngModel',
|
link: function(scope, elm, attr, ngModelCtrl) {
|
||||||
link: function(scope, elm, attr, ngModelCtrl) {
|
if (attr.type === 'radio' || attr.type === 'checkbox') {
|
||||||
if (attr.type === 'radio' || attr.type === 'checkbox') {
|
return;
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
elm.off('input keydown change');
|
||||||
|
elm.bind('blur', function() {
|
||||||
|
scope.$apply(function() {
|
||||||
|
ngModelCtrl.$setViewValue(elm.val());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function emptyToNull() {
|
||||||
|
return {
|
||||||
|
restrict: 'A',
|
||||||
|
require: 'ngModel',
|
||||||
|
link: function (scope, elm, attrs, ctrl) {
|
||||||
|
ctrl.$parsers.push(function (viewValue) {
|
||||||
|
if (viewValue === "") { return null; }
|
||||||
|
return viewValue;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function validTimeSpan() {
|
||||||
|
return {
|
||||||
|
require: 'ngModel',
|
||||||
|
link: function(scope, elm, attrs, ctrl) {
|
||||||
|
ctrl.$validators.integer = function(modelValue, viewValue) {
|
||||||
|
if (ctrl.$isEmpty(modelValue)) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
if (viewValue.indexOf('$') === 0 || viewValue.indexOf('+$') === 0) {
|
||||||
elm.off('input keydown change');
|
return true; // allow template variable
|
||||||
elm.bind('blur', function() {
|
}
|
||||||
scope.$apply(function() {
|
var info = rangeUtil.describeTextRange(viewValue);
|
||||||
ngModelCtrl.$setViewValue(elm.val());
|
return info.invalid !== true;
|
||||||
});
|
};
|
||||||
});
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
coreModule.directive('ngModelOnblur', ngModelOnBlur);
|
||||||
export class EmptyToNull {
|
coreModule.directive('emptyToNull', emptyToNull);
|
||||||
constructor() {
|
coreModule.directive('validTimeSpan', validTimeSpan);
|
||||||
return {
|
|
||||||
restrict: 'A',
|
|
||||||
require: 'ngModel',
|
|
||||||
link: function (scope, elm, attrs, ctrl) {
|
|
||||||
ctrl.$parsers.push(function (viewValue) {
|
|
||||||
if (viewValue === "") { return null; }
|
|
||||||
return viewValue;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ValidTimeSpan {
|
|
||||||
constructor() {
|
|
||||||
return {
|
|
||||||
require: 'ngModel',
|
|
||||||
link: function(scope, elm, attrs, ctrl) {
|
|
||||||
ctrl.$validators.integer = function(modelValue, viewValue) {
|
|
||||||
if (ctrl.$isEmpty(modelValue)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (viewValue.indexOf('$') === 0 || viewValue.indexOf('+$') === 0) {
|
|
||||||
return true; // allow template variable
|
|
||||||
}
|
|
||||||
var info = rangeUtil.describeTextRange(viewValue);
|
|
||||||
return info.invalid !== true;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 AdminListUsersCtrl from './admin_list_users_ctrl';
|
||||||
import './adminListOrgsCtrl';
|
import './admin_list_orgs_ctrl';
|
||||||
import './adminEditOrgCtrl';
|
import './admin_edit_org_ctrl';
|
||||||
import './adminEditUserCtrl';
|
import './admin_edit_user_ctrl';
|
||||||
|
|
||||||
import coreModule from 'app/core/core_module';
|
import coreModule from 'app/core/core_module';
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
define([
|
import angular from 'angular';
|
||||||
'angular',
|
|
||||||
],
|
|
||||||
function (angular) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var module = angular.module('grafana.controllers');
|
export class AdminEditOrgCtrl {
|
||||||
|
|
||||||
module.controller('AdminEditOrgCtrl', function($scope, $routeParams, backendSrv, $location, navModelSrv) {
|
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
constructor($scope, $routeParams, backendSrv, $location, navModelSrv) {
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
$scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs');
|
$scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs');
|
||||||
|
|
||||||
@@ -48,7 +44,7 @@ function (angular) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.init();
|
$scope.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
angular.module('grafana.controllers').controller('AdminEditOrgCtrl', AdminEditOrgCtrl);
|
||||||
|
|
||||||
});
|
|
||||||
@@ -1,13 +1,10 @@
|
|||||||
define([
|
import angular from 'angular';
|
||||||
'angular',
|
import _ from 'lodash';
|
||||||
'lodash',
|
|
||||||
],
|
|
||||||
function (angular, _) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
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.user = {};
|
||||||
$scope.newOrg = { name: '', role: 'Editor' };
|
$scope.newOrg = { name: '', role: 'Editor' };
|
||||||
$scope.permissions = {};
|
$scope.permissions = {};
|
||||||
@@ -106,6 +103,7 @@ function (angular, _) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.init();
|
$scope.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
angular.module('grafana.controllers').controller('AdminEditUserCtrl', AdminEditUserCtrl);
|
||||||
});
|
|
||||||
@@ -1,13 +1,9 @@
|
|||||||
define([
|
import angular from 'angular';
|
||||||
'angular',
|
|
||||||
],
|
|
||||||
function (angular) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var module = angular.module('grafana.controllers');
|
export class AdminListOrgsCtrl {
|
||||||
|
|
||||||
module.controller('AdminListOrgsCtrl', function($scope, backendSrv, navModelSrv) {
|
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
constructor($scope, backendSrv, navModelSrv) {
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
$scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs');
|
$scope.navModel = navModelSrv.getNav('cfg', 'admin', 'global-orgs');
|
||||||
$scope.getOrgs();
|
$scope.getOrgs();
|
||||||
@@ -35,7 +31,7 @@ function (angular) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.init();
|
$scope.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
angular.module('grafana.controllers').controller('AdminListOrgsCtrl', AdminListOrgsCtrl);
|
||||||
|
|
||||||
});
|
|
||||||
@@ -1,92 +1,89 @@
|
|||||||
define([
|
import angular from 'angular';
|
||||||
'angular',
|
import _ from 'lodash';
|
||||||
'lodash',
|
|
||||||
],
|
|
||||||
function (angular, _) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var module = angular.module('grafana.directives');
|
var iconMap = {
|
||||||
|
"external link": "fa-external-link",
|
||||||
|
"dashboard": "fa-th-large",
|
||||||
|
"question": "fa-question",
|
||||||
|
"info": "fa-info",
|
||||||
|
"bolt": "fa-bolt",
|
||||||
|
"doc": "fa-file-text-o",
|
||||||
|
"cloud": "fa-cloud",
|
||||||
|
};
|
||||||
|
|
||||||
var iconMap = {
|
function dashLinksEditor() {
|
||||||
"external link": "fa-external-link",
|
return {
|
||||||
"dashboard": "fa-th-large",
|
restrict: 'E',
|
||||||
"question": "fa-question",
|
controller: 'DashLinkEditorCtrl',
|
||||||
"info": "fa-info",
|
templateUrl: 'public/app/features/dashlinks/editor.html',
|
||||||
"bolt": "fa-bolt",
|
link: function() {
|
||||||
"doc": "fa-file-text-o",
|
}
|
||||||
"cloud": "fa-cloud",
|
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
module.directive('dashLinksEditor', function() {
|
function dashLinksContainer() {
|
||||||
return {
|
return {
|
||||||
restrict: 'E',
|
scope: {
|
||||||
controller: 'DashLinkEditorCtrl',
|
links: "="
|
||||||
templateUrl: 'public/app/features/dashlinks/editor.html',
|
},
|
||||||
link: function() {
|
restrict: 'E',
|
||||||
|
controller: 'DashLinksContainerCtrl',
|
||||||
|
template: '<dash-link ng-repeat="link in generatedLinks" link="link"></dash-link>',
|
||||||
|
link: function() { }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
function dashLink($compile, linkSrv) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
link: function(scope, elem) {
|
||||||
|
var link = scope.link;
|
||||||
|
var template = '<div class="gf-form">' +
|
||||||
|
'<a class="pointer gf-form-label" data-placement="bottom"' +
|
||||||
|
(link.asDropdown ? ' ng-click="fillDropdown(link)" data-toggle="dropdown"' : "") + '>' +
|
||||||
|
'<i></i> <span></span></a>';
|
||||||
|
|
||||||
|
if (link.asDropdown) {
|
||||||
|
template += '<ul class="dropdown-menu" role="menu">' +
|
||||||
|
'<li ng-repeat="dash in link.searchHits"><a href="{{dash.url}}">{{dash.title}}</a></li>' +
|
||||||
|
'</ul>';
|
||||||
}
|
}
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
module.directive('dashLinksContainer', function() {
|
template += '</div>';
|
||||||
return {
|
|
||||||
scope: {
|
|
||||||
links: "="
|
|
||||||
},
|
|
||||||
restrict: 'E',
|
|
||||||
controller: 'DashLinksContainerCtrl',
|
|
||||||
template: '<dash-link ng-repeat="link in generatedLinks" link="link"></dash-link>',
|
|
||||||
link: function() { }
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
module.directive('dashLink', function($compile, linkSrv) {
|
elem.html(template);
|
||||||
return {
|
$compile(elem.contents())(scope);
|
||||||
restrict: 'E',
|
|
||||||
link: function(scope, elem) {
|
|
||||||
var link = scope.link;
|
|
||||||
var template = '<div class="gf-form">' +
|
|
||||||
'<a class="pointer gf-form-label" data-placement="bottom"' +
|
|
||||||
(link.asDropdown ? ' ng-click="fillDropdown(link)" data-toggle="dropdown"' : "") + '>' +
|
|
||||||
'<i></i> <span></span></a>';
|
|
||||||
|
|
||||||
if (link.asDropdown) {
|
var anchor = elem.find('a');
|
||||||
template += '<ul class="dropdown-menu" role="menu">' +
|
var icon = elem.find('i');
|
||||||
'<li ng-repeat="dash in link.searchHits"><a href="{{dash.url}}">{{dash.title}}</a></li>' +
|
var span = elem.find('span');
|
||||||
'</ul>';
|
|
||||||
}
|
|
||||||
|
|
||||||
template += '</div>';
|
function update() {
|
||||||
|
var linkInfo = linkSrv.getAnchorInfo(link);
|
||||||
elem.html(template);
|
span.text(linkInfo.title);
|
||||||
$compile(elem.contents())(scope);
|
anchor.attr("href", linkInfo.href);
|
||||||
|
|
||||||
var anchor = elem.find('a');
|
|
||||||
var icon = elem.find('i');
|
|
||||||
var span = elem.find('span');
|
|
||||||
|
|
||||||
function update() {
|
|
||||||
var linkInfo = linkSrv.getAnchorInfo(link);
|
|
||||||
span.text(linkInfo.title);
|
|
||||||
anchor.attr("href", linkInfo.href);
|
|
||||||
}
|
|
||||||
|
|
||||||
// tooltip
|
|
||||||
elem.find('a').tooltip({ title: scope.link.tooltip, html: true, container: 'body' });
|
|
||||||
icon.attr('class', 'fa fa-fw ' + scope.link.icon);
|
|
||||||
anchor.attr('target', scope.link.target);
|
|
||||||
|
|
||||||
// fix for menus on the far right
|
|
||||||
if (link.asDropdown && scope.$last) {
|
|
||||||
elem.find('.dropdown-menu').addClass('pull-right');
|
|
||||||
}
|
|
||||||
|
|
||||||
update();
|
|
||||||
scope.$on('refresh', update);
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
module.controller("DashLinksContainerCtrl", function($scope, $rootScope, $q, backendSrv, dashboardSrv, linkSrv) {
|
// tooltip
|
||||||
|
elem.find('a').tooltip({ title: scope.link.tooltip, html: true, container: 'body' });
|
||||||
|
icon.attr('class', 'fa fa-fw ' + scope.link.icon);
|
||||||
|
anchor.attr('target', scope.link.target);
|
||||||
|
|
||||||
|
// fix for menus on the far right
|
||||||
|
if (link.asDropdown && scope.$last) {
|
||||||
|
elem.find('.dropdown-menu').addClass('pull-right');
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
scope.$on('refresh', update);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DashLinksContainerCtrl {
|
||||||
|
/** @ngInject */
|
||||||
|
constructor($scope, $rootScope, $q, backendSrv, dashboardSrv, linkSrv) {
|
||||||
var currentDashId = dashboardSrv.getCurrent().id;
|
var currentDashId = dashboardSrv.getCurrent().id;
|
||||||
|
|
||||||
function buildLinks(linkDef) {
|
function buildLinks(linkDef) {
|
||||||
@@ -162,10 +159,12 @@ function (angular, _) {
|
|||||||
|
|
||||||
updateDashLinks();
|
updateDashLinks();
|
||||||
$rootScope.onAppEvent('dash-links-updated', updateDashLinks, $scope);
|
$rootScope.onAppEvent('dash-links-updated', updateDashLinks, $scope);
|
||||||
});
|
}
|
||||||
|
}
|
||||||
module.controller('DashLinkEditorCtrl', function($scope, $rootScope) {
|
|
||||||
|
|
||||||
|
export class DashLinkEditorCtrl {
|
||||||
|
/** @ngInject */
|
||||||
|
constructor($scope, $rootScope) {
|
||||||
$scope.iconMap = iconMap;
|
$scope.iconMap = iconMap;
|
||||||
$scope.dashboard.links = $scope.dashboard.links || [];
|
$scope.dashboard.links = $scope.dashboard.links || [];
|
||||||
|
|
||||||
@@ -189,6 +188,11 @@ function (angular, _) {
|
|||||||
$scope.dashboard.updateSubmenuVisibility();
|
$scope.dashboard.updateSubmenuVisibility();
|
||||||
$scope.updated();
|
$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([
|
import angular from 'angular';
|
||||||
'angular',
|
import config from 'app/core/config';
|
||||||
'app/core/config',
|
|
||||||
],
|
|
||||||
function (angular, config) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
config = config.default;
|
export class ChangePasswordCtrl {
|
||||||
|
|
||||||
var module = angular.module('grafana.controllers');
|
|
||||||
|
|
||||||
module.controller('ChangePasswordCtrl', function($scope, backendSrv, $location, navModelSrv) {
|
|
||||||
|
|
||||||
|
/** @ngInject **/
|
||||||
|
constructor($scope, backendSrv, $location, navModelSrv) {
|
||||||
$scope.command = {};
|
$scope.command = {};
|
||||||
$scope.authProxyEnabled = config.authProxyEnabled;
|
$scope.authProxyEnabled = config.authProxyEnabled;
|
||||||
$scope.ldapEnabled = config.ldapEnabled;
|
$scope.ldapEnabled = config.ldapEnabled;
|
||||||
@@ -28,6 +22,7 @@ function (angular, config) {
|
|||||||
$location.path("profile");
|
$location.path("profile");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
angular.module('grafana.controllers').controller('ChangePasswordCtrl', ChangePasswordCtrl);
|
||||||
});
|
|
||||||
@@ -1,16 +1,10 @@
|
|||||||
define([
|
import angular from 'angular';
|
||||||
'angular',
|
import config from 'app/core/config';
|
||||||
'app/core/config',
|
|
||||||
],
|
|
||||||
function (angular, config) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
config = config.default;
|
export class NewOrgCtrl {
|
||||||
|
|
||||||
var module = angular.module('grafana.controllers');
|
|
||||||
|
|
||||||
module.controller('NewOrgCtrl', function($scope, $http, backendSrv, navModelSrv) {
|
|
||||||
|
|
||||||
|
/** @ngInject **/
|
||||||
|
constructor($scope, $http, backendSrv, navModelSrv) {
|
||||||
$scope.navModel = navModelSrv.getOrgNav(0);
|
$scope.navModel = navModelSrv.getOrgNav(0);
|
||||||
$scope.newOrg = {name: ''};
|
$scope.newOrg = {name: ''};
|
||||||
|
|
||||||
@@ -21,6 +15,7 @@ function (angular, config) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
angular.module('grafana.controllers').controller('NewOrgCtrl', NewOrgCtrl);
|
||||||
});
|
|
||||||
@@ -1,14 +1,11 @@
|
|||||||
define([
|
import angular from 'angular';
|
||||||
'angular',
|
|
||||||
],
|
|
||||||
function (angular) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var module = angular.module('grafana.controllers');
|
export class OrgApiKeysCtrl {
|
||||||
|
|
||||||
module.controller('OrgApiKeysCtrl', function($scope, $http, backendSrv, navModelSrv) {
|
|
||||||
|
|
||||||
|
/** @ngInject **/
|
||||||
|
constructor ($scope, $http, backendSrv, navModelSrv) {
|
||||||
$scope.navModel = navModelSrv.getNav('cfg', 'apikeys');
|
$scope.navModel = navModelSrv.getNav('cfg', 'apikeys');
|
||||||
|
|
||||||
$scope.roleTypes = ['Viewer', 'Editor', 'Admin'];
|
$scope.roleTypes = ['Viewer', 'Editor', 'Admin'];
|
||||||
$scope.token = { role: 'Viewer' };
|
$scope.token = { role: 'Viewer' };
|
||||||
|
|
||||||
@@ -43,6 +40,7 @@ function (angular) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.init();
|
$scope.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
angular.module('grafana.controllers').controller('OrgApiKeysCtrl', OrgApiKeysCtrl);
|
||||||
});
|
|
||||||
@@ -1,13 +1,9 @@
|
|||||||
define([
|
import angular from 'angular';
|
||||||
'angular',
|
|
||||||
],
|
|
||||||
function (angular) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var module = angular.module('grafana.controllers');
|
export class OrgDetailsCtrl {
|
||||||
|
|
||||||
module.controller('OrgDetailsCtrl', function($scope, $http, backendSrv, contextSrv, navModelSrv) {
|
|
||||||
|
|
||||||
|
/** @ngInject **/
|
||||||
|
constructor($scope, $http, backendSrv, contextSrv, navModelSrv) {
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
$scope.getOrgInfo();
|
$scope.getOrgInfo();
|
||||||
$scope.navModel = navModelSrv.getNav('cfg', 'org');
|
$scope.navModel = navModelSrv.getNav('cfg', 'org');
|
||||||
@@ -33,6 +29,7 @@ function (angular) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.init();
|
$scope.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
angular.module('grafana.controllers').controller('OrgDetailsCtrl', OrgDetailsCtrl);
|
||||||
});
|
|
||||||
@@ -1,16 +1,10 @@
|
|||||||
define([
|
import angular from 'angular';
|
||||||
'angular',
|
import config from 'app/core/config';
|
||||||
'app/core/config',
|
|
||||||
],
|
|
||||||
function (angular, config) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
config = config.default;
|
export class SelectOrgCtrl {
|
||||||
|
|
||||||
var module = angular.module('grafana.controllers');
|
|
||||||
|
|
||||||
module.controller('SelectOrgCtrl', function($scope, backendSrv, contextSrv) {
|
|
||||||
|
|
||||||
|
/** @ngInject **/
|
||||||
|
constructor($scope, backendSrv, contextSrv) {
|
||||||
contextSrv.sidemenu = false;
|
contextSrv.sidemenu = false;
|
||||||
|
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
@@ -30,6 +24,7 @@ function (angular, config) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.init();
|
$scope.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
angular.module('grafana.controllers').controller('SelectOrgCtrl', SelectOrgCtrl);
|
||||||
});
|
|
||||||
@@ -1,14 +1,10 @@
|
|||||||
define([
|
import angular from 'angular';
|
||||||
'angular',
|
import _ from 'lodash';
|
||||||
'lodash',
|
|
||||||
],
|
|
||||||
function (angular, _) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var module = angular.module('grafana.controllers');
|
export class UserInviteCtrl {
|
||||||
|
|
||||||
module.controller('UserInviteCtrl', function($scope, backendSrv) {
|
|
||||||
|
|
||||||
|
/** @ngInject **/
|
||||||
|
constructor($scope, backendSrv) {
|
||||||
$scope.invites = [
|
$scope.invites = [
|
||||||
{name: '', email: '', role: 'Editor'},
|
{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([
|
import angular from 'angular';
|
||||||
'angular',
|
import _ from 'lodash';
|
||||||
'lodash',
|
|
||||||
],
|
|
||||||
function (angular, _) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var module = angular.module('grafana.controllers');
|
export class CloudWatchQueryParameter {
|
||||||
|
|
||||||
module.directive('cloudwatchQueryParameter', function() {
|
constructor() {
|
||||||
return {
|
return {
|
||||||
templateUrl: 'public/app/plugins/datasource/cloudwatch/partials/query.parameter.html',
|
templateUrl: 'public/app/plugins/datasource/cloudwatch/partials/query.parameter.html',
|
||||||
controller: 'CloudWatchQueryParameterCtrl',
|
controller: 'CloudWatchQueryParameterCtrl',
|
||||||
@@ -18,9 +14,12 @@ function (angular, _) {
|
|||||||
onChange: "&",
|
onChange: "&",
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
|
||||||
module.controller('CloudWatchQueryParameterCtrl', function($scope, templateSrv, uiSegmentSrv, datasourceSrv, $q) {
|
export class CloudWatchQueryParameterCtrl {
|
||||||
|
|
||||||
|
constructor($scope, templateSrv, uiSegmentSrv, datasourceSrv, $q) {
|
||||||
|
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
var target = $scope.target;
|
var target = $scope.target;
|
||||||
@@ -120,8 +119,7 @@ function (angular, _) {
|
|||||||
|
|
||||||
if (segment.value === $scope.removeDimSegment.value) {
|
if (segment.value === $scope.removeDimSegment.value) {
|
||||||
$scope.dimSegments.splice(index, 3);
|
$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.newOperator('='));
|
||||||
$scope.dimSegments.push(uiSegmentSrv.newFake('select dimension value', 'value', 'query-segment-value'));
|
$scope.dimSegments.push(uiSegmentSrv.newFake('select dimension value', 'value', 'query-segment-value'));
|
||||||
segment.type = 'key';
|
segment.type = 'key';
|
||||||
@@ -195,7 +193,8 @@ function (angular, _) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.init();
|
$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) {
|
constructor($scope) {
|
||||||
this.current.jsonData.timeField = this.current.jsonData.timeField || '@timestamp';
|
this.current.jsonData.timeField = this.current.jsonData.timeField || '@timestamp';
|
||||||
this.current.jsonData.esVersion = this.current.jsonData.esVersion || 5;
|
this.current.jsonData.esVersion = this.current.jsonData.esVersion || 5;
|
||||||
|
this.current.jsonData.maxConcurrentShardRequests = this.current.jsonData.maxConcurrentShardRequests || 256;
|
||||||
}
|
}
|
||||||
|
|
||||||
indexPatternTypes = [
|
indexPatternTypes = [
|
||||||
@@ -22,6 +23,7 @@ export class ElasticConfigCtrl {
|
|||||||
esVersions = [
|
esVersions = [
|
||||||
{name: '2.x', value: 2},
|
{name: '2.x', value: 2},
|
||||||
{name: '5.x', value: 5},
|
{name: '5.x', value: 5},
|
||||||
|
{name: '5.6+', value: 56},
|
||||||
];
|
];
|
||||||
|
|
||||||
indexPatternTypeChanged() {
|
indexPatternTypeChanged() {
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export class ElasticDatasource {
|
|||||||
timeField: string;
|
timeField: string;
|
||||||
esVersion: number;
|
esVersion: number;
|
||||||
interval: string;
|
interval: string;
|
||||||
|
maxConcurrentShardRequests: number;
|
||||||
queryBuilder: ElasticQueryBuilder;
|
queryBuilder: ElasticQueryBuilder;
|
||||||
indexPattern: IndexPattern;
|
indexPattern: IndexPattern;
|
||||||
|
|
||||||
@@ -30,6 +31,7 @@ export class ElasticDatasource {
|
|||||||
this.esVersion = instanceSettings.jsonData.esVersion;
|
this.esVersion = instanceSettings.jsonData.esVersion;
|
||||||
this.indexPattern = new IndexPattern(instanceSettings.index, instanceSettings.jsonData.interval);
|
this.indexPattern = new IndexPattern(instanceSettings.index, instanceSettings.jsonData.interval);
|
||||||
this.interval = instanceSettings.jsonData.timeInterval;
|
this.interval = instanceSettings.jsonData.timeInterval;
|
||||||
|
this.maxConcurrentShardRequests = instanceSettings.jsonData.maxConcurrentShardRequests;
|
||||||
this.queryBuilder = new ElasticQueryBuilder({
|
this.queryBuilder = new ElasticQueryBuilder({
|
||||||
timeField: this.timeField,
|
timeField: this.timeField,
|
||||||
esVersion: this.esVersion,
|
esVersion: this.esVersion,
|
||||||
@@ -213,11 +215,15 @@ export class ElasticDatasource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getQueryHeader(searchType, timeFrom, timeTo) {
|
getQueryHeader(searchType, timeFrom, timeTo) {
|
||||||
return angular.toJson({
|
var query_header: any = {
|
||||||
search_type: searchType,
|
search_type: searchType,
|
||||||
"ignore_unavailable": true,
|
"ignore_unavailable": true,
|
||||||
index: this.indexPattern.getIndexList(timeFrom, timeTo),
|
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) {
|
query(options) {
|
||||||
|
|||||||
@@ -25,6 +25,10 @@
|
|||||||
<span class="gf-form-label width-9">Version</span>
|
<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>
|
<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>
|
||||||
|
<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-inline">
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<span class="gf-form-label width-9">Min interval</span>
|
<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([
|
import _ from 'lodash';
|
||||||
'angular',
|
import angular from 'angular';
|
||||||
'jquery',
|
|
||||||
'lodash',
|
|
||||||
], function(angular, jquery, _) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var module = angular.module('grafana.controllers');
|
export class SeriesOverridesCtrl {
|
||||||
|
|
||||||
module.controller('SeriesOverridesCtrl', function($scope, $element, popoverSrv) {
|
/** @ngInject */
|
||||||
|
constructor($scope, $element, popoverSrv) {
|
||||||
$scope.overrideMenu = [];
|
$scope.overrideMenu = [];
|
||||||
$scope.currentOverrides = [];
|
$scope.currentOverrides = [];
|
||||||
$scope.override = $scope.override || {};
|
$scope.override = $scope.override || {};
|
||||||
|
|
||||||
$scope.addOverrideOption = function(name, propertyName, values) {
|
$scope.addOverrideOption = function(name, propertyName, values) {
|
||||||
var option = {};
|
var option = {
|
||||||
option.text = name;
|
text: name,
|
||||||
option.propertyName = propertyName;
|
propertyName: propertyName,
|
||||||
option.index = $scope.overrideMenu.length;
|
index: $scope.overrideMenu.lenght,
|
||||||
option.values = values;
|
values: values,
|
||||||
|
submenu: _.map(values, function(value) {
|
||||||
option.submenu = _.map(values, function(value) {
|
return { text: String(value), value: value };
|
||||||
return { text: String(value), value: value };
|
})
|
||||||
});
|
};
|
||||||
|
|
||||||
$scope.overrideMenu.push(option);
|
$scope.overrideMenu.push(option);
|
||||||
};
|
};
|
||||||
@@ -97,22 +94,24 @@ define([
|
|||||||
|
|
||||||
$scope.addOverrideOption('Bars', 'bars', [true, false]);
|
$scope.addOverrideOption('Bars', 'bars', [true, false]);
|
||||||
$scope.addOverrideOption('Lines', 'lines', [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 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 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('Null point mode', 'nullPointMode', ['connected', 'null', 'null as zero']);
|
||||||
$scope.addOverrideOption('Fill below to', 'fillBelowTo', $scope.getSeriesNames());
|
$scope.addOverrideOption('Fill below to', 'fillBelowTo', $scope.getSeriesNames());
|
||||||
$scope.addOverrideOption('Staircase line', 'steppedLine', [true, false]);
|
$scope.addOverrideOption('Staircase line', 'steppedLine', [true, false]);
|
||||||
$scope.addOverrideOption('Dashes', 'dashes', [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 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 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', '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('Stack', 'stack', [true, false, 'A', 'B', 'C', 'D']);
|
||||||
$scope.addOverrideOption('Color', 'color', ['change']);
|
$scope.addOverrideOption('Color', 'color', ['change']);
|
||||||
$scope.addOverrideOption('Y-axis', 'yaxis', [1, 2]);
|
$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('Transform', 'transform', ['negative-Y']);
|
||||||
$scope.addOverrideOption('Legend', 'legend', [true, false]);
|
$scope.addOverrideOption('Legend', 'legend', [true, false]);
|
||||||
$scope.updateCurrentOverrides();
|
$scope.updateCurrentOverrides();
|
||||||
});
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
angular.module('grafana.controllers').controller('SeriesOverridesCtrl', SeriesOverridesCtrl);
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
"max-line-length": [true, 150],
|
"max-line-length": [true, 150],
|
||||||
"member-access": false,
|
"member-access": false,
|
||||||
"no-arg": true,
|
"no-arg": true,
|
||||||
"no-bitwise": true,
|
"no-bitwise": false,
|
||||||
"no-console": [true,
|
"no-console": [true,
|
||||||
"debug",
|
"debug",
|
||||||
"info",
|
"info",
|
||||||
|
|||||||
Reference in New Issue
Block a user