Merge branch 'master' into feature/version-clears-localstorage

pull/10616/head
Hunter Trujillo 2017-05-17 11:54:53 -06:00 committed by GitHub
commit 86bd10e6ab
35 changed files with 489 additions and 177 deletions

8
.bumpversion.cfg Normal file
View File

@ -0,0 +1,8 @@
[bumpversion]
current_version = 1.3.0
files = README.md server/swagger.json
[bumpversion:file:ui/package.json]
search = "version": "{current_version}"
replace = "version": "{new_version}"

View File

@ -3,12 +3,23 @@
### Bug Fixes
1. [#1450](https://github.com/influxdata/chronograf/pull/1450): Fix infinite spinner when using "/chronograf" as a basepath
1. [#1458](https://github.com/influxdata/chronograf/pull/1458): New versions of Chronograf will automatically clear localStorage settings until further notice.
1. [#1455](https://github.com/influxdata/chronograf/issues/1455): Fix backwards sort arrows in tables
1. [#1423](https://github.com/influxdata/chronograf/issues/1423): Make logout nav item consistent with design
1. [#1426](https://github.com/influxdata/chronograf/issues/1426): Fix graph loading spinner
1. [#1485](https://github.com/influxdata/chronograf/issues/1485): Filter out any template variable values that are empty, whitespace, or duplicates
### Features
1. [#1477](https://github.com/influxdata/chronograf/pull/1477): Add ability to log alerts
1. [#1474](https://github.com/influxdata/chronograf/pull/1474): Change behavior of template variable autocomplete to filter by exact match from front of string
1. [#1491](https://github.com/influxdata/chronograf/pull/1491): Update go vendoring to dep and committed vendor directory
### UI Improvements
1. [#1451](https://github.com/influxdata/chronograf/pull/1451): Refactor scrollbars to support non-webkit browsers
1. [#1453](https://github.com/influxdata/chronograf/pull/1453): Give QueryMaker a greater initial height than Visualization
1. [#1464](https://github.com/influxdata/chronograf/pull/1464): Make Template Variables Manager more space efficient
1. [#1464](https://github.com/influxdata/chronograf/pull/1464): Add page spinners to pages that did not have them
1. [#1464](https://github.com/influxdata/chronograf/pull/1464): Denote which source is connected in the Sources table
1. [#1478](https://github.com/influxdata/chronograf/pull/1478): InfluxDB dashboard uses milliseconds rather than nanoseconds
## v1.3.0 [2017-05-09]

19
Godeps
View File

@ -1,19 +0,0 @@
github.com/NYTimes/gziphandler 6710af535839f57c687b62c4c23d649f9545d885
github.com/Sirupsen/logrus 3ec0642a7fb6488f65b06f9040adc67e3990296a
github.com/boltdb/bolt 5cc10bbbc5c141029940133bb33c9e969512a698
github.com/bouk/httprouter ee8b3818a7f51fbc94cc709b5744b52c2c725e91
github.com/dgrijalva/jwt-go 24c63f56522a87ec5339cc3567883f1039378fdb
github.com/elazarl/go-bindata-assetfs 9a6736ed45b44bf3835afeebb3034b57ed329f3e
github.com/gogo/protobuf 6abcf94fd4c97dcb423fdafd42fe9f96ca7e421b
github.com/google/go-github 1bc362c7737e51014af7299e016444b654095ad9
github.com/google/go-querystring 9235644dd9e52eeae6fa48efd539fdc351a0af53
github.com/influxdata/influxdb af72d9b0e4ebe95be30e89b160f43eabaf0529ed
github.com/influxdata/kapacitor 5408057e5a3493d3b5bd38d5d535ea45b587f8ff
github.com/influxdata/usage-client 6d3895376368aa52a3a81d2a16e90f0f52371967
github.com/jessevdk/go-flags 4cc2832a6e6d1d3b815e2b9d544b2a4dfb3ce8fa
github.com/satori/go.uuid b061729afc07e77a8aa4fad0a2fd840958f1942a
github.com/sergi/go-diff 1d28411638c1e67fe1930830df207bef72496ae9
github.com/tylerb/graceful 50a48b6e73fcc75b45e22c05b79629a67c79e938
golang.org/x/net 749a502dd1eaf3e5bfd4f8956748c502357c0bbe
golang.org/x/oauth2 1e695b1c8febf17aad3bfa7bf0a819ef94b98ad5
google.golang.org/api bc20c61134e1d25265dd60049f5735381e79b631

132
Gopkg.lock generated Normal file
View File

@ -0,0 +1,132 @@
memo = "bac138180cd86a0ae604cd3aa7b6ba300673478c880882bd58a4bd7f8bff518d"
[[projects]]
name = "github.com/NYTimes/gziphandler"
packages = ["."]
revision = "6710af535839f57c687b62c4c23d649f9545d885"
[[projects]]
name = "github.com/Sirupsen/logrus"
packages = ["."]
revision = "3ec0642a7fb6488f65b06f9040adc67e3990296a"
[[projects]]
name = "github.com/boltdb/bolt"
packages = ["."]
revision = "5cc10bbbc5c141029940133bb33c9e969512a698"
[[projects]]
name = "github.com/bouk/httprouter"
packages = ["."]
revision = "ee8b3818a7f51fbc94cc709b5744b52c2c725e91"
[[projects]]
name = "github.com/dgrijalva/jwt-go"
packages = ["."]
revision = "24c63f56522a87ec5339cc3567883f1039378fdb"
[[projects]]
branch = "master"
name = "github.com/dustin/go-humanize"
packages = ["."]
revision = "259d2a102b871d17f30e3cd9881a642961a1e486"
[[projects]]
name = "github.com/elazarl/go-bindata-assetfs"
packages = ["."]
revision = "9a6736ed45b44bf3835afeebb3034b57ed329f3e"
[[projects]]
name = "github.com/gogo/protobuf"
packages = ["gogoproto","jsonpb","plugin/compare","plugin/defaultcheck","plugin/description","plugin/embedcheck","plugin/enumstringer","plugin/equal","plugin/face","plugin/gostring","plugin/marshalto","plugin/oneofcheck","plugin/populate","plugin/size","plugin/stringer","plugin/testgen","plugin/union","plugin/unmarshal","proto","protoc-gen-gogo","protoc-gen-gogo/descriptor","protoc-gen-gogo/generator","protoc-gen-gogo/grpc","protoc-gen-gogo/plugin","vanity","vanity/command"]
revision = "6abcf94fd4c97dcb423fdafd42fe9f96ca7e421b"
[[projects]]
name = "github.com/golang/protobuf"
packages = ["proto"]
revision = "8ee79997227bf9b34611aee7946ae64735e6fd93"
[[projects]]
name = "github.com/google/go-github"
packages = ["github"]
revision = "1bc362c7737e51014af7299e016444b654095ad9"
[[projects]]
name = "github.com/google/go-querystring"
packages = ["query"]
revision = "9235644dd9e52eeae6fa48efd539fdc351a0af53"
[[projects]]
name = "github.com/influxdata/influxdb"
packages = ["influxql","influxql/internal","influxql/neldermead","models","pkg/escape"]
revision = "af72d9b0e4ebe95be30e89b160f43eabaf0529ed"
[[projects]]
name = "github.com/influxdata/kapacitor"
packages = ["client/v1","influxdb","models","pipeline","services/k8s/client","tick","tick/ast","tick/stateful","udf"]
revision = "5408057e5a3493d3b5bd38d5d535ea45b587f8ff"
version = "v1.2.0"
[[projects]]
name = "github.com/influxdata/usage-client"
packages = ["v1"]
revision = "6d3895376368aa52a3a81d2a16e90f0f52371967"
[[projects]]
name = "github.com/jessevdk/go-flags"
packages = ["."]
revision = "4cc2832a6e6d1d3b815e2b9d544b2a4dfb3ce8fa"
[[projects]]
name = "github.com/jteeuwen/go-bindata"
packages = ["."]
revision = "a0ff2567cfb70903282db057e799fd826784d41d"
[[projects]]
branch = "master"
name = "github.com/pkg/errors"
packages = ["."]
revision = "ff09b135c25aae272398c51a07235b90a75aa4f0"
[[projects]]
name = "github.com/satori/go.uuid"
packages = ["."]
revision = "b061729afc07e77a8aa4fad0a2fd840958f1942a"
[[projects]]
name = "github.com/sergi/go-diff"
packages = ["diffmatchpatch"]
revision = "1d28411638c1e67fe1930830df207bef72496ae9"
[[projects]]
name = "github.com/tylerb/graceful"
packages = ["."]
revision = "50a48b6e73fcc75b45e22c05b79629a67c79e938"
version = "v1.2.13"
[[projects]]
name = "golang.org/x/net"
packages = ["context","context/ctxhttp"]
revision = "749a502dd1eaf3e5bfd4f8956748c502357c0bbe"
[[projects]]
name = "golang.org/x/oauth2"
packages = [".","github","heroku","internal"]
revision = "1e695b1c8febf17aad3bfa7bf0a819ef94b98ad5"
[[projects]]
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "f3918c30c5c2cb527c0b071a27c35120a6c0719a"
[[projects]]
name = "google.golang.org/api"
packages = ["gensupport","googleapi","googleapi/internal/uritemplates","oauth2/v2"]
revision = "bc20c61134e1d25265dd60049f5735381e79b631"
[[projects]]
name = "google.golang.org/appengine"
packages = ["internal","internal/base","internal/datastore","internal/log","internal/remote_api","internal/urlfetch","urlfetch"]
revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a"
version = "v1.0.0"

77
Gopkg.toml Normal file
View File

@ -0,0 +1,77 @@
required = ["github.com/jteeuwen/go-bindata","github.com/gogo/protobuf/proto","github.com/gogo/protobuf/jsonpb","github.com/gogo/protobuf/protoc-gen-gogo","github.com/gogo/protobuf/gogoproto"]
[[dependencies]]
name = "github.com/NYTimes/gziphandler"
revision = "6710af535839f57c687b62c4c23d649f9545d885"
[[dependencies]]
name = "github.com/Sirupsen/logrus"
revision = "3ec0642a7fb6488f65b06f9040adc67e3990296a"
[[dependencies]]
name = "github.com/boltdb/bolt"
revision = "5cc10bbbc5c141029940133bb33c9e969512a698"
[[dependencies]]
name = "github.com/bouk/httprouter"
revision = "ee8b3818a7f51fbc94cc709b5744b52c2c725e91"
[[dependencies]]
name = "github.com/dgrijalva/jwt-go"
revision = "24c63f56522a87ec5339cc3567883f1039378fdb"
[[dependencies]]
name = "github.com/elazarl/go-bindata-assetfs"
revision = "9a6736ed45b44bf3835afeebb3034b57ed329f3e"
[[dependencies]]
name = "github.com/gogo/protobuf"
revision = "6abcf94fd4c97dcb423fdafd42fe9f96ca7e421b"
[[dependencies]]
name = "github.com/google/go-github"
revision = "1bc362c7737e51014af7299e016444b654095ad9"
[[dependencies]]
name = "github.com/influxdata/influxdb"
revision = "af72d9b0e4ebe95be30e89b160f43eabaf0529ed"
[[dependencies]]
name = "github.com/influxdata/kapacitor"
version = "^1.2.0"
[[dependencies]]
name = "github.com/influxdata/usage-client"
revision = "6d3895376368aa52a3a81d2a16e90f0f52371967"
[[dependencies]]
name = "github.com/jessevdk/go-flags"
revision = "4cc2832a6e6d1d3b815e2b9d544b2a4dfb3ce8fa"
[[dependencies]]
name = "github.com/jteeuwen/go-bindata"
revision = "a0ff2567cfb70903282db057e799fd826784d41d"
[[dependencies]]
name = "github.com/satori/go.uuid"
revision = "b061729afc07e77a8aa4fad0a2fd840958f1942a"
[[dependencies]]
name = "github.com/sergi/go-diff"
revision = "1d28411638c1e67fe1930830df207bef72496ae9"
[[dependencies]]
name = "github.com/tylerb/graceful"
version = "^1.2.13"
[[dependencies]]
name = "golang.org/x/net"
revision = "749a502dd1eaf3e5bfd4f8956748c502357c0bbe"
[[dependencies]]
name = "golang.org/x/oauth2"
revision = "1e695b1c8febf17aad3bfa7bf0a819ef94b98ad5"
[[dependencies]]
name = "google.golang.org/api"
revision = "bc20c61134e1d25265dd60049f5735381e79b631"

View File

@ -2,11 +2,10 @@
VERSION ?= $(shell git describe --always --tags)
COMMIT ?= $(shell git rev-parse --short=8 HEAD)
GDM := $(shell command -v gdm 2> /dev/null)
GOBINDATA := $(shell go list -f {{.Root}} github.com/jteeuwen/go-bindata 2> /dev/null)
YARN := $(shell command -v yarn 2> /dev/null)
SOURCES := $(shell find . -name '*.go' ! -name '*_gen.go')
SOURCES := $(shell find . -name '*.go' ! -name '*_gen.go' -not -path "./vendor/*" )
UISOURCES := $(shell find ui -type f -not \( -path ui/build/\* -o -path ui/node_modules/\* -prune \) )
LDFLAGS=-ldflags "-s -X main.version=${VERSION} -X main.commit=${COMMIT}"
@ -70,16 +69,11 @@ canned/bin_gen.go: canned/*.json
dep: .jsdep .godep
.godep: Godeps
ifndef GDM
@echo "Installing GDM"
go get github.com/sparrc/gdm
endif
.godep:
ifndef GOBINDATA
@echo "Installing go-bindata"
go get -u github.com/jteeuwen/go-bindata/...
endif
gdm restore
@touch .godep
.jsdep: ui/yarn.lock
@ -90,16 +84,18 @@ else
@touch .jsdep
endif
gen: bolt/internal/internal.proto
gen: internal.pb.go
internal.pb.go: bolt/internal/internal.proto
go generate -x ./bolt/internal
test: jstest gotest gotestrace
gotest:
go test ./...
go test `go list ./... | grep -v /vendor/`
gotestrace:
go test -race ./...
go test -race `go list ./... | grep -v /vendor/`
jstest:
cd ui && npm test
@ -117,8 +113,5 @@ clean:
rm -f dist/dist_gen.go canned/bin_gen.go server/swagger_gen.go
@rm -f .godep .jsdep .jssrc .dev-jssrc .bindata
continuous:
while true; do if fswatch -e "\.git" -r --one-event .; then echo "#-> Starting build: `date`"; make dev; pkill -9 chronograf; make run-dev & echo "#-> Build complete."; fi; sleep 0.5; done
ctags:
ctags -R --languages="Go" --exclude=.git --exclude=ui .

View File

@ -110,8 +110,7 @@ Change the default root path of the Chronograf server with the `--basepath` opti
## Versions
The most recent version of Chronograf is v1.3.0.
We will be iterating quickly based on user feedback and recommend using the [nightly builds](https://www.influxdata.com/downloads/) for the time being.
The most recent version of Chronograf is [v1.3.0](https://www.influxdata.com/downloads/).
Spotted a bug or have a feature request?
Please open [an issue](https://github.com/influxdata/chronograf/issues/new)!
@ -136,16 +135,16 @@ By default, chronograf runs on port `8888`.
### With Docker
To get started right away with Docker, you can pull down our latest alpha:
To get started right away with Docker, you can pull down our latest release:
```sh
docker pull quay.io/influxdb/chronograf:latest
docker pull chronograf:1.3.0
```
### From Source
* Chronograf works with go 1.7.x, node 6.x/7.x, and yarn 0.18+.
* Chronograf requires [Kapacitor](https://github.com/influxdata/kapacitor) 1.1.x+ to create and store alerts.
* Chronograf works with go 1.8.x, node 6.x/7.x, and yarn 0.18+.
* Chronograf requires [Kapacitor](https://github.com/influxdata/kapacitor) 1.2.x+ to create and store alerts.
1. [Install Go](https://golang.org/doc/install)
1. [Install Node and NPM](https://nodejs.org/en/download/)

View File

@ -13,16 +13,18 @@
"name": "InfluxDB - Query Performance",
"queries": [
{
"query": "SELECT non_negative_derivative(max(\"queryDurationNs\"), 1s) AS \"duration\" FROM \"influxdb_queryExecutor\"",
"query": "SELECT non_negative_derivative(max(\"queryDurationNs\"), 1s) / 1000000 AS \"duration_ms\" FROM \"influxdb_queryExecutor\"",
"label": "ms",
"groupbys": [],
"wheres": []
},
{
"query": "SELECT non_negative_derivative(max(\"queriesExecuted\"), 1s) AS \"queries_executed\" FROM \"influxdb_queryExecutor\"",
"query": "SELECT non_negative_derivative(max(\"queriesExecuted\"), 1s) / 1000000 AS \"queries_executed_ms\" FROM \"influxdb_queryExecutor\"",
"label": "ms",
"groupbys": [],
"wheres": []
}
]
}
]
}
}

View File

@ -3,7 +3,7 @@ machine:
services:
- docker
environment:
DOCKER_TAG: chronograf-20170208
DOCKER_TAG: chronograf-20170516
dependencies:
override:

View File

@ -1,15 +1,40 @@
## Creating a release
The release process is handled via our [circle.yml](https://github.com/influxdata/chronograf/blob/master/circle.yml).
A release tag of the format `1.1.0-beta1` needs to be added. Afterwhich, circle
A release tag of the format `1.3.0` needs to be added. Afterwhich, circle
will build our packages for all of our platforms.
### Bumpversion
We use [bumpversion](https://github.com/peritus/bumpversion) to help us
remember all the places to increment our version number.
To install:
```sh
pip install --upgrade bumpversion
```
To use to increment third number (e.g. 1.3.0 -> 1.3.1):
```sh
bumpversion patch
```
To increment minor number (e.g. 1.3.5 -> 1.4.0):
```sh
bumpversion minor
```
The behavior of `bumpversion` is controlled by .bumpversion.cfg
### Creating Release tag
You can create a release tag from [Github](https://github.com/influxdata/chronograf/releases)
or create an annotated tag:
```sh
git tag -a 1.1.0-beta1 -m "Release 1.1.0-beta1"
git tag -a 1.3.0 -m "Release 1.3.0"
git push --tags
```
@ -22,7 +47,7 @@ git push --tags
* armel
* static_i386
* static_amd64
* OS X
* OS X
* amd64
* Windows
* amd64

View File

@ -18,9 +18,10 @@ RUN pip install boto requests python-jose --upgrade
RUN gem install fpm
# Install node
RUN wget -q https://nodejs.org/dist/latest-v6.x/node-v6.9.5-linux-x64.tar.gz; \
tar -xvf node-v6.9.5-linux-x64.tar.gz -C / --strip-components=1; \
rm -f node-v6.9.5-linux-x64.tar.gz
ENV NODE_VERSION v6.10.3
RUN wget -q https://nodejs.org/dist/latest-v6.x/node-${NODE_VERSION}-linux-x64.tar.gz; \
tar -xvf node-${NODE_VERSION}-linux-x64.tar.gz -C / --strip-components=1; \
rm -f node-${NODE_VERSION}-linux-x64.tar.gz
# Update npm
RUN cd $(npm root -g)/npm \
@ -34,7 +35,7 @@ RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
# Install go
ENV GOPATH /root/go
ENV GO_VERSION 1.7.5
ENV GO_VERSION 1.8.1
ENV GO_ARCH amd64
RUN wget https://storage.googleapis.com/golang/go${GO_VERSION}.linux-${GO_ARCH}.tar.gz; \
tar -C /usr/local/ -xf /go${GO_VERSION}.linux-${GO_ARCH}.tar.gz ; \

View File

@ -21,7 +21,7 @@ func kapaHandler(handler string) (string, error) {
return "email", nil
case "http":
return "post", nil
case "alerta", "sensu", "slack", "email", "talk", "telegram", "post", "tcp", "exec":
case "alerta", "sensu", "slack", "email", "talk", "telegram", "post", "tcp", "exec", "log":
return handler, nil
default:
return "", fmt.Errorf("Unsupported alert handler %s", handler)

View File

@ -95,6 +95,31 @@ func TestAlertServices(t *testing.T) {
},
wantErr: true,
},
{
name: "Test log",
rule: chronograf.AlertRule{
AlertNodes: []chronograf.KapacitorNode{
{
Name: "log",
Args: []string{"/tmp/alerts.log"},
},
},
},
want: `alert()
.log('/tmp/alerts.log')
`,
},
{
name: "Test log no argument",
rule: chronograf.AlertRule{
AlertNodes: []chronograf.KapacitorNode{
{
Name: "log",
},
},
},
wantErr: true,
},
{
name: "Test tcp no argument with other services",
rule: chronograf.AlertRule{

View File

@ -493,6 +493,7 @@ func extractAlertNodes(p *pipeline.Pipeline, rule *chronograf.AlertRule) {
extractTalk(t, rule)
extractTelegram(t, rule)
extractTCP(t, rule)
extractLog(t, rule)
extractExec(t, rule)
}
return nil
@ -801,6 +802,23 @@ func extractTCP(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
rule.AlertNodes = append(rule.AlertNodes, alert)
}
func extractLog(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if node.LogHandlers == nil {
return
}
rule.Alerts = append(rule.Alerts, "log")
log := node.LogHandlers[0]
alert := chronograf.KapacitorNode{
Name: "log",
}
if log.FilePath != "" {
alert.Args = []string{log.FilePath}
}
rule.AlertNodes = append(rule.AlertNodes, alert)
}
func extractExec(node *pipeline.AlertNode, rule *chronograf.AlertRule) {
if node.ExecHandlers == nil {
return

View File

@ -59,12 +59,13 @@ func TestReverse(t *testing.T) {
.slack()
.victorOps()
.email('howdy@howdy.com')
.log('/tmp/alerts.log')
`),
want: chronograf.AlertRule{
Name: "name",
Trigger: "threshold",
Alerts: []string{"victorops", "smtp", "slack"},
Alerts: []string{"victorops", "smtp", "slack", "log"},
AlertNodes: []chronograf.KapacitorNode{
{
Name: "victorops",
@ -76,6 +77,10 @@ func TestReverse(t *testing.T) {
{
Name: "slack",
},
{
Name: "log",
Args: []string{"/tmp/alerts.log"},
},
},
TriggerValues: chronograf.TriggerValues{
Operator: "greater than",

View File

@ -38,7 +38,7 @@ const AdminTabs = ({
}) => {
let tabs = [
{
type: 'DB Management',
type: 'Databases',
component: <DatabaseManagerPage source={source} />,
},
{

View File

@ -176,10 +176,10 @@ class AdminPage extends Component {
</div>
</div>
<FancyScrollbar className="page-contents">
<div className="container-fluid">
<div className="row">
{users
? <AdminTabs
{users
? <div className="container-fluid">
<div className="row">
<AdminTabs
users={users}
roles={roles}
source={source}
@ -204,9 +204,9 @@ class AdminPage extends Component {
onUpdateUserRoles={this.handleUpdateUserRoles}
onUpdateUserPassword={this.handleUpdateUserPassword}
/>
: <span>Loading...</span>}
</div>
</div>
</div>
</div>
: <div className="page-spinner" />}
</FancyScrollbar>
</div>
)

View File

@ -82,68 +82,83 @@ const AlertsTable = React.createClass({
<div className="panel panel-minimal">
<div className="panel-heading u-flex u-ai-center u-jc-space-between">
<h2 className="panel-title">{this.props.alerts.length} Alerts</h2>
<SearchBar onSearch={this.filterAlerts} />
{this.props.alerts.length
? <SearchBar onSearch={this.filterAlerts} />
: null}
</div>
<div className="panel-body">
<table className="table v-center">
<thead>
<tr>
<th
onClick={() => this.changeSort('name')}
className="sortable-header"
>
Name
</th>
<th
onClick={() => this.changeSort('level')}
className="sortable-header"
>
Level
</th>
<th
onClick={() => this.changeSort('time')}
className="sortable-header"
>
Time
</th>
<th
onClick={() => this.changeSort('host')}
className="sortable-header"
>
Host
</th>
<th
onClick={() => this.changeSort('value')}
className="sortable-header"
>
Value
</th>
</tr>
</thead>
<tbody>
{alerts.map(({name, level, time, host, value}) => {
return (
<tr key={`${name}-${level}-${time}-${host}-${value}`}>
<td className="monotype">{name}</td>
<td
className={`monotype alert-level-${level.toLowerCase()}`}
{this.props.alerts.length
? <table className="table v-center">
<thead>
<tr>
<th
onClick={() => this.changeSort('name')}
className="sortable-header"
>
{level}
</td>
<td className="monotype">
{new Date(Number(time)).toISOString()}
</td>
<td className="monotype">
<Link to={`/sources/${id}/hosts/${host}`}>
{host}
</Link>
</td>
<td className="monotype">{value}</td>
Name
</th>
<th
onClick={() => this.changeSort('level')}
className="sortable-header"
>
Level
</th>
<th
onClick={() => this.changeSort('time')}
className="sortable-header"
>
Time
</th>
<th
onClick={() => this.changeSort('host')}
className="sortable-header"
>
Host
</th>
<th
onClick={() => this.changeSort('value')}
className="sortable-header"
>
Value
</th>
</tr>
)
})}
</tbody>
</table>
</thead>
<tbody>
{alerts.map(({name, level, time, host, value}) => {
return (
<tr key={`${name}-${level}-${time}-${host}-${value}`}>
<td className="monotype">{name}</td>
<td
className={`monotype alert-level-${level.toLowerCase()}`}
>
{level}
</td>
<td className="monotype">
{new Date(Number(time)).toISOString()}
</td>
<td className="monotype">
<Link to={`/sources/${id}/hosts/${host}`}>
{host}
</Link>
</td>
<td className="monotype">{value}</td>
</tr>
)
})}
</tbody>
</table>
: <div className="generic-empty-state">
<h4 className="no-user-select">
Alerts appear here when you have Rules
</h4>
<br />
<Link
to={`/sources/${id}/alert-rules/new`}
className="btn btn-primary"
>
Create a Rule
</Link>
</div>}
</div>
</div>
)

View File

@ -95,18 +95,18 @@ class AlertsApp extends Component {
}
renderSubComponents() {
let component
if (this.state.loading) {
component = <p>Loading...</p>
} else {
const {source} = this.props
if (this.state.hasKapacitor) {
component = <AlertsTable source={source} alerts={this.state.alerts} />
} else {
component = <NoKapacitorError source={source} />
}
}
return component
const {source} = this.props
return (
<div className="container-fluid">
<div className="row">
<div className="col-md-12">
{this.state.hasKapacitor
? <AlertsTable source={source} alerts={this.state.alerts} />
: <NoKapacitorError source={source} />}
</div>
</div>
</div>
)
}
handleToggleTime() {
@ -151,13 +151,7 @@ class AlertsApp extends Component {
</div>
</div>
<FancyScrollbar className="page-contents">
<div className="container-fluid">
<div className="row">
<div className="col-md-12">
{this.renderSubComponents()}
</div>
</div>
</div>
{this.renderSubComponents()}
</FancyScrollbar>
</div>
)

View File

@ -16,7 +16,7 @@ const TemplateQueryBuilder = ({
}) => {
switch (selectedType) {
case 'csv':
return <div className="tvm-csv-instructions">Enter values below</div>
return null
case 'databases':
return <div className="tvm-query-builder--text">SHOW DATABASES</div>
case 'measurements':

View File

@ -2,6 +2,8 @@ import React, {PropTypes, Component} from 'react'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import uniq from 'lodash/uniq'
import OnClickOutside from 'react-onclickoutside'
import classnames from 'classnames'
@ -30,7 +32,9 @@ const RowValues = ({
onStartEdit,
autoFocusTarget,
}) => {
const _values = values.map(({value}) => value).join(', ')
const _values = uniq(values.map(({value}) => value))
.filter(value => /\S/.test(value))
.join(', ')
if (selectedType === 'csv') {
return (

View File

@ -164,7 +164,7 @@ class QueryEditor extends Component {
const start = this.editor.selectionStart
const end = this.editor.selectionEnd
const filteredTemplates = templates.filter(t =>
t.tempVar.includes(matched[0].substring(1))
t.tempVar.startsWith(matched[0])
)
const found = filteredTemplates.find(

View File

@ -84,9 +84,9 @@ const HostsTable = React.createClass({
sortableClasses(key) {
if (this.state.sortKey === key) {
if (this.state.sortDirection === 'asc') {
return 'sortable-header sorting-up'
return 'sortable-header sorting-ascending'
}
return 'sortable-header sorting-down'
return 'sortable-header sorting-descending'
}
return 'sortable-header'
},

View File

@ -1,5 +1,6 @@
import React, {PropTypes} from 'react'
import buildInfluxQLQuery from 'utils/influxql'
import classnames from 'classnames'
import DatabaseList from '../../data_explorer/components/DatabaseList'
import MeasurementList from '../../data_explorer/components/MeasurementList'
@ -76,16 +77,21 @@ export const DataSection = React.createClass({
render() {
const {query, timeRange: {lower}} = this.props
const statement =
query.rawText ||
buildInfluxQLQuery({lower}, query) ||
'Build a query below'
const statement = query.rawText || buildInfluxQLQuery({lower}, query)
return (
<div className="kapacitor-rule-section kapacitor-metric-selector">
<h3 className="rule-section-heading">Select a Time Series</h3>
<div className="rule-section-body">
<pre><code>{statement}</code></pre>
<pre>
<code
className={classnames({
'kapacitor-metric-placeholder': !statement,
})}
>
{statement || 'Build a query below'}
</code>
</pre>
{this.renderQueryBuilder()}
</div>
</div>

View File

@ -127,10 +127,11 @@ class KapacitorForm extends Component {
<h2 className="panel-title">Configure Alert Endpoints</h2>
</div>
<div className="panel-body">
<br />
<p className="text-center">
Connect to an active Kapacitor instance to configure alerting endpoints.
</p>
<div className="generic-empty-state">
<h4 className="no-user-select">
Connect to an active Kapacitor instance to configure alerting endpoints
</h4>
</div>
</div>
</div>
)

View File

@ -74,12 +74,13 @@ export const RULE_MESSAGE_TEMPLATES = {
},
}
export const DEFAULT_ALERTS = ['http', 'tcp', 'exec']
export const DEFAULT_ALERTS = ['http', 'tcp', 'exec', 'log']
export const DEFAULT_ALERT_LABELS = {
http: 'URL:',
tcp: 'Address:',
exec: 'Add Command (Arguments separated by Spaces):',
log: 'File',
smtp: 'Email Addresses (Separated by Spaces):',
slack: 'Send alerts to Slack channel:',
alerta: 'Paste Alerta TICKscript:',
@ -88,6 +89,7 @@ export const DEFAULT_ALERT_PLACEHOLDERS = {
http: 'Ex: http://example.com/api/alert',
tcp: 'Ex: exampleendpoint.com:5678',
exec: 'Ex: woogie boogie',
log: 'Ex: /tmp/alerts.log',
smtp: 'Ex: benedict@domain.com delaney@domain.com susan@domain.com',
slack: '#alerts',
alerta: 'alerta()',
@ -97,6 +99,7 @@ export const ALERT_NODES_ACCESSORS = {
http: rule => _.get(rule, 'alertNodes[0].args[0]', ''),
tcp: rule => _.get(rule, 'alertNodes[0].args[0]', ''),
exec: rule => _.get(rule, 'alertNodes[0].args', []).join(' '),
log: rule => _.get(rule, 'alertNodes[0].args[0]', ''),
smtp: rule => _.get(rule, 'alertNodes[0].args', []).join(' '),
slack: rule => _.get(rule, 'alertNodes[0].properties[0].args', ''),
alerta: rule =>

View File

@ -81,6 +81,7 @@ export default function rules(state = {}, action) {
switch (alertType) {
case 'http':
case 'tcp':
case 'log':
alertNodesByType = [
{
name: alertType,

View File

@ -81,9 +81,7 @@ const SideNav = React.createClass({
</NavBlock>
{showLogout
? <NavBlock icon="user-outline" className="sidebar__square-last">
<a className="sidebar__menu-item" href={logoutLink}>
Logout
</a>
<NavHeader link={logoutLink} title="Logout" />
</NavBlock>
: null}
</NavBar>

View File

@ -120,12 +120,16 @@ const InfluxTable = ({
)}
</td>
<td className="text-right">
<Link
className="btn btn-success btn-xs"
to={`/sources/${s.id}/hosts`}
>
Connect
</Link>
{s.id === source.id
? <span className="currently-connected-source">
<span className="icon checkmark" /> Connected
</span>
: <Link
className="btn btn-success btn-xs"
to={`/sources/${s.id}/hosts`}
>
Connect
</Link>}
<button
className="btn btn-danger btn-xs"
onClick={() => handleDeleteSource(s)}

View File

@ -107,8 +107,8 @@ $graph-gutter: 16px;
justify-content: center;
}
.graph-spinner {
width: 121px;
height: 121px;
width: 121px !important;
height: 121px !important;
background-image: url(assets/images/laser-spinner.png);
background-size: 100% 100%;
background-position: center center;
@ -123,4 +123,4 @@ $graph-gutter: 16px;
100% {
transform: rotate(360deg);
}
}
}

View File

@ -13,7 +13,7 @@
/* This is a hack to tell the browser to use the GPU when rendering the spinner. */
transform: translateZ(0);
animation: spinner 0.5s infinite linear;
animation: spinner 0.6s infinite linear;
}
@keyframes spinner {

View File

@ -56,7 +56,7 @@ table {
padding: 6px 8px !important;
}
tbody tr:hover {
background-color: $g5-pepper;
background-color: $g4-onyx;
td {
color: $g19-ghost !important;
@ -125,13 +125,9 @@ table .monotype {
cursor: pointer;
color: $g19-ghost;
background-color: $g5-pepper;
&:after {
opacity: 1;
}
}
&.sorting-down,
&.sorting-up {
&.sorting-ascending,
&.sorting-descending {
background-color: $g5-pepper;
color: $g19-ghost;
@ -139,11 +135,11 @@ table .monotype {
opacity: 1;
}
}
&.sorting-down {
&:after {
transform: translateY(-50%) rotate(180deg);
}
&.sorting-ascending:after {
transform: translateY(-50%) rotate(180deg);
}
&.sorting-descending:after {
transform: translateY(-50%) rotate(0deg);
}
}

View File

@ -108,6 +108,7 @@ $tvmp-table-gutter: 8px;
border-radius: $radius;
border: 2px solid $g5-pepper;
background-color: $g2-kevlar;
overflow: hidden;
transition:
border-color 0.25s ease;

View File

@ -185,6 +185,11 @@ $kapacitor-font-sm: 13px;
pre code {
line-height: ($kapacitor-font-sm + 3px);
white-space: pre-wrap;
&.kapacitor-metric-placeholder {
color: $g8-storm;
font-style: italic;
}
}
.query-builder {
height: 240px;

View File

@ -198,6 +198,13 @@
}
}
.currently-connected-source {
color: $c-rainforest;
font-weight: 600;
font-size: 12px;
margin: 0 4px;
@include no-user-select();
}