Merge branch 'master' into develop

This commit is contained in:
Torkel Ödegaard 2017-10-22 11:51:14 +02:00
commit fff0fa2aee
85 changed files with 4206 additions and 3294 deletions

2
.gitignore vendored
View File

@ -12,6 +12,8 @@ awsconfig
/tmp
vendor/phantomjs/phantomjs
vendor/phantomjs/phantomjs.exe
profile.out
coverage.txt
docs/AWS_S3_BUCKET
docs/GIT_BRANCH

View File

@ -7,6 +7,21 @@
- UX changes to nav & side menu
- New dashboard grid layout system
# 4.7.0 (unreleased)
## New Features
* **Data Source Proxy**: Add support for whitelisting specified cookies that will be passed through to the data source when proxying data source requests [#5457](https://github.com/grafana/grafana/issues/5457), thanks [@robingustafsson](https://github.com/robingustafsson)
* **Postgres**: modify group by time macro so it can be used in select clause [#9527](https://github.com/grafana/grafana/pull/9527), thanks [@svenklemm](https://github.com/svenklemm)
## Fixes
* **Sensu**: Send alert message to sensu output [#9551](https://github.com/grafana/grafana/issues/9551), thx [@cjchand](https://github.com/cjchand)
# 4.6.0-beta3 (unreleased)
* **Prometheus**: Fix for browser crash for short time ranges. [#9575](https://github.com/grafana/grafana/issues/9575)
* **Heatmap**: Fix for y-axis not showing. [#9576](https://github.com/grafana/grafana/issues/9576)
* **Save to file**: Fix for save to file in export modal. [#9586](https://github.com/grafana/grafana/issues/9586)
# 4.6.0-beta2 (2017-10-17)
## Fixes
@ -15,7 +30,9 @@
* **Cloudwatch**: Provide error message when failing to add cloudwatch datasource [#9534](https://github.com/grafana/grafana/pull/9534), thx [@mtanda](https://github.com/mtanda)
* **Cloudwatch**: Fix unused period parameter [#9536](https://github.com/grafana/grafana/pull/9536), thx [@mtanda](https://github.com/mtanda)
* **CSV Export**: Fix for broken CSV export [#9525](https://github.com/grafana/grafana/issues/9525)
* **Text panel**: Fixes issue with break lines in Firefox [#9491](https://github.com/grafana/grafana/issues/9491)
* **Text panel**: Fix for issue with break lines in Firefox [#9491](https://github.com/grafana/grafana/issues/9491)
* **Annotations**: Fix for issue saving annotation event in MySQL DB [#9550](https://github.com/grafana/grafana/issues/9550), thanks [@krise3k](https://github.com/krise3k)
# 4.6.0-beta1 (2017-10-13)

View File

@ -22,9 +22,10 @@ module.exports = function (grunt) {
}
}
config.coverage = grunt.option('coverage');
config.phjs = grunt.option('phjsToRelease');
config.pkg.version = grunt.option('pkgVer') || config.pkg.version;
console.log('Version', config.pkg.version);
// load plugins

View File

@ -1,4 +1,4 @@
[Grafana](https://grafana.com) [![Circle CI](https://circleci.com/gh/grafana/grafana.svg?style=svg)](https://circleci.com/gh/grafana/grafana) [![Go Report Card](https://goreportcard.com/badge/github.com/grafana/grafana)](https://goreportcard.com/report/github.com/grafana/grafana)
[Grafana](https://grafana.com) [![Circle CI](https://circleci.com/gh/grafana/grafana.svg?style=svg)](https://circleci.com/gh/grafana/grafana) [![Go Report Card](https://goreportcard.com/badge/github.com/grafana/grafana)](https://goreportcard.com/report/github.com/grafana/grafana) [![codecov](https://codecov.io/gh/grafana/grafana/branch/master/graph/badge.svg)](https://codecov.io/gh/grafana/grafana)
================
[Website](https://grafana.com) |
[Twitter](https://twitter.com/grafana) |
@ -81,6 +81,20 @@ You only need to add the options you want to override. Config files are applied
In your custom.ini uncomment (remove the leading `;`) sign. And set `app_mode = development`.
### Running tests
- You can run backend Golang tests using "go test ./pkg/...".
- Execute all frontend tests with "npm run test"
Writing & watching frontend tests (we have two test runners)
- jest for all new tests that do not require browser context (React+more)
- Start watcher: `npm run jest`
- Jest will run all test files that end with the name ".jest.ts"
- karma + mocha is used for testing angularjs components. We do want to migrate these test to jest over time (if possible).
- Start watcher: `npm run karma`
- Karma+Mocha runs all files that end with the name "_specs.ts".
## Contribute
If you have any idea for an improvement or found a bug do not hesitate to open an issue.

View File

@ -48,7 +48,7 @@ Macro example | Description
*$__timeFilter(dateColumn)* | Will be replaced by a time range filter using the specified column name. For example, *dateColumn > to_timestamp(1494410783) AND dateColumn < to_timestamp(1494497183)*
*$__timeFrom()* | Will be replaced by the start of the currently active time selection. For example, *to_timestamp(1494410783)*
*$__timeTo()* | Will be replaced by the end of the currently active time selection. For example, *to_timestamp(1494497183)*
*$__timeGroup(dateColumn,'5m')* | Will be replaced by an expression usable in GROUP BY clause. For example, *(extract(epoch from "dateColumn")/extract(epoch from '5m'::interval))::int*
*$__timeGroup(dateColumn,'5m')* | Will be replaced by an expression usable in GROUP BY clause. For example, *(extract(epoch from "dateColumn")/extract(epoch from '5m'::interval))::int*extract(epoch from '5m'::interval)*
*$__unixEpochFilter(dateColumn)* | Will be replaced by a time range filter using the specified column name with times represented as unix timestamp. For example, *dateColumn > 1494410783 AND dateColumn < 1494497183*
*$__unixEpochFrom()* | Will be replaced by the start of the currently active time selection as unix timestamp. For example, *1494410783*
*$__unixEpochTo()* | Will be replaced by the end of the currently active time selection as unix timestamp. For example, *1494497183*
@ -94,26 +94,26 @@ Example with `metric` column
```sql
SELECT
min(time_date_time) as time,
$__timeGroup(time_date_time,'5m') as time,
min(value_double),
'min' as metric
FROM test_data
WHERE $__timeFilter(time_date_time)
GROUP BY metric1, (extract(epoch from time_date_time)/extract(epoch from $__interval::interval))::int
ORDER BY time asc
GROUP BY time
ORDER BY time
```
Example with multiple columns:
```sql
SELECT
min(time_date_time) as time,
$__timeGroup(time_date_time,'5m') as time,
min(value_double) as min_value,
max(value_double) as max_value
FROM test_data
WHERE $__timeFilter(time_date_time)
GROUP BY metric1, (extract(epoch from time_date_time)/extract(epoch from $__interval::interval))::int
ORDER BY time asc
GROUP BY time
ORDER BY time
```
## Templating

View File

@ -120,6 +120,37 @@ Content-Type: application/json
{"message":"Annotation added"}
```
## Create Annotation in Graphite format
Creates an annotation by using Graphite-compatible event format. The `when` and `data` fields are optional. If `when` is not specified then the current time will be used as annotation's timestamp. The `tags` field can also be in prior to Graphite `0.10.0`
format (string with multiple tags being separated by a space).
`POST /api/annotations/graphite`
**Example Request**:
```json
POST /api/annotations/graphite HTTP/1.1
Accept: application/json
Content-Type: application/json
{
"what": "Event - deploy",
"tags": ["deploy", "production"],
"when": 1467844481,
"data": "deploy of master branch happened at Wed Jul 6 22:34:41 UTC 2016"
}
```
**Example Response**:
```json
HTTP/1.1 200
Content-Type: application/json
{"message":"Graphite annotation added"}
```
## Update Annotation
`PUT /api/annotations/:id`

View File

@ -84,6 +84,20 @@ bra run
You'll also need to run `npm run watch` to watch for changes to the front-end (typescript, html, sass)
### Running tests
- You can run backend Golang tests using "go test ./pkg/...".
- Execute all frontend tests with "npm run test"
Writing & watching frontend tests (we have two test runners)
- jest for all new tests that do not require browser context (React+more)
- Start watcher: `npm run jest`
- Jest will run all test files that end with the name ".jest.ts"
- karma + mocha is used for testing angularjs components. We do want to migrate these test to jest over time (if possible).
- Start watcher: `npm run karma`
- Karma+Mocha runs all files that end with the name "_specs.ts".
## Creating optimized release packages
This step builds linux packages and requires that fpm is installed. Install fpm via `gem install fpm`.

23
jest.config.js Normal file
View File

@ -0,0 +1,23 @@
module.exports = {
verbose: false,
"transform": {
"^.+\\.tsx?$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
"moduleDirectories": ["<rootDir>node_modules", "<rootDir>/public"],
"roots": [
"<rootDir>/public"
],
"testRegex": "(\\.|/)(jest)\\.(jsx?|tsx?)$",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json"
],
"setupFiles": [
"./public/test/jest-shim.ts",
"./public/test/jest-setup.ts"
]
};

View File

@ -12,6 +12,7 @@
"devDependencies": {
"@types/d3": "^4.10.1",
"@types/enzyme": "^2.8.9",
"@types/jest": "^21.1.4",
"@types/node": "^8.0.31",
"@types/react": "^16.0.5",
"@types/react-dom": "^15.5.4",
@ -22,8 +23,8 @@
"babel-loader": "^7.1.2",
"babel-preset-es2015": "^6.24.1",
"css-loader": "^0.28.7",
"enzyme": "^3.0.0",
"enzyme-adapter-react-16": "^1.0.0",
"enzyme": "^3.1.0",
"enzyme-adapter-react-16": "^1.0.1",
"es6-promise": "^3.0.2",
"es6-shim": "^0.35.3",
"expect.js": "~0.2.0",
@ -53,11 +54,11 @@
"html-loader": "^0.5.1",
"html-webpack-plugin": "^2.30.1",
"husky": "^0.14.3",
"jest": "^21.2.1",
"jshint-stylish": "~2.2.1",
"json-loader": "^0.5.7",
"karma": "1.7.0",
"karma-chrome-launcher": "~2.2.0",
"karma-coverage": "1.1.1",
"karma-expect": "~1.1.3",
"karma-mocha": "~1.3.0",
"karma-phantomjs-launcher": "1.0.4",
@ -82,6 +83,7 @@
"sinon": "1.17.6",
"systemjs": "0.20.19",
"systemjs-plugin-css": "^0.1.36",
"ts-jest": "^21.1.3",
"ts-loader": "^2.3.7",
"tslint": "^5.7.0",
"tslint-loader": "^3.5.3",
@ -97,8 +99,10 @@
"watch": "./node_modules/.bin/webpack --progress --colors --watch --config scripts/webpack/webpack.dev.js",
"build": "./node_modules/.bin/grunt build",
"test": "./node_modules/.bin/grunt test",
"test-ci": "./node_modules/.bin/grunt test --coverage=true",
"lint": "./node_modules/.bin/tslint -c tslint.json --project tsconfig.json --type-check",
"watch-test": "./node_modules/grunt-cli/bin/grunt karma:dev"
"karma": "./node_modules/grunt-cli/bin/grunt karma:dev",
"jest": "./node_modules/jest-cli/bin/jest --notify --watch"
},
"license": "Apache-2.0",
"dependencies": {

View File

@ -91,7 +91,7 @@ case "$1" in
then
sleep 1
# check if pid file has been written two
# check if pid file has been written to
if ! [[ -s $PID_FILE ]]; then
log_end_msg 1
exit 1

View File

@ -96,7 +96,7 @@ case "$1" in
if [ $return -eq 0 ]
then
sleep 1
# check if pid file has been written two
# check if pid file has been written to
if ! [[ -s $PID_FILE ]]; then
echo "FAILED"
exit 1

View File

@ -1,7 +1,6 @@
package api
import (
"fmt"
"strings"
"time"
@ -41,9 +40,22 @@ func GetAnnotations(c *middleware.Context) Response {
return Json(200, items)
}
type CreateAnnotationError struct {
message string
}
func (e *CreateAnnotationError) Error() string {
return e.message
}
func PostAnnotation(c *middleware.Context, cmd dtos.PostAnnotationsCmd) Response {
repo := annotations.GetRepository()
if cmd.Text == "" {
err := &CreateAnnotationError{"text field should not be empty"}
return ApiError(500, "Failed to save annotation", err)
}
item := annotations.Item{
OrgId: c.OrgId,
UserId: c.UserId,
@ -55,6 +67,10 @@ func PostAnnotation(c *middleware.Context, cmd dtos.PostAnnotationsCmd) Response
Tags: cmd.Tags,
}
if item.Epoch == 0 {
item.Epoch = time.Now().Unix()
}
if err := repo.Save(&item); err != nil {
return ApiError(500, "Failed to save annotation", err)
}
@ -82,21 +98,22 @@ func PostAnnotation(c *middleware.Context, cmd dtos.PostAnnotationsCmd) Response
return ApiSuccess("Annotation added")
}
type GraphiteAnnotationError struct {
message string
}
func (e *GraphiteAnnotationError) Error() string {
return e.message
}
func formatGraphiteAnnotation(what string, data string) string {
return fmt.Sprintf("%s\n%s", what, data)
text := what
if data != "" {
text = text + "\n" + data
}
return text
}
func PostGraphiteAnnotation(c *middleware.Context, cmd dtos.PostGraphiteAnnotationsCmd) Response {
repo := annotations.GetRepository()
if cmd.What == "" {
err := &CreateAnnotationError{"what field should not be empty"}
return ApiError(500, "Failed to save Graphite annotation", err)
}
if cmd.When == 0 {
cmd.When = time.Now().Unix()
}
@ -106,18 +123,22 @@ func PostGraphiteAnnotation(c *middleware.Context, cmd dtos.PostGraphiteAnnotati
var tagsArray []string
switch tags := cmd.Tags.(type) {
case string:
if tags != "" {
tagsArray = strings.Split(tags, " ")
} else {
tagsArray = []string{}
}
case []interface{}:
for _, t := range tags {
if tagStr, ok := t.(string); ok {
tagsArray = append(tagsArray, tagStr)
} else {
err := &GraphiteAnnotationError{"tag should be a string"}
err := &CreateAnnotationError{"tag should be a string"}
return ApiError(500, "Failed to save Graphite annotation", err)
}
}
default:
err := &GraphiteAnnotationError{"unsupported tags format"}
err := &CreateAnnotationError{"unsupported tags format"}
return ApiError(500, "Failed to save Graphite annotation", err)
}
@ -133,7 +154,7 @@ func PostGraphiteAnnotation(c *middleware.Context, cmd dtos.PostGraphiteAnnotati
return ApiError(500, "Failed to save Graphite annotation", err)
}
return ApiSuccess("Graphite Annotation added")
return ApiSuccess("Graphite annotation added")
}
func UpdateAnnotation(c *middleware.Context, cmd dtos.UpdateAnnotationsCmd) Response {

View File

@ -18,6 +18,7 @@ const (
DS_KAIROSDB = "kairosdb"
DS_PROMETHEUS = "prometheus"
DS_POSTGRES = "postgres"
DS_MYSQL = "mysql"
DS_ACCESS_DIRECT = "direct"
DS_ACCESS_PROXY = "proxy"
)
@ -64,6 +65,7 @@ var knownDatasourcePlugins map[string]bool = map[string]bool{
DS_PROMETHEUS: true,
DS_OPENTSDB: true,
DS_POSTGRES: true,
DS_MYSQL: true,
"opennms": true,
"druid": true,
"dalmatinerdb": true,

View File

@ -112,7 +112,7 @@ func (this *SensuNotifier) Notify(evalContext *alerting.EvalContext) error {
}
if evalContext.Rule.Message != "" {
bodyJSON.Set("message", evalContext.Rule.Message)
bodyJSON.Set("output", evalContext.Rule.Message)
}
body, _ := bodyJSON.MarshalJSON()

View File

@ -74,7 +74,7 @@ func (m *PostgresMacroEngine) evaluateMacro(name string, args []string) (string,
if len(args) == 0 {
return "", fmt.Errorf("missing time column argument for macro %v", name)
}
return fmt.Sprintf("%s >= to_timestamp(%d) AND %s <= to_timestamp(%d)", args[0], uint64(m.TimeRange.GetFromAsMsEpoch()/1000), args[0], uint64(m.TimeRange.GetToAsMsEpoch()/1000)), nil
return fmt.Sprintf("extract(epoch from %s) BETWEEN %d AND %d", args[0], uint64(m.TimeRange.GetFromAsMsEpoch()/1000), uint64(m.TimeRange.GetToAsMsEpoch()/1000)), nil
case "__timeFrom":
return fmt.Sprintf("to_timestamp(%d)", uint64(m.TimeRange.GetFromAsMsEpoch()/1000)), nil
case "__timeTo":
@ -83,7 +83,7 @@ func (m *PostgresMacroEngine) evaluateMacro(name string, args []string) (string,
if len(args) < 2 {
return "", fmt.Errorf("macro %v needs time column and interval", name)
}
return fmt.Sprintf("(extract(epoch from \"%s\")/extract(epoch from %s::interval))::int", args[0], args[1]), nil
return fmt.Sprintf("(extract(epoch from \"%s\")/extract(epoch from %s::interval))::int*extract(epoch from %s::interval)", args[0], args[1], args[1]), nil
case "__unixEpochFilter":
if len(args) == 0 {
return "", fmt.Errorf("missing time column argument for macro %v", name)

View File

@ -30,7 +30,7 @@ func TestMacroEngine(t *testing.T) {
sql, err := engine.Interpolate(timeRange, "WHERE $__timeFilter(time_column)")
So(err, ShouldBeNil)
So(sql, ShouldEqual, "WHERE time_column >= to_timestamp(18446744066914186738) AND time_column <= to_timestamp(18446744066914187038)")
So(sql, ShouldEqual, "WHERE extract(epoch from time_column) BETWEEN 18446744066914186738 AND 18446744066914187038")
})
Convey("interpolate __timeFrom function", func() {
@ -45,7 +45,7 @@ func TestMacroEngine(t *testing.T) {
sql, err := engine.Interpolate(timeRange, "GROUP BY $__timeGroup(time_column,'5m')")
So(err, ShouldBeNil)
So(sql, ShouldEqual, "GROUP BY (extract(epoch from \"time_column\")/extract(epoch from '5m'::interval))::int")
So(sql, ShouldEqual, "GROUP BY (extract(epoch from \"time_column\")/extract(epoch from '5m'::interval))::int*extract(epoch from '5m'::interval)")
})
Convey("interpolate __timeTo function", func() {

View File

@ -0,0 +1,8 @@
import { react2AngularDirective } from 'app/core/utils/react2angular';
import { PasswordStrength } from './ui/PasswordStrength';
export function registerAngularDirectives() {
react2AngularDirective('passwordStrength', PasswordStrength, ['password']);
}

View File

@ -43,7 +43,6 @@ import {assignModelProperties} from './utils/model_utils';
import {contextSrv} from './services/context_srv';
import {KeybindingSrv} from './services/keybindingSrv';
import {helpModal} from './components/help/help';
import {PasswordStrength} from './components/PasswordStrength';
import {JsonExplorer} from './components/json_explorer/json_explorer';
import {NavModelSrv, NavModel} from './nav_model_srv';
import {userPicker} from './components/user_picker';
@ -52,6 +51,9 @@ import {geminiScrollbar} from './components/scroll/scroll';
import {gfPageDirective} from './components/gf_page';
import {orgSwitcher} from './components/org_switcher';
import {profiler} from './profiler';
import {registerAngularDirectives} from './angular_wrappers';
registerAngularDirectives();
export {
profiler,
@ -82,6 +84,5 @@ export {
userGroupPicker,
geminiScrollbar,
gfPageDirective,
orgSwitcher,
PasswordStrength,
orgSwitcher
};

View File

@ -7,6 +7,8 @@ define([
function (angular, require, coreModule, kbn) {
'use strict';
kbn = kbn.default;
coreModule.default.directive('tip', function($compile) {
return {
restrict: 'E',

View File

@ -1,9 +1,8 @@
define([
'../core_module',
'app/core/utils/kbn',
'app/core/utils/rangeutil',
],
function (coreModule, kbn, rangeUtil) {
function (coreModule, rangeUtil) {
'use strict';
coreModule.default.directive('ngModelOnblur', function() {

View File

@ -1,24 +1,23 @@
import React from 'react';
import {describe, it, expect} from 'test/lib/common';
import {shallow} from 'enzyme';
import {PasswordStrength} from '../components/PasswordStrength';
import {PasswordStrength} from '../ui/PasswordStrength';
describe('PasswordStrength', () => {
it('should have class bad if length below 4', () => {
const wrapper = shallow(<PasswordStrength password="asd" />);
expect(wrapper.find(".password-strength-bad")).to.have.length(1);
expect(wrapper.find(".password-strength-bad")).toHaveLength(1);
});
it('should have class ok if length below 8', () => {
const wrapper = shallow(<PasswordStrength password="asdasd" />);
expect(wrapper.find(".password-strength-ok")).to.have.length(1);
expect(wrapper.find(".password-strength-ok")).toHaveLength(1);
});
it('should have class good if length above 8', () => {
const wrapper = shallow(<PasswordStrength password="asdaasdda" />);
expect(wrapper.find(".password-strength-good")).to.have.length(1);
expect(wrapper.find(".password-strength-good")).toHaveLength(1);
});
});

View File

@ -1,4 +1,4 @@
import {describe, beforeEach, afterEach, it, sinon, expect} from 'test/lib/common';
import sinon from 'sinon';
import * as dateMath from 'app/core/utils/datemath';
import moment from 'moment';
@ -13,25 +13,25 @@ describe("DateMath", () => {
describe('errors', () => {
it('should return undefined if passed something falsy', () => {
expect(dateMath.parse(false)).to.be(undefined);
expect(dateMath.parse(false)).toBe(undefined);
});
it('should return undefined if I pass an operator besides [+-/]', () => {
expect(dateMath.parse('now&1d')).to.be(undefined);
expect(dateMath.parse('now&1d')).toBe(undefined);
});
it('should return undefined if I pass a unit besides' + spans.toString(), () => {
expect(dateMath.parse('now+5f')).to.be(undefined);
expect(dateMath.parse('now+5f')).toBe(undefined);
});
it('should return undefined if rounding unit is not 1', () => {
expect(dateMath.parse('now/2y')).to.be(undefined);
expect(dateMath.parse('now/0.5y')).to.be(undefined);
expect(dateMath.parse('now/2y')).toBe(undefined);
expect(dateMath.parse('now/0.5y')).toBe(undefined);
});
it('should not go into an infinite loop when missing a unit', () => {
expect(dateMath.parse('now-0')).to.be(undefined);
expect(dateMath.parse('now-00')).to.be(undefined);
expect(dateMath.parse('now-0')).toBe(undefined);
expect(dateMath.parse('now-00')).toBe(undefined);
});
});
@ -43,7 +43,7 @@ describe("DateMath", () => {
expected.setMilliseconds(0);
var startOfDay = dateMath.parse('now/d', false).valueOf();
expect(startOfDay).to.be(expected.getTime());
expect(startOfDay).toBe(expected.getTime());
});
it("now/d on a utc dashboard should be start of the current day in UTC time", () => {
@ -51,7 +51,7 @@ describe("DateMath", () => {
var expected = new Date(Date.UTC(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0, 0));
var startOfDay = dateMath.parse('now/d', false, 'utc').valueOf();
expect(startOfDay).to.be(expected.getTime());
expect(startOfDay).toBe(expected.getTime());
});
describe('subtraction', () => {
@ -69,11 +69,11 @@ describe("DateMath", () => {
var thenEx = anchor + '||-5' + span;
it('should return 5' + span + ' ago', () => {
expect(dateMath.parse(nowEx).format(format)).to.eql(now.subtract(5, span).format(format));
expect(dateMath.parse(nowEx).format(format)).toEqual(now.subtract(5, span).format(format));
});
it('should return 5' + span + ' before ' + anchor, () => {
expect(dateMath.parse(thenEx).format(format)).to.eql(anchored.subtract(5, span).format(format));
expect(dateMath.parse(thenEx).format(format)).toEqual(anchored.subtract(5, span).format(format));
});
});
@ -94,11 +94,11 @@ describe("DateMath", () => {
_.each(spans, (span) => {
it('should round now to the beginning of the ' + span, function () {
expect(dateMath.parse('now/' + span).format(format)).to.eql(now.startOf(span).format(format));
expect(dateMath.parse('now/' + span).format(format)).toEqual(now.startOf(span).format(format));
});
it('should round now to the end of the ' + span, function () {
expect(dateMath.parse('now/' + span, true).format(format)).to.eql(now.endOf(span).format(format));
expect(dateMath.parse('now/' + span, true).format(format)).toEqual(now.endOf(span).format(format));
});
});
@ -109,27 +109,27 @@ describe("DateMath", () => {
describe('isValid', () => {
it('should return false when invalid date text', () => {
expect(dateMath.isValid('asd')).to.be(false);
expect(dateMath.isValid('asd')).toBe(false);
});
it('should return true when valid date text', () => {
expect(dateMath.isValid('now-1h')).to.be(true);
expect(dateMath.isValid('now-1h')).toBe(true);
});
});
describe('relative time to date parsing', function() {
it('should handle negative time', function() {
var date = dateMath.parseDateMath('-2d', moment([2014, 1, 5]));
expect(date.valueOf()).to.equal(moment([2014, 1, 3]).valueOf());
expect(date.valueOf()).toEqual(moment([2014, 1, 3]).valueOf());
});
it('should handle multiple math expressions', function() {
var date = dateMath.parseDateMath('-2d-6h', moment([2014, 1, 5]));
expect(date.valueOf()).to.equal(moment([2014, 1, 2, 18]).valueOf());
expect(date.valueOf()).toEqual(moment([2014, 1, 2, 18]).valueOf());
});
it('should return false when invalid expression', function() {
var date = dateMath.parseDateMath('2', moment([2014, 1, 5]));
expect(date).to.equal(undefined);
expect(date).toEqual(undefined);
});
});

View File

@ -1,6 +1,4 @@
import {describe, it, expect} from 'test/lib/common';
import {Emitter} from 'app/core/core';
import {Emitter} from '../utils/emitter';
describe("Emitter", () => {
@ -20,8 +18,8 @@ describe("Emitter", () => {
events.emit('test', null);
expect(sub1Called).to.be(true);
expect(sub2Called).to.be(true);
expect(sub1Called).toBe(true);
expect(sub2Called).toBe(true);
});
it('when subscribing twice', () => {
@ -37,7 +35,7 @@ describe("Emitter", () => {
events.emit('test', null);
expect(sub1Called).to.be(2);
expect(sub1Called).toBe(2);
});
it('should handle errors', () => {
@ -57,8 +55,8 @@ describe("Emitter", () => {
try { events.emit('test', null); } catch (_) { }
try { events.emit('test', null); } catch (_) {}
expect(sub1Called).to.be(2);
expect(sub2Called).to.be(0);
expect(sub1Called).toBe(2);
expect(sub2Called).toBe(0);
});
});
});

View File

@ -1,5 +1,3 @@
import {describe, it, expect} from 'test/lib/common';
import flatten from 'app/core/utils/flatten';
describe("flatten", () => {
@ -15,9 +13,9 @@ describe("flatten", () => {
}
}, null);
expect(flattened['level1']).to.be('level1-value');
expect(flattened['deeper.level2']).to.be('level2-value');
expect(flattened['deeper.deeper.level3']).to.be('level3-value');
expect(flattened['level1']).toBe('level1-value');
expect(flattened['deeper.level2']).toBe('level2-value');
expect(flattened['deeper.deeper.level3']).toBe('level3-value');
});
});

View File

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

View File

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

View File

@ -1,5 +1,3 @@
import {describe, beforeEach, it, expect} from 'test/lib/common';
import TableModel from 'app/core/table_model';
describe('when sorting table desc', () => {
@ -16,14 +14,14 @@ describe('when sorting table desc', () => {
});
it('should sort by time', () => {
expect(table.rows[0][0]).to.be(105);
expect(table.rows[1][0]).to.be(103);
expect(table.rows[2][0]).to.be(100);
expect(table.rows[0][0]).toBe(105);
expect(table.rows[1][0]).toBe(103);
expect(table.rows[2][0]).toBe(100);
});
it ('should mark column being sorted', () => {
expect(table.columns[0].sort).to.be(true);
expect(table.columns[0].desc).to.be(true);
expect(table.columns[0].sort).toBe(true);
expect(table.columns[0].desc).toBe(true);
});
});
@ -42,9 +40,9 @@ describe('when sorting table asc', () => {
});
it('should sort by time', () => {
expect(table.rows[0][1]).to.be(10);
expect(table.rows[1][1]).to.be(11);
expect(table.rows[2][1]).to.be(15);
expect(table.rows[0][1]).toBe(10);
expect(table.rows[1][1]).toBe(11);
expect(table.rows[2][1]).toBe(15);
});
});

View File

@ -1,4 +1,3 @@
import {describe, beforeEach, it, expect} from 'test/lib/common';
import TimeSeries from 'app/core/time_series2';
describe("TimeSeries", function() {
@ -19,14 +18,14 @@ describe("TimeSeries", function() {
it('with connected style, should ignore nulls', function() {
series = new TimeSeries(testData);
points = series.getFlotPairs('connected', yAxisFormats);
expect(points.length).to.be(3);
expect(points.length).toBe(3);
});
it('with null as zero style, should replace nulls with zero', function() {
series = new TimeSeries(testData);
points = series.getFlotPairs('null as zero', yAxisFormats);
expect(points.length).to.be(4);
expect(points[1][1]).to.be(0);
expect(points.length).toBe(4);
expect(points[1][1]).toBe(0);
});
it('if last is null current should pick next to last', function() {
@ -34,7 +33,7 @@ describe("TimeSeries", function() {
datapoints: [[10,1], [null, 2]]
});
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.current).to.be(10);
expect(series.stats.current).toBe(10);
});
it('max value should work for negative values', function() {
@ -42,13 +41,13 @@ describe("TimeSeries", function() {
datapoints: [[-10,1], [-4, 2]]
});
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.max).to.be(-4);
expect(series.stats.max).toBe(-4);
});
it('average value should ignore nulls', function() {
series = new TimeSeries(testData);
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.avg).to.be(6.333333333333333);
expect(series.stats.avg).toBe(6.333333333333333);
});
it('the delta value should account for nulls', function() {
@ -56,7 +55,7 @@ describe("TimeSeries", function() {
datapoints: [[1,2],[3,3],[null,4],[10,5],[15,6]]
});
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.delta).to.be(14);
expect(series.stats.delta).toBe(14);
});
it('the delta value should account for nulls on first', function() {
@ -64,7 +63,7 @@ describe("TimeSeries", function() {
datapoints: [[null,2],[1,3],[10,4],[15,5]]
});
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.delta).to.be(14);
expect(series.stats.delta).toBe(14);
});
it('the delta value should account for nulls on last', function() {
@ -72,7 +71,7 @@ describe("TimeSeries", function() {
datapoints: [[1,2],[5,3],[10,4],[null,5]]
});
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.delta).to.be(9);
expect(series.stats.delta).toBe(9);
});
it('the delta value should account for resets', function() {
@ -80,7 +79,7 @@ describe("TimeSeries", function() {
datapoints: [[1,2],[5,3],[10,4],[0,5],[10,6]]
});
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.delta).to.be(19);
expect(series.stats.delta).toBe(19);
});
it('the delta value should account for resets on last', function() {
@ -88,30 +87,30 @@ describe("TimeSeries", function() {
datapoints: [[1,2],[2,3],[10,4],[8,5]]
});
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.delta).to.be(17);
expect(series.stats.delta).toBe(17);
});
it('the range value should be max - min', function() {
series = new TimeSeries(testData);
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.range).to.be(9);
expect(series.stats.range).toBe(9);
});
it('first value should ingone nulls', function() {
series = new TimeSeries(testData);
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.first).to.be(1);
expect(series.stats.first).toBe(1);
series = new TimeSeries({
datapoints: [[null,2],[1,3],[10,4],[8,5]]
});
series.getFlotPairs('null', yAxisFormats);
expect(series.stats.first).to.be(1);
expect(series.stats.first).toBe(1);
});
it('with null as zero style, average value should treat nulls as 0', function() {
series = new TimeSeries(testData);
series.getFlotPairs('null as zero', yAxisFormats);
expect(series.stats.avg).to.be(4.75);
expect(series.stats.avg).toBe(4.75);
});
it('average value should be null if all values is null', function() {
@ -119,7 +118,7 @@ describe("TimeSeries", function() {
datapoints: [[null,2],[null,3],[null,4],[null,5]]
});
series.getFlotPairs('null');
expect(series.stats.avg).to.be(null);
expect(series.stats.avg).toBe(null);
});
});
@ -130,7 +129,7 @@ describe("TimeSeries", function() {
});
it('should set hasMsResolution to false', function() {
expect(series.hasMsResolution).to.be(false);
expect(series.hasMsResolution).toBe(false);
});
});
@ -140,7 +139,7 @@ describe("TimeSeries", function() {
});
it('should show millisecond resolution tooltip', function() {
expect(series.hasMsResolution).to.be(true);
expect(series.hasMsResolution).toBe(true);
});
});
@ -150,7 +149,7 @@ describe("TimeSeries", function() {
});
it('should not show millisecond resolution tooltip', function() {
expect(series.hasMsResolution).to.be(false);
expect(series.hasMsResolution).toBe(false);
});
});
});
@ -165,13 +164,13 @@ describe("TimeSeries", function() {
it('missing datapoint with ms precision', function() {
fakedata.datapoints[0] = [1337, 1234567890000];
series = new TimeSeries(fakedata);
expect(series.isMsResolutionNeeded()).to.be(false);
expect(series.isMsResolutionNeeded()).toBe(false);
});
it('contains datapoint with ms precision', function() {
fakedata.datapoints[0] = [1337, 1236547890001];
series = new TimeSeries(fakedata);
expect(series.isMsResolutionNeeded()).to.be(true);
expect(series.isMsResolutionNeeded()).toBe(true);
});
});
@ -188,8 +187,8 @@ describe("TimeSeries", function() {
});
it('should set fill zero, and enable points', function() {
expect(series.lines.fill).to.be(0.001);
expect(series.points.show).to.be(true);
expect(series.lines.fill).toBe(0.001);
expect(series.points.show).toBe(true);
});
});
@ -200,8 +199,8 @@ describe("TimeSeries", function() {
});
it('should disable lines, and enable bars', function() {
expect(series.lines.show).to.be(false);
expect(series.bars.show).to.be(true);
expect(series.lines.show).toBe(false);
expect(series.bars.show).toBe(true);
});
});
@ -212,8 +211,8 @@ describe("TimeSeries", function() {
});
it('should disable stack, and set lineWidth', function() {
expect(series.stack).to.be(false);
expect(series.lines.lineWidth).to.be(5);
expect(series.stack).toBe(false);
expect(series.lines.lineWidth).toBe(5);
});
});
@ -224,9 +223,9 @@ describe("TimeSeries", function() {
});
it('should enable dashes, set dashes lineWidth to 5 and lines lineWidth to 0', function() {
expect(series.dashes.show).to.be(true);
expect(series.dashes.lineWidth).to.be(5);
expect(series.lines.lineWidth).to.be(0);
expect(series.dashes.show).toBe(true);
expect(series.dashes.lineWidth).toBe(5);
expect(series.lines.lineWidth).toBe(0);
});
});
@ -237,7 +236,7 @@ describe("TimeSeries", function() {
});
it('should disable line fill and add fillBelowTo', function() {
expect(series.fillBelowTo).to.be('min');
expect(series.fillBelowTo).toBe('min');
});
});
@ -248,8 +247,8 @@ describe("TimeSeries", function() {
});
it('should set pointradius, and set steppedLine', function() {
expect(series.points.radius).to.be(5);
expect(series.lines.steps).to.be(true);
expect(series.points.radius).toBe(5);
expect(series.lines.steps).toBe(true);
});
});
@ -260,7 +259,7 @@ describe("TimeSeries", function() {
});
it('should match second series', function() {
expect(series.lines.show).to.be(false);
expect(series.lines.show).toBe(false);
});
});
@ -271,11 +270,11 @@ describe("TimeSeries", function() {
});
it('should set yaxis', function() {
expect(series.yaxis).to.be(2);
expect(series.yaxis).toBe(2);
});
it('should set zindex', function() {
expect(series.zindex).to.be(2);
expect(series.zindex).toBe(2);
});
});
@ -288,11 +287,11 @@ describe("TimeSeries", function() {
});
it('should format non-numeric values as empty string', function() {
expect(series.formatValue(null)).to.be("");
expect(series.formatValue(undefined)).to.be("");
expect(series.formatValue(NaN)).to.be("");
expect(series.formatValue(Infinity)).to.be("");
expect(series.formatValue(-Infinity)).to.be("");
expect(series.formatValue(null)).toBe("");
expect(series.formatValue(undefined)).toBe("");
expect(series.formatValue(NaN)).toBe("");
expect(series.formatValue(Infinity)).toBe("");
expect(series.formatValue(-Infinity)).toBe("");
});
});

View File

@ -1,7 +0,0 @@
define([
'./time_series2'
], function(timeSeries) {
'use strict';
// backward compatability hack;
return timeSeries.default;
});

View File

@ -1,5 +1,4 @@
import React from 'react';
import { react2AngularDirective } from 'app/core/utils/react2angular';
export interface IProps {
password: string;
@ -33,5 +32,4 @@ export class PasswordStrength extends React.Component<IProps, any> {
}
}
react2AngularDirective('passwordStrength', PasswordStrength, ['password']);

View File

@ -1,936 +0,0 @@
define([
'jquery',
'lodash',
'moment'
],
function($, _, moment) {
'use strict';
var kbn = {};
kbn.valueFormats = {};
kbn.regexEscape = function(value) {
return value.replace(/[\\^$*+?.()|[\]{}\/]/g, '\\$&');
};
///// HELPER FUNCTIONS /////
kbn.round_interval = function(interval) {
switch (true) {
// 0.015s
case (interval < 15):
return 10; // 0.01s
// 0.035s
case (interval < 35):
return 20; // 0.02s
// 0.075s
case (interval < 75):
return 50; // 0.05s
// 0.15s
case (interval < 150):
return 100; // 0.1s
// 0.35s
case (interval < 350):
return 200; // 0.2s
// 0.75s
case (interval < 750):
return 500; // 0.5s
// 1.5s
case (interval < 1500):
return 1000; // 1s
// 3.5s
case (interval < 3500):
return 2000; // 2s
// 7.5s
case (interval < 7500):
return 5000; // 5s
// 12.5s
case (interval < 12500):
return 10000; // 10s
// 17.5s
case (interval < 17500):
return 15000; // 15s
// 25s
case (interval < 25000):
return 20000; // 20s
// 45s
case (interval < 45000):
return 30000; // 30s
// 1.5m
case (interval < 90000):
return 60000; // 1m
// 3.5m
case (interval < 210000):
return 120000; // 2m
// 7.5m
case (interval < 450000):
return 300000; // 5m
// 12.5m
case (interval < 750000):
return 600000; // 10m
// 12.5m
case (interval < 1050000):
return 900000; // 15m
// 25m
case (interval < 1500000):
return 1200000; // 20m
// 45m
case (interval < 2700000):
return 1800000; // 30m
// 1.5h
case (interval < 5400000):
return 3600000; // 1h
// 2.5h
case (interval < 9000000):
return 7200000; // 2h
// 4.5h
case (interval < 16200000):
return 10800000; // 3h
// 9h
case (interval < 32400000):
return 21600000; // 6h
// 1d
case (interval < 86400000):
return 43200000; // 12h
// 1w
case (interval < 604800000):
return 86400000; // 1d
// 3w
case (interval < 1814400000):
return 604800000; // 1w
// 6w
case (interval < 3628800000):
return 2592000000; // 30d
default:
return 31536000000; // 1y
}
};
kbn.secondsToHms = function(seconds) {
var numyears = Math.floor(seconds / 31536000);
if(numyears){
return numyears + 'y';
}
var numdays = Math.floor((seconds % 31536000) / 86400);
if(numdays){
return numdays + 'd';
}
var numhours = Math.floor(((seconds % 31536000) % 86400) / 3600);
if(numhours){
return numhours + 'h';
}
var numminutes = Math.floor((((seconds % 31536000) % 86400) % 3600) / 60);
if(numminutes){
return numminutes + 'm';
}
var numseconds = Math.floor((((seconds % 31536000) % 86400) % 3600) % 60);
if(numseconds){
return numseconds + 's';
}
var nummilliseconds = Math.floor(seconds * 1000.0);
if(nummilliseconds){
return nummilliseconds + 'ms';
}
return 'less than a millisecond'; //'just now' //or other string you like;
};
kbn.to_percent = function(number,outof) {
return Math.floor((number/outof)*10000)/100 + "%";
};
kbn.addslashes = function(str) {
str = str.replace(/\\/g, '\\\\');
str = str.replace(/\'/g, '\\\'');
str = str.replace(/\"/g, '\\"');
str = str.replace(/\0/g, '\\0');
return str;
};
kbn.interval_regex = /(\d+(?:\.\d+)?)(ms|[Mwdhmsy])/;
// histogram & trends
kbn.intervals_in_seconds = {
y: 31536000,
M: 2592000,
w: 604800,
d: 86400,
h: 3600,
m: 60,
s: 1,
ms: 0.001
};
kbn.calculateInterval = function(range, resolution, lowLimitInterval) {
var lowLimitMs = 1; // 1 millisecond default low limit
var intervalMs;
if (lowLimitInterval) {
if (lowLimitInterval[0] === '>') {
lowLimitInterval = lowLimitInterval.slice(1);
}
lowLimitMs = kbn.interval_to_ms(lowLimitInterval);
}
intervalMs = kbn.round_interval((range.to.valueOf() - range.from.valueOf()) / resolution);
if (lowLimitMs > intervalMs) {
intervalMs = lowLimitMs;
}
return {
intervalMs: intervalMs,
interval: kbn.secondsToHms(intervalMs / 1000),
};
};
kbn.describe_interval = function (string) {
var matches = string.match(kbn.interval_regex);
if (!matches || !_.has(kbn.intervals_in_seconds, matches[2])) {
throw new Error('Invalid interval string, expecting a number followed by one of "Mwdhmsy"');
} else {
return {
sec: kbn.intervals_in_seconds[matches[2]],
type: matches[2],
count: parseInt(matches[1], 10)
};
}
};
kbn.interval_to_ms = function(string) {
var info = kbn.describe_interval(string);
return info.sec * 1000 * info.count;
};
kbn.interval_to_seconds = function (string) {
var info = kbn.describe_interval(string);
return info.sec * info.count;
};
kbn.query_color_dot = function (color, diameter) {
return '<div class="icon-circle" style="' + [
'display:inline-block',
'color:' + color,
'font-size:' + diameter + 'px',
].join(';') + '"></div>';
};
kbn.slugifyForUrl = function(str) {
return str
.toLowerCase()
.replace(/[^\w ]+/g,'')
.replace(/ +/g,'-');
};
kbn.stringToJsRegex = function(str) {
if (str[0] !== '/') {
return new RegExp('^' + str + '$');
}
var match = str.match(new RegExp('^/(.*?)/(g?i?m?y?)$'));
return new RegExp(match[1], match[2]);
};
kbn.toFixed = function(value, decimals) {
if (value === null) {
return "";
}
var factor = decimals ? Math.pow(10, Math.max(0, decimals)) : 1;
var formatted = String(Math.round(value * factor) / factor);
// if exponent return directly
if (formatted.indexOf('e') !== -1 || value === 0) {
return formatted;
}
// If tickDecimals was specified, ensure that we have exactly that
// much precision; otherwise default to the value's own precision.
if (decimals != null) {
var decimalPos = formatted.indexOf(".");
var precision = decimalPos === -1 ? 0 : formatted.length - decimalPos - 1;
if (precision < decimals) {
return (precision ? formatted : formatted + ".") + (String(factor)).substr(1, decimals - precision);
}
}
return formatted;
};
kbn.toFixedScaled = function(value, decimals, scaledDecimals, additionalDecimals, ext) {
if (scaledDecimals === null) {
return kbn.toFixed(value, decimals) + ext;
} else {
return kbn.toFixed(value, scaledDecimals + additionalDecimals) + ext;
}
};
kbn.roundValue = function (num, decimals) {
if (num === null) { return null; }
var n = Math.pow(10, decimals);
return Math.round((n * num).toFixed(decimals)) / n;
};
///// FORMAT FUNCTION CONSTRUCTORS /////
kbn.formatBuilders = {};
// Formatter which always appends a fixed unit string to the value. No
// scaling of the value is performed.
kbn.formatBuilders.fixedUnit = function(unit) {
return function(size, decimals) {
if (size === null) { return ""; }
return kbn.toFixed(size, decimals) + ' ' + unit;
};
};
// Formatter which scales the unit string geometrically according to the given
// numeric factor. Repeatedly scales the value down by the factor until it is
// less than the factor in magnitude, or the end of the array is reached.
kbn.formatBuilders.scaledUnits = function(factor, extArray) {
return function(size, decimals, scaledDecimals) {
if (size === null) {
return "";
}
var steps = 0;
var limit = extArray.length;
while (Math.abs(size) >= factor) {
steps++;
size /= factor;
if (steps >= limit) { return "NA"; }
}
if (steps > 0 && scaledDecimals !== null) {
decimals = scaledDecimals + (3 * steps);
}
return kbn.toFixed(size, decimals) + extArray[steps];
};
};
// Extension of the scaledUnits builder which uses SI decimal prefixes. If an
// offset is given, it adjusts the starting units at the given prefix; a value
// of 0 starts at no scale; -3 drops to nano, +2 starts at mega, etc.
kbn.formatBuilders.decimalSIPrefix = function(unit, offset) {
var prefixes = ['n', 'µ', 'm', '', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
prefixes = prefixes.slice(3 + (offset || 0));
var units = prefixes.map(function(p) { return ' ' + p + unit; });
return kbn.formatBuilders.scaledUnits(1000, units);
};
// Extension of the scaledUnits builder which uses SI binary prefixes. If
// offset is given, it starts the units at the given prefix; otherwise, the
// offset defaults to zero and the initial unit is not prefixed.
kbn.formatBuilders.binarySIPrefix = function(unit, offset) {
var prefixes = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'].slice(offset);
var units = prefixes.map(function(p) { return ' ' + p + unit; });
return kbn.formatBuilders.scaledUnits(1024, units);
};
// Currency formatter for prefixing a symbol onto a number. Supports scaling
// up to the trillions.
kbn.formatBuilders.currency = function(symbol) {
var units = ['', 'K', 'M', 'B', 'T'];
var scaler = kbn.formatBuilders.scaledUnits(1000, units);
return function(size, decimals, scaledDecimals) {
if (size === null) { return ""; }
var scaled = scaler(size, decimals, scaledDecimals);
return symbol + scaled;
};
};
kbn.formatBuilders.simpleCountUnit = function(symbol) {
var units = ['', 'K', 'M', 'B', 'T'];
var scaler = kbn.formatBuilders.scaledUnits(1000, units);
return function(size, decimals, scaledDecimals) {
if (size === null) { return ""; }
var scaled = scaler(size, decimals, scaledDecimals);
return scaled + " " + symbol;
};
};
///// VALUE FORMATS /////
// Dimensionless Units
kbn.valueFormats.none = kbn.toFixed;
kbn.valueFormats.short = kbn.formatBuilders.scaledUnits(1000, ['', ' K', ' Mil', ' Bil', ' Tri', ' Quadr', ' Quint', ' Sext', ' Sept']);
kbn.valueFormats.dB = kbn.formatBuilders.fixedUnit('dB');
kbn.valueFormats.ppm = kbn.formatBuilders.fixedUnit('ppm');
kbn.valueFormats.percent = function(size, decimals) {
if (size === null) { return ""; }
return kbn.toFixed(size, decimals) + '%';
};
kbn.valueFormats.percentunit = function(size, decimals) {
if (size === null) { return ""; }
return kbn.toFixed(100*size, decimals) + '%';
};
/* Formats the value to hex. Uses float if specified decimals are not 0.
* There are two options, one with 0x, and one without */
kbn.valueFormats.hex = function(value, decimals) {
if (value == null) { return ""; }
return parseFloat(kbn.toFixed(value, decimals)).toString(16).toUpperCase();
};
kbn.valueFormats.hex0x = function(value, decimals) {
if (value == null) { return ""; }
var hexString = kbn.valueFormats.hex(value, decimals);
if (hexString.substring(0,1) === "-") {
return "-0x" + hexString.substring(1);
}
return "0x" + hexString;
};
kbn.valueFormats.sci = function(value, decimals) {
return value.toExponential(decimals);
};
kbn.valueFormats.locale = function(value, decimals) {
return value.toLocaleString(undefined, {maximumFractionDigits: decimals});
};
// Currencies
kbn.valueFormats.currencyUSD = kbn.formatBuilders.currency('$');
kbn.valueFormats.currencyGBP = kbn.formatBuilders.currency('£');
kbn.valueFormats.currencyEUR = kbn.formatBuilders.currency('€');
kbn.valueFormats.currencyJPY = kbn.formatBuilders.currency('¥');
kbn.valueFormats.currencyRUB = kbn.formatBuilders.currency('₽');
kbn.valueFormats.currencyUAH = kbn.formatBuilders.currency('₴');
kbn.valueFormats.currencyBRL = kbn.formatBuilders.currency('R$');
kbn.valueFormats.currencyDKK = kbn.formatBuilders.currency('kr');
kbn.valueFormats.currencyISK = kbn.formatBuilders.currency('kr');
kbn.valueFormats.currencyNOK = kbn.formatBuilders.currency('kr');
kbn.valueFormats.currencySEK = kbn.formatBuilders.currency('kr');
// Data (Binary)
kbn.valueFormats.bits = kbn.formatBuilders.binarySIPrefix('b');
kbn.valueFormats.bytes = kbn.formatBuilders.binarySIPrefix('B');
kbn.valueFormats.kbytes = kbn.formatBuilders.binarySIPrefix('B', 1);
kbn.valueFormats.mbytes = kbn.formatBuilders.binarySIPrefix('B', 2);
kbn.valueFormats.gbytes = kbn.formatBuilders.binarySIPrefix('B', 3);
// Data (Decimal)
kbn.valueFormats.decbits = kbn.formatBuilders.decimalSIPrefix('b');
kbn.valueFormats.decbytes = kbn.formatBuilders.decimalSIPrefix('B');
kbn.valueFormats.deckbytes = kbn.formatBuilders.decimalSIPrefix('B', 1);
kbn.valueFormats.decmbytes = kbn.formatBuilders.decimalSIPrefix('B', 2);
kbn.valueFormats.decgbytes = kbn.formatBuilders.decimalSIPrefix('B', 3);
// Data Rate
kbn.valueFormats.pps = kbn.formatBuilders.decimalSIPrefix('pps');
kbn.valueFormats.bps = kbn.formatBuilders.decimalSIPrefix('bps');
kbn.valueFormats.Bps = kbn.formatBuilders.decimalSIPrefix('Bps');
kbn.valueFormats.KBs = kbn.formatBuilders.decimalSIPrefix('Bs', 1);
kbn.valueFormats.Kbits = kbn.formatBuilders.decimalSIPrefix('bps', 1);
kbn.valueFormats.MBs = kbn.formatBuilders.decimalSIPrefix('Bs', 2);
kbn.valueFormats.Mbits = kbn.formatBuilders.decimalSIPrefix('bps', 2);
kbn.valueFormats.GBs = kbn.formatBuilders.decimalSIPrefix('Bs', 3);
kbn.valueFormats.Gbits = kbn.formatBuilders.decimalSIPrefix('bps', 3);
// Throughput
kbn.valueFormats.ops = kbn.formatBuilders.simpleCountUnit('ops');
kbn.valueFormats.rps = kbn.formatBuilders.simpleCountUnit('rps');
kbn.valueFormats.wps = kbn.formatBuilders.simpleCountUnit('wps');
kbn.valueFormats.iops = kbn.formatBuilders.simpleCountUnit('iops');
kbn.valueFormats.opm = kbn.formatBuilders.simpleCountUnit('opm');
kbn.valueFormats.rpm = kbn.formatBuilders.simpleCountUnit('rpm');
kbn.valueFormats.wpm = kbn.formatBuilders.simpleCountUnit('wpm');
// Energy
kbn.valueFormats.watt = kbn.formatBuilders.decimalSIPrefix('W');
kbn.valueFormats.kwatt = kbn.formatBuilders.decimalSIPrefix('W', 1);
kbn.valueFormats.voltamp = kbn.formatBuilders.decimalSIPrefix('VA');
kbn.valueFormats.kvoltamp = kbn.formatBuilders.decimalSIPrefix('VA', 1);
kbn.valueFormats.voltampreact = kbn.formatBuilders.decimalSIPrefix('var');
kbn.valueFormats.kvoltampreact = kbn.formatBuilders.decimalSIPrefix('var', 1);
kbn.valueFormats.watth = kbn.formatBuilders.decimalSIPrefix('Wh');
kbn.valueFormats.kwatth = kbn.formatBuilders.decimalSIPrefix('Wh', 1);
kbn.valueFormats.joule = kbn.formatBuilders.decimalSIPrefix('J');
kbn.valueFormats.ev = kbn.formatBuilders.decimalSIPrefix('eV');
kbn.valueFormats.amp = kbn.formatBuilders.decimalSIPrefix('A');
kbn.valueFormats.kamp = kbn.formatBuilders.decimalSIPrefix('A', 1);
kbn.valueFormats.volt = kbn.formatBuilders.decimalSIPrefix('V');
kbn.valueFormats.kvolt = kbn.formatBuilders.decimalSIPrefix('V', 1);
kbn.valueFormats.dBm = kbn.formatBuilders.decimalSIPrefix('dBm');
// Temperature
kbn.valueFormats.celsius = kbn.formatBuilders.fixedUnit('°C');
kbn.valueFormats.farenheit = kbn.formatBuilders.fixedUnit('°F');
kbn.valueFormats.kelvin = kbn.formatBuilders.fixedUnit('K');
kbn.valueFormats.humidity = kbn.formatBuilders.fixedUnit('%H');
// Pressure
kbn.valueFormats.pressurebar = kbn.formatBuilders.decimalSIPrefix('bar');
kbn.valueFormats.pressurembar = kbn.formatBuilders.decimalSIPrefix('bar', -1);
kbn.valueFormats.pressurekbar = kbn.formatBuilders.decimalSIPrefix('bar', 1);
kbn.valueFormats.pressurehpa = kbn.formatBuilders.fixedUnit('hPa');
kbn.valueFormats.pressurehg = kbn.formatBuilders.fixedUnit('"Hg');
kbn.valueFormats.pressurepsi = kbn.formatBuilders.scaledUnits(1000, [' psi', ' ksi', ' Mpsi']);
// Force
kbn.valueFormats.forceNm = kbn.formatBuilders.decimalSIPrefix('Nm');
kbn.valueFormats.forcekNm = kbn.formatBuilders.decimalSIPrefix('Nm', 1);
kbn.valueFormats.forceN = kbn.formatBuilders.decimalSIPrefix('N');
kbn.valueFormats.forcekN = kbn.formatBuilders.decimalSIPrefix('N', 1);
// Length
kbn.valueFormats.lengthm = kbn.formatBuilders.decimalSIPrefix('m');
kbn.valueFormats.lengthmm = kbn.formatBuilders.decimalSIPrefix('m', -1);
kbn.valueFormats.lengthkm = kbn.formatBuilders.decimalSIPrefix('m', 1);
kbn.valueFormats.lengthmi = kbn.formatBuilders.fixedUnit('mi');
// Mass
kbn.valueFormats.massmg = kbn.formatBuilders.decimalSIPrefix('g', -1);
kbn.valueFormats.massg = kbn.formatBuilders.decimalSIPrefix('g');
kbn.valueFormats.masskg = kbn.formatBuilders.decimalSIPrefix('g', 1);
kbn.valueFormats.masst = kbn.formatBuilders.fixedUnit('t');
// Velocity
kbn.valueFormats.velocityms = kbn.formatBuilders.fixedUnit('m/s');
kbn.valueFormats.velocitykmh = kbn.formatBuilders.fixedUnit('km/h');
kbn.valueFormats.velocitymph = kbn.formatBuilders.fixedUnit('mph');
kbn.valueFormats.velocityknot = kbn.formatBuilders.fixedUnit('kn');
// Volume
kbn.valueFormats.litre = kbn.formatBuilders.decimalSIPrefix('L');
kbn.valueFormats.mlitre = kbn.formatBuilders.decimalSIPrefix('L', -1);
kbn.valueFormats.m3 = kbn.formatBuilders.decimalSIPrefix('m3');
kbn.valueFormats.dm3 = kbn.formatBuilders.decimalSIPrefix('dm3');
kbn.valueFormats.gallons = kbn.formatBuilders.fixedUnit('gal');
// Flow
kbn.valueFormats.flowgpm = kbn.formatBuilders.fixedUnit('gpm');
kbn.valueFormats.flowcms = kbn.formatBuilders.fixedUnit('cms');
kbn.valueFormats.flowcfs = kbn.formatBuilders.fixedUnit('cfs');
kbn.valueFormats.flowcfm = kbn.formatBuilders.fixedUnit('cfm');
// Time
kbn.valueFormats.hertz = kbn.formatBuilders.decimalSIPrefix('Hz');
kbn.valueFormats.ms = function(size, decimals, scaledDecimals) {
if (size === null) { return ""; }
if (Math.abs(size) < 1000) {
return kbn.toFixed(size, decimals) + " ms";
}
// Less than 1 min
else if (Math.abs(size) < 60000) {
return kbn.toFixedScaled(size / 1000, decimals, scaledDecimals, 3, " s");
}
// Less than 1 hour, devide in minutes
else if (Math.abs(size) < 3600000) {
return kbn.toFixedScaled(size / 60000, decimals, scaledDecimals, 5, " min");
}
// Less than one day, devide in hours
else if (Math.abs(size) < 86400000) {
return kbn.toFixedScaled(size / 3600000, decimals, scaledDecimals, 7, " hour");
}
// Less than one year, devide in days
else if (Math.abs(size) < 31536000000) {
return kbn.toFixedScaled(size / 86400000, decimals, scaledDecimals, 8, " day");
}
return kbn.toFixedScaled(size / 31536000000, decimals, scaledDecimals, 10, " year");
};
kbn.valueFormats.s = function(size, decimals, scaledDecimals) {
if (size === null) { return ""; }
// Less than 1 µs, devide in ns
if (Math.abs(size) < 0.000001) {
return kbn.toFixedScaled(size * 1.e9, decimals, scaledDecimals - decimals, -9, " ns");
}
// Less than 1 ms, devide in µs
if (Math.abs(size) < 0.001) {
return kbn.toFixedScaled(size * 1.e6, decimals, scaledDecimals - decimals, -6, " µs");
}
// Less than 1 second, devide in ms
if (Math.abs(size) < 1) {
return kbn.toFixedScaled(size * 1.e3, decimals, scaledDecimals - decimals, -3, " ms");
}
if (Math.abs(size) < 60) {
return kbn.toFixed(size, decimals) + " s";
}
// Less than 1 hour, devide in minutes
else if (Math.abs(size) < 3600) {
return kbn.toFixedScaled(size / 60, decimals, scaledDecimals, 1, " min");
}
// Less than one day, devide in hours
else if (Math.abs(size) < 86400) {
return kbn.toFixedScaled(size / 3600, decimals, scaledDecimals, 4, " hour");
}
// Less than one week, devide in days
else if (Math.abs(size) < 604800) {
return kbn.toFixedScaled(size / 86400, decimals, scaledDecimals, 5, " day");
}
// Less than one year, devide in week
else if (Math.abs(size) < 31536000) {
return kbn.toFixedScaled(size / 604800, decimals, scaledDecimals, 6, " week");
}
return kbn.toFixedScaled(size / 3.15569e7, decimals, scaledDecimals, 7, " year");
};
kbn.valueFormats['µs'] = function(size, decimals, scaledDecimals) {
if (size === null) { return ""; }
if (Math.abs(size) < 1000) {
return kbn.toFixed(size, decimals) + " µs";
}
else if (Math.abs(size) < 1000000) {
return kbn.toFixedScaled(size / 1000, decimals, scaledDecimals, 3, " ms");
}
else {
return kbn.toFixedScaled(size / 1000000, decimals, scaledDecimals, 6, " s");
}
};
kbn.valueFormats.ns = function(size, decimals, scaledDecimals) {
if (size === null) { return ""; }
if (Math.abs(size) < 1000) {
return kbn.toFixed(size, decimals) + " ns";
}
else if (Math.abs(size) < 1000000) {
return kbn.toFixedScaled(size / 1000, decimals, scaledDecimals, 3, " µs");
}
else if (Math.abs(size) < 1000000000) {
return kbn.toFixedScaled(size / 1000000, decimals, scaledDecimals, 6, " ms");
}
else if (Math.abs(size) < 60000000000){
return kbn.toFixedScaled(size / 1000000000, decimals, scaledDecimals, 9, " s");
}
else {
return kbn.toFixedScaled(size / 60000000000, decimals, scaledDecimals, 12, " min");
}
};
kbn.valueFormats.m = function(size, decimals, scaledDecimals) {
if (size === null) { return ""; }
if (Math.abs(size) < 60) {
return kbn.toFixed(size, decimals) + " min";
}
else if (Math.abs(size) < 1440) {
return kbn.toFixedScaled(size / 60, decimals, scaledDecimals, 2, " hour");
}
else if (Math.abs(size) < 10080) {
return kbn.toFixedScaled(size / 1440, decimals, scaledDecimals, 3, " day");
}
else if (Math.abs(size) < 604800) {
return kbn.toFixedScaled(size / 10080, decimals, scaledDecimals, 4, " week");
}
else {
return kbn.toFixedScaled(size / 5.25948e5, decimals, scaledDecimals, 5, " year");
}
};
kbn.valueFormats.h = function(size, decimals, scaledDecimals) {
if (size === null) { return ""; }
if (Math.abs(size) < 24) {
return kbn.toFixed(size, decimals) + " hour";
}
else if (Math.abs(size) < 168) {
return kbn.toFixedScaled(size / 24, decimals, scaledDecimals, 2, " day");
}
else if (Math.abs(size) < 8760) {
return kbn.toFixedScaled(size / 168, decimals, scaledDecimals, 3, " week");
}
else {
return kbn.toFixedScaled(size / 8760, decimals, scaledDecimals, 4, " year");
}
};
kbn.valueFormats.d = function(size, decimals, scaledDecimals) {
if (size === null) { return ""; }
if (Math.abs(size) < 7) {
return kbn.toFixed(size, decimals) + " day";
}
else if (Math.abs(size) < 365) {
return kbn.toFixedScaled(size / 7, decimals, scaledDecimals, 2, " week");
}
else {
return kbn.toFixedScaled(size / 365, decimals, scaledDecimals, 3, " year");
}
};
kbn.toDuration = function(size, decimals, timeScale) {
if (size === null) { return ""; }
if (size === 0) { return "0 " + timeScale + "s"; }
if (size < 0) { return kbn.toDuration(-size, decimals, timeScale) + " ago"; }
var units = [
{short: "y", long: "year"},
{short: "M", long: "month"},
{short: "w", long: "week"},
{short: "d", long: "day"},
{short: "h", long: "hour"},
{short: "m", long: "minute"},
{short: "s", long: "second"},
{short: "ms", long: "millisecond"}
];
// convert $size to milliseconds
// intervals_in_seconds uses seconds (duh), convert them to milliseconds here to minimize floating point errors
size *= kbn.intervals_in_seconds[units.find(function(e) { return e.long === timeScale; }).short] * 1000;
var string = [];
// after first value >= 1 print only $decimals more
var decrementDecimals = false;
for (var i = 0; i < units.length && decimals >= 0; i++) {
var interval = kbn.intervals_in_seconds[units[i].short] * 1000;
var value = size / interval;
if (value >= 1 || decrementDecimals) {
decrementDecimals = true;
var floor = Math.floor(value);
var unit = units[i].long + (floor !== 1 ? "s" : "");
string.push(floor + " " + unit);
size = size % interval;
decimals--;
}
}
return string.join(", ");
};
kbn.valueFormats.dtdurationms = function(size, decimals) {
return kbn.toDuration(size, decimals, 'millisecond');
};
kbn.valueFormats.dtdurations = function(size, decimals) {
return kbn.toDuration(size, decimals, 'second');
};
kbn.valueFormats.dateTimeAsIso = function(epoch) {
var time = moment(epoch);
if (moment().isSame(epoch, 'day')) {
return time.format('HH:mm:ss');
}
return time.format('YYYY-MM-DD HH:mm:ss');
};
kbn.valueFormats.dateTimeAsUS = function(epoch) {
var time = moment(epoch);
if (moment().isSame(epoch, 'day')) {
return time.format('h:mm:ss a');
}
return time.format('MM/DD/YYYY h:mm:ss a');
};
kbn.valueFormats.dateTimeFromNow = function(epoch) {
return moment(epoch).fromNow();
};
///// FORMAT MENU /////
kbn.getUnitFormats = function() {
return [
{
text: 'none',
submenu: [
{text: 'none' , value: 'none' },
{text: 'short', value: 'short' },
{text: 'percent (0-100)', value: 'percent' },
{text: 'percent (0.0-1.0)', value: 'percentunit'},
{text: 'Humidity (%H)', value: 'humidity' },
{text: 'ppm', value: 'ppm' },
{text: 'decibel', value: 'dB' },
{text: 'hexadecimal (0x)', value: 'hex0x' },
{text: 'hexadecimal', value: 'hex' },
{text: 'scientific notation', value: 'sci' },
{text: 'locale format', value: 'locale' },
]
},
{
text: 'currency',
submenu: [
{text: 'Dollars ($)', value: 'currencyUSD'},
{text: 'Pounds (£)', value: 'currencyGBP'},
{text: 'Euro (€)', value: 'currencyEUR'},
{text: 'Yen (¥)', value: 'currencyJPY'},
{text: 'Rubles (₽)', value: 'currencyRUB'},
{text: 'Hryvnias (₴)', value: 'currencyUAH'},
{text: 'Real (R$)', value: 'currencyBRL'},
{text: 'Danish Krone (kr)', value: 'currencyDKK'},
{text: 'Icelandic Krone (kr)', value: 'currencyISK'},
{text: 'Norwegian Krone (kr)', value: 'currencyNOK'},
{text: 'Swedish Krone (kr)', value: 'currencySEK'},
]
},
{
text: 'time',
submenu: [
{text: 'Hertz (1/s)', value: 'hertz'},
{text: 'nanoseconds (ns)' , value: 'ns' },
{text: 'microseconds (µs)', value: 'µs' },
{text: 'milliseconds (ms)', value: 'ms' },
{text: 'seconds (s)', value: 's' },
{text: 'minutes (m)', value: 'm' },
{text: 'hours (h)', value: 'h' },
{text: 'days (d)', value: 'd' },
{text: 'duration (ms)', value: 'dtdurationms' },
{text: 'duration (s)', value: 'dtdurations' },
]
},
{
text: 'date & time',
submenu: [
{text: 'YYYY-MM-DD HH:mm:ss', value: 'dateTimeAsIso' },
{text: 'DD/MM/YYYY h:mm:ss a', value: 'dateTimeAsUS' },
{text: 'From Now', value: 'dateTimeFromNow' },
]
},
{
text: 'data (IEC)',
submenu: [
{text: 'bits', value: 'bits' },
{text: 'bytes', value: 'bytes' },
{text: 'kibibytes', value: 'kbytes'},
{text: 'mebibytes', value: 'mbytes'},
{text: 'gibibytes', value: 'gbytes'},
]
},
{
text: 'data (Metric)',
submenu: [
{text: 'bits', value: 'decbits' },
{text: 'bytes', value: 'decbytes' },
{text: 'kilobytes', value: 'deckbytes'},
{text: 'megabytes', value: 'decmbytes'},
{text: 'gigabytes', value: 'decgbytes'},
]
},
{
text: 'data rate',
submenu: [
{text: 'packets/sec', value: 'pps'},
{text: 'bits/sec', value: 'bps'},
{text: 'bytes/sec', value: 'Bps'},
{text: 'kilobits/sec', value: 'Kbits'},
{text: 'kilobytes/sec', value: 'KBs'},
{text: 'megabits/sec', value: 'Mbits'},
{text: 'megabytes/sec', value: 'MBs'},
{text: 'gigabytes/sec', value: 'GBs'},
{text: 'gigabits/sec', value: 'Gbits'},
]
},
{
text: 'throughput',
submenu: [
{text: 'ops/sec (ops)', value: 'ops' },
{text: 'reads/sec (rps)', value: 'rps' },
{text: 'writes/sec (wps)', value: 'wps' },
{text: 'I/O ops/sec (iops)', value: 'iops'},
{text: 'ops/min (opm)', value: 'opm' },
{text: 'reads/min (rpm)', value: 'rpm' },
{text: 'writes/min (wpm)', value: 'wpm' },
]
},
{
text: 'length',
submenu: [
{text: 'millimetre (mm)', value: 'lengthmm'},
{text: 'meter (m)', value: 'lengthm' },
{text: 'kilometer (km)', value: 'lengthkm'},
{text: 'mile (mi)', value: 'lengthmi'},
]
},
{
text: 'mass',
submenu: [
{text: 'milligram (mg)', value: 'massmg'},
{text: 'gram (g)', value: 'massg' },
{text: 'kilogram (kg)', value: 'masskg'},
{text: 'metric ton (t)', value: 'masst' },
]
},
{
text: 'velocity',
submenu: [
{text: 'm/s', value: 'velocityms' },
{text: 'km/h', value: 'velocitykmh' },
{text: 'mph', value: 'velocitymph' },
{text: 'knot (kn)', value: 'velocityknot'},
]
},
{
text: 'volume',
submenu: [
{text: 'millilitre', value: 'mlitre' },
{text: 'litre', value: 'litre' },
{text: 'cubic metre', value: 'm3' },
{text: 'cubic decimetre', value: 'dm3' },
{text: 'gallons', value: 'gallons'},
]
},
{
text: 'energy',
submenu: [
{text: 'watt (W)', value: 'watt' },
{text: 'kilowatt (kW)', value: 'kwatt' },
{text: 'volt-ampere (VA)', value: 'voltamp' },
{text: 'kilovolt-ampere (kVA)', value: 'kvoltamp' },
{text: 'volt-ampere reactive (var)', value: 'voltampreact'},
{text: 'kilovolt-ampere reactive (kvar)', value: 'kvoltampreact'},
{text: 'watt-hour (Wh)', value: 'watth' },
{text: 'kilowatt-hour (kWh)', value: 'kwatth' },
{text: 'joule (J)', value: 'joule' },
{text: 'electron volt (eV)', value: 'ev' },
{text: 'Ampere (A)', value: 'amp' },
{text: 'Kiloampere (kA)', value: 'kamp' },
{text: 'Volt (V)', value: 'volt' },
{text: 'Kilovolt (kV)', value: 'kvolt' },
{text: 'Decibel-milliwatt (dBm)', value: 'dBm' },
]
},
{
text: 'temperature',
submenu: [
{text: 'Celsius (°C)', value: 'celsius' },
{text: 'Farenheit (°F)', value: 'farenheit' },
{text: 'Kelvin (K)', value: 'kelvin' },
]
},
{
text: 'pressure',
submenu: [
{text: 'Millibars', value: 'pressurembar'},
{text: 'Bars', value: 'pressurebar' },
{text: 'Kilobars', value: 'pressurekbar'},
{text: 'Hectopascals', value: 'pressurehpa' },
{text: 'Inches of mercury', value: 'pressurehg' },
{text: 'PSI', value: 'pressurepsi' },
]
},
{
text: 'force',
submenu: [
{text: 'Newton-meters (Nm)', value: 'forceNm' },
{text: 'Kilonewton-meters (kNm)', value: 'forcekNm' },
{text: 'Newtons (N)', value: 'forceN' },
{text: 'Kilonewtons (kN)', value: 'forcekN' },
]
},
{
text: 'flow',
submenu: [
{text: 'Gallons/min (gpm)', value: 'flowgpm' },
{text: 'Cubic meters/sec (cms)', value: 'flowcms' },
{text: 'Cubic feet/sec (cfs)', value: 'flowcfs' },
{text: 'Cubic feet/min (cfm)', value: 'flowcfm' },
]
}
];
};
return kbn;
});

View File

@ -0,0 +1,968 @@
import _ from 'lodash';
import moment from 'moment';
var kbn: any = {};
kbn.valueFormats = {};
kbn.regexEscape = function(value) {
return value.replace(/[\\^$*+?.()|[\]{}\/]/g, '\\$&');
};
///// HELPER FUNCTIONS /////
kbn.round_interval = function(interval) {
switch (true) {
// 0.015s
case interval < 15:
return 10; // 0.01s
// 0.035s
case interval < 35:
return 20; // 0.02s
// 0.075s
case interval < 75:
return 50; // 0.05s
// 0.15s
case interval < 150:
return 100; // 0.1s
// 0.35s
case interval < 350:
return 200; // 0.2s
// 0.75s
case interval < 750:
return 500; // 0.5s
// 1.5s
case interval < 1500:
return 1000; // 1s
// 3.5s
case interval < 3500:
return 2000; // 2s
// 7.5s
case interval < 7500:
return 5000; // 5s
// 12.5s
case interval < 12500:
return 10000; // 10s
// 17.5s
case interval < 17500:
return 15000; // 15s
// 25s
case interval < 25000:
return 20000; // 20s
// 45s
case interval < 45000:
return 30000; // 30s
// 1.5m
case interval < 90000:
return 60000; // 1m
// 3.5m
case interval < 210000:
return 120000; // 2m
// 7.5m
case interval < 450000:
return 300000; // 5m
// 12.5m
case interval < 750000:
return 600000; // 10m
// 12.5m
case interval < 1050000:
return 900000; // 15m
// 25m
case interval < 1500000:
return 1200000; // 20m
// 45m
case interval < 2700000:
return 1800000; // 30m
// 1.5h
case interval < 5400000:
return 3600000; // 1h
// 2.5h
case interval < 9000000:
return 7200000; // 2h
// 4.5h
case interval < 16200000:
return 10800000; // 3h
// 9h
case interval < 32400000:
return 21600000; // 6h
// 1d
case interval < 86400000:
return 43200000; // 12h
// 1w
case interval < 604800000:
return 86400000; // 1d
// 3w
case interval < 1814400000:
return 604800000; // 1w
// 6w
case interval < 3628800000:
return 2592000000; // 30d
default:
return 31536000000; // 1y
}
};
kbn.secondsToHms = function(seconds) {
var numyears = Math.floor(seconds / 31536000);
if (numyears) {
return numyears + 'y';
}
var numdays = Math.floor((seconds % 31536000) / 86400);
if (numdays) {
return numdays + 'd';
}
var numhours = Math.floor(((seconds % 31536000) % 86400) / 3600);
if (numhours) {
return numhours + 'h';
}
var numminutes = Math.floor((((seconds % 31536000) % 86400) % 3600) / 60);
if (numminutes) {
return numminutes + 'm';
}
var numseconds = Math.floor((((seconds % 31536000) % 86400) % 3600) % 60);
if (numseconds) {
return numseconds + 's';
}
var nummilliseconds = Math.floor(seconds * 1000.0);
if (nummilliseconds) {
return nummilliseconds + 'ms';
}
return 'less than a millisecond'; //'just now' //or other string you like;
};
kbn.to_percent = function(nr, outof) {
return Math.floor(nr / outof * 10000) / 100 + '%';
};
kbn.addslashes = function(str) {
str = str.replace(/\\/g, '\\\\');
str = str.replace(/\'/g, "\\'");
str = str.replace(/\"/g, '\\"');
str = str.replace(/\0/g, '\\0');
return str;
};
kbn.interval_regex = /(\d+(?:\.\d+)?)(ms|[Mwdhmsy])/;
// histogram & trends
kbn.intervals_in_seconds = {
y: 31536000,
M: 2592000,
w: 604800,
d: 86400,
h: 3600,
m: 60,
s: 1,
ms: 0.001,
};
kbn.calculateInterval = function(range, resolution, lowLimitInterval) {
var lowLimitMs = 1; // 1 millisecond default low limit
var intervalMs;
if (lowLimitInterval) {
if (lowLimitInterval[0] === '>') {
lowLimitInterval = lowLimitInterval.slice(1);
}
lowLimitMs = kbn.interval_to_ms(lowLimitInterval);
}
intervalMs = kbn.round_interval((range.to.valueOf() - range.from.valueOf()) / resolution);
if (lowLimitMs > intervalMs) {
intervalMs = lowLimitMs;
}
return {
intervalMs: intervalMs,
interval: kbn.secondsToHms(intervalMs / 1000),
};
};
kbn.describe_interval = function(str) {
var matches = str.match(kbn.interval_regex);
if (!matches || !_.has(kbn.intervals_in_seconds, matches[2])) {
throw new Error('Invalid interval string, expecting a number followed by one of "Mwdhmsy"');
} else {
return {
sec: kbn.intervals_in_seconds[matches[2]],
type: matches[2],
count: parseInt(matches[1], 10),
};
}
};
kbn.interval_to_ms = function(str) {
var info = kbn.describe_interval(str);
return info.sec * 1000 * info.count;
};
kbn.interval_to_seconds = function(str) {
var info = kbn.describe_interval(str);
return info.sec * info.count;
};
kbn.query_color_dot = function(color, diameter) {
return (
'<div class="icon-circle" style="' +
['display:inline-block', 'color:' + color, 'font-size:' + diameter + 'px'].join(';') +
'"></div>'
);
};
kbn.slugifyForUrl = function(str) {
return str
.toLowerCase()
.replace(/[^\w ]+/g, '')
.replace(/ +/g, '-');
};
kbn.stringToJsRegex = function(str) {
if (str[0] !== '/') {
return new RegExp('^' + str + '$');
}
var match = str.match(new RegExp('^/(.*?)/(g?i?m?y?)$'));
return new RegExp(match[1], match[2]);
};
kbn.toFixed = function(value, decimals) {
if (value === null) {
return '';
}
var factor = decimals ? Math.pow(10, Math.max(0, decimals)) : 1;
var formatted = String(Math.round(value * factor) / factor);
// if exponent return directly
if (formatted.indexOf('e') !== -1 || value === 0) {
return formatted;
}
// If tickDecimals was specified, ensure that we have exactly that
// much precision; otherwise default to the value's own precision.
if (decimals != null) {
var decimalPos = formatted.indexOf('.');
var precision = decimalPos === -1 ? 0 : formatted.length - decimalPos - 1;
if (precision < decimals) {
return (precision ? formatted : formatted + '.') + String(factor).substr(1, decimals - precision);
}
}
return formatted;
};
kbn.toFixedScaled = function(value, decimals, scaledDecimals, additionalDecimals, ext) {
if (scaledDecimals === null) {
return kbn.toFixed(value, decimals) + ext;
} else {
return kbn.toFixed(value, scaledDecimals + additionalDecimals) + ext;
}
};
kbn.roundValue = function(num, decimals) {
if (num === null) {
return null;
}
var n = Math.pow(10, decimals);
var formatted = (n * num).toFixed(decimals);
return Math.round(parseFloat(formatted)) / n;
};
///// FORMAT FUNCTION CONSTRUCTORS /////
kbn.formatBuilders = {};
// Formatter which always appends a fixed unit string to the value. No
// scaling of the value is performed.
kbn.formatBuilders.fixedUnit = function(unit) {
return function(size, decimals) {
if (size === null) {
return '';
}
return kbn.toFixed(size, decimals) + ' ' + unit;
};
};
// Formatter which scales the unit string geometrically according to the given
// numeric factor. Repeatedly scales the value down by the factor until it is
// less than the factor in magnitude, or the end of the array is reached.
kbn.formatBuilders.scaledUnits = function(factor, extArray) {
return function(size, decimals, scaledDecimals) {
if (size === null) {
return '';
}
var steps = 0;
var limit = extArray.length;
while (Math.abs(size) >= factor) {
steps++;
size /= factor;
if (steps >= limit) {
return 'NA';
}
}
if (steps > 0 && scaledDecimals !== null) {
decimals = scaledDecimals + 3 * steps;
}
return kbn.toFixed(size, decimals) + extArray[steps];
};
};
// Extension of the scaledUnits builder which uses SI decimal prefixes. If an
// offset is given, it adjusts the starting units at the given prefix; a value
// of 0 starts at no scale; -3 drops to nano, +2 starts at mega, etc.
kbn.formatBuilders.decimalSIPrefix = function(unit, offset) {
var prefixes = ['n', 'µ', 'm', '', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'];
prefixes = prefixes.slice(3 + (offset || 0));
var units = prefixes.map(function(p) {
return ' ' + p + unit;
});
return kbn.formatBuilders.scaledUnits(1000, units);
};
// Extension of the scaledUnits builder which uses SI binary prefixes. If
// offset is given, it starts the units at the given prefix; otherwise, the
// offset defaults to zero and the initial unit is not prefixed.
kbn.formatBuilders.binarySIPrefix = function(unit, offset) {
var prefixes = ['', 'Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'].slice(offset);
var units = prefixes.map(function(p) {
return ' ' + p + unit;
});
return kbn.formatBuilders.scaledUnits(1024, units);
};
// Currency formatter for prefixing a symbol onto a number. Supports scaling
// up to the trillions.
kbn.formatBuilders.currency = function(symbol) {
var units = ['', 'K', 'M', 'B', 'T'];
var scaler = kbn.formatBuilders.scaledUnits(1000, units);
return function(size, decimals, scaledDecimals) {
if (size === null) {
return '';
}
var scaled = scaler(size, decimals, scaledDecimals);
return symbol + scaled;
};
};
kbn.formatBuilders.simpleCountUnit = function(symbol) {
var units = ['', 'K', 'M', 'B', 'T'];
var scaler = kbn.formatBuilders.scaledUnits(1000, units);
return function(size, decimals, scaledDecimals) {
if (size === null) {
return '';
}
var scaled = scaler(size, decimals, scaledDecimals);
return scaled + ' ' + symbol;
};
};
///// VALUE FORMATS /////
// Dimensionless Units
kbn.valueFormats.none = kbn.toFixed;
kbn.valueFormats.short = kbn.formatBuilders.scaledUnits(1000, [
'',
' K',
' Mil',
' Bil',
' Tri',
' Quadr',
' Quint',
' Sext',
' Sept',
]);
kbn.valueFormats.dB = kbn.formatBuilders.fixedUnit('dB');
kbn.valueFormats.ppm = kbn.formatBuilders.fixedUnit('ppm');
kbn.valueFormats.percent = function(size, decimals) {
if (size === null) {
return '';
}
return kbn.toFixed(size, decimals) + '%';
};
kbn.valueFormats.percentunit = function(size, decimals) {
if (size === null) {
return '';
}
return kbn.toFixed(100 * size, decimals) + '%';
};
/* Formats the value to hex. Uses float if specified decimals are not 0.
* There are two options, one with 0x, and one without */
kbn.valueFormats.hex = function(value, decimals) {
if (value == null) {
return '';
}
return parseFloat(kbn.toFixed(value, decimals))
.toString(16)
.toUpperCase();
};
kbn.valueFormats.hex0x = function(value, decimals) {
if (value == null) {
return '';
}
var hexString = kbn.valueFormats.hex(value, decimals);
if (hexString.substring(0, 1) === '-') {
return '-0x' + hexString.substring(1);
}
return '0x' + hexString;
};
kbn.valueFormats.sci = function(value, decimals) {
return value.toExponential(decimals);
};
kbn.valueFormats.locale = function(value, decimals) {
return value.toLocaleString(undefined, { maximumFractionDigits: decimals });
};
// Currencies
kbn.valueFormats.currencyUSD = kbn.formatBuilders.currency('$');
kbn.valueFormats.currencyGBP = kbn.formatBuilders.currency('£');
kbn.valueFormats.currencyEUR = kbn.formatBuilders.currency('€');
kbn.valueFormats.currencyJPY = kbn.formatBuilders.currency('¥');
kbn.valueFormats.currencyRUB = kbn.formatBuilders.currency('₽');
kbn.valueFormats.currencyUAH = kbn.formatBuilders.currency('₴');
kbn.valueFormats.currencyBRL = kbn.formatBuilders.currency('R$');
kbn.valueFormats.currencyDKK = kbn.formatBuilders.currency('kr');
kbn.valueFormats.currencyISK = kbn.formatBuilders.currency('kr');
kbn.valueFormats.currencyNOK = kbn.formatBuilders.currency('kr');
kbn.valueFormats.currencySEK = kbn.formatBuilders.currency('kr');
// Data (Binary)
kbn.valueFormats.bits = kbn.formatBuilders.binarySIPrefix('b');
kbn.valueFormats.bytes = kbn.formatBuilders.binarySIPrefix('B');
kbn.valueFormats.kbytes = kbn.formatBuilders.binarySIPrefix('B', 1);
kbn.valueFormats.mbytes = kbn.formatBuilders.binarySIPrefix('B', 2);
kbn.valueFormats.gbytes = kbn.formatBuilders.binarySIPrefix('B', 3);
// Data (Decimal)
kbn.valueFormats.decbits = kbn.formatBuilders.decimalSIPrefix('b');
kbn.valueFormats.decbytes = kbn.formatBuilders.decimalSIPrefix('B');
kbn.valueFormats.deckbytes = kbn.formatBuilders.decimalSIPrefix('B', 1);
kbn.valueFormats.decmbytes = kbn.formatBuilders.decimalSIPrefix('B', 2);
kbn.valueFormats.decgbytes = kbn.formatBuilders.decimalSIPrefix('B', 3);
// Data Rate
kbn.valueFormats.pps = kbn.formatBuilders.decimalSIPrefix('pps');
kbn.valueFormats.bps = kbn.formatBuilders.decimalSIPrefix('bps');
kbn.valueFormats.Bps = kbn.formatBuilders.decimalSIPrefix('Bps');
kbn.valueFormats.KBs = kbn.formatBuilders.decimalSIPrefix('Bs', 1);
kbn.valueFormats.Kbits = kbn.formatBuilders.decimalSIPrefix('bps', 1);
kbn.valueFormats.MBs = kbn.formatBuilders.decimalSIPrefix('Bs', 2);
kbn.valueFormats.Mbits = kbn.formatBuilders.decimalSIPrefix('bps', 2);
kbn.valueFormats.GBs = kbn.formatBuilders.decimalSIPrefix('Bs', 3);
kbn.valueFormats.Gbits = kbn.formatBuilders.decimalSIPrefix('bps', 3);
// Throughput
kbn.valueFormats.ops = kbn.formatBuilders.simpleCountUnit('ops');
kbn.valueFormats.rps = kbn.formatBuilders.simpleCountUnit('rps');
kbn.valueFormats.wps = kbn.formatBuilders.simpleCountUnit('wps');
kbn.valueFormats.iops = kbn.formatBuilders.simpleCountUnit('iops');
kbn.valueFormats.opm = kbn.formatBuilders.simpleCountUnit('opm');
kbn.valueFormats.rpm = kbn.formatBuilders.simpleCountUnit('rpm');
kbn.valueFormats.wpm = kbn.formatBuilders.simpleCountUnit('wpm');
// Energy
kbn.valueFormats.watt = kbn.formatBuilders.decimalSIPrefix('W');
kbn.valueFormats.kwatt = kbn.formatBuilders.decimalSIPrefix('W', 1);
kbn.valueFormats.voltamp = kbn.formatBuilders.decimalSIPrefix('VA');
kbn.valueFormats.kvoltamp = kbn.formatBuilders.decimalSIPrefix('VA', 1);
kbn.valueFormats.voltampreact = kbn.formatBuilders.decimalSIPrefix('var');
kbn.valueFormats.kvoltampreact = kbn.formatBuilders.decimalSIPrefix('var', 1);
kbn.valueFormats.watth = kbn.formatBuilders.decimalSIPrefix('Wh');
kbn.valueFormats.kwatth = kbn.formatBuilders.decimalSIPrefix('Wh', 1);
kbn.valueFormats.joule = kbn.formatBuilders.decimalSIPrefix('J');
kbn.valueFormats.ev = kbn.formatBuilders.decimalSIPrefix('eV');
kbn.valueFormats.amp = kbn.formatBuilders.decimalSIPrefix('A');
kbn.valueFormats.kamp = kbn.formatBuilders.decimalSIPrefix('A', 1);
kbn.valueFormats.volt = kbn.formatBuilders.decimalSIPrefix('V');
kbn.valueFormats.kvolt = kbn.formatBuilders.decimalSIPrefix('V', 1);
kbn.valueFormats.dBm = kbn.formatBuilders.decimalSIPrefix('dBm');
// Temperature
kbn.valueFormats.celsius = kbn.formatBuilders.fixedUnit('°C');
kbn.valueFormats.farenheit = kbn.formatBuilders.fixedUnit('°F');
kbn.valueFormats.kelvin = kbn.formatBuilders.fixedUnit('K');
kbn.valueFormats.humidity = kbn.formatBuilders.fixedUnit('%H');
// Pressure
kbn.valueFormats.pressurebar = kbn.formatBuilders.decimalSIPrefix('bar');
kbn.valueFormats.pressurembar = kbn.formatBuilders.decimalSIPrefix('bar', -1);
kbn.valueFormats.pressurekbar = kbn.formatBuilders.decimalSIPrefix('bar', 1);
kbn.valueFormats.pressurehpa = kbn.formatBuilders.fixedUnit('hPa');
kbn.valueFormats.pressurehg = kbn.formatBuilders.fixedUnit('"Hg');
kbn.valueFormats.pressurepsi = kbn.formatBuilders.scaledUnits(1000, [' psi', ' ksi', ' Mpsi']);
// Force
kbn.valueFormats.forceNm = kbn.formatBuilders.decimalSIPrefix('Nm');
kbn.valueFormats.forcekNm = kbn.formatBuilders.decimalSIPrefix('Nm', 1);
kbn.valueFormats.forceN = kbn.formatBuilders.decimalSIPrefix('N');
kbn.valueFormats.forcekN = kbn.formatBuilders.decimalSIPrefix('N', 1);
// Length
kbn.valueFormats.lengthm = kbn.formatBuilders.decimalSIPrefix('m');
kbn.valueFormats.lengthmm = kbn.formatBuilders.decimalSIPrefix('m', -1);
kbn.valueFormats.lengthkm = kbn.formatBuilders.decimalSIPrefix('m', 1);
kbn.valueFormats.lengthmi = kbn.formatBuilders.fixedUnit('mi');
// Mass
kbn.valueFormats.massmg = kbn.formatBuilders.decimalSIPrefix('g', -1);
kbn.valueFormats.massg = kbn.formatBuilders.decimalSIPrefix('g');
kbn.valueFormats.masskg = kbn.formatBuilders.decimalSIPrefix('g', 1);
kbn.valueFormats.masst = kbn.formatBuilders.fixedUnit('t');
// Velocity
kbn.valueFormats.velocityms = kbn.formatBuilders.fixedUnit('m/s');
kbn.valueFormats.velocitykmh = kbn.formatBuilders.fixedUnit('km/h');
kbn.valueFormats.velocitymph = kbn.formatBuilders.fixedUnit('mph');
kbn.valueFormats.velocityknot = kbn.formatBuilders.fixedUnit('kn');
// Volume
kbn.valueFormats.litre = kbn.formatBuilders.decimalSIPrefix('L');
kbn.valueFormats.mlitre = kbn.formatBuilders.decimalSIPrefix('L', -1);
kbn.valueFormats.m3 = kbn.formatBuilders.decimalSIPrefix('m3');
kbn.valueFormats.dm3 = kbn.formatBuilders.decimalSIPrefix('dm3');
kbn.valueFormats.gallons = kbn.formatBuilders.fixedUnit('gal');
// Flow
kbn.valueFormats.flowgpm = kbn.formatBuilders.fixedUnit('gpm');
kbn.valueFormats.flowcms = kbn.formatBuilders.fixedUnit('cms');
kbn.valueFormats.flowcfs = kbn.formatBuilders.fixedUnit('cfs');
kbn.valueFormats.flowcfm = kbn.formatBuilders.fixedUnit('cfm');
// Time
kbn.valueFormats.hertz = kbn.formatBuilders.decimalSIPrefix('Hz');
kbn.valueFormats.ms = function(size, decimals, scaledDecimals) {
if (size === null) {
return '';
}
if (Math.abs(size) < 1000) {
return kbn.toFixed(size, decimals) + ' ms';
} else if (Math.abs(size) < 60000) {
// Less than 1 min
return kbn.toFixedScaled(size / 1000, decimals, scaledDecimals, 3, ' s');
} else if (Math.abs(size) < 3600000) {
// Less than 1 hour, devide in minutes
return kbn.toFixedScaled(size / 60000, decimals, scaledDecimals, 5, ' min');
} else if (Math.abs(size) < 86400000) {
// Less than one day, devide in hours
return kbn.toFixedScaled(size / 3600000, decimals, scaledDecimals, 7, ' hour');
} else if (Math.abs(size) < 31536000000) {
// Less than one year, devide in days
return kbn.toFixedScaled(size / 86400000, decimals, scaledDecimals, 8, ' day');
}
return kbn.toFixedScaled(size / 31536000000, decimals, scaledDecimals, 10, ' year');
};
kbn.valueFormats.s = function(size, decimals, scaledDecimals) {
if (size === null) {
return '';
}
// Less than 1 µs, devide in ns
if (Math.abs(size) < 0.000001) {
return kbn.toFixedScaled(size * 1e9, decimals, scaledDecimals - decimals, -9, ' ns');
}
// Less than 1 ms, devide in µs
if (Math.abs(size) < 0.001) {
return kbn.toFixedScaled(size * 1e6, decimals, scaledDecimals - decimals, -6, ' µs');
}
// Less than 1 second, devide in ms
if (Math.abs(size) < 1) {
return kbn.toFixedScaled(size * 1e3, decimals, scaledDecimals - decimals, -3, ' ms');
}
if (Math.abs(size) < 60) {
return kbn.toFixed(size, decimals) + ' s';
} else if (Math.abs(size) < 3600) {
// Less than 1 hour, devide in minutes
return kbn.toFixedScaled(size / 60, decimals, scaledDecimals, 1, ' min');
} else if (Math.abs(size) < 86400) {
// Less than one day, devide in hours
return kbn.toFixedScaled(size / 3600, decimals, scaledDecimals, 4, ' hour');
} else if (Math.abs(size) < 604800) {
// Less than one week, devide in days
return kbn.toFixedScaled(size / 86400, decimals, scaledDecimals, 5, ' day');
} else if (Math.abs(size) < 31536000) {
// Less than one year, devide in week
return kbn.toFixedScaled(size / 604800, decimals, scaledDecimals, 6, ' week');
}
return kbn.toFixedScaled(size / 3.15569e7, decimals, scaledDecimals, 7, ' year');
};
kbn.valueFormats['µs'] = function(size, decimals, scaledDecimals) {
if (size === null) {
return '';
}
if (Math.abs(size) < 1000) {
return kbn.toFixed(size, decimals) + ' µs';
} else if (Math.abs(size) < 1000000) {
return kbn.toFixedScaled(size / 1000, decimals, scaledDecimals, 3, ' ms');
} else {
return kbn.toFixedScaled(size / 1000000, decimals, scaledDecimals, 6, ' s');
}
};
kbn.valueFormats.ns = function(size, decimals, scaledDecimals) {
if (size === null) {
return '';
}
if (Math.abs(size) < 1000) {
return kbn.toFixed(size, decimals) + ' ns';
} else if (Math.abs(size) < 1000000) {
return kbn.toFixedScaled(size / 1000, decimals, scaledDecimals, 3, ' µs');
} else if (Math.abs(size) < 1000000000) {
return kbn.toFixedScaled(size / 1000000, decimals, scaledDecimals, 6, ' ms');
} else if (Math.abs(size) < 60000000000) {
return kbn.toFixedScaled(size / 1000000000, decimals, scaledDecimals, 9, ' s');
} else {
return kbn.toFixedScaled(size / 60000000000, decimals, scaledDecimals, 12, ' min');
}
};
kbn.valueFormats.m = function(size, decimals, scaledDecimals) {
if (size === null) {
return '';
}
if (Math.abs(size) < 60) {
return kbn.toFixed(size, decimals) + ' min';
} else if (Math.abs(size) < 1440) {
return kbn.toFixedScaled(size / 60, decimals, scaledDecimals, 2, ' hour');
} else if (Math.abs(size) < 10080) {
return kbn.toFixedScaled(size / 1440, decimals, scaledDecimals, 3, ' day');
} else if (Math.abs(size) < 604800) {
return kbn.toFixedScaled(size / 10080, decimals, scaledDecimals, 4, ' week');
} else {
return kbn.toFixedScaled(size / 5.25948e5, decimals, scaledDecimals, 5, ' year');
}
};
kbn.valueFormats.h = function(size, decimals, scaledDecimals) {
if (size === null) {
return '';
}
if (Math.abs(size) < 24) {
return kbn.toFixed(size, decimals) + ' hour';
} else if (Math.abs(size) < 168) {
return kbn.toFixedScaled(size / 24, decimals, scaledDecimals, 2, ' day');
} else if (Math.abs(size) < 8760) {
return kbn.toFixedScaled(size / 168, decimals, scaledDecimals, 3, ' week');
} else {
return kbn.toFixedScaled(size / 8760, decimals, scaledDecimals, 4, ' year');
}
};
kbn.valueFormats.d = function(size, decimals, scaledDecimals) {
if (size === null) {
return '';
}
if (Math.abs(size) < 7) {
return kbn.toFixed(size, decimals) + ' day';
} else if (Math.abs(size) < 365) {
return kbn.toFixedScaled(size / 7, decimals, scaledDecimals, 2, ' week');
} else {
return kbn.toFixedScaled(size / 365, decimals, scaledDecimals, 3, ' year');
}
};
kbn.toDuration = function(size, decimals, timeScale) {
if (size === null) {
return '';
}
if (size === 0) {
return '0 ' + timeScale + 's';
}
if (size < 0) {
return kbn.toDuration(-size, decimals, timeScale) + ' ago';
}
var units = [
{ short: 'y', long: 'year' },
{ short: 'M', long: 'month' },
{ short: 'w', long: 'week' },
{ short: 'd', long: 'day' },
{ short: 'h', long: 'hour' },
{ short: 'm', long: 'minute' },
{ short: 's', long: 'second' },
{ short: 'ms', long: 'millisecond' },
];
// convert $size to milliseconds
// intervals_in_seconds uses seconds (duh), convert them to milliseconds here to minimize floating point errors
size *=
kbn.intervals_in_seconds[
units.find(function(e) {
return e.long === timeScale;
}).short
] * 1000;
var strings = [];
// after first value >= 1 print only $decimals more
var decrementDecimals = false;
for (var i = 0; i < units.length && decimals >= 0; i++) {
var interval = kbn.intervals_in_seconds[units[i].short] * 1000;
var value = size / interval;
if (value >= 1 || decrementDecimals) {
decrementDecimals = true;
var floor = Math.floor(value);
var unit = units[i].long + (floor !== 1 ? 's' : '');
strings.push(floor + ' ' + unit);
size = size % interval;
decimals--;
}
}
return strings.join(', ');
};
kbn.valueFormats.dtdurationms = function(size, decimals) {
return kbn.toDuration(size, decimals, 'millisecond');
};
kbn.valueFormats.dtdurations = function(size, decimals) {
return kbn.toDuration(size, decimals, 'second');
};
kbn.valueFormats.dateTimeAsIso = function(epoch) {
var time = moment(epoch);
if (moment().isSame(epoch, 'day')) {
return time.format('HH:mm:ss');
}
return time.format('YYYY-MM-DD HH:mm:ss');
};
kbn.valueFormats.dateTimeAsUS = function(epoch) {
var time = moment(epoch);
if (moment().isSame(epoch, 'day')) {
return time.format('h:mm:ss a');
}
return time.format('MM/DD/YYYY h:mm:ss a');
};
kbn.valueFormats.dateTimeFromNow = function(epoch) {
return moment(epoch).fromNow();
};
///// FORMAT MENU /////
kbn.getUnitFormats = function() {
return [
{
text: 'none',
submenu: [
{ text: 'none', value: 'none' },
{ text: 'short', value: 'short' },
{ text: 'percent (0-100)', value: 'percent' },
{ text: 'percent (0.0-1.0)', value: 'percentunit' },
{ text: 'Humidity (%H)', value: 'humidity' },
{ text: 'ppm', value: 'ppm' },
{ text: 'decibel', value: 'dB' },
{ text: 'hexadecimal (0x)', value: 'hex0x' },
{ text: 'hexadecimal', value: 'hex' },
{ text: 'scientific notation', value: 'sci' },
{ text: 'locale format', value: 'locale' },
],
},
{
text: 'currency',
submenu: [
{ text: 'Dollars ($)', value: 'currencyUSD' },
{ text: 'Pounds (£)', value: 'currencyGBP' },
{ text: 'Euro (€)', value: 'currencyEUR' },
{ text: 'Yen (¥)', value: 'currencyJPY' },
{ text: 'Rubles (₽)', value: 'currencyRUB' },
{ text: 'Hryvnias (₴)', value: 'currencyUAH' },
{ text: 'Real (R$)', value: 'currencyBRL' },
{ text: 'Danish Krone (kr)', value: 'currencyDKK' },
{ text: 'Icelandic Krone (kr)', value: 'currencyISK' },
{ text: 'Norwegian Krone (kr)', value: 'currencyNOK' },
{ text: 'Swedish Krone (kr)', value: 'currencySEK' },
],
},
{
text: 'time',
submenu: [
{ text: 'Hertz (1/s)', value: 'hertz' },
{ text: 'nanoseconds (ns)', value: 'ns' },
{ text: 'microseconds (µs)', value: 'µs' },
{ text: 'milliseconds (ms)', value: 'ms' },
{ text: 'seconds (s)', value: 's' },
{ text: 'minutes (m)', value: 'm' },
{ text: 'hours (h)', value: 'h' },
{ text: 'days (d)', value: 'd' },
{ text: 'duration (ms)', value: 'dtdurationms' },
{ text: 'duration (s)', value: 'dtdurations' },
],
},
{
text: 'date & time',
submenu: [
{ text: 'YYYY-MM-DD HH:mm:ss', value: 'dateTimeAsIso' },
{ text: 'DD/MM/YYYY h:mm:ss a', value: 'dateTimeAsUS' },
{ text: 'From Now', value: 'dateTimeFromNow' },
],
},
{
text: 'data (IEC)',
submenu: [
{ text: 'bits', value: 'bits' },
{ text: 'bytes', value: 'bytes' },
{ text: 'kibibytes', value: 'kbytes' },
{ text: 'mebibytes', value: 'mbytes' },
{ text: 'gibibytes', value: 'gbytes' },
],
},
{
text: 'data (Metric)',
submenu: [
{ text: 'bits', value: 'decbits' },
{ text: 'bytes', value: 'decbytes' },
{ text: 'kilobytes', value: 'deckbytes' },
{ text: 'megabytes', value: 'decmbytes' },
{ text: 'gigabytes', value: 'decgbytes' },
],
},
{
text: 'data rate',
submenu: [
{ text: 'packets/sec', value: 'pps' },
{ text: 'bits/sec', value: 'bps' },
{ text: 'bytes/sec', value: 'Bps' },
{ text: 'kilobits/sec', value: 'Kbits' },
{ text: 'kilobytes/sec', value: 'KBs' },
{ text: 'megabits/sec', value: 'Mbits' },
{ text: 'megabytes/sec', value: 'MBs' },
{ text: 'gigabytes/sec', value: 'GBs' },
{ text: 'gigabits/sec', value: 'Gbits' },
],
},
{
text: 'throughput',
submenu: [
{ text: 'ops/sec (ops)', value: 'ops' },
{ text: 'reads/sec (rps)', value: 'rps' },
{ text: 'writes/sec (wps)', value: 'wps' },
{ text: 'I/O ops/sec (iops)', value: 'iops' },
{ text: 'ops/min (opm)', value: 'opm' },
{ text: 'reads/min (rpm)', value: 'rpm' },
{ text: 'writes/min (wpm)', value: 'wpm' },
],
},
{
text: 'length',
submenu: [
{ text: 'millimetre (mm)', value: 'lengthmm' },
{ text: 'meter (m)', value: 'lengthm' },
{ text: 'kilometer (km)', value: 'lengthkm' },
{ text: 'mile (mi)', value: 'lengthmi' },
],
},
{
text: 'mass',
submenu: [
{ text: 'milligram (mg)', value: 'massmg' },
{ text: 'gram (g)', value: 'massg' },
{ text: 'kilogram (kg)', value: 'masskg' },
{ text: 'metric ton (t)', value: 'masst' },
],
},
{
text: 'velocity',
submenu: [
{ text: 'm/s', value: 'velocityms' },
{ text: 'km/h', value: 'velocitykmh' },
{ text: 'mph', value: 'velocitymph' },
{ text: 'knot (kn)', value: 'velocityknot' },
],
},
{
text: 'volume',
submenu: [
{ text: 'millilitre', value: 'mlitre' },
{ text: 'litre', value: 'litre' },
{ text: 'cubic metre', value: 'm3' },
{ text: 'cubic decimetre', value: 'dm3' },
{ text: 'gallons', value: 'gallons' },
],
},
{
text: 'energy',
submenu: [
{ text: 'watt (W)', value: 'watt' },
{ text: 'kilowatt (kW)', value: 'kwatt' },
{ text: 'volt-ampere (VA)', value: 'voltamp' },
{ text: 'kilovolt-ampere (kVA)', value: 'kvoltamp' },
{ text: 'volt-ampere reactive (var)', value: 'voltampreact' },
{ text: 'kilovolt-ampere reactive (kvar)', value: 'kvoltampreact' },
{ text: 'watt-hour (Wh)', value: 'watth' },
{ text: 'kilowatt-hour (kWh)', value: 'kwatth' },
{ text: 'joule (J)', value: 'joule' },
{ text: 'electron volt (eV)', value: 'ev' },
{ text: 'Ampere (A)', value: 'amp' },
{ text: 'Kiloampere (kA)', value: 'kamp' },
{ text: 'Volt (V)', value: 'volt' },
{ text: 'Kilovolt (kV)', value: 'kvolt' },
{ text: 'Decibel-milliwatt (dBm)', value: 'dBm' },
],
},
{
text: 'temperature',
submenu: [
{ text: 'Celsius (°C)', value: 'celsius' },
{ text: 'Farenheit (°F)', value: 'farenheit' },
{ text: 'Kelvin (K)', value: 'kelvin' },
],
},
{
text: 'pressure',
submenu: [
{ text: 'Millibars', value: 'pressurembar' },
{ text: 'Bars', value: 'pressurebar' },
{ text: 'Kilobars', value: 'pressurekbar' },
{ text: 'Hectopascals', value: 'pressurehpa' },
{ text: 'Inches of mercury', value: 'pressurehg' },
{ text: 'PSI', value: 'pressurepsi' },
],
},
{
text: 'force',
submenu: [
{ text: 'Newton-meters (Nm)', value: 'forceNm' },
{ text: 'Kilonewton-meters (kNm)', value: 'forcekNm' },
{ text: 'Newtons (N)', value: 'forceN' },
{ text: 'Kilonewtons (kN)', value: 'forcekN' },
],
},
{
text: 'flow',
submenu: [
{ text: 'Gallons/min (gpm)', value: 'flowgpm' },
{ text: 'Cubic meters/sec (cms)', value: 'flowcms' },
{ text: 'Cubic feet/sec (cfs)', value: 'flowcfs' },
{ text: 'Cubic feet/min (cfm)', value: 'flowcfm' },
],
},
];
};
export default kbn;

View File

@ -11,6 +11,8 @@ define([
function (angular, moment, _, $, kbn, dateMath, impressionStore) {
'use strict';
kbn = kbn.default;
var module = angular.module('grafana.services');
module.service('dashboardLoaderSrv', function(backendSrv,

View File

@ -1,8 +1,7 @@
///<reference path="../../../headers/common.d.ts" />
import angular from 'angular';
import coreModule from 'app/core/core_module';
import {saveAs} from 'file-saver';
import coreModule from 'app/core/core_module';
import {DashboardExporter} from './exporter';
export class DashExportCtrl {
@ -22,9 +21,8 @@ export class DashExportCtrl {
}
save() {
var blob = new Blob([angular.toJson(this.dash, true)], { type: "application/json;charset=utf-8" });
var wnd: any = window;
wnd.saveAs(blob, this.dash.title + '-' + new Date().getTime() + '.json');
var blob = new Blob([angular.toJson(this.dash, true)], {type: 'application/json;charset=utf-8'});
saveAs(blob, this.dash.title + '-' + new Date().getTime() + '.json');
}
saveJson() {
@ -44,7 +42,7 @@ export function dashExportDirective() {
controller: DashExportCtrl,
bindToController: true,
controllerAs: 'ctrl',
scope: {dismiss: "&"}
scope: {dismiss: '&'},
};
}

View File

@ -6,6 +6,8 @@ define([
function (angular, _, kbn) {
'use strict';
kbn = kbn.default;
angular
.module('grafana.services')
.service('linkSrv', function(templateSrv, timeSrv) {

View File

@ -9,15 +9,24 @@ import config from 'app/core/config';
import TimeSeries from 'app/core/time_series2';
import TableModel from 'app/core/table_model';
import {coreModule, appEvents, contextSrv} from 'app/core/core';
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
import * as datemath from 'app/core/utils/datemath';
import * as fileExport from 'app/core/utils/file_export';
import * as flatten from 'app/core/utils/flatten';
import * as ticks from 'app/core/utils/ticks';
import builtInPlugins from './buit_in_plugins';
import {impressions} from 'app/features/dashboard/impression_store';
import builtInPlugins from './built_in_plugins';
import d3 from 'vendor/d3/d3';
// rxjs
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';
// these imports add functions to Observable
import 'rxjs/add/observable/empty';
import 'rxjs/add/observable/from';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/combineAll';
System.config({
baseURL: 'public',
defaultExtension: 'js',
@ -30,6 +39,9 @@ System.config({
text: 'vendor/plugin-text/text.js',
css: 'vendor/plugin-css/css.js'
},
meta: {
'*': {esModule: true}
}
});
// add cache busting
@ -56,8 +68,13 @@ exposeToPlugin('rxjs/Subject', Subject);
exposeToPlugin('rxjs/Observable', Observable);
exposeToPlugin('d3', d3);
exposeToPlugin('app/plugins/sdk', sdk);
exposeToPlugin('app/features/dashboard/impression_store', {
impressions: impressions,
__esModule: true
});
exposeToPlugin('app/plugins/sdk', sdk);
exposeToPlugin('app/core/utils/datemath', datemath);
exposeToPlugin('app/core/utils/file_export', fileExport);
exposeToPlugin('app/core/utils/flatten', flatten);

View File

@ -1,5 +1,3 @@
///<reference path="../../headers/common.d.ts" />
import _ from 'lodash';
import {Variable, assignModelProperties, variableTypes} from './variable';

View File

@ -1,6 +1,7 @@
import './templateSrv';
import './editor_ctrl';
import coreModule from 'app/core/core_module';
import { TemplateSrv } from './template_srv';
import { VariableSrv } from './variable_srv';
import { IntervalVariable } from './interval_variable';
import { QueryVariable } from './query_variable';
@ -9,7 +10,10 @@ import {CustomVariable} from './custom_variable';
import { ConstantVariable } from './constant_variable';
import { AdhocVariable } from './adhoc_variable';
coreModule.service('templateSrv', TemplateSrv);
export {
TemplateSrv,
VariableSrv,
IntervalVariable,
QueryVariable,

View File

@ -1,5 +1,3 @@
///<reference path="../../headers/common.d.ts" />
import _ from 'lodash';
import kbn from 'app/core/utils/kbn';
import {Variable, containsVariable, assignModelProperties, variableTypes} from './variable';

View File

@ -1,5 +1,3 @@
import {describe, it, expect} from 'test/lib/common';
import {AdhocVariable} from '../adhoc_variable';
describe('AdhocVariable', function() {
@ -15,7 +13,7 @@ describe('AdhocVariable', function() {
]
});
var urlValue = variable.getValueForUrl();
expect(urlValue).to.eql(["key1|=|value1", "key2|!=|value2", "key3|=|value3a__gfp__value3b__gfp__value3c"]);
expect(urlValue).toMatchObject(["key1|=|value1", "key2|!=|value2", "key3|=|value3a__gfp__value3b__gfp__value3c"]);
});
});
@ -26,17 +24,17 @@ describe('AdhocVariable', function() {
var variable = new AdhocVariable({});
variable.setValueFromUrl(["key1|=|value1", "key2|!=|value2", "key3|=|value3a__gfp__value3b__gfp__value3c"]);
expect(variable.filters[0].key).to.be('key1');
expect(variable.filters[0].operator).to.be('=');
expect(variable.filters[0].value).to.be('value1');
expect(variable.filters[0].key).toBe('key1');
expect(variable.filters[0].operator).toBe('=');
expect(variable.filters[0].value).toBe('value1');
expect(variable.filters[1].key).to.be('key2');
expect(variable.filters[1].operator).to.be('!=');
expect(variable.filters[1].value).to.be('value2');
expect(variable.filters[1].key).toBe('key2');
expect(variable.filters[1].operator).toBe('!=');
expect(variable.filters[1].value).toBe('value2');
expect(variable.filters[2].key).to.be('key3');
expect(variable.filters[2].operator).to.be('=');
expect(variable.filters[2].value).to.be('value3a|value3b|value3c');
expect(variable.filters[2].key).toBe('key3');
expect(variable.filters[2].operator).toBe('=');
expect(variable.filters[2].value).toBe('value3a|value3b|value3c');
});
});

View File

@ -1,5 +1,3 @@
import {describe, it, expect} from 'test/lib/common';
import {QueryVariable} from '../query_variable';
describe('QueryVariable', () => {
@ -8,14 +6,14 @@ describe('QueryVariable', () => {
it('should set defaults', () => {
var variable = new QueryVariable({}, null, null, null, null);
expect(variable.datasource).to.be(null);
expect(variable.refresh).to.be(0);
expect(variable.sort).to.be(0);
expect(variable.name).to.be('');
expect(variable.hide).to.be(0);
expect(variable.options.length).to.be(0);
expect(variable.multi).to.be(false);
expect(variable.includeAll).to.be(false);
expect(variable.datasource).toBe(null);
expect(variable.refresh).toBe(0);
expect(variable.sort).toBe(0);
expect(variable.name).toBe('');
expect(variable.hide).toBe(0);
expect(variable.options.length).toBe(0);
expect(variable.multi).toBe(false);
expect(variable.includeAll).toBe(false);
});
it('get model should copy changes back to model', () => {
@ -26,11 +24,11 @@ describe('QueryVariable', () => {
variable.sort = 50;
var model = variable.getSaveModel();
expect(model.options.length).to.be(1);
expect(model.options[0].text).to.be('test');
expect(model.datasource).to.be('google');
expect(model.regex).to.be('asd');
expect(model.sort).to.be(50);
expect(model.options.length).toBe(1);
expect(model.options[0].text).toBe('test');
expect(model.datasource).toBe('google');
expect(model.regex).toBe('asd');
expect(model.sort).toBe(50);
});
it('if refresh != 0 then remove options in presisted mode', () => {
@ -39,7 +37,7 @@ describe('QueryVariable', () => {
variable.refresh = 1;
var model = variable.getSaveModel();
expect(model.options.length).to.be(0);
expect(model.options.length).toBe(0);
});
});
@ -67,14 +65,14 @@ describe('QueryVariable', () => {
it('should return in same order', () => {
var i = 0;
expect(result.length).to.be(11);
expect(result[i++].text).to.be('');
expect(result[i++].text).to.be('0');
expect(result[i++].text).to.be('1');
expect(result[i++].text).to.be('3');
expect(result[i++].text).to.be('4');
expect(result[i++].text).to.be('5');
expect(result[i++].text).to.be('6');
expect(result.length).toBe(11);
expect(result[i++].text).toBe('');
expect(result[i++].text).toBe('0');
expect(result[i++].text).toBe('1');
expect(result[i++].text).toBe('3');
expect(result[i++].text).toBe('4');
expect(result[i++].text).toBe('5');
expect(result[i++].text).toBe('6');
});
});
});

View File

@ -1,28 +1,11 @@
import {describe, beforeEach, it, expect, angularMocks} from 'test/lib/common';
import '../all';
import {Emitter} from 'app/core/core';
import { TemplateSrv } from '../template_srv';
describe('templateSrv', function() {
var _templateSrv, _variableSrv;
beforeEach(angularMocks.module('grafana.core'));
beforeEach(angularMocks.module('grafana.services'));
beforeEach(angularMocks.module($provide => {
$provide.value('timeSrv', {});
$provide.value('datasourceSrv', {});
}));
beforeEach(angularMocks.inject(function(variableSrv, templateSrv) {
_templateSrv = templateSrv;
_variableSrv = variableSrv;
}));
var _templateSrv;
function initTemplateSrv(variables) {
_variableSrv.init({
templating: {list: variables},
events: new Emitter(),
});
_templateSrv = new TemplateSrv();
_templateSrv.init(variables);
}
describe('init', function() {
@ -32,7 +15,7 @@ describe('templateSrv', function() {
it('should initialize template data', function() {
var target = _templateSrv.replace('this.[[test]].filters');
expect(target).to.be('this.oogle.filters');
expect(target).toBe('this.oogle.filters');
});
});
@ -43,12 +26,12 @@ describe('templateSrv', function() {
it('should replace $test with scoped value', function() {
var target = _templateSrv.replace('this.$test.filters', {'test': {value: 'mupp', text: 'asd'}});
expect(target).to.be('this.mupp.filters');
expect(target).toBe('this.mupp.filters');
});
it('should replace $test with scoped text', function() {
var target = _templateSrv.replaceWithText('this.$test.filters', {'test': {value: 'mupp', text: 'asd'}});
expect(target).to.be('this.asd.filters');
expect(target).toBe('this.asd.filters');
});
});
@ -63,17 +46,17 @@ describe('templateSrv', function() {
it('should return filters if datasourceName match', function() {
var filters = _templateSrv.getAdhocFilters('oogle');
expect(filters).to.eql([1]);
expect(filters).toMatchObject([1]);
});
it('should return empty array if datasourceName does not match', function() {
var filters = _templateSrv.getAdhocFilters('oogleasdasd');
expect(filters).to.eql([]);
expect(filters).toMatchObject([]);
});
it('should return filters when datasourceName match via data source variable', function() {
var filters = _templateSrv.getAdhocFilters('logstash');
expect(filters).to.eql([2]);
expect(filters).toMatchObject([2]);
});
});
@ -84,17 +67,17 @@ describe('templateSrv', function() {
it('should replace $test with globbed value', function() {
var target = _templateSrv.replace('this.$test.filters', {}, 'glob');
expect(target).to.be('this.{value1,value2}.filters');
expect(target).toBe('this.{value1,value2}.filters');
});
it('should replace $test with piped value', function() {
var target = _templateSrv.replace('this=$test', {}, 'pipe');
expect(target).to.be('this=value1|value2');
expect(target).toBe('this=value1|value2');
});
it('should replace $test with piped value', function() {
var target = _templateSrv.replace('this=$test', {}, 'pipe');
expect(target).to.be('this=value1|value2');
expect(target).toBe('this=value1|value2');
});
});
@ -112,7 +95,7 @@ describe('templateSrv', function() {
it('should replace $test with formatted all value', function() {
var target = _templateSrv.replace('this.$test.filters', {}, 'glob');
expect(target).to.be('this.{value1,value2}.filters');
expect(target).toBe('this.{value1,value2}.filters');
});
});
@ -131,12 +114,12 @@ describe('templateSrv', function() {
it('should replace $test with formatted all value', function() {
var target = _templateSrv.replace('this.$test.filters', {}, 'glob');
expect(target).to.be('this.*.filters');
expect(target).toBe('this.*.filters');
});
it('should not escape custom all value', function() {
var target = _templateSrv.replace('this.$test', {}, 'regex');
expect(target).to.be('this.*');
expect(target).toBe('this.*');
});
});
@ -144,49 +127,49 @@ describe('templateSrv', function() {
it('should properly escape $test with lucene escape sequences', function() {
initTemplateSrv([{type: 'query', name: 'test', current: {value: 'value/4' }}]);
var target = _templateSrv.replace('this:$test', {}, 'lucene');
expect(target).to.be("this:value\\\/4");
expect(target).toBe("this:value\\\/4");
});
});
describe('format variable to string values', function() {
it('single value should return value', function() {
var result = _templateSrv.formatValue('test');
expect(result).to.be('test');
expect(result).toBe('test');
});
it('multi value and glob format should render glob string', function() {
var result = _templateSrv.formatValue(['test','test2'], 'glob');
expect(result).to.be('{test,test2}');
expect(result).toBe('{test,test2}');
});
it('multi value and lucene should render as lucene expr', function() {
var result = _templateSrv.formatValue(['test','test2'], 'lucene');
expect(result).to.be('("test" OR "test2")');
expect(result).toBe('("test" OR "test2")');
});
it('multi value and regex format should render regex string', function() {
var result = _templateSrv.formatValue(['test.','test2'], 'regex');
expect(result).to.be('(test\\.|test2)');
expect(result).toBe('(test\\.|test2)');
});
it('multi value and pipe should render pipe string', function() {
var result = _templateSrv.formatValue(['test','test2'], 'pipe');
expect(result).to.be('test|test2');
expect(result).toBe('test|test2');
});
it('multi value and distributed should render distributed string', function() {
var result = _templateSrv.formatValue(['test','test2'], 'distributed', { name: 'build' });
expect(result).to.be('test,build=test2');
expect(result).toBe('test,build=test2');
});
it('multi value and distributed should render when not string', function() {
var result = _templateSrv.formatValue(['test'], 'distributed', { name: 'build' });
expect(result).to.be('test');
expect(result).toBe('test');
});
it('slash should be properly escaped in regex format', function() {
var result = _templateSrv.formatValue('Gi3/14', 'regex');
expect(result).to.be('Gi3\\/14');
expect(result).toBe('Gi3\\/14');
});
});
@ -198,7 +181,7 @@ describe('templateSrv', function() {
it('should return true if exists', function() {
var result = _templateSrv.variableExists('$test');
expect(result).to.be(true);
expect(result).toBe(true);
});
});
@ -209,17 +192,17 @@ describe('templateSrv', function() {
it('should insert html', function() {
var result = _templateSrv.highlightVariablesAsHtml('$test');
expect(result).to.be('<span class="template-variable">$test</span>');
expect(result).toBe('<span class="template-variable">$test</span>');
});
it('should insert html anywhere in string', function() {
var result = _templateSrv.highlightVariablesAsHtml('this $test ok');
expect(result).to.be('this <span class="template-variable">$test</span> ok');
expect(result).toBe('this <span class="template-variable">$test</span> ok');
});
it('should ignore if variables does not exist', function() {
var result = _templateSrv.highlightVariablesAsHtml('this $google ok');
expect(result).to.be('this $google ok');
expect(result).toBe('this $google ok');
});
});
@ -230,19 +213,28 @@ describe('templateSrv', function() {
it('should set current value and update template data', function() {
var target = _templateSrv.replace('this.[[test]].filters');
expect(target).to.be('this.muuuu.filters');
expect(target).toBe('this.muuuu.filters');
});
});
describe('fillVariableValuesForUrl with multi value', function() {
beforeEach(function() {
initTemplateSrv([{type: 'query', name: 'test', current: { value: ['val1', 'val2'] }}]);
initTemplateSrv([
{
type: 'query',
name: 'test',
current: { value: ['val1', 'val2'] },
getValueForUrl: function() {
return this.current.value;
}
}
]);
});
it('should set multiple url params', function() {
var params = {};
_templateSrv.fillVariableValuesForUrl(params);
expect(params['var-test']).to.eql(['val1', 'val2']);
expect(params['var-test']).toMatchObject(['val1', 'val2']);
});
});
@ -254,7 +246,7 @@ describe('templateSrv', function() {
it('should set scoped value as url params', function() {
var params = {};
_templateSrv.fillVariableValuesForUrl(params, {'test': {value: 'val1'}});
expect(params['var-test']).to.eql('val1');
expect(params['var-test']).toBe('val1');
});
});
@ -270,7 +262,7 @@ describe('templateSrv', function() {
it('should replace with text except for grafanaVariables', function() {
var target = _templateSrv.replaceWithText('Server: $server, period: $period');
expect(target).to.be('Server: All, period: 13m');
expect(target).toBe('Server: All, period: 13m');
});
});
@ -281,7 +273,7 @@ describe('templateSrv', function() {
it('should replace $__interval_ms with interval milliseconds', function() {
var target = _templateSrv.replace('10 * $__interval_ms', {"__interval_ms": {text: "100", value: "100"}});
expect(target).to.be('10 * 100');
expect(target).toBe('10 * 100');
});
});

View File

@ -1,253 +0,0 @@
define([
'angular',
'lodash',
'app/core/utils/kbn',
],
function (angular, _, kbn) {
'use strict';
var module = angular.module('grafana.services');
module.service('templateSrv', function() {
var self = this;
this._regex = /\$(\w+)|\[\[([\s\S]+?)\]\]/g;
this._index = {};
this._texts = {};
this._grafanaVariables = {};
// default built ins
this._builtIns = {};
this._builtIns['__interval'] = {text: '1s', value: '1s'};
this._builtIns['__interval_ms'] = {text: '100', value: '100'};
this.init = function(variables) {
this.variables = variables;
this.updateTemplateData();
};
this.updateTemplateData = function() {
this._index = {};
this._filters = {};
for (var i = 0; i < this.variables.length; i++) {
var variable = this.variables[i];
if (!variable.current || !variable.current.isNone && !variable.current.value) {
continue;
}
this._index[variable.name] = variable;
}
};
this.variableInitialized = function(variable) {
this._index[variable.name] = variable;
};
this.getAdhocFilters = function(datasourceName) {
var filters = [];
for (var i = 0; i < this.variables.length; i++) {
var variable = this.variables[i];
if (variable.type !== 'adhoc') {
continue;
}
if (variable.datasource === datasourceName) {
filters = filters.concat(variable.filters);
}
if (variable.datasource.indexOf('$') === 0) {
if (this.replace(variable.datasource) === datasourceName) {
filters = filters.concat(variable.filters);
}
}
}
return filters;
};
function luceneEscape(value) {
return value.replace(/([\!\*\+\-\=<>\s\&\|\(\)\[\]\{\}\^\~\?\:\\/"])/g, "\\$1");
}
this.luceneFormat = function(value) {
if (typeof value === 'string') {
return luceneEscape(value);
}
var quotedValues = _.map(value, function(val) {
return '\"' + luceneEscape(val) + '\"';
});
return '(' + quotedValues.join(' OR ') + ')';
};
this.formatValue = function(value, format, variable) {
// for some scopedVars there is no variable
variable = variable || {};
if (typeof format === 'function') {
return format(value, variable, this.formatValue);
}
switch(format) {
case "regex": {
if (typeof value === 'string') {
return kbn.regexEscape(value);
}
var escapedValues = _.map(value, kbn.regexEscape);
return '(' + escapedValues.join('|') + ')';
}
case "lucene": {
return this.luceneFormat(value, format, variable);
}
case "pipe": {
if (typeof value === 'string') {
return value;
}
return value.join('|');
}
case "distributed": {
if (typeof value === 'string') {
return value;
}
return this.distributeVariable(value, variable.name);
}
default: {
if (_.isArray(value)) {
return '{' + value.join(',') + '}';
}
return value;
}
}
};
this.setGrafanaVariable = function (name, value) {
this._grafanaVariables[name] = value;
};
this.getVariableName = function(expression) {
this._regex.lastIndex = 0;
var match = this._regex.exec(expression);
if (!match) {
return null;
}
return match[1] || match[2];
};
this.variableExists = function(expression) {
var name = this.getVariableName(expression);
return name && (self._index[name] !== void 0);
};
this.highlightVariablesAsHtml = function(str) {
if (!str || !_.isString(str)) { return str; }
str = _.escape(str);
this._regex.lastIndex = 0;
return str.replace(this._regex, function(match, g1, g2) {
if (self._index[g1 || g2] || self._builtIns[g1 || g2]) {
return '<span class="template-variable">' + match + '</span>';
}
return match;
});
};
this.getAllValue = function(variable) {
if (variable.allValue) {
return variable.allValue;
}
var values = [];
for (var i = 1; i < variable.options.length; i++) {
values.push(variable.options[i].value);
}
return values;
};
this.replace = function(target, scopedVars, format) {
if (!target) { return target; }
var variable, systemValue, value;
this._regex.lastIndex = 0;
return target.replace(this._regex, function(match, g1, g2) {
variable = self._index[g1 || g2];
if (scopedVars) {
value = scopedVars[g1 || g2];
if (value) {
return self.formatValue(value.value, format, variable);
}
}
if (!variable) {
return match;
}
systemValue = self._grafanaVariables[variable.current.value];
if (systemValue) {
return self.formatValue(systemValue, format, variable);
}
value = variable.current.value;
if (self.isAllValue(value)) {
value = self.getAllValue(variable);
// skip formating of custom all values
if (variable.allValue) {
return value;
}
}
var res = self.formatValue(value, format, variable);
return res;
});
};
this.isAllValue = function(value) {
return value === '$__all' || Array.isArray(value) && value[0] === '$__all';
};
this.replaceWithText = function(target, scopedVars) {
if (!target) { return target; }
var variable;
this._regex.lastIndex = 0;
return target.replace(this._regex, function(match, g1, g2) {
if (scopedVars) {
var option = scopedVars[g1 || g2];
if (option) { return option.text; }
}
variable = self._index[g1 || g2];
if (!variable) { return match; }
return self._grafanaVariables[variable.current.value] || variable.current.text;
});
};
this.fillVariableValuesForUrl = function(params, scopedVars) {
_.each(this.variables, function(variable) {
if (scopedVars && scopedVars[variable.name] !== void 0) {
params['var-' + variable.name] = scopedVars[variable.name].value;
} else {
params['var-' + variable.name] = variable.getValueForUrl();
}
});
};
this.distributeVariable = function(value, variable) {
value = _.map(value, function(val, index) {
if (index !== 0) {
return variable + "=" + val;
} else {
return val;
}
});
return value.join(',');
};
});
});

View File

@ -0,0 +1,244 @@
import kbn from 'app/core/utils/kbn';
import _ from 'lodash';
function luceneEscape(value) {
return value.replace(/([\!\*\+\-\=<>\s\&\|\(\)\[\]\{\}\^\~\?\:\\/"])/g, "\\$1");
}
export class TemplateSrv {
variables: any[];
private regex = /\$(\w+)|\[\[([\s\S]+?)\]\]/g;
private index = {};
private grafanaVariables = {};
private builtIns = {};
private filters = {};
constructor() {
this.builtIns['__interval'] = {text: '1s', value: '1s'};
this.builtIns['__interval_ms'] = {text: '100', value: '100'};
}
init(variables) {
this.variables = variables;
this.updateTemplateData();
}
updateTemplateData() {
this.index = {};
this.filters = {};
for (var i = 0; i < this.variables.length; i++) {
var variable = this.variables[i];
if (!variable.current || !variable.current.isNone && !variable.current.value) {
continue;
}
this.index[variable.name] = variable;
}
}
variableInitialized(variable) {
this.index[variable.name] = variable;
}
getAdhocFilters(datasourceName) {
var filters = [];
for (var i = 0; i < this.variables.length; i++) {
var variable = this.variables[i];
if (variable.type !== 'adhoc') {
continue;
}
if (variable.datasource === datasourceName) {
filters = filters.concat(variable.filters);
}
if (variable.datasource.indexOf('$') === 0) {
if (this.replace(variable.datasource) === datasourceName) {
filters = filters.concat(variable.filters);
}
}
}
return filters;
}
luceneFormat(value) {
if (typeof value === 'string') {
return luceneEscape(value);
}
var quotedValues = _.map(value, function(val) {
return '\"' + luceneEscape(val) + '\"';
});
return '(' + quotedValues.join(' OR ') + ')';
}
formatValue(value, format, variable) {
// for some scopedVars there is no variable
variable = variable || {};
if (typeof format === 'function') {
return format(value, variable, this.formatValue);
}
switch (format) {
case "regex": {
if (typeof value === 'string') {
return kbn.regexEscape(value);
}
var escapedValues = _.map(value, kbn.regexEscape);
return '(' + escapedValues.join('|') + ')';
}
case "lucene": {
return this.luceneFormat(value);
}
case "pipe": {
if (typeof value === 'string') {
return value;
}
return value.join('|');
}
case "distributed": {
if (typeof value === 'string') {
return value;
}
return this.distributeVariable(value, variable.name);
}
default: {
if (_.isArray(value)) {
return '{' + value.join(',') + '}';
}
return value;
}
}
}
setGrafanaVariable(name, value) {
this.grafanaVariables[name] = value;
}
getVariableName(expression) {
this.regex.lastIndex = 0;
var match = this.regex.exec(expression);
if (!match) {
return null;
}
return match[1] || match[2];
}
variableExists(expression) {
var name = this.getVariableName(expression);
return name && (this.index[name] !== void 0);
}
highlightVariablesAsHtml(str) {
if (!str || !_.isString(str)) { return str; }
str = _.escape(str);
this.regex.lastIndex = 0;
return str.replace(this.regex, (match, g1, g2) => {
if (this.index[g1 || g2] || this.builtIns[g1 || g2]) {
return '<span class="template-variable">' + match + '</span>';
}
return match;
});
}
getAllValue(variable) {
if (variable.allValue) {
return variable.allValue;
}
var values = [];
for (var i = 1; i < variable.options.length; i++) {
values.push(variable.options[i].value);
}
return values;
}
replace(target, scopedVars?, format?) {
if (!target) { return target; }
var variable, systemValue, value;
this.regex.lastIndex = 0;
return target.replace(this.regex, (match, g1, g2) => {
variable = this.index[g1 || g2];
if (scopedVars) {
value = scopedVars[g1 || g2];
if (value) {
return this.formatValue(value.value, format, variable);
}
}
if (!variable) {
return match;
}
systemValue = this.grafanaVariables[variable.current.value];
if (systemValue) {
return this.formatValue(systemValue, format, variable);
}
value = variable.current.value;
if (this.isAllValue(value)) {
value = this.getAllValue(variable);
// skip formating of custom all values
if (variable.allValue) {
return value;
}
}
var res = this.formatValue(value, format, variable);
return res;
});
}
isAllValue(value) {
return value === '$__all' || Array.isArray(value) && value[0] === '$__all';
}
replaceWithText(target, scopedVars) {
if (!target) { return target; }
var variable;
this.regex.lastIndex = 0;
return target.replace(this.regex, (match, g1, g2) => {
if (scopedVars) {
var option = scopedVars[g1 || g2];
if (option) { return option.text; }
}
variable = this.index[g1 || g2];
if (!variable) { return match; }
return this.grafanaVariables[variable.current.value] || variable.current.text;
});
}
fillVariableValuesForUrl(params, scopedVars) {
_.each(this.variables, function(variable) {
if (scopedVars && scopedVars[variable.name] !== void 0) {
params['var-' + variable.name] = scopedVars[variable.name].value;
} else {
params['var-' + variable.name] = variable.getValueForUrl();
}
});
}
distributeVariable(value, variable) {
value = _.map(value, function(val, index) {
if (index !== 0) {
return variable + "=" + val;
} else {
return val;
}
});
return value.join(',');
}
}

View File

@ -1,7 +1,5 @@
///<reference path="../../headers/common.d.ts" />
import kbn from 'app/core/utils/kbn';
import {assignModelProperties} from 'app/core/core';
import {assignModelProperties} from 'app/core/utils/model_utils';
export interface Variable {
setValue(option);

View File

@ -9,6 +9,8 @@ define([
function (angular, _, moment, dateMath, kbn, templatingVariable) {
'use strict';
kbn = kbn.default;
/** @ngInject */
function CloudWatchDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv) {
this.type = 'cloudwatch';
@ -354,6 +356,7 @@ function (angular, _, moment, dateMath, kbn, templatingVariable) {
var t = angular.copy(target);
var scopedVar = {};
scopedVar[variable.name] = v;
t.refId = target.refId + '_' + v.value;
t.dimensions[dimensionKey] = templateSrv.replace(t.dimensions[dimensionKey], scopedVar);
return t;
}).value();

View File

@ -75,6 +75,12 @@ export class ElasticDatasource {
return this.request('POST', url, data).then(function(results) {
results.data.$$config = results.config;
return results.data;
}).catch(err => {
if (err.data && err.data.error) {
throw {message: 'Elasticsearch error: ' + err.data.error.reason, error: err.data.error};
}
throw err;
});
}

View File

@ -7,6 +7,8 @@ define([
function (angular, _, $, gfunc) {
'use strict';
gfunc = gfunc.default;
angular
.module('grafana.directives')
.directive('graphiteAddFunc', function($compile) {

View File

@ -1,2 +0,0 @@
declare var test: any;
export default test;

View File

@ -1,986 +0,0 @@
define([
'lodash',
'jquery'
],
function (_, $) {
'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 isVersionGreaterOrEqual(graphiteVersion, func.version) || !func.version;
}
function isVersionGreaterOrEqual(a, b) {
var a_num = Number(a);
var b_num = Number(b);
return a_num >= b_num;
}
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

View File

@ -1,25 +1,23 @@
import {describe, it, expect} from 'test/lib/common';
import gfunc from '../gfunc';
describe('when creating func instance from func names', function() {
it('should return func instance', function() {
var func = gfunc.createFuncInstance('sumSeries');
expect(func).to.be.ok();
expect(func.def.name).to.equal('sumSeries');
expect(func.def.params.length).to.equal(5);
expect(func.def.defaultParams.length).to.equal(1);
expect(func).toBeTruthy();
expect(func.def.name).toEqual('sumSeries');
expect(func.def.params.length).toEqual(5);
expect(func.def.defaultParams.length).toEqual(1);
});
it('should return func instance with shortName', function() {
var func = gfunc.createFuncInstance('sum');
expect(func).to.be.ok();
expect(func).toBeTruthy();
});
it('should return func instance from funcDef', function() {
var func = gfunc.createFuncInstance('sum');
var func2 = gfunc.createFuncInstance(func.def);
expect(func2).to.be.ok();
expect(func2).toBeTruthy();
});
it('func instance should have text representation', function() {
@ -27,7 +25,7 @@ describe('when creating func instance from func names', function() {
func.params[0] = 5;
func.params[1] = 'avg';
func.updateText();
expect(func.text).to.equal("groupByNode(5, avg)");
expect(func.text).toEqual("groupByNode(5, avg)");
});
});
@ -35,51 +33,51 @@ describe('when rendering func instance', function() {
it('should handle single metric param', function() {
var func = gfunc.createFuncInstance('sumSeries');
expect(func.render('hello.metric')).to.equal("sumSeries(hello.metric)");
expect(func.render('hello.metric')).toEqual("sumSeries(hello.metric)");
});
it('should include default params if options enable it', function() {
var func = gfunc.createFuncInstance('scaleToSeconds', { withDefaultParams: true });
expect(func.render('hello')).to.equal("scaleToSeconds(hello, 1)");
expect(func.render('hello')).toEqual("scaleToSeconds(hello, 1)");
});
it('should handle int or interval params with number', function() {
var func = gfunc.createFuncInstance('movingMedian');
func.params[0] = '5';
expect(func.render('hello')).to.equal("movingMedian(hello, 5)");
expect(func.render('hello')).toEqual("movingMedian(hello, 5)");
});
it('should handle int or interval params with interval string', function() {
var func = gfunc.createFuncInstance('movingMedian');
func.params[0] = '5min';
expect(func.render('hello')).to.equal("movingMedian(hello, '5min')");
expect(func.render('hello')).toEqual("movingMedian(hello, '5min')");
});
it('should handle metric param and int param and string param', function() {
var func = gfunc.createFuncInstance('groupByNode');
func.params[0] = 5;
func.params[1] = 'avg';
expect(func.render('hello.metric')).to.equal("groupByNode(hello.metric, 5, 'avg')");
expect(func.render('hello.metric')).toEqual("groupByNode(hello.metric, 5, 'avg')");
});
it('should handle function with no metric param', function() {
var func = gfunc.createFuncInstance('randomWalk');
func.params[0] = 'test';
expect(func.render(undefined)).to.equal("randomWalk('test')");
expect(func.render(undefined)).toEqual("randomWalk('test')");
});
it('should handle function multiple series params', function() {
var func = gfunc.createFuncInstance('asPercent');
func.params[0] = '#B';
expect(func.render('#A')).to.equal("asPercent(#A, #B)");
expect(func.render('#A')).toEqual("asPercent(#A, #B)");
});
});
describe('when requesting function categories', function() {
it('should return function categories', function() {
var catIndex = gfunc.getCategories();
expect(catIndex.Special.length).to.be.greaterThan(8);
var catIndex = gfunc.getCategories('1.0');
expect(catIndex.Special.length).toBeGreaterThan(8);
});
});
@ -87,14 +85,14 @@ describe('when updating func param', function() {
it('should update param value and update text representation', function() {
var func = gfunc.createFuncInstance('summarize', { withDefaultParams: true });
func.updateParam('1h', 0);
expect(func.params[0]).to.be('1h');
expect(func.text).to.be('summarize(1h, sum, false)');
expect(func.params[0]).toBe('1h');
expect(func.text).toBe('summarize(1h, sum, false)');
});
it('should parse numbers as float', function() {
var func = gfunc.createFuncInstance('scale');
func.updateParam('0.001', 0);
expect(func.params[0]).to.be('0.001');
expect(func.params[0]).toBe('0.001');
});
});
@ -102,24 +100,24 @@ describe('when updating func param with optional second parameter', function() {
it('should update value and text', function() {
var func = gfunc.createFuncInstance('aliasByNode');
func.updateParam('1', 0);
expect(func.params[0]).to.be('1');
expect(func.params[0]).toBe('1');
});
it('should slit text and put value in second param', function() {
var func = gfunc.createFuncInstance('aliasByNode');
func.updateParam('4,-5', 0);
expect(func.params[0]).to.be('4');
expect(func.params[1]).to.be('-5');
expect(func.text).to.be('aliasByNode(4, -5)');
expect(func.params[0]).toBe('4');
expect(func.params[1]).toBe('-5');
expect(func.text).toBe('aliasByNode(4, -5)');
});
it('should remove second param when empty string is set', function() {
var func = gfunc.createFuncInstance('aliasByNode');
func.updateParam('4,-5', 0);
func.updateParam('', 1);
expect(func.params[0]).to.be('4');
expect(func.params[1]).to.be(undefined);
expect(func.text).to.be('aliasByNode(4)');
expect(func.params[0]).toBe('4');
expect(func.params[1]).toBe(undefined);
expect(func.text).toBe('aliasByNode(4)');
});
});

View File

@ -1,5 +1,3 @@
import {describe, it, expect} from 'test/lib/common';
import {Lexer} from '../lexer';
describe('when lexing graphite expression', function() {
@ -7,120 +5,120 @@ describe('when lexing graphite expression', function() {
it('should tokenize metric expression', function() {
var lexer = new Lexer('metric.test.*.asd.count');
var tokens = lexer.tokenize();
expect(tokens[0].value).to.be('metric');
expect(tokens[1].value).to.be('.');
expect(tokens[2].type).to.be('identifier');
expect(tokens[4].type).to.be('identifier');
expect(tokens[4].pos).to.be(13);
expect(tokens[0].value).toBe('metric');
expect(tokens[1].value).toBe('.');
expect(tokens[2].type).toBe('identifier');
expect(tokens[4].type).toBe('identifier');
expect(tokens[4].pos).toBe(13);
});
it('should tokenize metric expression with dash', function() {
var lexer = new Lexer('metric.test.se1-server-*.asd.count');
var tokens = lexer.tokenize();
expect(tokens[4].type).to.be('identifier');
expect(tokens[4].value).to.be('se1-server-*');
expect(tokens[4].type).toBe('identifier');
expect(tokens[4].value).toBe('se1-server-*');
});
it('should tokenize metric expression with dash2', function() {
var lexer = new Lexer('net.192-168-1-1.192-168-1-9.ping_value.*');
var tokens = lexer.tokenize();
expect(tokens[0].value).to.be('net');
expect(tokens[2].value).to.be('192-168-1-1');
expect(tokens[0].value).toBe('net');
expect(tokens[2].value).toBe('192-168-1-1');
});
it('should tokenize metric expression with equal sign', function() {
var lexer = new Lexer('apps=test');
var tokens = lexer.tokenize();
expect(tokens[0].value).to.be('apps=test');
expect(tokens[0].value).toBe('apps=test');
});
it('simple function2', function() {
var lexer = new Lexer('offset(test.metric, -100)');
var tokens = lexer.tokenize();
expect(tokens[2].type).to.be('identifier');
expect(tokens[4].type).to.be('identifier');
expect(tokens[6].type).to.be('number');
expect(tokens[2].type).toBe('identifier');
expect(tokens[4].type).toBe('identifier');
expect(tokens[6].type).toBe('number');
});
it('should tokenize metric expression with curly braces', function() {
var lexer = new Lexer('metric.se1-{first, second}.count');
var tokens = lexer.tokenize();
expect(tokens.length).to.be(10);
expect(tokens[3].type).to.be('{');
expect(tokens[4].value).to.be('first');
expect(tokens[5].value).to.be(',');
expect(tokens[6].value).to.be('second');
expect(tokens.length).toBe(10);
expect(tokens[3].type).toBe('{');
expect(tokens[4].value).toBe('first');
expect(tokens[5].value).toBe(',');
expect(tokens[6].value).toBe('second');
});
it('should tokenize metric expression with number segments', function() {
var lexer = new Lexer("metric.10.12_10.test");
var tokens = lexer.tokenize();
expect(tokens[0].type).to.be('identifier');
expect(tokens[2].type).to.be('identifier');
expect(tokens[2].value).to.be('10');
expect(tokens[4].value).to.be('12_10');
expect(tokens[4].type).to.be('identifier');
expect(tokens[0].type).toBe('identifier');
expect(tokens[2].type).toBe('identifier');
expect(tokens[2].value).toBe('10');
expect(tokens[4].value).toBe('12_10');
expect(tokens[4].type).toBe('identifier');
});
it('should tokenize metric expression with segment that start with number', function() {
var lexer = new Lexer("metric.001-server");
var tokens = lexer.tokenize();
expect(tokens[0].type).to.be('identifier');
expect(tokens[2].type).to.be('identifier');
expect(tokens.length).to.be(3);
expect(tokens[0].type).toBe('identifier');
expect(tokens[2].type).toBe('identifier');
expect(tokens.length).toBe(3);
});
it('should tokenize func call with numbered metric and number arg', function() {
var lexer = new Lexer("scale(metric.10, 15)");
var tokens = lexer.tokenize();
expect(tokens[0].type).to.be('identifier');
expect(tokens[2].type).to.be('identifier');
expect(tokens[2].value).to.be('metric');
expect(tokens[4].value).to.be('10');
expect(tokens[4].type).to.be('number');
expect(tokens[6].type).to.be('number');
expect(tokens[0].type).toBe('identifier');
expect(tokens[2].type).toBe('identifier');
expect(tokens[2].value).toBe('metric');
expect(tokens[4].value).toBe('10');
expect(tokens[4].type).toBe('number');
expect(tokens[6].type).toBe('number');
});
it('should tokenize metric with template parameter', function() {
var lexer = new Lexer("metric.[[server]].test");
var tokens = lexer.tokenize();
expect(tokens[2].type).to.be('identifier');
expect(tokens[2].value).to.be('[[server]]');
expect(tokens[4].type).to.be('identifier');
expect(tokens[2].type).toBe('identifier');
expect(tokens[2].value).toBe('[[server]]');
expect(tokens[4].type).toBe('identifier');
});
it('should tokenize metric with question mark', function() {
var lexer = new Lexer("metric.server_??.test");
var tokens = lexer.tokenize();
expect(tokens[2].type).to.be('identifier');
expect(tokens[2].value).to.be('server_??');
expect(tokens[4].type).to.be('identifier');
expect(tokens[2].type).toBe('identifier');
expect(tokens[2].value).toBe('server_??');
expect(tokens[4].type).toBe('identifier');
});
it('should handle error with unterminated string', function() {
var lexer = new Lexer("alias(metric, 'asd)");
var tokens = lexer.tokenize();
expect(tokens[0].value).to.be('alias');
expect(tokens[1].value).to.be('(');
expect(tokens[2].value).to.be('metric');
expect(tokens[3].value).to.be(',');
expect(tokens[4].type).to.be('string');
expect(tokens[4].isUnclosed).to.be(true);
expect(tokens[4].pos).to.be(20);
expect(tokens[0].value).toBe('alias');
expect(tokens[1].value).toBe('(');
expect(tokens[2].value).toBe('metric');
expect(tokens[3].value).toBe(',');
expect(tokens[4].type).toBe('string');
expect(tokens[4].isUnclosed).toBe(true);
expect(tokens[4].pos).toBe(20);
});
it('should handle float parameters', function() {
var lexer = new Lexer("alias(metric, 0.002)");
var tokens = lexer.tokenize();
expect(tokens[4].type).to.be('number');
expect(tokens[4].value).to.be('0.002');
expect(tokens[4].type).toBe('number');
expect(tokens[4].value).toBe('0.002');
});
it('should handle bool parameters', function() {
var lexer = new Lexer("alias(metric, true, false)");
var tokens = lexer.tokenize();
expect(tokens[4].type).to.be('bool');
expect(tokens[4].value).to.be('true');
expect(tokens[6].type).to.be('bool');
expect(tokens[4].type).toBe('bool');
expect(tokens[4].value).toBe('true');
expect(tokens[6].type).toBe('bool');
});
});

View File

@ -0,0 +1,182 @@
import {Parser} from '../parser';
describe('when parsing', function() {
it('simple metric expression', function() {
var parser = new Parser('metric.test.*.asd.count');
var rootNode = parser.getAst();
expect(rootNode.type).toBe('metric');
expect(rootNode.segments.length).toBe(5);
expect(rootNode.segments[0].value).toBe('metric');
});
it('simple metric expression with numbers in segments', function() {
var parser = new Parser('metric.10.15_20.5');
var rootNode = parser.getAst();
expect(rootNode.type).toBe('metric');
expect(rootNode.segments.length).toBe(4);
expect(rootNode.segments[1].value).toBe('10');
expect(rootNode.segments[2].value).toBe('15_20');
expect(rootNode.segments[3].value).toBe('5');
});
it('simple metric expression with curly braces', function() {
var parser = new Parser('metric.se1-{count, max}');
var rootNode = parser.getAst();
expect(rootNode.type).toBe('metric');
expect(rootNode.segments.length).toBe(2);
expect(rootNode.segments[1].value).toBe('se1-{count,max}');
});
it('simple metric expression with curly braces at start of segment and with post chars', function() {
var parser = new Parser('metric.{count, max}-something.count');
var rootNode = parser.getAst();
expect(rootNode.type).toBe('metric');
expect(rootNode.segments.length).toBe(3);
expect(rootNode.segments[1].value).toBe('{count,max}-something');
});
it('simple function', function() {
var parser = new Parser('sum(test)');
var rootNode = parser.getAst();
expect(rootNode.type).toBe('function');
expect(rootNode.params.length).toBe(1);
});
it('simple function2', function() {
var parser = new Parser('offset(test.metric, -100)');
var rootNode = parser.getAst();
expect(rootNode.type).toBe('function');
expect(rootNode.params[0].type).toBe('metric');
expect(rootNode.params[1].type).toBe('number');
});
it('simple function with string arg', function() {
var parser = new Parser("randomWalk('test')");
var rootNode = parser.getAst();
expect(rootNode.type).toBe('function');
expect(rootNode.params.length).toBe(1);
expect(rootNode.params[0].type).toBe('string');
});
it('function with multiple args', function() {
var parser = new Parser("sum(test, 1, 'test')");
var rootNode = parser.getAst();
expect(rootNode.type).toBe('function');
expect(rootNode.params.length).toBe(3);
expect(rootNode.params[0].type).toBe('metric');
expect(rootNode.params[1].type).toBe('number');
expect(rootNode.params[2].type).toBe('string');
});
it('function with nested function', function() {
var parser = new Parser("sum(scaleToSeconds(test, 1))");
var rootNode = parser.getAst();
expect(rootNode.type).toBe('function');
expect(rootNode.params.length).toBe(1);
expect(rootNode.params[0].type).toBe('function');
expect(rootNode.params[0].name).toBe('scaleToSeconds');
expect(rootNode.params[0].params.length).toBe(2);
expect(rootNode.params[0].params[0].type).toBe('metric');
expect(rootNode.params[0].params[1].type).toBe('number');
});
it('function with multiple series', function() {
var parser = new Parser("sum(test.test.*.count, test.timers.*.count)");
var rootNode = parser.getAst();
expect(rootNode.type).toBe('function');
expect(rootNode.params.length).toBe(2);
expect(rootNode.params[0].type).toBe('metric');
expect(rootNode.params[1].type).toBe('metric');
});
it('function with templated series', function() {
var parser = new Parser("sum(test.[[server]].count)");
var rootNode = parser.getAst();
expect(rootNode.message).toBe(undefined);
expect(rootNode.params[0].type).toBe('metric');
expect(rootNode.params[0].segments[1].type).toBe('segment');
expect(rootNode.params[0].segments[1].value).toBe('[[server]]');
});
it('invalid metric expression', function() {
var parser = new Parser('metric.test.*.asd.');
var rootNode = parser.getAst();
expect(rootNode.message).toBe('Expected metric identifier instead found end of string');
expect(rootNode.pos).toBe(19);
});
it('invalid function expression missing closing parenthesis', function() {
var parser = new Parser('sum(test');
var rootNode = parser.getAst();
expect(rootNode.message).toBe('Expected closing parenthesis instead found end of string');
expect(rootNode.pos).toBe(9);
});
it('unclosed string in function', function() {
var parser = new Parser("sum('test)");
var rootNode = parser.getAst();
expect(rootNode.message).toBe('Unclosed string parameter');
expect(rootNode.pos).toBe(11);
});
it('handle issue #69', function() {
var parser = new Parser('cactiStyle(offset(scale(net.192-168-1-1.192-168-1-9.ping_value.*,0.001),-100))');
var rootNode = parser.getAst();
expect(rootNode.type).toBe('function');
});
it('handle float function arguments', function() {
var parser = new Parser('scale(test, 0.002)');
var rootNode = parser.getAst();
expect(rootNode.type).toBe('function');
expect(rootNode.params[1].type).toBe('number');
expect(rootNode.params[1].value).toBe(0.002);
});
it('handle curly brace pattern at start', function() {
var parser = new Parser('{apps}.test');
var rootNode = parser.getAst();
expect(rootNode.type).toBe('metric');
expect(rootNode.segments[0].value).toBe('{apps}');
expect(rootNode.segments[1].value).toBe('test');
});
it('series parameters', function() {
var parser = new Parser('asPercent(#A, #B)');
var rootNode = parser.getAst();
expect(rootNode.type).toBe('function');
expect(rootNode.params[0].type).toBe('series-ref');
expect(rootNode.params[0].value).toBe('#A');
expect(rootNode.params[1].value).toBe('#B');
});
it('series parameters, issue 2788', function() {
var parser = new Parser("summarize(diffSeries(#A, #B), '10m', 'sum', false)");
var rootNode = parser.getAst();
expect(rootNode.type).toBe('function');
expect(rootNode.params[0].type).toBe('function');
expect(rootNode.params[1].value).toBe('10m');
expect(rootNode.params[3].type).toBe('bool');
});
it('should parse metric expression with ip number segments', function() {
var parser = new Parser('5.10.123.5');
var rootNode = parser.getAst();
expect(rootNode.segments[0].value).toBe('5');
expect(rootNode.segments[1].value).toBe('10');
expect(rootNode.segments[2].value).toBe('123');
expect(rootNode.segments[3].value).toBe('5');
});
});

View File

@ -1,183 +0,0 @@
import {describe, it, expect} from 'test/lib/common';
import {Parser} from '../parser';
describe('when parsing', function() {
it('simple metric expression', function() {
var parser = new Parser('metric.test.*.asd.count');
var rootNode = parser.getAst();
expect(rootNode.type).to.be('metric');
expect(rootNode.segments.length).to.be(5);
expect(rootNode.segments[0].value).to.be('metric');
});
it('simple metric expression with numbers in segments', function() {
var parser = new Parser('metric.10.15_20.5');
var rootNode = parser.getAst();
expect(rootNode.type).to.be('metric');
expect(rootNode.segments.length).to.be(4);
expect(rootNode.segments[1].value).to.be('10');
expect(rootNode.segments[2].value).to.be('15_20');
expect(rootNode.segments[3].value).to.be('5');
});
it('simple metric expression with curly braces', function() {
var parser = new Parser('metric.se1-{count, max}');
var rootNode = parser.getAst();
expect(rootNode.type).to.be('metric');
expect(rootNode.segments.length).to.be(2);
expect(rootNode.segments[1].value).to.be('se1-{count,max}');
});
it('simple metric expression with curly braces at start of segment and with post chars', function() {
var parser = new Parser('metric.{count, max}-something.count');
var rootNode = parser.getAst();
expect(rootNode.type).to.be('metric');
expect(rootNode.segments.length).to.be(3);
expect(rootNode.segments[1].value).to.be('{count,max}-something');
});
it('simple function', function() {
var parser = new Parser('sum(test)');
var rootNode = parser.getAst();
expect(rootNode.type).to.be('function');
expect(rootNode.params.length).to.be(1);
});
it('simple function2', function() {
var parser = new Parser('offset(test.metric, -100)');
var rootNode = parser.getAst();
expect(rootNode.type).to.be('function');
expect(rootNode.params[0].type).to.be('metric');
expect(rootNode.params[1].type).to.be('number');
});
it('simple function with string arg', function() {
var parser = new Parser("randomWalk('test')");
var rootNode = parser.getAst();
expect(rootNode.type).to.be('function');
expect(rootNode.params.length).to.be(1);
expect(rootNode.params[0].type).to.be('string');
});
it('function with multiple args', function() {
var parser = new Parser("sum(test, 1, 'test')");
var rootNode = parser.getAst();
expect(rootNode.type).to.be('function');
expect(rootNode.params.length).to.be(3);
expect(rootNode.params[0].type).to.be('metric');
expect(rootNode.params[1].type).to.be('number');
expect(rootNode.params[2].type).to.be('string');
});
it('function with nested function', function() {
var parser = new Parser("sum(scaleToSeconds(test, 1))");
var rootNode = parser.getAst();
expect(rootNode.type).to.be('function');
expect(rootNode.params.length).to.be(1);
expect(rootNode.params[0].type).to.be('function');
expect(rootNode.params[0].name).to.be('scaleToSeconds');
expect(rootNode.params[0].params.length).to.be(2);
expect(rootNode.params[0].params[0].type).to.be('metric');
expect(rootNode.params[0].params[1].type).to.be('number');
});
it('function with multiple series', function() {
var parser = new Parser("sum(test.test.*.count, test.timers.*.count)");
var rootNode = parser.getAst();
expect(rootNode.type).to.be('function');
expect(rootNode.params.length).to.be(2);
expect(rootNode.params[0].type).to.be('metric');
expect(rootNode.params[1].type).to.be('metric');
});
it('function with templated series', function() {
var parser = new Parser("sum(test.[[server]].count)");
var rootNode = parser.getAst();
expect(rootNode.message).to.be(undefined);
expect(rootNode.params[0].type).to.be('metric');
expect(rootNode.params[0].segments[1].type).to.be('segment');
expect(rootNode.params[0].segments[1].value).to.be('[[server]]');
});
it('invalid metric expression', function() {
var parser = new Parser('metric.test.*.asd.');
var rootNode = parser.getAst();
expect(rootNode.message).to.be('Expected metric identifier instead found end of string');
expect(rootNode.pos).to.be(19);
});
it('invalid function expression missing closing parenthesis', function() {
var parser = new Parser('sum(test');
var rootNode = parser.getAst();
expect(rootNode.message).to.be('Expected closing parenthesis instead found end of string');
expect(rootNode.pos).to.be(9);
});
it('unclosed string in function', function() {
var parser = new Parser("sum('test)");
var rootNode = parser.getAst();
expect(rootNode.message).to.be('Unclosed string parameter');
expect(rootNode.pos).to.be(11);
});
it('handle issue #69', function() {
var parser = new Parser('cactiStyle(offset(scale(net.192-168-1-1.192-168-1-9.ping_value.*,0.001),-100))');
var rootNode = parser.getAst();
expect(rootNode.type).to.be('function');
});
it('handle float function arguments', function() {
var parser = new Parser('scale(test, 0.002)');
var rootNode = parser.getAst();
expect(rootNode.type).to.be('function');
expect(rootNode.params[1].type).to.be('number');
expect(rootNode.params[1].value).to.be(0.002);
});
it('handle curly brace pattern at start', function() {
var parser = new Parser('{apps}.test');
var rootNode = parser.getAst();
expect(rootNode.type).to.be('metric');
expect(rootNode.segments[0].value).to.be('{apps}');
expect(rootNode.segments[1].value).to.be('test');
});
it('series parameters', function() {
var parser = new Parser('asPercent(#A, #B)');
var rootNode = parser.getAst();
expect(rootNode.type).to.be('function');
expect(rootNode.params[0].type).to.be('series-ref');
expect(rootNode.params[0].value).to.be('#A');
expect(rootNode.params[1].value).to.be('#B');
});
it('series parameters, issue 2788', function() {
var parser = new Parser("summarize(diffSeries(#A, #B), '10m', 'sum', false)");
var rootNode = parser.getAst();
expect(rootNode.type).to.be('function');
expect(rootNode.params[0].type).to.be('function');
expect(rootNode.params[1].value).to.be('10m');
expect(rootNode.params[3].type).to.be('bool');
});
it('should parse metric expression with ip number segments', function() {
var parser = new Parser('5.10.123.5');
var rootNode = parser.getAst();
expect(rootNode.segments[0].value).to.be('5');
expect(rootNode.segments[1].value).to.be('10');
expect(rootNode.segments[2].value).to.be('123');
expect(rootNode.segments[3].value).to.be('5');
});
});

View File

@ -20,6 +20,10 @@ export class PostgresDatasource {
return '\'' + value + '\'';
}
if (typeof value === 'number') {
return value.toString();
}
var quotedValues = _.map(value, function(val) {
return '\'' + val + '\'';
});

View File

@ -16,8 +16,8 @@ class PostgresConfigCtrl {
const defaultQuery = `SELECT
extract(epoch from time_column) AS time,
title_column as title,
description_column as text
text_column as text,
tags_column as tags
FROM
metric_table
WHERE

View File

@ -8,7 +8,7 @@ export class PromCompleter {
labelNameCache: any;
labelValueCache: any;
identifierRegexps = [/[\[\]a-zA-Z_0-9=]/];
identifierRegexps = [/\[/, /[a-zA-Z0-9_:]/];
constructor(private datasource: PrometheusDatasource) {
this.labelQueryCache = {};
@ -73,13 +73,15 @@ export class PromCompleter {
});
}
if (prefix === '[') {
if (token.type === 'paren.lparen' && token.value === '[') {
var vectors = [];
for (let unit of ['s', 'm', 'h']) {
for (let value of [1,5,10,30]) {
vectors.push({caption: value+unit, value: '['+value+unit, meta: 'range vector'});
}
}
vectors.push({caption: '$__interval', value: '[$__interval', meta: 'range vector'});
vectors.push({caption: '$__interval_ms', value: '[$__interval_ms', meta: 'range vector'});
callback(null, vectors);
return;
}

View File

@ -168,7 +168,7 @@ export class PrometheusDatasource {
if (interval !== 0 && range / intervalFactor / interval > 11000) {
interval = Math.ceil(range / intervalFactor / 11000);
}
return Math.max(interval * intervalFactor, minInterval);
return Math.max(interval * intervalFactor, minInterval, 1);
}
performTimeSeriesQuery(query, start, end) {

View File

@ -43,10 +43,10 @@ var PrometheusHighlightRules = function() {
regex : "\\d+[smhdwy]"
}, {
token : keywordMapper,
regex : "[a-zA-Z_$][a-zA-Z0-9_$]*\\b"
regex : "[a-zA-Z_:][a-zA-Z0-9_:]*"
}, {
token : "keyword.operator",
regex : "\\+|\\-|\\*|\\/|%|\\^|=|==|!=|<=|>=|<|>|=\\~|!\\~"
regex : "\\+|\\-|\\*|\\/|%|\\^|==|!=|<=|>=|<|>"
}, {
token : "paren.lparen",
regex : "[[(]"
@ -75,8 +75,7 @@ var PrometheusHighlightRules = function() {
regex : '"[^"]*"|\'[^\']*\''
}, {
token : "punctuation.operator",
regex : ",",
push : 'start-label-matcher'
regex : ","
}, {
token : "paren.rparen",
regex : "}",
@ -112,11 +111,6 @@ var keyWordsCompletions = prometheusKeyWords.map(function(word) {
});
var prometheusFunctions = [
{
name: 'abs()', value: 'abs',
def: 'abs(v instant-vector)',
docText: 'Returns the input vector with all sample values converted to their absolute value.'
},
{
name: 'abs()', value: 'abs',
def: 'abs(v instant-vector)',

View File

@ -44,12 +44,18 @@ describe('Prometheus editor completer', function() {
describe('When inside brackets', () => {
it('Should return range vectors', () => {
const session = getSessionStub({
currentToken: {},
tokens: [],
line: '',
currentToken: {type: 'paren.lparen', value: '[', index: 2, start: 9},
tokens: [
{type: 'identifier', value: 'node_cpu'},
{type: 'paren.lparen', value: '['}
],
line: 'node_cpu[',
});
completer.getCompletions(editor, session, {row: 0, column: 10}, '[', (s, res) => {
expect(res[0]).to.eql({caption: '1s', value: '[1s', meta: 'range vector'});
return completer.getCompletions(editor, session, {row: 0, column: 10}, '[', (s, res) => {
expect(res[0].caption).to.eql('1s');
expect(res[0].value).to.eql('[1s');
expect(res[0].meta).to.eql('range vector');
});
});
});

View File

@ -294,6 +294,20 @@ describe('PrometheusDatasource', function() {
ctx.ds.query(query);
ctx.$httpBackend.verifyNoOutstandingExpectation();
});
it('step should never go below 1', function() {
var query = {
// 6 hour range
range: { from: moment(1508318768202), to: moment(1508318770118) },
targets: [{expr: 'test'}],
interval: '100ms'
};
var urlExpected = 'proxied/api/v1/query_range?query=test&start=1508318769&end=1508318771&step=1';
ctx.$httpBackend.expect('GET', urlExpected).respond(response);
ctx.ds.query(query);
ctx.$httpBackend.verifyNoOutstandingExpectation();
});
it('should be auto interval when greater than min interval', function() {
var query = {
// 6 hour range

View File

@ -34,7 +34,7 @@ class GettingStartedPanelCtrl extends PanelCtrl {
check: () => {
return $q.when(
datasourceSrv.getMetricSources().filter(item => {
return item.meta.builtIn === false;
return item.meta.builtIn !== true;
}).length > 0
);
}

View File

@ -343,7 +343,7 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
eventManager.addFlotEvents(annotations, options);
configureAxisOptions(data, options);
sortedSeries = _.sortBy(data, function(series) { return series.zindex; });
sortedSeries = sortSeries(data, ctrl.panel);
function callPlot(incrementRenderCounter) {
try {
@ -374,6 +374,41 @@ function graphDirective($rootScope, timeSrv, popoverSrv, contextSrv) {
}
}
function sortSeries(series, panel) {
var sortBy = panel.legend.sort;
var sortOrder = panel.legend.sortDesc;
var haveSortBy = sortBy !== null || sortBy !== undefined;
var haveSortOrder = sortOrder !== null || sortOrder !== undefined;
if (panel.stack && haveSortBy && haveSortOrder) {
var desc = desc = panel.legend.sortDesc === true ? 1 : -1;
series.sort((x, y) => {
if (x.stats[sortBy] > y.stats[sortBy]) {
return 1 * desc;
}
if (x.stats[sortBy] < y.stats[sortBy]) {
return -1 * desc;
}
return 0;
});
}
series.sort((x, y) => {
if (x.zindex > y.zindex) {
return 1;
}
if (x.zindex < y.zindex) {
return -1;
}
return 0;
});
return series;
}
function translateFillOption(fill) {
if (panel.percentage && panel.stack) {
return fill === 0 ? 0.001 : fill/10;

View File

@ -80,13 +80,13 @@ function (angular, _, $) {
if (panel.legend.sortDesc === false) {
panel.legend.sort = null;
panel.legend.sortDesc = null;
render();
ctrl.render();
return;
}
panel.legend.sortDesc = !panel.legend.sortDesc;
panel.legend.sort = stat;
render();
ctrl.render();
}
function getTableHeaderHtml(statName) {

View File

@ -15,16 +15,16 @@ describe('grafanaGraph', function() {
beforeEach(angularMocks.module('grafana.core'));
function graphScenario(desc, func, elementWidth = 500) {
describe(desc, function() {
describe(desc, () => {
var ctx: any = {};
ctx.setup = function(setupFunc) {
ctx.setup = (setupFunc) => {
beforeEach(angularMocks.module(function($provide) {
beforeEach(angularMocks.module(($provide) => {
$provide.value("timeSrv", new helpers.TimeSrvStub());
}));
beforeEach(angularMocks.inject(function($rootScope, $compile) {
beforeEach(angularMocks.inject(($rootScope, $compile) => {
var ctrl: any = {
height: 200,
panel: {
@ -75,7 +75,7 @@ describe('grafanaGraph', function() {
alias: 'series1'
}));
ctx.data.push(new TimeSeries({
datapoints: [[1,1],[2,2]],
datapoints: [[1,10],[2,20]],
alias: 'series2'
}));
@ -96,15 +96,15 @@ describe('grafanaGraph', function() {
});
}
graphScenario('simple lines options', function(ctx) {
ctx.setup(function(ctrl) {
graphScenario('simple lines options', (ctx) => {
ctx.setup((ctrl) => {
ctrl.panel.lines = true;
ctrl.panel.fill = 5;
ctrl.panel.linewidth = 3;
ctrl.panel.steppedLine = true;
});
it('should configure plot with correct options', function() {
it('should configure plot with correct options', () => {
expect(ctx.plotOptions.series.lines.show).to.be(true);
expect(ctx.plotOptions.series.lines.fill).to.be(0.5);
expect(ctx.plotOptions.series.lines.lineWidth).to.be(3);
@ -112,6 +112,55 @@ describe('grafanaGraph', function() {
});
});
graphScenario('sort series as legend', (ctx) => {
describe("with sort as legend undefined", () => {
ctx.setup((ctrl) => {
ctrl.panel.legend.sort = undefined;
});
it("should not modify order of time series", () => {
expect(ctx.plotData[0].alias).to.be('series1');
expect(ctx.plotData[1].alias).to.be('series2');
});
});
describe("with sort as legend set to min. descending order", () => {
ctx.setup((ctrl) => {
ctrl.panel.legend.sort = 'min';
ctrl.panel.legend.sortDesc = true;
});
it("highest value should be first", () => {
expect(ctx.plotData[1].alias).to.be('series2');
expect(ctx.plotData[0].alias).to.be('series1');
});
});
describe("with sort as legend set to min. ascending order", () => {
ctx.setup((ctrl) => {
ctrl.panel.legend.sort = 'min';
ctrl.panel.legend.sortDesc = true;
});
it("lowest value should be first", () => {
expect(ctx.plotData[0].alias).to.be('series1');
expect(ctx.plotData[1].alias).to.be('series2');
});
});
describe("with sort as legend set to current. ascending order", () => {
ctx.setup((ctrl) => {
ctrl.panel.legend.sort = 'current';
ctrl.panel.legend.sortDesc = false;
});
it("highest last value should be first", () => {
expect(ctx.plotData[1].alias).to.be('series2');
expect(ctx.plotData[0].alias).to.be('series1');
});
});
});
graphScenario('when logBase is log 10', function(ctx) {
ctx.setup(function(ctrl, data) {
ctrl.panel.yaxes[0].logBase = 10;
@ -251,7 +300,7 @@ describe('grafanaGraph', function() {
});
it('should set barWidth', function() {
expect(ctx.plotOptions.series.bars.barWidth).to.be(1/1.5);
expect(ctx.plotOptions.series.bars.barWidth).to.be(10/1.5);
});
});

View File

@ -152,7 +152,7 @@ function drawLegendValues(elem, colorScale, rangeFrom, rangeTo, maxValue, minVal
.tickSize(2);
let colorRect = legendElem.find(":first-child");
let posY = colorRect.height() + 2;
let posY = getSvgElemHeight(legendElem) + 2;
let posX = getSvgElemX(colorRect);
d3.select(legendElem.get(0)).append("g")
@ -256,7 +256,16 @@ function getOpacityScale(options, maxValue, minValue = 0) {
function getSvgElemX(elem) {
let svgElem = elem.get(0);
if (svgElem && svgElem.x && svgElem.x.baseVal) {
return elem.get(0).x.baseVal.value;
return svgElem.x.baseVal.value;
} else {
return 0;
}
}
function getSvgElemHeight(elem) {
let svgElem = elem.get(0);
if (svgElem && svgElem.height && svgElem.height.baseVal) {
return svgElem.height.baseVal.value;
} else {
return 0;
}

View File

@ -1,13 +1,11 @@
///<reference path="../../../headers/common.d.ts" />
import {MetricsPanelCtrl} from 'app/plugins/sdk';
import _ from 'lodash';
import kbn from 'app/core/utils/kbn';
import TimeSeries from 'app/core/time_series';
import TimeSeries from 'app/core/time_series2';
import {axesEditor} from './axes_editor';
import {heatmapDisplayEditor} from './display_editor';
import rendering from './rendering';
import {convertToHeatMap, convertToCards, elasticHistogramToHeatmap, calculateBucketSize, getMinLog} from './heatmap_data_converter';
import {convertToHeatMap, convertToCards, elasticHistogramToHeatmap, calculateBucketSize } from './heatmap_data_converter';
let X_BUCKET_NUMBER_DEFAULT = 30;
let Y_BUCKET_NUMBER_DEFAULT = 10;
@ -250,7 +248,6 @@ export class HeatmapCtrl extends MetricsPanelCtrl {
});
series.flotpairs = series.getFlotPairs(this.panel.nullPointMode);
series.minLog = getMinLog(series);
let datapoints = seriesData.datapoints || [];
if (datapoints && datapoints.length > 0) {
@ -266,7 +263,7 @@ export class HeatmapCtrl extends MetricsPanelCtrl {
parseSeries(series) {
let min = _.min(_.map(series, s => s.stats.min));
let minLog = _.min(_.map(series, s => s.minLog));
let minLog = _.min(_.map(series, s => s.stats.logmin));
let max = _.max(_.map(series, s => s.stats.max));
return {

View File

@ -1,5 +1,3 @@
///<reference path="../../../headers/common.d.ts" />
import _ from 'lodash';
let VALUE_INDEX = 0;
@ -320,12 +318,6 @@ function convertToLogScaleValueBuckets(xBucket, yBucketSplitFactor, logBase) {
return buckets;
}
// Get minimum non zero value.
function getMinLog(series) {
let values = _.compact(_.map(series.datapoints, p => p[0]));
return _.min(values);
}
/**
* Logarithm for custom base
* @param value
@ -432,7 +424,6 @@ export {
elasticHistogramToHeatmap,
convertToCards,
mergeZeroBuckets,
getMinLog,
getValueBucketBound,
isHeatmapDataEqual,
calculateBucketSize

View File

@ -71,9 +71,8 @@ export default function link(scope, elem, attrs, ctrl) {
function getYAxisWidth(elem) {
let axis_text = elem.selectAll(".axis-y text").nodes();
let max_text_width = _.max(_.map(axis_text, text => {
let el = $(text);
// Use JQuery outerWidth() to compute full element width
return el.outerWidth();
// Use SVG getBBox method
return text.getBBox().width;
}));
return max_text_width;

View File

@ -1,5 +1,3 @@
///<reference path="../../../../headers/common.d.ts" />
import _ from 'lodash';
import { describe, beforeEach, it, expect } from '../../../../../test/lib/common';
import TimeSeries from 'app/core/time_series2';
@ -45,23 +43,23 @@ describe('isHeatmapDataEqual', () => {
let emptyValues = _.cloneDeep(ctx.heatmapA);
emptyValues['1422774000000'].buckets['1'].values = [];
expect(isHeatmapDataEqual(ctx.heatmapA, ctx.heatmapB)).to.be(true);
expect(isHeatmapDataEqual(ctx.heatmapB, ctx.heatmapA)).to.be(true);
expect(isHeatmapDataEqual(ctx.heatmapA, ctx.heatmapB)).toBe(true);
expect(isHeatmapDataEqual(ctx.heatmapB, ctx.heatmapA)).toBe(true);
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapC)).to.be(true);
expect(isHeatmapDataEqual(heatmapC, ctx.heatmapA)).to.be(true);
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapC)).toBe(true);
expect(isHeatmapDataEqual(heatmapC, ctx.heatmapA)).toBe(true);
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapD)).to.be(false);
expect(isHeatmapDataEqual(heatmapD, ctx.heatmapA)).to.be(false);
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapD)).toBe(false);
expect(isHeatmapDataEqual(heatmapD, ctx.heatmapA)).toBe(false);
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapE)).to.be(false);
expect(isHeatmapDataEqual(heatmapE, ctx.heatmapA)).to.be(false);
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapE)).toBe(false);
expect(isHeatmapDataEqual(heatmapE, ctx.heatmapA)).toBe(false);
expect(isHeatmapDataEqual(empty, ctx.heatmapA)).to.be(false);
expect(isHeatmapDataEqual(ctx.heatmapA, empty)).to.be(false);
expect(isHeatmapDataEqual(empty, ctx.heatmapA)).toBe(false);
expect(isHeatmapDataEqual(ctx.heatmapA, empty)).toBe(false);
expect(isHeatmapDataEqual(emptyValues, ctx.heatmapA)).to.be(false);
expect(isHeatmapDataEqual(ctx.heatmapA, emptyValues)).to.be(false);
expect(isHeatmapDataEqual(emptyValues, ctx.heatmapA)).toBe(false);
expect(isHeatmapDataEqual(ctx.heatmapA, emptyValues)).toBe(false);
});
});
@ -87,7 +85,7 @@ describe('calculateBucketSize', () => {
it('should properly calculate bucket size', () => {
_.each(ctx.bounds_set, (b) => {
let bucketSize = calculateBucketSize(b.bounds, ctx.logBase);
expect(bucketSize).to.be(b.size);
expect(bucketSize).toBe(b.size);
});
});
});
@ -108,7 +106,7 @@ describe('calculateBucketSize', () => {
it('should properly calculate bucket size', () => {
_.each(ctx.bounds_set, (b) => {
let bucketSize = calculateBucketSize(b.bounds, ctx.logBase);
expect(isEqual(bucketSize, b.size)).to.be(true);
expect(isEqual(bucketSize, b.size)).toBe(true);
});
});
});
@ -162,7 +160,7 @@ describe('HeatmapDataConverter', () => {
};
let heatmap = convertToHeatMap(ctx.series, ctx.yBucketSize, ctx.xBucketSize, ctx.logBase);
expect(isHeatmapDataEqual(heatmap, expectedHeatmap)).to.be(true);
expect(isHeatmapDataEqual(heatmap, expectedHeatmap)).toBe(true);
});
});
@ -190,7 +188,7 @@ describe('HeatmapDataConverter', () => {
};
let heatmap = convertToHeatMap(ctx.series, ctx.yBucketSize, ctx.xBucketSize, ctx.logBase);
expect(isHeatmapDataEqual(heatmap, expectedHeatmap)).to.be(true);
expect(isHeatmapDataEqual(heatmap, expectedHeatmap)).toBe(true);
});
});
});
@ -240,7 +238,7 @@ describe('ES Histogram converter', () => {
};
let heatmap = elasticHistogramToHeatmap(ctx.series);
expect(heatmap).to.eql(expectedHeatmap);
expect(heatmap).toMatchObject(expectedHeatmap);
});
});
});
@ -273,13 +271,13 @@ describe('convertToCards', () => {
{x: 1422774060000, y: 2, count: 2, values: [2, 3], yBounds: {}}
];
let res = convertToCards(buckets);
expect(res.cards).to.eql(expectedCards);
expect(res.cards).toMatchObject(expectedCards);
});
it('should build proper cards stats', () => {
let expectedStats = {min: 1, max: 2};
let res = convertToCards(buckets);
expect(res.cardStats).to.eql(expectedStats);
expect(res.cardStats).toMatchObject(expectedStats);
});
});

View File

@ -1,5 +1,3 @@
///<reference path="../../../headers/common.d.ts" />
import _ from 'lodash';
import moment from 'moment';
import kbn from 'app/core/utils/kbn';

View File

@ -1,5 +1,3 @@
import {describe, it, expect} from 'test/lib/common';
import _ from 'lodash';
import TableModel from 'app/core/table_model';
import {TableRenderer} from '../renderer';
@ -92,84 +90,84 @@ describe('when rendering table', () => {
it('time column should be formated', () => {
var html = renderer.renderCell(0, 0, 1388556366666);
expect(html).to.be('<td>2014-01-01T06:06:06Z</td>');
expect(html).toBe('<td>2014-01-01T06:06:06Z</td>');
});
it('undefined time column should be rendered as -', () => {
var html = renderer.renderCell(0, 0, undefined);
expect(html).to.be('<td>-</td>');
expect(html).toBe('<td>-</td>');
});
it('null time column should be rendered as -', () => {
var html = renderer.renderCell(0, 0, null);
expect(html).to.be('<td>-</td>');
expect(html).toBe('<td>-</td>');
});
it('number column with unit specified should ignore style unit', () => {
var html = renderer.renderCell(5, 0, 1230);
expect(html).to.be('<td>1.23 kbps</td>');
expect(html).toBe('<td>1.23 kbps</td>');
});
it('number column should be formated', () => {
var html = renderer.renderCell(1, 0, 1230);
expect(html).to.be('<td>1.230 s</td>');
expect(html).toBe('<td>1.230 s</td>');
});
it('number style should ignore string values', () => {
var html = renderer.renderCell(1, 0, 'asd');
expect(html).to.be('<td>asd</td>');
expect(html).toBe('<td>asd</td>');
});
it('colored cell should have style', () => {
var html = renderer.renderCell(2, 0, 40);
expect(html).to.be('<td style="color:green">40.0</td>');
expect(html).toBe('<td style="color:green">40.0</td>');
});
it('colored cell should have style', () => {
var html = renderer.renderCell(2, 0, 55);
expect(html).to.be('<td style="color:orange">55.0</td>');
expect(html).toBe('<td style="color:orange">55.0</td>');
});
it('colored cell should have style', () => {
var html = renderer.renderCell(2, 0, 85);
expect(html).to.be('<td style="color:red">85.0</td>');
expect(html).toBe('<td style="color:red">85.0</td>');
});
it('unformated undefined should be rendered as string', () => {
var html = renderer.renderCell(3, 0, 'value');
expect(html).to.be('<td>value</td>');
expect(html).toBe('<td>value</td>');
});
it('string style with escape html should return escaped html', () => {
var html = renderer.renderCell(4, 0, "&breaking <br /> the <br /> row");
expect(html).to.be('<td>&amp;breaking &lt;br /&gt; the &lt;br /&gt; row</td>');
expect(html).toBe('<td>&amp;breaking &lt;br /&gt; the &lt;br /&gt; row</td>');
});
it('undefined formater should return escaped html', () => {
var html = renderer.renderCell(3, 0, "&breaking <br /> the <br /> row");
expect(html).to.be('<td>&amp;breaking &lt;br /&gt; the &lt;br /&gt; row</td>');
expect(html).toBe('<td>&amp;breaking &lt;br /&gt; the &lt;br /&gt; row</td>');
});
it('undefined value should render as -', () => {
var html = renderer.renderCell(3, 0, undefined);
expect(html).to.be('<td></td>');
expect(html).toBe('<td></td>');
});
it('sanitized value should render as', () => {
var html = renderer.renderCell(6, 0, 'text <a href="http://google.com">link</a>');
expect(html).to.be('<td>sanitized</td>');
expect(html).toBe('<td>sanitized</td>');
});
it('Time column title should be Timestamp', () => {
expect(table.columns[0].title).to.be('Timestamp');
expect(table.columns[0].title).toBe('Timestamp');
});
it('Value column title should be Val', () => {
expect(table.columns[1].title).to.be('Val');
expect(table.columns[1].title).toBe('Val');
});
it('Colored column title should be Colored', () => {
expect(table.columns[2].title).to.be('Colored');
expect(table.columns[2].title).toBe('Colored');
});
it('link should render as', () => {
@ -182,7 +180,7 @@ describe('when rendering table', () => {
</a>
</td>
`;
expect(normalize(html)).to.be(normalize(expectedHtml));
expect(normalize(html)).toBe(normalize(expectedHtml));
});
});
});

View File

@ -1,5 +1,3 @@
import {describe, beforeEach, it, expect} from 'test/lib/common';
import {transformers, transformDataToTable} from '../transformers';
describe('when transforming time series table', () => {
@ -29,18 +27,18 @@ describe('when transforming time series table', () => {
});
it('should return 3 rows', () => {
expect(table.rows.length).to.be(3);
expect(table.rows[0][1]).to.be('series1');
expect(table.rows[1][1]).to.be('series1');
expect(table.rows[2][1]).to.be('series2');
expect(table.rows[0][2]).to.be(12.12);
expect(table.rows.length).toBe(3);
expect(table.rows[0][1]).toBe('series1');
expect(table.rows[1][1]).toBe('series1');
expect(table.rows[2][1]).toBe('series2');
expect(table.rows[0][2]).toBe(12.12);
});
it('should return 3 rows', () => {
expect(table.columns.length).to.be(3);
expect(table.columns[0].text).to.be('Time');
expect(table.columns[1].text).to.be('Metric');
expect(table.columns[2].text).to.be('Value');
expect(table.columns.length).toBe(3);
expect(table.columns[0].text).toBe('Time');
expect(table.columns[1].text).toBe('Metric');
expect(table.columns[2].text).toBe('Value');
});
});
@ -54,20 +52,20 @@ describe('when transforming time series table', () => {
});
it ('should return 3 columns', () => {
expect(table.columns.length).to.be(3);
expect(table.columns[0].text).to.be('Time');
expect(table.columns[1].text).to.be('series1');
expect(table.columns[2].text).to.be('series2');
expect(table.columns.length).toBe(3);
expect(table.columns[0].text).toBe('Time');
expect(table.columns[1].text).toBe('series1');
expect(table.columns[2].text).toBe('series2');
});
it ('should return 2 rows', () => {
expect(table.rows.length).to.be(2);
expect(table.rows[0][1]).to.be(12.12);
expect(table.rows[0][2]).to.be(16.12);
expect(table.rows.length).toBe(2);
expect(table.rows[0][1]).toBe(12.12);
expect(table.rows[0][2]).toBe(16.12);
});
it ('should be undefined when no value for timestamp', () => {
expect(table.rows[1][2]).to.be(undefined);
expect(table.rows[1][2]).toBe(undefined);
});
});
@ -83,17 +81,17 @@ describe('when transforming time series table', () => {
});
it('should return 2 rows', () => {
expect(table.rows.length).to.be(2);
expect(table.rows[0][0]).to.be('series1');
expect(table.rows[0][1]).to.be(14.44);
expect(table.rows[0][2]).to.be(12.12);
expect(table.rows.length).toBe(2);
expect(table.rows[0][0]).toBe('series1');
expect(table.rows[0][1]).toBe(14.44);
expect(table.rows[0][2]).toBe(12.12);
});
it('should return 2 columns', () => {
expect(table.columns.length).to.be(3);
expect(table.columns[0].text).to.be('Metric');
expect(table.columns[1].text).to.be('Max');
expect(table.columns[2].text).to.be('Min');
expect(table.columns.length).toBe(3);
expect(table.columns[0].text).toBe('Metric');
expect(table.columns[1].text).toBe('Max');
expect(table.columns[2].text).toBe('Min');
});
});
@ -124,9 +122,9 @@ describe('when transforming time series table', () => {
describe('getColumns', function() {
it('should return nested properties', function() {
var columns = transformers['json'].getColumns(rawData);
expect(columns[0].text).to.be('timestamp');
expect(columns[1].text).to.be('message');
expect(columns[2].text).to.be('nested.level2');
expect(columns[0].text).toBe('timestamp');
expect(columns[1].text).toBe('message');
expect(columns[2].text).toBe('nested.level2');
});
});
@ -136,17 +134,17 @@ describe('when transforming time series table', () => {
});
it ('should return 2 columns', () => {
expect(table.columns.length).to.be(3);
expect(table.columns[0].text).to.be('Timestamp');
expect(table.columns[1].text).to.be('Message');
expect(table.columns[2].text).to.be('nested.level2');
expect(table.columns.length).toBe(3);
expect(table.columns[0].text).toBe('Timestamp');
expect(table.columns[1].text).toBe('Message');
expect(table.columns[2].text).toBe('nested.level2');
});
it ('should return 2 rows', () => {
expect(table.rows.length).to.be(1);
expect(table.rows[0][0]).to.be('time');
expect(table.rows[0][1]).to.be('message');
expect(table.rows[0][2]).to.be('level2-value');
expect(table.rows.length).toBe(1);
expect(table.rows[0][0]).toBe('time');
expect(table.rows[0][1]).toBe('message');
expect(table.rows[0][2]).toBe('level2-value');
});
});
});
@ -169,16 +167,16 @@ describe('when transforming time series table', () => {
});
it ('should return 4 columns', () => {
expect(table.columns.length).to.be(4);
expect(table.columns[0].text).to.be('Time');
expect(table.columns[1].text).to.be('Title');
expect(table.columns[2].text).to.be('Text');
expect(table.columns[3].text).to.be('Tags');
expect(table.columns.length).toBe(4);
expect(table.columns[0].text).toBe('Time');
expect(table.columns[1].text).toBe('Title');
expect(table.columns[2].text).toBe('Text');
expect(table.columns[3].text).toBe('Tags');
});
it ('should return 1 rows', () => {
expect(table.rows.length).to.be(1);
expect(table.rows[0][0]).to.be(1000);
expect(table.rows.length).toBe(1);
expect(table.rows[0][0]).toBe(1000);
});
});

View File

@ -1,5 +1,3 @@
///<reference path="../../../headers/common.d.ts" />
import _ from 'lodash';
import flatten from '../../../core/utils/flatten';
import TimeSeries from '../../../core/time_series2';

View File

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

View File

@ -0,0 +1,4 @@
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });

6
public/test/jest-shim.ts Normal file
View File

@ -0,0 +1,6 @@
declare var global: NodeJS.Global;
(<any>global).requestAnimationFrame = (callback) => {
setTimeout(callback, 0);
};

View File

@ -16,8 +16,16 @@ rm -rf node_modules
npm install -g yarn --quiet
yarn install --pure-lockfile --no-progress
exit_if_fail npm test
exit_if_fail npm build
exit_if_fail npm run test-ci
exit_if_fail npm run build
# publish code coverage
echo "Publishing javascript code coverage"
bash <(curl -s https://codecov.io/bash) -cF javascript
rm -rf coverage
# npm install -g codecov
# codecov
# cat ./coverage/lcov.info | node ./node_modules/coveralls/bin/coveralls.js
echo "running go fmt"
exit_if_fail test -z "$(gofmt -s -l ./pkg | tee /dev/stderr)"
@ -29,4 +37,17 @@ echo "building binaries"
exit_if_fail go run build.go build
echo "running go test"
exit_if_fail go test -v ./pkg/...
set -e
echo "" > coverage.txt
for d in $(go list ./pkg/...); do
exit_if_fail go test -race -coverprofile=profile.out -covermode=atomic $d
if [ -f profile.out ]; then
cat profile.out >> coverage.txt
rm profile.out
fi
done
echo "Publishing go code coverage"
bash <(curl -s https://codecov.io/bash) -cF go

View File

@ -14,6 +14,7 @@ module.exports = function(grunt) {
'jshint',
'sasslint',
'exec:tslint',
"exec:jest",
'karma:test',
'no-only-tests'
]);

View File

@ -1,6 +1,13 @@
module.exports = function(config, grunt) {
'use strict'
var coverage = '';
if (config.coverage) {
coverage = '--coverage';
}
return {
tslint : "node ./node_modules/tslint/lib/tslint-cli.js -c tslint.json --project ./tsconfig.json --type-check",
tslint : "node ./node_modules/tslint/lib/tslint-cli.js -c tslint.json --project ./tsconfig.json",
jest : "node ./node_modules/jest-cli/bin/jest.js " + coverage,
};
};

View File

@ -26,6 +26,10 @@ module.exports = merge(common, {
]
},
devServer: {
stats: 'errors-only',
},
plugins: [
new ExtractTextPlugin({
filename: 'grafana.[name].css',

View File

@ -2,7 +2,8 @@
"rules": {
"no-string-throw": true,
"no-unused-expression": true,
"no-unused-variable": true,
"no-unused-variable": false,
"no-use-before-declare": false,
"no-duplicate-variable": true,
"curly": true,
"class-name": true,
@ -33,7 +34,6 @@
"no-string-literal": false,
"no-switch-case-fall-through": false,
"no-trailing-whitespace": true,
"no-use-before-declare": true,
"no-var-keyword": false,
"object-literal-sort-keys": false,
"one-line": [true,

775
yarn.lock

File diff suppressed because it is too large Load Diff