Merge branch 'master' into feature/status_page-1556

pull/10616/head
Jared Scheib 2017-06-07 12:07:27 -05:00
commit f7bc85f708
68 changed files with 916 additions and 828 deletions

View File

@ -179,7 +179,7 @@
'one-var': 0,
'operator-assignment': [2, 'always'],
'padded-blocks': [2, 'never'],
'quote-props': [2, 'as-needed', {keywords: true, numbers: false }],
'quote-props': [2, 'as-needed', {keywords: false, numbers: false }],
'require-jsdoc': 0,
'semi-spacing': [2, {before: false, after: true}],
'semi': [2, 'never'],
@ -234,6 +234,5 @@
'react/require-extension': 0,
'react/self-closing-comp': 0, // TODO: we can re-enable this if some brave soul wants to update the code (mostly spans acting as icons)
'react/sort-comp': 0, // TODO: 2
'react/jsx-wrap-multilines': ['error', {'declaration': false, 'assignment': false}],
},
}

View File

@ -144,11 +144,7 @@ describe('Admin.Reducers', () => {
it('can add a database', () => {
const actual = reducer(state, addDatabase())
const expected = [
{...NEW_DEFAULT_DATABASE, isEditing: true},
db1,
db2,
]
const expected = [{...NEW_DEFAULT_DATABASE, isEditing: true}, db1, db2]
expect(actual.databases).to.deep.equal(expected)
})
@ -170,10 +166,7 @@ describe('Admin.Reducers', () => {
it('can add a database delete code', () => {
const actual = reducer(state, addDatabaseDeleteCode(db1))
const expected = [
{...db1, deleteCode: ''},
db2,
]
const expected = [{...db1, deleteCode: ''}, db2]
expect(actual.databases).to.deep.equal(expected)
})
@ -181,10 +174,7 @@ describe('Admin.Reducers', () => {
it('can remove the delete code', () => {
const actual = reducer(state, removeDatabaseDeleteCode(db2))
delete db2.deleteCode
const expected = [
db1,
db2,
]
const expected = [db1, db2]
expect(actual.databases).to.deep.equal(expected)
})
@ -195,18 +185,14 @@ describe('Admin.Reducers', () => {
it('can add a retention policy', () => {
const actual = reducer(state, addRetentionPolicy(db1))
const expected = [
{...db1, retentionPolicies: [NEW_EMPTY_RP, rp1]},
]
const expected = [{...db1, retentionPolicies: [NEW_EMPTY_RP, rp1]}]
expect(actual.databases).to.deep.equal(expected)
})
it('can remove a retention policy', () => {
const actual = reducer(state, removeRetentionPolicy(db1, rp1))
const expected = [
{...db1, retentionPolicies: []},
]
const expected = [{...db1, retentionPolicies: []}]
expect(actual.databases).to.deep.equal(expected)
})
@ -214,9 +200,7 @@ describe('Admin.Reducers', () => {
it('can edit a retention policy', () => {
const updates = {name: 'rpOne', duration: '100y', replication: '42'}
const actual = reducer(state, editRetentionPolicy(db1, rp1, updates))
const expected = [
{...db1, retentionPolicies: [{...rp1, ...updates}]},
]
const expected = [{...db1, retentionPolicies: [{...rp1, ...updates}]}]
expect(actual.databases).to.deep.equal(expected)
})
@ -224,17 +208,12 @@ describe('Admin.Reducers', () => {
it('it can add a user', () => {
state = {
users: [
u1,
],
users: [u1],
}
const actual = reducer(state, addUser())
const expected = {
users: [
{...NEW_DEFAULT_USER, isEditing: true},
u1,
],
users: [{...NEW_DEFAULT_USER, isEditing: true}, u1],
}
expect(actual.users).to.deep.equal(expected.users)
@ -268,17 +247,12 @@ describe('Admin.Reducers', () => {
it('it can add a role', () => {
state = {
roles: [
r1,
],
roles: [r1],
}
const actual = reducer(state, addRole())
const expected = {
roles: [
{...NEW_DEFAULT_ROLE, isEditing: true},
r1,
],
roles: [{...NEW_DEFAULT_ROLE, isEditing: true}, r1],
}
expect(actual.roles).to.deep.equal(expected.roles)
@ -321,9 +295,7 @@ describe('Admin.Reducers', () => {
it('it can delete a role', () => {
state = {
roles: [
r1,
],
roles: [r1],
}
const actual = reducer(state, deleteRole(r1))
@ -336,9 +308,7 @@ describe('Admin.Reducers', () => {
it('it can delete a user', () => {
state = {
users: [
u1,
],
users: [u1],
}
const actual = reducer(state, deleteUser(u1))
@ -358,10 +328,7 @@ describe('Admin.Reducers', () => {
const actual = reducer(state, filterRoles(text))
const expected = {
roles: [
{...r1, hidden: false},
{...r2, hidden: true},
],
roles: [{...r1, hidden: false}, {...r2, hidden: true}],
}
expect(actual.roles).to.deep.equal(expected.roles)
@ -376,10 +343,7 @@ describe('Admin.Reducers', () => {
const actual = reducer(state, filterUsers(text))
const expected = {
users: [
{...u1, hidden: true},
{...u2, hidden: false},
],
users: [{...u1, hidden: true}, {...u2, hidden: false}],
}
expect(actual.users).to.deep.equal(expected.users)

View File

@ -10,61 +10,103 @@ describe('buildInfluxQLQuery', () => {
describe('when information is missing', () => {
it('returns a null select statement', () => {
expect(buildInfluxQLQuery({}, mergeConfig())).to.equal(null)
expect(buildInfluxQLQuery({}, mergeConfig({database: 'db1'}))).to.equal(null) // no measurement
expect(buildInfluxQLQuery({}, mergeConfig({database: 'db1', measurement: 'm1'}))).to.equal(null) // no fields
expect(buildInfluxQLQuery({}, mergeConfig({database: 'db1'}))).to.equal(
null
) // no measurement
expect(
buildInfluxQLQuery(
{},
mergeConfig({database: 'db1', measurement: 'm1'})
)
).to.equal(null) // no fields
})
})
describe('with a database, measurement, field, and NO retention policy', () => {
beforeEach(() => {
config = mergeConfig({database: 'db1', measurement: 'm1', fields: [{field: 'f1', func: null}]})
config = mergeConfig({
database: 'db1',
measurement: 'm1',
fields: [{field: 'f1', func: null}],
})
})
it('builds the right query', () => {
expect(buildInfluxQLQuery({}, config)).to.equal('SELECT "f1" FROM "db1".."m1"')
expect(buildInfluxQLQuery({}, config)).to.equal(
'SELECT "f1" FROM "db1".."m1"'
)
})
})
describe('with a database, measurement, retention policy, and field', () => {
beforeEach(() => {
config = mergeConfig({database: 'db1', measurement: 'm1', retentionPolicy: 'rp1', fields: [{field: 'f1', func: null}]})
config = mergeConfig({
database: 'db1',
measurement: 'm1',
retentionPolicy: 'rp1',
fields: [{field: 'f1', func: null}],
})
timeBounds = {lower: 'now() - 1hr'}
})
it('builds the right query', () => {
expect(buildInfluxQLQuery({}, config)).to.equal('SELECT "f1" FROM "db1"."rp1"."m1"')
expect(buildInfluxQLQuery({}, config)).to.equal(
'SELECT "f1" FROM "db1"."rp1"."m1"'
)
})
it('builds the right query with a time range', () => {
expect(buildInfluxQLQuery(timeBounds, config)).to.equal('SELECT "f1" FROM "db1"."rp1"."m1" WHERE time > now() - 1hr')
expect(buildInfluxQLQuery(timeBounds, config)).to.equal(
'SELECT "f1" FROM "db1"."rp1"."m1" WHERE time > now() - 1hr'
)
})
})
describe('when the field is *', () => {
beforeEach(() => {
config = mergeConfig({database: 'db1', measurement: 'm1', retentionPolicy: 'rp1', fields: [{field: '*', func: null}]})
config = mergeConfig({
database: 'db1',
measurement: 'm1',
retentionPolicy: 'rp1',
fields: [{field: '*', func: null}],
})
})
it('does not quote the star', () => {
expect(buildInfluxQLQuery({}, config)).to.equal('SELECT * FROM "db1"."rp1"."m1"')
expect(buildInfluxQLQuery({}, config)).to.equal(
'SELECT * FROM "db1"."rp1"."m1"'
)
})
})
describe('with a measurement and one field, an aggregate, and a GROUP BY time()', () => {
beforeEach(() => {
config = mergeConfig({database: 'db1', measurement: 'm0', retentionPolicy: 'rp1', fields: [{field: 'value', funcs: ['min']}], groupBy: {time: '10m', tags: []}})
config = mergeConfig({
database: 'db1',
measurement: 'm0',
retentionPolicy: 'rp1',
fields: [{field: 'value', funcs: ['min']}],
groupBy: {time: '10m', tags: []},
})
timeBounds = {lower: 'now() - 12h'}
})
it('builds the right query', () => {
const expected = 'SELECT min("value") AS "min_value" FROM "db1"."rp1"."m0" WHERE time > now() - 12h GROUP BY time(10m)'
const expected =
'SELECT min("value") AS "min_value" FROM "db1"."rp1"."m0" WHERE time > now() - 12h GROUP BY time(10m)'
expect(buildInfluxQLQuery(timeBounds, config)).to.equal(expected)
})
})
describe('with a measurement and one field, an aggregate, and a GROUP BY tags', () => {
beforeEach(() => {
config = mergeConfig({database: 'db1', measurement: 'm0', retentionPolicy: 'rp1', fields: [{field: 'value', funcs: ['min']}], groupBy: {time: null, tags: ['t1', 't2']}})
config = mergeConfig({
database: 'db1',
measurement: 'm0',
retentionPolicy: 'rp1',
fields: [{field: 'value', funcs: ['min']}],
groupBy: {time: null, tags: ['t1', 't2']},
})
timeBounds = {lower: 'now() - 12h'}
})
@ -76,36 +118,59 @@ describe('buildInfluxQLQuery', () => {
describe('with a measurement, one field, and an upper / lower absolute time range', () => {
beforeEach(() => {
config = mergeConfig({database: 'db1', retentionPolicy: 'rp1', measurement: 'm0', fields: [{field: 'value', funcs: []}]})
timeBounds = {lower: "'2015-07-23T15:52:24.447Z'", upper: "'2015-07-24T15:52:24.447Z'"}
config = mergeConfig({
database: 'db1',
retentionPolicy: 'rp1',
measurement: 'm0',
fields: [{field: 'value', funcs: []}],
})
timeBounds = {
lower: "'2015-07-23T15:52:24.447Z'",
upper: "'2015-07-24T15:52:24.447Z'",
}
})
it('builds the right query', () => {
const expected = 'SELECT "value" FROM "db1"."rp1"."m0" WHERE time > \'2015-07-23T15:52:24.447Z\' AND time < \'2015-07-24T15:52:24.447Z\''
const expected =
'SELECT "value" FROM "db1"."rp1"."m0" WHERE time > \'2015-07-23T15:52:24.447Z\' AND time < \'2015-07-24T15:52:24.447Z\''
expect(buildInfluxQLQuery(timeBounds, config)).to.equal(expected)
})
})
describe('with a measurement and one field, an aggregate, and a GROUP BY time(), and tags', () => {
beforeEach(() => {
config = mergeConfig({database: 'db1', retentionPolicy: 'rp1', measurement: 'm0', fields: [{field: 'value', funcs: ['min']}], groupBy: {time: '10m', tags: ['t1', 't2']}})
config = mergeConfig({
database: 'db1',
retentionPolicy: 'rp1',
measurement: 'm0',
fields: [{field: 'value', funcs: ['min']}],
groupBy: {time: '10m', tags: ['t1', 't2']},
})
timeBounds = {lower: 'now() - 12h'}
})
it('builds the right query', () => {
const expected = 'SELECT min("value") AS "min_value" FROM "db1"."rp1"."m0" WHERE time > now() - 12h GROUP BY time(10m), "t1", "t2"'
const expected =
'SELECT min("value") AS "min_value" FROM "db1"."rp1"."m0" WHERE time > now() - 12h GROUP BY time(10m), "t1", "t2"'
expect(buildInfluxQLQuery(timeBounds, config)).to.equal(expected)
})
})
describe('with a measurement and two fields', () => {
beforeEach(() => {
config = mergeConfig({database: 'db1', retentionPolicy: 'rp1', measurement: 'm0', fields: [{field: 'f0', funcs: []}, {field: 'f1', funcs: []}]})
config = mergeConfig({
database: 'db1',
retentionPolicy: 'rp1',
measurement: 'm0',
fields: [{field: 'f0', funcs: []}, {field: 'f1', funcs: []}],
})
timeBounds = {upper: "'2015-02-24T00:00:00Z'"}
})
it('builds the right query', () => {
expect(buildInfluxQLQuery({}, config)).to.equal('SELECT "f0", "f1" FROM "db1"."rp1"."m0"')
expect(buildInfluxQLQuery({}, config)).to.equal(
'SELECT "f0", "f1" FROM "db1"."rp1"."m0"'
)
})
it('builds the right query with a time range', () => {
@ -121,14 +186,8 @@ describe('buildInfluxQLQuery', () => {
retentionPolicy: 'rp1',
fields: [{field: 'f0', funcs: []}],
tags: {
k1: [
'v1',
'v3',
'v4',
],
k2: [
'v2',
],
k1: ['v1', 'v3', 'v4'],
k2: ['v2'],
},
})
timeBounds = {lower: 'now() - 6h'}

View File

@ -3,31 +3,31 @@ import InfluxQL from 'src/influxql'
describe('influxql astToString', () => {
it('simple query', () => {
const ast = InfluxQL({
"fields": [
fields: [
{
"column": {
"expr": "binary",
"op": "+",
"lhs": {
"expr": "literal",
"val": "1",
"type": "integer"
column: {
expr: 'binary',
op: '+',
lhs: {
expr: 'literal',
val: '1',
type: 'integer',
},
"rhs": {
"expr": "reference",
"val": "A"
}
}
}
rhs: {
expr: 'reference',
val: 'A',
},
},
},
],
"sources": [
sources: [
{
"database": "",
"retentionPolicy": "",
"name": "howdy",
"type": "measurement"
}
]
database: '',
retentionPolicy: '',
name: 'howdy',
type: 'measurement',
},
],
})
const expected = `SELECT 1 + "A" FROM "howdy"`
@ -40,37 +40,37 @@ describe('influxql astToString', () => {
it('simple query w/ multiple sources', () => {
const ast = InfluxQL({
"fields": [
fields: [
{
"column": {
"expr": "binary",
"op": "+",
"lhs": {
"expr": "literal",
"val": "1",
"type": "integer"
column: {
expr: 'binary',
op: '+',
lhs: {
expr: 'literal',
val: '1',
type: 'integer',
},
"rhs": {
"expr": "reference",
"val": "A"
}
}
}
rhs: {
expr: 'reference',
val: 'A',
},
},
},
],
"sources": [
sources: [
{
"database": "",
"retentionPolicy": "",
"name": "howdy",
"type": "measurement"
database: '',
retentionPolicy: '',
name: 'howdy',
type: 'measurement',
},
{
"database": "telegraf",
"retentionPolicy": "autogen",
"name": "doody",
"type": "measurement"
}
]
database: 'telegraf',
retentionPolicy: 'autogen',
name: 'doody',
type: 'measurement',
},
],
})
const expected = `SELECT 1 + "A" FROM "howdy", "telegraf"."autogen"."doody"`
@ -84,32 +84,32 @@ describe('influxql astToString', () => {
it('query with AS', () => {
const ast = InfluxQL({
"fields": [
fields: [
{
"alias": "B",
"column": {
"expr": "binary",
"op": "+",
"lhs": {
"expr": "literal",
"val": "1",
"type": "integer"
alias: 'B',
column: {
expr: 'binary',
op: '+',
lhs: {
expr: 'literal',
val: '1',
type: 'integer',
},
"rhs": {
"expr": "reference",
"val": "A"
}
}
}
rhs: {
expr: 'reference',
val: 'A',
},
},
},
],
"sources": [
sources: [
{
"database": "",
"retentionPolicy": "",
"name": "howdy",
"type": "measurement"
}
]
database: '',
retentionPolicy: '',
name: 'howdy',
type: 'measurement',
},
],
})
const expected = `SELECT 1 + "A" AS "B" FROM "howdy"`
@ -122,52 +122,52 @@ describe('influxql astToString', () => {
it('query with 2x func', () => {
const ast = InfluxQL({
"fields": [
fields: [
{
"column": {
"expr": "binary",
"op": "/",
"lhs": {
"expr": "call",
"name": "derivative",
"args": [
column: {
expr: 'binary',
op: '/',
lhs: {
expr: 'call',
name: 'derivative',
args: [
{
"expr": "reference",
"val": "field1"
expr: 'reference',
val: 'field1',
},
{
"expr": "literal",
"val": "1h",
"type": "duration"
}
]
expr: 'literal',
val: '1h',
type: 'duration',
},
],
},
"rhs": {
"expr": "call",
"name": "derivative",
"args": [
rhs: {
expr: 'call',
name: 'derivative',
args: [
{
"expr": "reference",
"val": "field2"
expr: 'reference',
val: 'field2',
},
{
"expr": "literal",
"val": "1h",
"type": "duration"
}
]
}
}
}
expr: 'literal',
val: '1h',
type: 'duration',
},
],
},
},
},
],
"sources": [
sources: [
{
"database": "",
"retentionPolicy": "",
"name": "myseries",
"type": "measurement"
}
]
database: '',
retentionPolicy: '',
name: 'myseries',
type: 'measurement',
},
],
})
const expected = `SELECT derivative("field1", 1h) / derivative("field2", 1h) FROM "myseries"`
@ -181,121 +181,119 @@ describe('influxql astToString', () => {
it('query with where and groupby', () => {
const ast = InfluxQL({
"condition": {
"expr": "binary",
"op": "AND",
"lhs": {
"expr": "binary",
"op": "AND",
"lhs": {
"expr": "binary",
"op": "=~",
"lhs": {
"expr": "reference",
"val": "cluster_id"
condition: {
expr: 'binary',
op: 'AND',
lhs: {
expr: 'binary',
op: 'AND',
lhs: {
expr: 'binary',
op: '=~',
lhs: {
expr: 'reference',
val: 'cluster_id',
},
rhs: {
expr: 'literal',
val: '/^23/',
type: 'regex',
},
"rhs": {
"expr": "literal",
"val": "/^23/",
"type": "regex"
}
},
"rhs": {
"expr": "binary",
"op": "=",
"lhs": {
"expr": "reference",
"val": "host"
rhs: {
expr: 'binary',
op: '=',
lhs: {
expr: 'reference',
val: 'host',
},
"rhs": {
"expr": "literal",
"val": "prod-2ccccc04-us-east-1-data-3",
"type": "string"
}
}
rhs: {
expr: 'literal',
val: 'prod-2ccccc04-us-east-1-data-3',
type: 'string',
},
},
},
"rhs": {
"expr": "binary",
"op": "\u003e",
"lhs": {
"expr": "reference",
"val": "time"
rhs: {
expr: 'binary',
op: '\u003e',
lhs: {
expr: 'reference',
val: 'time',
},
"rhs": {
"expr": "binary",
"op": "-",
"lhs": {
"expr": "call",
"name": "now"
rhs: {
expr: 'binary',
op: '-',
lhs: {
expr: 'call',
name: 'now',
},
"rhs": {
"expr": "literal",
"val": "15m",
"type": "duration"
}
}
}
rhs: {
expr: 'literal',
val: '15m',
type: 'duration',
},
},
},
},
"fields": [
fields: [
{
"alias": "max_cpus",
"column": {
"expr": "call",
"name": "max",
"args": [
alias: 'max_cpus',
column: {
expr: 'call',
name: 'max',
args: [
{
"expr": "reference",
"val": "n_cpus"
}
]
}
expr: 'reference',
val: 'n_cpus',
},
],
},
},
{
"column": {
"expr": "call",
"name": "non_negative_derivative",
"args": [
column: {
expr: 'call',
name: 'non_negative_derivative',
args: [
{
"expr": "call",
"name": "median",
"args": [
expr: 'call',
name: 'median',
args: [
{
"expr": "reference",
"val": "n_users"
}
]
expr: 'reference',
val: 'n_users',
},
],
},
{
"expr": "literal",
"val": "5m",
"type": "duration"
}
]
}
}
],
"groupBy": {
"time": {
"interval": "15m",
"offset": "10s"
expr: 'literal',
val: '5m',
type: 'duration',
},
],
},
},
"tags": [
"host",
"tag_x"
],
"fill": "10"
],
groupBy: {
time: {
interval: '15m',
offset: '10s',
},
tags: ['host', 'tag_x'],
fill: '10',
},
"sources": [
sources: [
{
"database": "",
"retentionPolicy": "",
"name": "system",
"type": "measurement"
}
]
database: '',
retentionPolicy: '',
name: 'system',
type: 'measurement',
},
],
})
const expected = "SELECT max(\"n_cpus\") AS \"max_cpus\", non_negative_derivative(median(\"n_users\"), 5m) FROM \"system\" WHERE \"cluster_id\" =~ /^23/ AND \"host\" = 'prod-2ccccc04-us-east-1-data-3' AND time > now() - 15m GROUP BY time(15m, 10s),host,tag_x fill(10)"
const expected =
'SELECT max("n_cpus") AS "max_cpus", non_negative_derivative(median("n_users"), 5m) FROM "system" WHERE "cluster_id" =~ /^23/ AND "host" = \'prod-2ccccc04-us-east-1-data-3\' AND time > now() - 15m GROUP BY time(15m, 10s),host,tag_x fill(10)'
const actual = ast.toString()
// console.log('actual ', actual)
@ -306,98 +304,98 @@ describe('influxql astToString', () => {
it('query with orderby and limit', () => {
const ast = InfluxQL({
"condition": {
"expr": "binary",
"op": "AND",
"lhs": {
"expr": "binary",
"op": "=",
"lhs": {
"expr": "reference",
"val": "host"
condition: {
expr: 'binary',
op: 'AND',
lhs: {
expr: 'binary',
op: '=',
lhs: {
expr: 'reference',
val: 'host',
},
"rhs": {
"expr": "literal",
"val": "hosta.influxdb.org",
"type": "string"
}
},
"rhs": {
"expr": "binary",
"op": "\u003e",
"lhs": {
"expr": "reference",
"val": "time"
rhs: {
expr: 'literal',
val: 'hosta.influxdb.org',
type: 'string',
},
"rhs": {
"expr": "literal",
"val": "2017-02-07T01:43:02.245407693Z",
"type": "string"
}
}
},
rhs: {
expr: 'binary',
op: '\u003e',
lhs: {
expr: 'reference',
val: 'time',
},
rhs: {
expr: 'literal',
val: '2017-02-07T01:43:02.245407693Z',
type: 'string',
},
},
},
"fields": [
fields: [
{
"column": {
"expr": "call",
"name": "mean",
"args": [
column: {
expr: 'call',
name: 'mean',
args: [
{
"expr": "reference",
"val": "field1"
}
]
}
expr: 'reference',
val: 'field1',
},
],
},
},
{
"column": {
"expr": "call",
"name": "sum",
"args": [
column: {
expr: 'call',
name: 'sum',
args: [
{
"expr": "reference",
"val": "field2"
}
]
}
expr: 'reference',
val: 'field2',
},
],
},
},
{
"alias": "field_x",
"column": {
"expr": "call",
"name": "count",
"args": [
alias: 'field_x',
column: {
expr: 'call',
name: 'count',
args: [
{
"expr": "reference",
"val": "field3"
}
]
}
}
expr: 'reference',
val: 'field3',
},
],
},
},
],
"groupBy": {
"time": {
"interval": "10h"
}
groupBy: {
time: {
interval: '10h',
},
},
"limits": {
"limit": 20,
"offset": 10
limits: {
limit: 20,
offset: 10,
},
"orderbys": [
orderbys: [
{
"name": "time",
"order": "descending"
}
name: 'time',
order: 'descending',
},
],
"sources": [
sources: [
{
"database": "",
"retentionPolicy": "",
"name": "myseries",
"type": "measurement"
}
]
database: '',
retentionPolicy: '',
name: 'myseries',
type: 'measurement',
},
],
})
const expected = `SELECT mean("field1"), sum("field2"), count("field3") AS "field_x" FROM "myseries" WHERE "host" = 'hosta.influxdb.org' AND time > '2017-02-07T01:43:02.245407693Z' GROUP BY time(10h) ORDER BY time DESC LIMIT 20 OFFSET 10`

View File

@ -1,11 +1,52 @@
import {diskBytesFromShard, diskBytesFromShardForDatabase} from 'shared/parsing/diskBytes'
import {
diskBytesFromShard,
diskBytesFromShardForDatabase,
} from 'shared/parsing/diskBytes'
describe('diskBytesFromShard', () => {
it('sums all the disk bytes in multiple series', () => {
const response = {results: [
{series: [{name: "shard", tags: {clusterID: "6272208615254493595", database: "_internal", engine: "tsm1", hostname: "WattsInfluxDB", id: "1", nodeID: "localhost:8088", path: "/Users/watts/.influxdb/data/_internal/monitor/1", retentionPolicy: "monitor"}, columns: ["time", "last"], values: [[1464811503000000000, 100]]}]},
{series: [{name: "shard", tags: {clusterID: "6272208615254493595", database: "telegraf", engine: "tsm1", hostname: "WattsInfluxDB", id: "2", nodeID: "localhost:8088", path: "/Users/watts/.influxdb/data/telegraf/default/2", retentionPolicy: "default"}, columns: ["time", "last"], values: [[1464811503000000000, 200]]}]},
]}
const response = {
results: [
{
series: [
{
name: 'shard',
tags: {
clusterID: '6272208615254493595',
database: '_internal',
engine: 'tsm1',
hostname: 'WattsInfluxDB',
id: '1',
nodeID: 'localhost:8088',
path: '/Users/watts/.influxdb/data/_internal/monitor/1',
retentionPolicy: 'monitor',
},
columns: ['time', 'last'],
values: [[1464811503000000000, 100]],
},
],
},
{
series: [
{
name: 'shard',
tags: {
clusterID: '6272208615254493595',
database: 'telegraf',
engine: 'tsm1',
hostname: 'WattsInfluxDB',
id: '2',
nodeID: 'localhost:8088',
path: '/Users/watts/.influxdb/data/telegraf/default/2',
retentionPolicy: 'default',
},
columns: ['time', 'last'],
values: [[1464811503000000000, 200]],
},
],
},
],
}
const result = diskBytesFromShard(response)
const expectedTotal = 300
@ -24,7 +65,7 @@ describe('diskBytesFromShard', () => {
})
it('exposes the server error', () => {
const response = {results: [{error: "internal server error?"}]}
const response = {results: [{error: 'internal server error?'}]}
const result = diskBytesFromShard(response)
@ -35,17 +76,65 @@ describe('diskBytesFromShard', () => {
describe('diskBytesFromShardForDatabase', () => {
it('return parses data as expected', () => {
const response = {results: [{series: [
{name: "shard", tags: {nodeID: "localhost:8088", path: "/Users/watts/.influxdb/data/_internal/monitor/1", retentionPolicy: "monitor"}, columns: ["time", "last"], values: [["2016-06-02T01:06:13Z", 100]]},
{name: "shard", tags: {nodeID: "localhost:8088", path: "/Users/watts/.influxdb/data/_internal/monitor/3", retentionPolicy: "monitor"}, columns: ["time", "last"], values: [["2016-06-02T01:06:13Z", 200]]},
{name: "shard", tags: {nodeID: "localhost:8188", path: "/Users/watts/.influxdb/data/_internal/monitor/1", retentionPolicy: "monitor"}, columns: ["time", "last"], values: [["2016-06-02T01:06:13Z", 100]]},
{name: "shard", tags: {nodeID: "localhost:8188", path: "/Users/watts/.influxdb/data/_internal/monitor/3", retentionPolicy: "monitor"}, columns: ["time", "last"], values: [["2016-06-02T01:06:13Z", 200]]},
]}]}
const response = {
results: [
{
series: [
{
name: 'shard',
tags: {
nodeID: 'localhost:8088',
path: '/Users/watts/.influxdb/data/_internal/monitor/1',
retentionPolicy: 'monitor',
},
columns: ['time', 'last'],
values: [['2016-06-02T01:06:13Z', 100]],
},
{
name: 'shard',
tags: {
nodeID: 'localhost:8088',
path: '/Users/watts/.influxdb/data/_internal/monitor/3',
retentionPolicy: 'monitor',
},
columns: ['time', 'last'],
values: [['2016-06-02T01:06:13Z', 200]],
},
{
name: 'shard',
tags: {
nodeID: 'localhost:8188',
path: '/Users/watts/.influxdb/data/_internal/monitor/1',
retentionPolicy: 'monitor',
},
columns: ['time', 'last'],
values: [['2016-06-02T01:06:13Z', 100]],
},
{
name: 'shard',
tags: {
nodeID: 'localhost:8188',
path: '/Users/watts/.influxdb/data/_internal/monitor/3',
retentionPolicy: 'monitor',
},
columns: ['time', 'last'],
values: [['2016-06-02T01:06:13Z', 200]],
},
],
},
],
}
const result = diskBytesFromShardForDatabase(response)
const expected = {
1: [{nodeID: 'localhost:8088', diskUsage: 100}, {nodeID: 'localhost:8188', diskUsage: 100}],
3: [{nodeID: 'localhost:8088', diskUsage: 200}, {nodeID: 'localhost:8188', diskUsage: 200}],
1: [
{nodeID: 'localhost:8088', diskUsage: 100},
{nodeID: 'localhost:8188', diskUsage: 100},
],
3: [
{nodeID: 'localhost:8088', diskUsage: 200},
{nodeID: 'localhost:8188', diskUsage: 200},
],
}
expect(result.shardData).to.deep.equal(expected)
@ -61,7 +150,7 @@ describe('diskBytesFromShardForDatabase', () => {
})
it('exposes the server error', () => {
const response = {results: [{error: "internal server error?"}]}
const response = {results: [{error: 'internal server error?'}]}
const result = diskBytesFromShardForDatabase(response)

View File

@ -43,14 +43,20 @@ describe('getRangeForDygraphSpec', () => {
const timeSeries = [[date, max], [date, mid], [date, min]]
it('can pad positive values', () => {
const [actualMin, actualMax] = getRange(timeSeries, undefined, {...kapacitor, value: 20})
const [actualMin, actualMax] = getRange(timeSeries, undefined, {
...kapacitor,
value: 20,
})
expect(actualMin).to.equal(min)
expect(actualMax).to.be.above(max)
})
it('can pad negative values', () => {
const [actualMin, actualMax] = getRange(timeSeries, undefined, {...kapacitor, value: -10})
const [actualMin, actualMax] = getRange(timeSeries, undefined, {
...kapacitor,
value: -10,
})
expect(actualMin).to.be.below(min)
expect(actualMax).to.equal(max)
@ -60,7 +66,10 @@ describe('getRangeForDygraphSpec', () => {
it('subtracts from a positive value', () => {
const value = 2
const opAndValue = {operator: 'less than', value}
const [actualMin, actualMax] = getRange(timeSeries, undefined, {...kapacitor, ...opAndValue})
const [actualMin, actualMax] = getRange(timeSeries, undefined, {
...kapacitor,
...opAndValue,
})
expect(actualMin).to.be.lessThan(value)
expect(actualMax).to.equal(max)
@ -72,14 +81,20 @@ describe('getRangeForDygraphSpec', () => {
const timeSeries = [[date, max], [date, min], [date, mid]]
it('can pad positive values', () => {
const [actualMin, actualMax] = getRange(timeSeries, undefined, {...kapacitor, rangeValue: 20})
const [actualMin, actualMax] = getRange(timeSeries, undefined, {
...kapacitor,
rangeValue: 20,
})
expect(actualMin).to.equal(min)
expect(actualMax).to.be.above(max)
})
it('can pad negative values', () => {
const [actualMin, actualMax] = getRange(timeSeries, undefined, {...kapacitor, rangeValue: -10})
const [actualMin, actualMax] = getRange(timeSeries, undefined, {
...kapacitor,
rangeValue: -10,
})
expect(actualMin).to.be.below(min)
expect(actualMax).to.equal(max)

View File

@ -15,36 +15,24 @@ it('can parse an alerta tick script', () => {
const expectedObj = [
{
name: "resource",
args: [
"Hostname or service",
],
name: 'resource',
args: ['Hostname or service'],
},
{
name: "event",
args: [
"Something went wrong",
],
name: 'event',
args: ['Something went wrong'],
},
{
name: "environment",
args: [
"Development",
],
name: 'environment',
args: ['Development'],
},
{
name: "group",
args: [
"Dev. Servers",
],
name: 'group',
args: ['Dev. Servers'],
},
{
name: "services",
args: [
"a",
"b",
"c",
],
name: 'services',
args: ['a', 'b', 'c'],
},
]

View File

@ -2,7 +2,11 @@ import showDatabases from 'shared/parsing/showDatabases'
describe('showDatabases', () => {
it('exposes all the database properties', () => {
const response = {results: [{series: [{columns: ["name"], values: [["mydb1"], ["mydb2"]]}]}]}
const response = {
results: [
{series: [{columns: ['name'], values: [['mydb1'], ['mydb2']]}]},
],
}
const result = showDatabases(response)
@ -13,7 +17,7 @@ describe('showDatabases', () => {
})
it('returns an empty array when there are no databases', () => {
const response = {results: [{series: [{columns: ["name"]}]}]}
const response = {results: [{series: [{columns: ['name']}]}]}
const result = showDatabases(response)
@ -22,7 +26,7 @@ describe('showDatabases', () => {
})
it('exposes the server error', () => {
const response = {results: [{error: "internal server error?"}]}
const response = {results: [{error: 'internal server error?'}]}
const result = showDatabases(response)

View File

@ -2,7 +2,15 @@ import parseShowFieldKeys from 'shared/parsing/showFieldKeys'
describe('parseShowFieldKeys', () => {
it('parses a single result', () => {
const response = {results: [{series: [{name: "m1", columns: ["fieldKey"], values: [["f1"], ["f2"]]}]}]}
const response = {
results: [
{
series: [
{name: 'm1', columns: ['fieldKey'], values: [['f1'], ['f2']]},
],
},
],
}
const result = parseShowFieldKeys(response)
expect(result.errors).to.eql([])
@ -12,7 +20,20 @@ describe('parseShowFieldKeys', () => {
})
it('parses multiple results', () => {
const response = {results: [{series: [{name: "m1", columns: ["fieldKey"], values: [["f1"], ["f2"]]}]}, {series: [{name: "m2", columns: ["fieldKey"], values: [["f3"], ["f4"]]}]}]}
const response = {
results: [
{
series: [
{name: 'm1', columns: ['fieldKey'], values: [['f1'], ['f2']]},
],
},
{
series: [
{name: 'm2', columns: ['fieldKey'], values: [['f3'], ['f4']]},
],
},
],
}
const result = parseShowFieldKeys(response)
expect(result.errors).to.eql([])
expect(result.fieldSets).to.eql({
@ -22,14 +43,31 @@ describe('parseShowFieldKeys', () => {
})
it('parses multiple errors', () => {
const response = {results: [{error: "measurement not found: m1"}, {error: "measurement not found: m2"}]}
const response = {
results: [
{error: 'measurement not found: m1'},
{error: 'measurement not found: m2'},
],
}
const result = parseShowFieldKeys(response)
expect(result.errors).to.eql(['measurement not found: m1', 'measurement not found: m2'])
expect(result.errors).to.eql([
'measurement not found: m1',
'measurement not found: m2',
])
expect(result.fieldSets).to.eql({})
})
it('parses a mix of results and errors', () => {
const response = {results: [{series: [{name: "m1", columns: ["fieldKey"], values: [["f1"], ["f2"]]}]}, {error: "measurement not found: m2"}]}
const response = {
results: [
{
series: [
{name: 'm1', columns: ['fieldKey'], values: [['f1'], ['f2']]},
],
},
{error: 'measurement not found: m2'},
],
}
const result = parseShowFieldKeys(response)
expect(result.errors).to.eql(['measurement not found: m2'])
expect(result.fieldSets).to.eql({

View File

@ -2,7 +2,21 @@ import showQueriesParser from 'shared/parsing/showQueries'
describe('showQueriesParser', () => {
it('exposes all currently running queries', () => {
const response = {results: [{series: [{columns: ["qid", "query", "database", "duration"], values: [[1, "SHOW QUERIES", "db1", "1s"], [2, "SELECT foo FROM bar", "db1", "2s"]]}]}]}
const response = {
results: [
{
series: [
{
columns: ['qid', 'query', 'database', 'duration'],
values: [
[1, 'SHOW QUERIES', 'db1', '1s'],
[2, 'SELECT foo FROM bar', 'db1', '2s'],
],
},
],
},
],
}
const result = showQueriesParser(response)
@ -24,7 +38,7 @@ describe('showQueriesParser', () => {
})
it('exposes the server error', () => {
const response = {results: [{error: "internal server error?"}]}
const response = {results: [{error: 'internal server error?'}]}
const result = showQueriesParser(response)

View File

@ -2,7 +2,15 @@ import parseShowTagKeys from 'shared/parsing/showTagKeys'
describe('parseShowTagKeys', () => {
it('parses the tag keys', () => {
const response = {results: [{series: [{name: "cpu", columns: ["tagKey"], values: [["cpu"], ["host"]]}]}]}
const response = {
results: [
{
series: [
{name: 'cpu', columns: ['tagKey'], values: [['cpu'], ['host']]},
],
},
],
}
const result = parseShowTagKeys(response)
expect(result.errors).to.eql([])
@ -18,7 +26,7 @@ describe('parseShowTagKeys', () => {
})
it('handles errors', () => {
const response = {results: [{error: "influxdb error"}]}
const response = {results: [{error: 'influxdb error'}]}
const result = parseShowTagKeys(response)
expect(result.errors).to.eql([response.results[0].error])

View File

@ -16,13 +16,13 @@ describe('showTagValuesParser', () => {
{
series: [
{
name: "measurementA",
columns: ["key", "value"],
name: 'measurementA',
columns: ['key', 'value'],
values: [
["host", "hostA"],
["host", "hostB"],
["cpu", "cpu0"],
["cpu", "cpu1"],
['host', 'hostA'],
['host', 'hostB'],
['cpu', 'cpu0'],
['cpu', 'cpu1'],
],
},
],
@ -34,14 +34,8 @@ describe('showTagValuesParser', () => {
expect(result.errors).to.eql([])
expect(result.tags).to.eql({
host: [
'hostA',
'hostB',
],
cpu: [
'cpu0',
'cpu1',
],
host: ['hostA', 'hostB'],
cpu: ['cpu0', 'cpu1'],
})
})
})

View File

@ -1,20 +1,15 @@
import {
buildRoles,
buildClusterAccounts,
} from 'shared/presenters'
import {buildRoles, buildClusterAccounts} from 'shared/presenters'
describe('Presenters', function() {
describe('roles utils', function() {
describe('buildRoles', function() {
describe('when a role has no users', function() {
it('sets a role\'s users as an empty array', function() {
it("sets a role's users as an empty array", function() {
const roles = [
{
name: "Marketing",
name: 'Marketing',
permissions: {
"": [
"ViewAdmin",
],
'': ['ViewAdmin'],
},
},
]
@ -26,14 +21,11 @@ describe('Presenters', function() {
})
describe('when a role has no permissions', function() {
it('set\'s a roles permission as an empty array', function() {
it("set's a roles permission as an empty array", function() {
const roles = [
{
name: "Marketing",
users: [
"roley@influxdb.com",
"will@influxdb.com",
],
name: 'Marketing',
users: ['roley@influxdb.com', 'will@influxdb.com'],
},
]
@ -47,23 +39,13 @@ describe('Presenters', function() {
beforeEach(function() {
const roles = [
{
name: "Marketing",
name: 'Marketing',
permissions: {
"": [
"ViewAdmin",
],
db1: [
"ReadData",
],
db2: [
"ReadData",
"AddRemoveNode",
],
'': ['ViewAdmin'],
db1: ['ReadData'],
db2: ['ReadData', 'AddRemoveNode'],
},
users: [
"roley@influxdb.com",
"will@influxdb.com",
],
users: ['roley@influxdb.com', 'will@influxdb.com'],
},
]
@ -73,8 +55,8 @@ describe('Presenters', function() {
it('each role has a name and a list of users (if they exist)', function() {
const role = this.roles[0]
expect(role.name).to.equal('Marketing')
expect(role.users).to.contain("roley@influxdb.com")
expect(role.users).to.contain("will@influxdb.com")
expect(role.users).to.contain('roley@influxdb.com')
expect(role.users).to.contain('will@influxdb.com')
})
it('transforms permissions into a list of objects and each permission has a list of resources', function() {
@ -109,46 +91,33 @@ describe('Presenters', function() {
it('adds role information to each cluster account and parses permissions', function() {
const users = [
{
name: "jon@example.com",
hash: "xxxxx",
name: 'jon@example.com',
hash: 'xxxxx',
permissions: {
"": [
"ViewAdmin",
],
db1: [
"ReadData",
],
'': ['ViewAdmin'],
db1: ['ReadData'],
},
},
{
name: "ned@example.com",
hash: "xxxxx",
name: 'ned@example.com',
hash: 'xxxxx',
},
]
const roles = [
{
name: "Admin",
name: 'Admin',
permissions: {
db2: [
"ViewAdmin",
],
db2: ['ViewAdmin'],
},
users: [
"jon@example.com",
"ned@example.com",
],
users: ['jon@example.com', 'ned@example.com'],
},
{
name: "Marketing",
name: 'Marketing',
permissions: {
db3: [
"ReadData",
],
db3: ['ReadData'],
},
users: [
"jon@example.com",
],
users: ['jon@example.com'],
},
]
@ -156,8 +125,8 @@ describe('Presenters', function() {
const expected = [
{
name: "jon@example.com",
hash: "xxxxx",
name: 'jon@example.com',
hash: 'xxxxx',
permissions: [
{
name: 'ViewAdmin',
@ -174,7 +143,7 @@ describe('Presenters', function() {
],
roles: [
{
name: "Admin",
name: 'Admin',
permissions: [
{
name: 'ViewAdmin',
@ -183,13 +152,10 @@ describe('Presenters', function() {
resources: ['db2'],
},
],
users: [
"jon@example.com",
"ned@example.com",
],
users: ['jon@example.com', 'ned@example.com'],
},
{
name: "Marketing",
name: 'Marketing',
permissions: [
{
name: 'ReadData',
@ -198,19 +164,17 @@ describe('Presenters', function() {
resources: ['db3'],
},
],
users: [
"jon@example.com",
],
users: ['jon@example.com'],
},
],
},
{
name: "ned@example.com",
hash: "xxxxx",
name: 'ned@example.com',
hash: 'xxxxx',
permissions: [],
roles: [
{
name: "Admin",
name: 'Admin',
permissions: [
{
name: 'ViewAdmin',
@ -219,10 +183,7 @@ describe('Presenters', function() {
resources: ['db2'],
},
],
users: [
"jon@example.com",
"ned@example.com",
],
users: ['jon@example.com', 'ned@example.com'],
},
],
},
@ -241,10 +202,12 @@ describe('Presenters', function() {
})
it('sets roles to an empty array if a user has no roles', function() {
const users = [{
name: "ned@example.com",
hash: "xxxxx",
}]
const users = [
{
name: 'ned@example.com',
hash: 'xxxxx',
},
]
const roles = []
const actual = buildClusterAccounts(users, roles)

View File

@ -5,56 +5,51 @@ import {errorThrown} from 'shared/actions/errors'
import {HTTP_FORBIDDEN} from 'shared/constants'
const errorForbidden = {
"data":"",
"status":403,
"statusText":"Forbidden",
"headers":{
"date":"Mon, 17 Apr 2017 18:35:34 GMT",
"content-length":"0",
"x-chronograf-version":"1.2.0-beta8-71-gd875ea4a",
"content-type":"text/plain; charset=utf-8"
},
"config":{
"transformRequest":{
data: '',
status: 403,
statusText: 'Forbidden',
headers: {
date: 'Mon, 17 Apr 2017 18:35:34 GMT',
'content-length': '0',
'x-chronograf-version': '1.2.0-beta8-71-gd875ea4a',
'content-type': 'text/plain; charset=utf-8',
},
config: {
transformRequest: {},
transformResponse: {},
headers: {
Accept: 'application/json, text/plain, */*',
'Content-Type': 'application/json;charset=utf-8',
},
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
method: 'GET',
url: '/chronograf/v1/me',
data: '{}',
params: {},
},
request: {},
auth: {
links: [
{
name: 'github',
label: 'Github',
login: '/oauth/github/login',
logout: '/oauth/github/logout',
callback: '/oauth/github/callback',
},
"transformResponse":{
},
"headers":{
"Accept":"application/json, text/plain, *\/*",
"Content-Type":"application/json;charset=utf-8"
},
"timeout":0,
"xsrfCookieName":"XSRF-TOKEN",
"xsrfHeaderName":"X-XSRF-TOKEN",
"maxContentLength":-1,
"method":"GET",
"url":"/chronograf/v1/me",
"data":"{}",
"params":{
}
},
"request":{
},
"auth":{
"links":[
{
"name":"github",
"label":"Github",
"login":"/oauth/github/login",
"logout":"/oauth/github/logout",
"callback":"/oauth/github/callback"
}
]
}
],
},
}
describe('Shared.Reducers.errorsReducer', () => {
it('should handle ERROR_THROWN', () => {
const reducedState = errorsReducer(initialState, errorThrown(errorForbidden))
const reducedState = errorsReducer(
initialState,
errorThrown(errorForbidden)
)
expect(reducedState.error.status).to.equal(HTTP_FORBIDDEN)
})

View File

@ -1,45 +1,56 @@
import reducer from 'shared/reducers/sources'
import {
loadSources,
updateSource,
addSource,
} from 'shared/actions/sources'
import {loadSources, updateSource, addSource} from 'shared/actions/sources'
describe('Shared.Reducers.sources', () => {
it('can correctly show default sources when adding a source', () => {
let state = []
state = reducer(state, addSource({
id: '1',
"default": true,
}))
state = reducer(
state,
addSource({
id: '1',
default: true,
})
)
state = reducer(state, addSource({
id: '2',
"default": true,
}))
state = reducer(
state,
addSource({
id: '2',
default: true,
})
)
expect(state.filter((s) => s.default).length).to.equal(1)
expect(state.filter(s => s.default).length).to.equal(1)
})
it('can correctly show default sources when updating a source', () => {
let state = []
state = reducer(state, addSource({
id: '1',
"default": true,
}))
state = reducer(
state,
addSource({
id: '1',
default: true,
})
)
state = reducer(state, addSource({
id: '2',
"default": true,
}))
state = reducer(
state,
addSource({
id: '2',
default: true,
})
)
state = reducer(state, updateSource({
id: '1',
"default": true,
}))
state = reducer(
state,
updateSource({
id: '1',
default: true,
})
)
expect(state.find(({id}) => id === '1').default).to.equal(true)
expect(state.find(({id}) => id === '2').default).to.equal(false)

View File

@ -14,7 +14,7 @@ describe('Formatting helpers', () => {
expect(actual).to.equal('0 Bytes')
})
it('converts a raw byte value into it\'s most appropriate unit', () => {
it("converts a raw byte value into it's most appropriate unit", () => {
expect(formatBytes(1000)).to.equal('1 KB')
expect(formatBytes(1000000)).to.equal('1 MB')
expect(formatBytes(1000000000)).to.equal('1 GB')

View File

@ -4,14 +4,13 @@ describe('timeSeriesToDygraph', () => {
it('parses a raw InfluxDB response into a dygraph friendly data format', () => {
const influxResponse = [
{
response:
{
response: {
results: [
{
series: [
{
name: "m1",
columns: ["time", "f1"],
name: 'm1',
columns: ['time', 'f1'],
values: [[1000, 1], [2000, 2]],
},
],
@ -19,8 +18,8 @@ describe('timeSeriesToDygraph', () => {
{
series: [
{
name: "m1",
columns: ["time", "f2"],
name: 'm1',
columns: ['time', 'f2'],
values: [[2000, 3], [4000, 4]],
},
],
@ -33,11 +32,7 @@ describe('timeSeriesToDygraph', () => {
const actual = timeSeriesToDygraph(influxResponse)
const expected = {
labels: [
'time',
`m1.f1`,
`m1.f2`,
],
labels: ['time', `m1.f1`, `m1.f2`],
timeSeries: [
[new Date(1000), 1, null],
[new Date(2000), 2, 3],
@ -59,14 +54,13 @@ describe('timeSeriesToDygraph', () => {
it('can sort numerical timestamps correctly', () => {
const influxResponse = [
{
response:
{
response: {
results: [
{
series: [
{
name: "m1",
columns: ["time", "f1"],
name: 'm1',
columns: ['time', 'f1'],
values: [[100, 1], [3000, 3], [200, 2]],
},
],
@ -76,19 +70,11 @@ describe('timeSeriesToDygraph', () => {
},
]
const actual = timeSeriesToDygraph(influxResponse)
const expected = {
labels: [
'time',
'm1.f1',
],
timeSeries: [
[new Date(100), 1],
[new Date(200), 2],
[new Date(3000), 3],
],
labels: ['time', 'm1.f1'],
timeSeries: [[new Date(100), 1], [new Date(200), 2], [new Date(3000), 3]],
}
expect(actual.timeSeries).to.deep.equal(expected.timeSeries)
@ -97,14 +83,13 @@ describe('timeSeriesToDygraph', () => {
it('can parse multiple responses into two axes', () => {
const influxResponse = [
{
response:
{
response: {
results: [
{
series: [
{
name: "m1",
columns: ["time", "f1"],
name: 'm1',
columns: ['time', 'f1'],
values: [[1000, 1], [2000, 2]],
},
],
@ -112,8 +97,8 @@ describe('timeSeriesToDygraph', () => {
{
series: [
{
name: "m1",
columns: ["time", "f2"],
name: 'm1',
columns: ['time', 'f2'],
values: [[2000, 3], [4000, 4]],
},
],
@ -122,14 +107,13 @@ describe('timeSeriesToDygraph', () => {
},
},
{
response:
{
response: {
results: [
{
series: [
{
name: "m3",
columns: ["time", "f3"],
name: 'm3',
columns: ['time', 'f3'],
values: [[1000, 1], [2000, 2]],
},
],
@ -159,14 +143,13 @@ describe('timeSeriesToDygraph', () => {
it('can parse multiple responses with the same field and measurement', () => {
const influxResponse = [
{
response:
{
response: {
results: [
{
series: [
{
name: "m1",
columns: ["time", "f1"],
name: 'm1',
columns: ['time', 'f1'],
values: [[1000, 1], [2000, 2]],
},
],
@ -175,14 +158,13 @@ describe('timeSeriesToDygraph', () => {
},
},
{
response:
{
response: {
results: [
{
series: [
{
name: "m1",
columns: ["time", "f1"],
name: 'm1',
columns: ['time', 'f1'],
values: [[2000, 3], [4000, 4]],
},
],
@ -195,11 +177,7 @@ describe('timeSeriesToDygraph', () => {
const actual = timeSeriesToDygraph(influxResponse)
const expected = {
labels: [
'time',
`m1.f1`,
`m1.f1`,
],
labels: ['time', `m1.f1`, `m1.f1`],
timeSeries: [
[new Date(1000), 1, null],
[new Date(2000), 2, 3],
@ -218,14 +196,13 @@ describe('timeSeriesToDygraph', () => {
it('it does not use multiple axes if being used for the DataExplorer', () => {
const influxResponse = [
{
response:
{
response: {
results: [
{
series: [
{
name: "m1",
columns: ["time", "f1"],
name: 'm1',
columns: ['time', 'f1'],
values: [[1000, 1], [2000, 2]],
},
],
@ -234,14 +211,13 @@ describe('timeSeriesToDygraph', () => {
},
},
{
response:
{
response: {
results: [
{
series: [
{
name: "m1",
columns: ["time", "f2"],
name: 'm1',
columns: ['time', 'f2'],
values: [[2000, 3], [4000, 4]],
},
],
@ -252,7 +228,11 @@ describe('timeSeriesToDygraph', () => {
]
const isInDataExplorer = true
const actual = timeSeriesToDygraph(influxResponse, undefined, isInDataExplorer)
const actual = timeSeriesToDygraph(
influxResponse,
undefined,
isInDataExplorer
)
const expected = {}
@ -262,14 +242,13 @@ describe('timeSeriesToDygraph', () => {
it('parses a raw InfluxDB response into a dygraph friendly data format', () => {
const influxResponse = [
{
response:
{
response: {
results: [
{
series: [
{
name: "mb",
columns: ["time", "f1"],
name: 'mb',
columns: ['time', 'f1'],
values: [[1000, 1], [2000, 2]],
},
],
@ -277,8 +256,8 @@ describe('timeSeriesToDygraph', () => {
{
series: [
{
name: "ma",
columns: ["time", "f1"],
name: 'ma',
columns: ['time', 'f1'],
values: [[1000, 1], [2000, 2]],
},
],
@ -286,8 +265,8 @@ describe('timeSeriesToDygraph', () => {
{
series: [
{
name: "mc",
columns: ["time", "f2"],
name: 'mc',
columns: ['time', 'f2'],
values: [[2000, 3], [4000, 4]],
},
],
@ -295,8 +274,8 @@ describe('timeSeriesToDygraph', () => {
{
series: [
{
name: "mc",
columns: ["time", "f1"],
name: 'mc',
columns: ['time', 'f1'],
values: [[2000, 3], [4000, 4]],
},
],
@ -308,13 +287,7 @@ describe('timeSeriesToDygraph', () => {
const actual = timeSeriesToDygraph(influxResponse)
const expected = [
'time',
`ma.f1`,
`mb.f1`,
`mc.f1`,
`mc.f2`,
]
const expected = ['time', `ma.f1`, `mb.f1`, `mc.f1`, `mc.f2`]
expect(actual.labels).to.deep.equal(expected)
})

View File

@ -1,11 +1,5 @@
import React, {PropTypes} from 'react'
import {
Tab,
Tabs,
TabPanel,
TabPanels,
TabList,
} from 'shared/components/Tabs'
import {Tab, Tabs, TabPanel, TabPanels, TabList} from 'shared/components/Tabs'
import UsersTable from 'src/admin/components/UsersTable'
import RolesTable from 'src/admin/components/RolesTable'
import QueriesPage from 'src/admin/containers/QueriesPage'
@ -97,9 +91,9 @@ const AdminTabs = ({
{tabs.map((t, i) => <Tab key={tabs[i].type}>{tabs[i].type}</Tab>)}
</TabList>
<TabPanels customClass="col-md-10 admin-tabs--content">
{tabs.map((t, i) => (
{tabs.map((t, i) =>
<TabPanel key={tabs[i].type}>{t.component}</TabPanel>
))}
)}
</TabPanels>
</Tabs>
)

View File

@ -41,7 +41,7 @@ const DatabaseManager = ({
</button>
</div>
<div className="panel-body">
{databases.map(db => (
{databases.map(db =>
<DatabaseTable
key={db.links.self}
database={db}
@ -63,7 +63,7 @@ const DatabaseManager = ({
onRemoveRetentionPolicy={onRemoveRetentionPolicy}
onDeleteRetentionPolicy={onDeleteRetentionPolicy}
/>
))}
)}
</div>
</div>
)

View File

@ -54,7 +54,7 @@ class DatabaseRow extends Component {
defaultValue={name}
placeholder="Name this RP"
onKeyDown={e => this.handleKeyDown(e, database)}
ref={r => this.name = r}
ref={r => (this.name = r)}
autoFocus={true}
spellCheck={false}
autoComplete={false}
@ -69,7 +69,7 @@ class DatabaseRow extends Component {
defaultValue={formattedDuration}
placeholder="How long should Data last"
onKeyDown={e => this.handleKeyDown(e, database)}
ref={r => this.duration = r}
ref={r => (this.duration = r)}
autoFocus={!isNew}
spellCheck={false}
autoComplete={false}
@ -85,7 +85,7 @@ class DatabaseRow extends Component {
defaultValue={replication || 1}
placeholder="# of Nodes"
onKeyDown={e => this.handleKeyDown(e, database)}
ref={r => this.replication = r}
ref={r => (this.replication = r)}
spellCheck={false}
autoComplete={false}
/>

View File

@ -111,7 +111,7 @@ const Header = ({
)
}
const EditHeader = ({database, onEdit, onKeyDown, onConfirm, onCancel}) => (
const EditHeader = ({database, onEdit, onKeyDown, onConfirm, onCancel}) =>
<div className="db-manager-header db-manager-header--edit">
<input
className="form-control input-sm"
@ -127,7 +127,6 @@ const EditHeader = ({database, onEdit, onKeyDown, onConfirm, onCancel}) => (
/>
<ConfirmButtons item={database} onConfirm={onConfirm} onCancel={onCancel} />
</div>
)
const {func, shape, bool} = PropTypes

View File

@ -1,12 +1,11 @@
import React, {PropTypes} from 'react'
const EmptyRow = ({tableName}) => (
const EmptyRow = ({tableName}) =>
<tr className="table-empty-state">
<th colSpan="5">
<p>You don't have any {tableName},<br />why not create one?</p>
</th>
</tr>
)
const {string} = PropTypes

View File

@ -3,7 +3,7 @@ import React, {PropTypes} from 'react'
import QueryRow from 'src/admin/components/QueryRow'
import {QUERIES_TABLE} from 'src/admin/constants/tableSizing'
const QueriesTable = ({queries, onKillQuery}) => (
const QueriesTable = ({queries, onKillQuery}) =>
<div>
<div className="panel panel-default">
<div className="panel-body">
@ -21,15 +21,14 @@ const QueriesTable = ({queries, onKillQuery}) => (
</tr>
</thead>
<tbody>
{queries.map(q => (
{queries.map(q =>
<QueryRow key={q.id} query={q} onKill={onKillQuery} />
))}
)}
</tbody>
</table>
</div>
</div>
</div>
)
const {arrayOf, func, shape} = PropTypes

View File

@ -89,12 +89,9 @@ const RoleRow = ({
onApply={handleUpdateUsers}
buttonSize="btn-xs"
buttonColor="btn-primary"
customClass={classnames(
`dropdown-${ROLES_TABLE.colUsers}`,
{
'admin-table--multi-select-empty': !users.length,
}
)}
customClass={classnames(`dropdown-${ROLES_TABLE.colUsers}`, {
'admin-table--multi-select-empty': !users.length,
})}
/>
: null}
</td>

View File

@ -16,7 +16,7 @@ const RolesTable = ({
onFilter,
onUpdateRoleUsers,
onUpdateRolePermissions,
}) => (
}) =>
<div className="panel panel-default">
<FilterBar
type="roles"
@ -38,7 +38,7 @@ const RolesTable = ({
{roles.length
? roles
.filter(r => !r.hidden)
.map(role => (
.map(role =>
<RoleRow
key={role.links.self}
allUsers={allUsers}
@ -53,13 +53,12 @@ const RolesTable = ({
isEditing={role.isEditing}
isNew={role.isNew}
/>
))
)
: <EmptyRow tableName={'Roles'} />}
</tbody>
</table>
</div>
</div>
)
const {arrayOf, bool, func, shape, string} = PropTypes

View File

@ -93,12 +93,9 @@ const UserRow = ({
onApply={handleUpdateRoles}
buttonSize="btn-xs"
buttonColor="btn-primary"
customClass={classnames(
`dropdown-${USERS_TABLE.colRoles}`,
{
'admin-table--multi-select-empty': !roles.length,
}
)}
customClass={classnames(`dropdown-${USERS_TABLE.colRoles}`, {
'admin-table--multi-select-empty': !roles.length,
})}
/>
</td>
: null}

View File

@ -19,7 +19,7 @@ const UsersTable = ({
onUpdatePermissions,
onUpdateRoles,
onUpdatePassword,
}) => (
}) =>
<div className="panel panel-default">
<FilterBar
type="users"
@ -42,7 +42,7 @@ const UsersTable = ({
{users.length
? users
.filter(u => !u.hidden)
.map(user => (
.map(user =>
<UserRow
key={user.links.self}
user={user}
@ -59,13 +59,12 @@ const UsersTable = ({
onUpdateRoles={onUpdateRoles}
onUpdatePassword={onUpdatePassword}
/>
))
)
: <EmptyRow tableName={'Users'} />}
</tbody>
</table>
</div>
</div>
)
const {arrayOf, bool, func, shape, string} = PropTypes

View File

@ -62,7 +62,7 @@ export default function admin(state = initialState, action) {
const {database} = action.payload
const databases = state.databases.map(
db =>
(db.links.self === database.links.self
db.links.self === database.links.self
? {
...database,
retentionPolicies: [
@ -70,7 +70,7 @@ export default function admin(state = initialState, action) {
...database.retentionPolicies,
],
}
: db)
: db
)
return {...state, databases}
@ -112,15 +112,15 @@ export default function admin(state = initialState, action) {
const newState = {
databases: state.databases.map(
db =>
(db.links.self === database.links.self
db.links.self === database.links.self
? {
...db,
retentionPolicies: db.retentionPolicies.map(
rp =>
(rp.links.self === stale.links.self ? {...synced} : rp)
rp.links.self === stale.links.self ? {...synced} : rp
),
}
: db)
: db
),
}
@ -152,7 +152,7 @@ export default function admin(state = initialState, action) {
const newState = {
databases: state.databases.map(
db =>
(db.links.self === database.links.self ? {...db, ...updates} : db)
db.links.self === database.links.self ? {...db, ...updates} : db
),
}
@ -165,17 +165,17 @@ export default function admin(state = initialState, action) {
const newState = {
databases: state.databases.map(
db =>
(db.links.self === database.links.self
db.links.self === database.links.self
? {
...db,
retentionPolicies: db.retentionPolicies.map(
rp =>
(rp.links.self === retentionPolicy.links.self
rp.links.self === retentionPolicy.links.self
? {...rp, ...updates}
: rp)
: rp
),
}
: db)
: db
),
}
@ -216,14 +216,14 @@ export default function admin(state = initialState, action) {
const newState = {
databases: state.databases.map(
db =>
(db.links.self === database.links.self
db.links.self === database.links.self
? {
...db,
retentionPolicies: db.retentionPolicies.filter(
rp => rp.links.self !== retentionPolicy.links.self
),
}
: db)
: db
),
}
@ -235,9 +235,7 @@ export default function admin(state = initialState, action) {
const newState = {
databases: state.databases.map(
db =>
(db.links.self === database.links.self
? {...db, deleteCode: ''}
: db)
db.links.self === database.links.self ? {...db, deleteCode: ''} : db
),
}

View File

@ -17,12 +17,12 @@ const Login = ({authData: {auth}}) => {
<h1 className="auth-text-logo">Chronograf</h1>
<p><strong>{VERSION}</strong> / Time-Series Data Visualization</p>
{auth.links &&
auth.links.map(({name, login, label}) => (
auth.links.map(({name, login, label}) =>
<a key={name} className="btn btn-primary" href={login}>
<span className={`icon ${name}`} />
Login with {label}
</a>
))}
)}
</div>
<p className="auth-credits">
Made by <span className="icon cubo-uniform" />InfluxData

View File

@ -19,7 +19,7 @@ const OverlayControls = props => {
<div className="overlay-controls--right">
<p>Visualization Type:</p>
<ul className="nav nav-tablist nav-tablist-sm">
{graphTypes.map(graphType => (
{graphTypes.map(graphType =>
<li
key={graphType.type}
className={classnames({
@ -29,7 +29,7 @@ const OverlayControls = props => {
>
{graphType.menuOption}
</li>
))}
)}
</ul>
<ConfirmButtons
onCancel={onCancel}

View File

@ -10,7 +10,7 @@ const TemplateControlBar = ({
onSelectTemplate,
onOpenTemplateManager,
isOpen,
}) => (
}) =>
<div className={classnames('template-control-bar', {show: isOpen})}>
<div className="template-control--container">
<div className="template-control--controls">
@ -53,7 +53,6 @@ const TemplateControlBar = ({
</button>
</div>
</div>
)
const {arrayOf, bool, func, shape, string} = PropTypes

View File

@ -2,8 +2,7 @@ import React, {Component, PropTypes} from 'react'
import classnames from 'classnames'
import uuid from 'node-uuid'
import TemplateVariableTable
from 'src/dashboards/components/TemplateVariableTable'
import TemplateVariableTable from 'src/dashboards/components/TemplateVariableTable'
import {TEMPLATE_VARIABLE_TYPES} from 'src/dashboards/constants'
@ -19,7 +18,7 @@ const TemplateVariableManager = ({
onDelete,
tempVarAlreadyExists,
isEdited,
}) => (
}) =>
<div className="template-variable-manager">
<div className="template-variable-manager--header">
<div className="page-header__left">
@ -59,7 +58,6 @@ const TemplateVariableManager = ({
/>
</div>
</div>
)
class TemplateVariableManagerWrapper extends Component {
constructor(props) {

View File

@ -9,18 +9,14 @@ import classnames from 'classnames'
import Dropdown from 'shared/components/Dropdown'
import DeleteConfirmButtons from 'shared/components/DeleteConfirmButtons'
import TemplateQueryBuilder
from 'src/dashboards/components/TemplateQueryBuilder'
import TemplateQueryBuilder from 'src/dashboards/components/TemplateQueryBuilder'
import {
runTemplateVariableQuery as runTemplateVariableQueryAJAX,
} from 'src/dashboards/apis'
import {runTemplateVariableQuery as runTemplateVariableQueryAJAX} from 'src/dashboards/apis'
import parsers from 'shared/parsing'
import {TEMPLATE_TYPES} from 'src/dashboards/constants'
import generateTemplateVariableQuery
from 'src/dashboards/utils/templateVariableQueryGenerator'
import generateTemplateVariableQuery from 'src/dashboards/utils/templateVariableQueryGenerator'
import {errorThrown as errorThrownAction} from 'shared/actions/errors'
import {publishAutoDismissingNotification} from 'shared/dispatchers'
@ -117,7 +113,7 @@ const TemplateVariableRow = ({
onSubmit,
onDelete,
onErrorThrown,
}) => (
}) =>
<form
className={classnames('template-variable-manager--table-row', {
editing: isEditing,
@ -178,7 +174,6 @@ const TemplateVariableRow = ({
/>
</div>
</form>
)
const TableInput = ({
name,

View File

@ -9,7 +9,7 @@ const TemplateVariableTable = ({
onRunQueryFailure,
onDelete,
tempVarAlreadyExists,
}) => (
}) =>
<div className="template-variable-manager--table">
{templates.length
? <div className="template-variable-manager--table-container">
@ -20,7 +20,7 @@ const TemplateVariableTable = ({
<div className="tvm--col-4" />
</div>
<div className="template-variable-manager--table-rows">
{templates.map(t => (
{templates.map(t =>
<TemplateVariableRow
key={t.id}
source={source}
@ -30,7 +30,7 @@ const TemplateVariableTable = ({
onDelete={onDelete}
tempVarAlreadyExists={tempVarAlreadyExists}
/>
))}
)}
</div>
</div>
: <div className="generic-empty-state">
@ -39,7 +39,6 @@ const TemplateVariableTable = ({
</h4>
</div>}
</div>
)
const {arrayOf, bool, func, shape, string} = PropTypes

View File

@ -68,7 +68,8 @@ export const TEMPLATE_VARIABLE_QUERIES = {
measurements: 'SHOW MEASUREMENTS ON :database:',
fieldKeys: 'SHOW FIELD KEYS ON :database: FROM :measurement:',
tagKeys: 'SHOW TAG KEYS ON :database: FROM :measurement:',
tagValues: 'SHOW TAG VALUES ON :database: FROM :measurement: WITH KEY=:tagKey:',
tagValues:
'SHOW TAG VALUES ON :database: FROM :measurement: WITH KEY=:tagKey:',
}
export const MATCH_INCOMPLETE_TEMPLATES = /:[\w-]*/g

View File

@ -10,8 +10,7 @@ import CellEditorOverlay from 'src/dashboards/components/CellEditorOverlay'
import DashboardHeader from 'src/dashboards/components/DashboardHeader'
import DashboardHeaderEdit from 'src/dashboards/components/DashboardHeaderEdit'
import Dashboard from 'src/dashboards/components/Dashboard'
import TemplateVariableManager
from 'src/dashboards/components/TemplateVariableManager'
import TemplateVariableManager from 'src/dashboards/components/TemplateVariableManager'
import {errorThrown as errorThrownAction} from 'shared/actions/errors'
@ -257,8 +256,8 @@ class DashboardPage extends Component {
],
}
const templatesIncludingDashTime = (dashboard &&
dashboard.templates.concat(dashboardTime)) || []
const templatesIncludingDashTime =
(dashboard && dashboard.templates.concat(dashboardTime)) || []
const {selectedCell, isEditMode, isTemplating} = this.state
@ -311,13 +310,13 @@ class DashboardPage extends Component {
showTemplateControlBar={showTemplateControlBar}
>
{dashboards
? dashboards.map((d, i) => (
? dashboards.map((d, i) =>
<li className="dropdown-item" key={i}>
<Link to={`/sources/${sourceID}/dashboards/${d.id}`}>
{d.name}
</Link>
</li>
))
)
: null}
</DashboardHeader>}
{dashboard

View File

@ -97,7 +97,7 @@ const DashboardsPage = React.createClass({
</tr>
</thead>
<tbody>
{dashboards.map(dashboard => (
{dashboards.map(dashboard =>
<tr key={dashboard.id} className="">
<td className="monotype">
<Link
@ -112,7 +112,7 @@ const DashboardsPage = React.createClass({
buttonSize="btn-xs"
/>
</tr>
))}
)}
</tbody>
</table>
: <div className="generic-empty-state">

View File

@ -1,6 +1,4 @@
import {
writeLineProtocol as writeLineProtocolAJAX,
} from 'src/data_explorer/apis'
import {writeLineProtocol as writeLineProtocolAJAX} from 'src/data_explorer/apis'
import {errorThrown} from 'shared/actions/errors'
import {publishAutoDismissingNotification} from 'shared/dispatchers'

View File

@ -66,9 +66,16 @@ const DatabaseDropdown = React.createClass({
return (
<Dropdown
className="dropdown-160 query-builder--db-dropdown"
items={namespaces.map(n => ({...n, text: `${n.database}.${n.retentionPolicy}`}))}
items={namespaces.map(n => ({
...n,
text: `${n.database}.${n.retentionPolicy}`,
}))}
onChoose={onChooseNamespace}
selected={(query.database && query.retentionPolicy) ? `${query.database}.${query.retentionPolicy}` : 'Choose a DB & RP'}
selected={
query.database && query.retentionPolicy
? `${query.database}.${query.retentionPolicy}`
: 'Choose a DB & RP'
}
/>
)
},

View File

@ -1,8 +1,7 @@
import React, {PropTypes} from 'react'
import FieldListItem from 'src/data_explorer/components/FieldListItem'
import GroupByTimeDropdown
from 'src/data_explorer/components/GroupByTimeDropdown'
import GroupByTimeDropdown from 'src/data_explorer/components/GroupByTimeDropdown'
import FancyScrollbar from 'shared/components/FancyScrollbar'
import {showFieldKeys} from 'shared/apis/metaQuery'

View File

@ -69,7 +69,12 @@ const QueryMaker = React.createClass({
render() {
const {height, top, layout} = this.props
return (
<div className={classnames('query-maker', {'query-maker--panel': layout === 'panel'})} style={{height, top}}>
<div
className={classnames('query-maker', {
'query-maker--panel': layout === 'panel',
})}
style={{height, top}}
>
{this.renderQueryTabList()}
{this.renderQueryBuilder()}
</div>
@ -77,7 +82,14 @@ const QueryMaker = React.createClass({
},
renderQueryBuilder() {
const {timeRange, actions, source, templates, layout, isInDataExplorer} = this.props
const {
timeRange,
actions,
source,
templates,
layout,
isInDataExplorer,
} = this.props
const query = this.getActiveQuery()
if (!query) {
@ -145,8 +157,8 @@ const QueryMaker = React.createClass({
onDelete={onDeleteQuery}
queryTabText={
q.rawText ||
buildInfluxQLQuery(timeRange, q) ||
`Query ${i + 1}`
buildInfluxQLQuery(timeRange, q) ||
`Query ${i + 1}`
}
/>
)

View File

@ -153,7 +153,7 @@ const ChronoTable = React.createClass({
<div style={{width: '100%', height: '100%', position: 'relative'}}>
{series.length < maximumTabsCount
? <div className="table--tabs">
{series.map(({name}, i) => (
{series.map(({name}, i) =>
<TabItem
isActive={i === activeSeriesIndex}
key={i}
@ -161,7 +161,7 @@ const ChronoTable = React.createClass({
index={i}
onClickTab={this.handleClickTab}
/>
))}
)}
</div>
: <Dropdown
className="dropdown-160 table--tabs-dropdown"
@ -192,12 +192,11 @@ const ChronoTable = React.createClass({
key={columnName}
columnKey={columnName}
header={<Cell>{columnName}</Cell>}
cell={({rowIndex}) => (
cell={({rowIndex}) =>
<CustomCell
columnName={columnName}
data={values[rowIndex][colIndex]}
/>
)}
/>}
width={columnWidths[columnName] || width}
minWidth={minWidth}
/>
@ -210,14 +209,13 @@ const ChronoTable = React.createClass({
},
})
const TabItem = ({name, index, onClickTab, isActive}) => (
const TabItem = ({name, index, onClickTab, isActive}) =>
<div
className={classnames('table--tab', {active: isActive})}
onClick={() => onClickTab(index)}
>
{name}
</div>
)
TabItem.propTypes = {
name: string,

View File

@ -2,11 +2,11 @@ import React, {PropTypes} from 'react'
import classnames from 'classnames'
import _ from 'lodash'
const VisHeader = ({views, view, onToggleView, name}) => (
const VisHeader = ({views, view, onToggleView, name}) =>
<div className="graph-heading">
{views.length
? <ul className="nav nav-tablist nav-tablist-sm">
{views.map(v => (
{views.map(v =>
<li
key={v}
onClick={() => onToggleView(v)}
@ -14,12 +14,11 @@ const VisHeader = ({views, view, onToggleView, name}) => (
>
{_.upperFirst(v)}
</li>
))}
)}
</ul>
: null}
<div className="graph-title">{name}</div>
</div>
)
const {arrayOf, func, string} = PropTypes

View File

@ -34,7 +34,8 @@ export const QUERY_TEMPLATES = [
},
{
text: 'Show Tag Values',
query: 'SHOW TAG VALUES ON "db_name" FROM "measurement_name" WITH KEY = "tag_key"',
query:
'SHOW TAG VALUES ON "db_name" FROM "measurement_name" WITH KEY = "tag_key"',
},
{text: `${SEPARATOR}`},
{
@ -43,7 +44,8 @@ export const QUERY_TEMPLATES = [
},
{
text: 'Create Retention Policy',
query: 'CREATE RETENTION POLICY "rp_name" ON "db_name" DURATION 30d REPLICATION 1 DEFAULT',
query:
'CREATE RETENTION POLICY "rp_name" ON "db_name" DURATION 30d REPLICATION 1 DEFAULT',
},
{
text: 'Drop Retention Policy',
@ -56,7 +58,8 @@ export const QUERY_TEMPLATES = [
},
{
text: 'Create Continuous Query',
query: 'CREATE CONTINUOUS QUERY "cq_name" ON "db_name" BEGIN SELECT min("field") INTO "target_measurement" FROM "current_measurement" GROUP BY time(30m) END',
query:
'CREATE CONTINUOUS QUERY "cq_name" ON "db_name" BEGIN SELECT min("field") INTO "target_measurement" FROM "current_measurement" GROUP BY time(30m) END',
},
{
text: 'Drop Continuous Query',
@ -70,7 +73,8 @@ export const QUERY_TEMPLATES = [
},
{
text: 'Create Admin User',
query: 'CREATE USER "username" WITH PASSWORD \'password\' WITH ALL PRIVILEGES',
query:
'CREATE USER "username" WITH PASSWORD \'password\' WITH ALL PRIVILEGES',
},
{text: 'Drop User', query: 'DROP USER "username"'},
{text: `${SEPARATOR}`},

View File

@ -231,9 +231,9 @@ class AlertTabs extends Component {
{tabs.map((t, i) => <Tab key={tabs[i].type}>{tabs[i].type}</Tab>)}
</TabList>
<TabPanels customClass="config-endpoint--tab-contents">
{tabs.map((t, i) => (
{tabs.map((t, i) =>
<TabPanel key={tabs[i].type}>{t.component}</TabPanel>
))}
)}
</TabPanels>
</Tabs>
</div>

View File

@ -129,7 +129,8 @@ class KapacitorForm extends Component {
<div className="panel-body">
<div className="generic-empty-state">
<h4 className="no-user-select">
Connect to an active Kapacitor instance to configure alerting endpoints
Connect to an active Kapacitor instance to configure alerting
endpoints
</h4>
</div>
</div>

View File

@ -29,7 +29,9 @@ const KapacitorRules = ({
</PageContents>
)
}
const tableHeader = rules.length === 1 ? '1 Alert Rule' : `${rules.length} Alert Rules`
const tableHeader = rules.length === 1
? '1 Alert Rule'
: `${rules.length} Alert Rules`
return (
<PageContents source={source}>
<div className="panel-heading u-flex u-ai-center u-jc-space-between">
@ -51,7 +53,7 @@ const KapacitorRules = ({
)
}
const PageContents = ({children, source}) => (
const PageContents = ({children, source}) =>
<div className="page">
<div className="page-header">
<div className="page-header__container">
@ -75,7 +77,6 @@ const PageContents = ({children, source}) => (
</div>
</FancyScrollbar>
</div>
)
const {arrayOf, bool, func, shape, node} = PropTypes

View File

@ -1,7 +1,7 @@
import React, {PropTypes} from 'react'
import {Link} from 'react-router'
const KapacitorRulesTable = ({rules, source, onDelete, onChangeRuleStatus}) => (
const KapacitorRulesTable = ({rules, source, onDelete, onChangeRuleStatus}) =>
<div className="panel-body">
<table className="table v-center">
<thead>
@ -29,9 +29,8 @@ const KapacitorRulesTable = ({rules, source, onDelete, onChangeRuleStatus}) => (
</tbody>
</table>
</div>
)
const RuleRow = ({rule, source, onDelete, onChangeRuleStatus}) => (
const RuleRow = ({rule, source, onDelete, onChangeRuleStatus}) =>
<tr key={rule.id}>
<td className="monotype">
<RuleTitle rule={rule} source={source} />
@ -57,7 +56,6 @@ const RuleRow = ({rule, source, onDelete, onChangeRuleStatus}) => (
</button>
</td>
</tr>
)
const RuleTitle = ({rule: {id, name, query}, source}) => {
// no queryConfig means the rule was manually created outside of Chronograf

View File

@ -2,8 +2,7 @@ import React, {PropTypes} from 'react'
import classnames from 'classnames'
import ReactTooltip from 'react-tooltip'
import RuleMessageAlertConfig
from 'src/kapacitor/components/RuleMessageAlertConfig'
import RuleMessageAlertConfig from 'src/kapacitor/components/RuleMessageAlertConfig'
import {RULE_MESSAGE_TEMPLATES as templates, DEFAULT_ALERTS} from '../constants'
@ -59,7 +58,7 @@ export const RuleMessage = React.createClass({
<div className="rule-section--row rule-section--row-first rule-section--border-bottom">
<p>Send this Alert to:</p>
<ul className="nav nav-tablist nav-tablist-sm nav-tablist-malachite">
{alerts.map(alert => (
{alerts.map(alert =>
<li
key={alert.text}
className={classnames({
@ -69,7 +68,7 @@ export const RuleMessage = React.createClass({
>
{alert.text}
</li>
))}
)}
</ul>
</div>
<RuleMessageAlertConfig

View File

@ -27,9 +27,9 @@ export const ValuesSection = React.createClass({
<div className="rule-section--body">
<Tabs initialIndex={initialIndex} onSelect={this.handleChooseTrigger}>
<TabList isKapacitorTabs="true">
{TABS.map(tab => (
{TABS.map(tab =>
<Tab key={tab} isKapacitorTab={true}>{tab}</Tab>
))}
)}
</TabList>
<TabPanels>

View File

@ -157,7 +157,8 @@ const TelegramConfig = React.createClass({
ref={r => (this.disableNotification = r)}
/>
<label htmlFor="disableNotification">
Disable notifications on iOS devices and disable sounds on Android devices. Android users continue to receive notifications.
Disable notifications on iOS devices and disable sounds on Android
devices. Android users continue to receive notifications.
</label>
</div>
</div>

View File

@ -56,19 +56,23 @@ export const RULE_MESSAGE_TEMPLATES = {
taskName: {label: '{{.TaskName}}', text: 'The name of the task'},
group: {
label: '{{.Group}}',
text: 'Concatenation of all group-by tags of the form <code>&#91;key=value,&#93;+</code>. If no groupBy is performed equal to literal &quot;nil&quot;',
text:
'Concatenation of all group-by tags of the form <code>&#91;key=value,&#93;+</code>. If no groupBy is performed equal to literal &quot;nil&quot;',
},
tags: {
label: '{{.Tags}}',
text: 'Map of tags. Use <code>&#123;&#123; index .Tags &quot;key&quot; &#125;&#125;</code> to get a specific tag value',
text:
'Map of tags. Use <code>&#123;&#123; index .Tags &quot;key&quot; &#125;&#125;</code> to get a specific tag value',
},
level: {
label: '{{.Level}}',
text: 'Alert Level, one of: <code>INFO</code><code>WARNING</code><code>CRITICAL</code>',
text:
'Alert Level, one of: <code>INFO</code><code>WARNING</code><code>CRITICAL</code>',
},
fields: {
label: '{{ index .Fields "value" }}',
text: 'Map of fields. Use <code>&#123;&#123; index .Fields &quot;key&quot; &#125;&#125;</code> to get a specific field value',
text:
'Map of fields. Use <code>&#123;&#123; index .Fields &quot;key&quot; &#125;&#125;</code> to get a specific field value',
},
time: {
label: '{{.Time}}',

View File

@ -1,13 +1,7 @@
import React, {PropTypes} from 'react'
import classnames from 'classnames'
const ConfirmButtons = ({
onConfirm,
item,
onCancel,
buttonSize,
isDisabled,
}) => (
const ConfirmButtons = ({onConfirm, item, onCancel, buttonSize, isDisabled}) =>
<div className="confirm-buttons">
<button
className={classnames('btn btn-info btn-square', {
@ -28,7 +22,6 @@ const ConfirmButtons = ({
<span className="icon checkmark" />
</button>
</div>
)
const {func, oneOfType, shape, string, bool} = PropTypes

View File

@ -54,7 +54,9 @@ class CustomTimeRangeDropdown extends Component {
onClick={onToggle}
>
<span className="icon clock" />
<span className="dropdown-selected">{`${moment(lower).format('MMM Do HH:mm')}${moment(upper).format('MMM Do HH:mm')}`}</span>
<span className="dropdown-selected">{`${moment(lower).format(
'MMM Do HH:mm'
)} ${moment(upper).format('MMM Do HH:mm')}`}</span>
<span className="caret" />
</button>
<div className="custom-time--container">

View File

@ -4,7 +4,7 @@ import classnames from 'classnames'
import OnClickOutside from 'shared/components/OnClickOutside'
import ConfirmButtons from 'shared/components/ConfirmButtons'
const DeleteButton = ({onClickDelete, buttonSize}) => (
const DeleteButton = ({onClickDelete, buttonSize}) =>
<button
className={classnames('btn btn-danger table--show-on-row-hover', {
[buttonSize]: buttonSize,
@ -13,7 +13,6 @@ const DeleteButton = ({onClickDelete, buttonSize}) => (
>
Delete
</button>
)
class DeleteConfirmButtons extends Component {
constructor(props) {

View File

@ -3,10 +3,9 @@ import React from 'react'
import DeleteConfirmButtons from 'shared/components/DeleteConfirmButtons'
import {ADMIN_TABLE} from 'src/admin/constants/tableSizing'
const DeleteConfirmTableCell = props => (
const DeleteConfirmTableCell = props =>
<td className="text-right" style={{width: `${ADMIN_TABLE.colDelete}px`}}>
<DeleteConfirmButtons {...props} />
</td>
)
export default DeleteConfirmTableCell

View File

@ -25,18 +25,14 @@ class FancyScrollbar extends Component {
autoHideDuration={250}
autoHeight={autoHeight}
autoHeightMax={maxHeight}
renderTrackHorizontal={props => (
<div {...props} className="fancy-scroll--track-h" />
)}
renderTrackVertical={props => (
<div {...props} className="fancy-scroll--track-v" />
)}
renderThumbHorizontal={props => (
<div {...props} className="fancy-scroll--thumb-h" />
)}
renderThumbVertical={props => (
<div {...props} className="fancy-scroll--thumb-v" />
)}
renderTrackHorizontal={props =>
<div {...props} className="fancy-scroll--track-h" />}
renderTrackVertical={props =>
<div {...props} className="fancy-scroll--track-v" />}
renderThumbHorizontal={props =>
<div {...props} className="fancy-scroll--thumb-h" />}
renderThumbVertical={props =>
<div {...props} className="fancy-scroll--thumb-v" />}
>
{children}
</Scrollbars>

View File

@ -1,12 +1,11 @@
import React, {PropTypes} from 'react'
const LoadingDots = ({className}) => (
const LoadingDots = ({className}) =>
<div className={`loading-dots ${className}`}>
<div />
<div />
<div />
</div>
)
const {string} = PropTypes

View File

@ -116,7 +116,7 @@ const NameableGraph = React.createClass({
})
const ContextMenu = OnClickOutside(
({isOpen, toggleMenu, onEdit, onRename, onDelete, cell}) => (
({isOpen, toggleMenu, onEdit, onRename, onDelete, cell}) =>
<div
className={classnames('dash-graph--options', {
'dash-graph--options-show': isOpen,
@ -132,6 +132,5 @@ const ContextMenu = OnClickOutside(
<li onClick={() => onDelete(cell)}>Delete</li>
</ul>
</div>
)
)
export default NameableGraph

View File

@ -13,7 +13,8 @@ const NoKapacitorError = React.createClass({
return (
<div>
<p>
The current source does not have an associated Kapacitor instance, please configure one.
The current source does not have an associated Kapacitor instance,
please configure one.
</p>
<Link to={path}>Add Kapacitor</Link>
</div>

View File

@ -2,9 +2,8 @@ import React, {PropTypes} from 'react'
import {OVERLAY_TECHNOLOGY} from 'shared/constants/classNames'
const OverlayTechnologies = ({children}) => (
const OverlayTechnologies = ({children}) =>
<div className={OVERLAY_TECHNOLOGY}>{children}</div>
)
const {node} = PropTypes

View File

@ -1,7 +1,7 @@
import React, {PropTypes} from 'react'
import ReactTooltip from 'react-tooltip'
const QuestionMarkTooltip = ({tipID, tipContent}) => (
const QuestionMarkTooltip = ({tipID, tipContent}) =>
<div className="question-mark-tooltip">
<div
className="question-mark-tooltip--icon"
@ -19,7 +19,6 @@ const QuestionMarkTooltip = ({tipID, tipContent}) => (
class="influx-tooltip__hover place-bottom"
/>
</div>
)
const {string} = PropTypes

View File

@ -7,9 +7,9 @@ const TemplateDrawer = ({
selected,
onMouseOverTempVar,
onClickTempVar,
}) => (
}) =>
<div className="template-drawer">
{templates.map(t => (
{templates.map(t =>
<div
className={classnames('template-drawer--item', {
'template-drawer--selected': t.tempVar === selected.tempVar,
@ -22,9 +22,8 @@ const TemplateDrawer = ({
>
{' '}{t.tempVar}{' '}
</div>
))}
)}
</div>
)
const {arrayOf, func, shape, string} = PropTypes

View File

@ -1,7 +1,7 @@
import React, {PropTypes} from 'react'
import ReactTooltip from 'react-tooltip'
const Tooltip = ({tip, children}) => (
const Tooltip = ({tip, children}) =>
<div>
<div data-tip={tip}>{children}</div>
<ReactTooltip
@ -12,7 +12,6 @@ const Tooltip = ({tip, children}) => (
class="influx-tooltip place-bottom"
/>
</div>
)
const {shape, string} = PropTypes

View File

@ -1,7 +1,7 @@
import React, {PropTypes} from 'react'
import classnames from 'classnames'
const YesNoButtons = ({onConfirm, onCancel, buttonSize}) => (
const YesNoButtons = ({onConfirm, onCancel, buttonSize}) =>
<div>
<button
className={classnames('btn btn-square btn-info', {
@ -20,7 +20,6 @@ const YesNoButtons = ({onConfirm, onCancel, buttonSize}) => (
<span className="icon checkmark" />
</button>
</div>
)
const {func, string} = PropTypes

View File

@ -41,7 +41,8 @@ const RenameCluster = React.createClass({
<div className="row">
<div className="col-md-8 col-md-offset-2 text-center">
<p>
A cluster can have an alias that replaces its ID in the interface.
A cluster can have an alias that replaces its ID in the
interface.
<br />
This does not affect the cluster ID.
</p>

View File

@ -73,7 +73,7 @@ const InfluxTable = ({
router,
setActiveKapacitor,
handleDeleteKapacitor,
}) => (
}) =>
<div className="row">
<div className="col-md-12">
<div className="panel panel-minimal">
@ -146,7 +146,6 @@ const InfluxTable = ({
</div>
</div>
</div>
)
const {array, func, shape, string} = PropTypes

View File

@ -22,7 +22,7 @@ export const SourceForm = React.createClass({
name: this.sourceName.value,
username: this.sourceUsername.value,
password: this.sourcePassword.value,
'default': this.sourceDefault.checked,
default: this.sourceDefault.checked,
telegraf: this.sourceTelegraf.value,
insecureSkipVerify: this.sourceInsecureSkipVerify
? this.sourceInsecureSkipVerify.checked