From 68d9d6610b436fb1e35e944eaa196b251b8c748b Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Mon, 9 Apr 2018 17:07:58 -0700 Subject: [PATCH 01/18] Fix logout link with basepath Remove double-prefixing by removing the prefixing logic of the InterceptingResponseWriter. Fix the logout link route for its handler to not include a basepath prefix. Remove obsolete tests for prefixing redirector. Co-authored-by: Michael Desa --- server/mux.go | 2 +- server/prefixing_redirector.go | 12 ---- server/prefixing_redirector_test.go | 87 ----------------------------- 3 files changed, 1 insertion(+), 100 deletions(-) delete mode 100644 server/prefixing_redirector_test.go diff --git a/server/mux.go b/server/mux.go index f8b316092..5ea7b7487 100644 --- a/server/mux.go +++ b/server/mux.go @@ -326,7 +326,7 @@ func NewMux(opts MuxOpts, service Service) http.Handler { allRoutes.LogoutLink = path.Join(opts.Basepath, "/oauth/logout") // Create middleware that redirects to the appropriate provider logout - router.GET(allRoutes.LogoutLink, Logout("/", basepath, allRoutes.AuthRoutes)) + router.GET("/oauth/logout", Logout("/", basepath, allRoutes.AuthRoutes)) out = Logger(opts.Logger, PrefixedRedirect(opts.Basepath, auth)) } else { out = Logger(opts.Logger, PrefixedRedirect(opts.Basepath, router)) diff --git a/server/prefixing_redirector.go b/server/prefixing_redirector.go index 2c4652d87..14f4611d3 100644 --- a/server/prefixing_redirector.go +++ b/server/prefixing_redirector.go @@ -2,9 +2,6 @@ package server import ( "net/http" - "net/url" - "path" - "strings" ) type interceptingResponseWriter struct { @@ -14,15 +11,6 @@ type interceptingResponseWriter struct { } func (i *interceptingResponseWriter) WriteHeader(status int) { - if status >= 300 && status < 400 { - location := i.ResponseWriter.Header().Get("Location") - if u, err := url.Parse(location); err == nil && !u.IsAbs() { - hasPrefix := strings.HasPrefix(u.Path, i.Prefix) - if !hasPrefix || (hasPrefix && !strings.HasPrefix(u.Path[len(i.Prefix):], i.Prefix)) { - i.ResponseWriter.Header().Set("Location", path.Join(i.Prefix, location)+"/") - } - } - } i.ResponseWriter.WriteHeader(status) } diff --git a/server/prefixing_redirector_test.go b/server/prefixing_redirector_test.go deleted file mode 100644 index 728c90604..000000000 --- a/server/prefixing_redirector_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package server - -import ( - "net/http" - "net/http/httptest" - "strings" - "testing" -) - -var prefixingRedirectTests = []struct { - CaseName string - RedirectTarget string - Prefix string - Expected string -}{ - { - "ChronografBasepath", - "/chronograf/v1/", - "/chronograf", - "/chronograf/chronograf/v1/", - }, - { - "DifferentBasepath", - "/chronograf/v1/", - "/delorean", - "/delorean/chronograf/v1/", - }, - { - "TrailingSlashPrefix", - "/chronograf/v1/", - "/delorean/", - "/delorean/chronograf/v1/", - }, - { - "NoPrefix", - "/chronograf/v1/", - "", - "/chronograf/v1/", - }, - { - "SlashPrefix", - "/chronograf/v1/", - "/", - "/chronograf/v1/", - }, - { - "AlreadyPrefixed", - "/chronograf/chronograf/v1/", - "/chronograf", - "/chronograf/chronograf/v1/", - }, -} - -func Test_PrefixingRedirector(t *testing.T) { - t.Parallel() - for _, p := range prefixingRedirectTests { - t.Run(p.CaseName, func(subt *testing.T) { - hf := http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - rw.Header().Set("Location", p.RedirectTarget) - rw.WriteHeader(http.StatusTemporaryRedirect) - }) - pr := PrefixedRedirect(p.Prefix, hf) - - ts := httptest.NewServer(pr) - defer ts.Close() - - hc := http.Client{ - CheckRedirect: func(req *http.Request, via []*http.Request) error { - return http.ErrUseLastResponse - }, - } - - mockBody := strings.NewReader("") - req, _ := http.NewRequest("GET", ts.URL, mockBody) - - resp, err := hc.Do(req) - if err != nil { - subt.Fatal("Unexpected http err:", err) - } - - expected := p.Expected - if loc := resp.Header.Get("Location"); loc != expected { - subt.Fatal("Unexpected redirected location. Expected:", expected, "Actual:", loc) - } - }) - } -} From eaefe0da632e84a3ac57d2b4cb87b174ac40d02b Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Mon, 9 Apr 2018 17:10:35 -0700 Subject: [PATCH 02/18] Fail server if basepath contains trailing or starting '/' --- server/server.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/server/server.go b/server/server.go index c783e34f2..de29104b3 100644 --- a/server/server.go +++ b/server/server.go @@ -3,6 +3,7 @@ package server import ( "context" "crypto/tls" + "fmt" "log" "math/rand" "net" @@ -12,6 +13,7 @@ import ( "path" "runtime" "strconv" + "strings" "time" "github.com/influxdata/chronograf" @@ -344,12 +346,20 @@ func (s *Server) Serve(ctx context.Context) error { return err } - basepath = s.Basepath - if basepath != "" && s.PrefixRoutes == false { + if strings.HasPrefix(s.Basepath, "/") { + err := fmt.Errorf("Basepath must begin with '/'") + logger. + WithField("component", "server"). + WithField("basepath", "invalid"). + Error(err) + return err + } + if s.Basepath != "" && s.PrefixRoutes == false { logger. WithField("component", "server"). Info("Note: you may want to use --prefix-routes with --basepath. Try `./chronograf --help` for more info.") } + basepath = s.Basepath providerFuncs := []func(func(oauth2.Provider, oauth2.Mux)){} From b9f2029bb2d62d178ae40fb7175bbca804fdc5d0 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 20 Apr 2018 11:39:42 -0700 Subject: [PATCH 03/18] Match basepath against regexp to ensure proper format --- server/server.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/server/server.go b/server/server.go index de29104b3..7bff45f21 100644 --- a/server/server.go +++ b/server/server.go @@ -11,9 +11,9 @@ import ( "net/url" "os" "path" + "regexp" "runtime" "strconv" - "strings" "time" "github.com/influxdata/chronograf" @@ -346,8 +346,9 @@ func (s *Server) Serve(ctx context.Context) error { return err } - if strings.HasPrefix(s.Basepath, "/") { - err := fmt.Errorf("Basepath must begin with '/'") + re := regexp.MustCompile(`(\/{1}\w+)+`) + if len(re.ReplaceAllLiteralString(s.Basepath, "")) > 0 { + err := fmt.Errorf("Invalid basepath, must follow format \"/mybasepath\"") logger. WithField("component", "server"). WithField("basepath", "invalid"). From ece8bad9f09be410e3ea061ade6f134658f2e172 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 20 Apr 2018 15:50:19 -0700 Subject: [PATCH 04/18] Remove prefix-routes & clean up basepath var and flag use Now, if basepath is set, it will be prefixed to all routes. There is no more additional option of prefix-routes. --- server/mux.go | 21 +++++---------------- server/server.go | 13 ++----------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/server/mux.go b/server/mux.go index 5ea7b7487..af1722e9d 100644 --- a/server/mux.go +++ b/server/mux.go @@ -25,7 +25,6 @@ type MuxOpts struct { Logger chronograf.Logger Develop bool // Develop loads assets from filesystem instead of bindata Basepath string // URL path prefix under which all chronograf routes will be mounted - PrefixRoutes bool // Mounts all backend routes under route specified by the Basepath UseAuth bool // UseAuth turns on Github OAuth and JWT Auth oauth2.Authenticator // Auth is used to authenticate and authorize ProviderFuncs []func(func(oauth2.Provider, oauth2.Mux)) @@ -44,7 +43,7 @@ func NewMux(opts MuxOpts, service Service) http.Handler { }) // Prefix any URLs found in the React assets with any configured basepath - prefixedAssets := NewDefaultURLPrefixer(basepath, assets, opts.Logger) + prefixedAssets := NewDefaultURLPrefixer(opts.Basepath, assets, opts.Logger) // Compress the assets with gzip if an accepted encoding compressed := gziphandler.GzipHandler(prefixedAssets) @@ -57,7 +56,7 @@ func NewMux(opts MuxOpts, service Service) http.Handler { var router chronograf.Router = hr // Set route prefix for all routes if basepath is present - if opts.PrefixRoutes { + if opts.Basepath != "" { router = &MountableRouter{ Prefix: opts.Basepath, Delegate: hr, @@ -313,11 +312,6 @@ func NewMux(opts MuxOpts, service Service) http.Handler { var out http.Handler - basepath := "" - if opts.PrefixRoutes { - basepath = opts.Basepath - } - /* Authentication */ if opts.UseAuth { // Encapsulate the router with OAuth2 @@ -326,7 +320,7 @@ func NewMux(opts MuxOpts, service Service) http.Handler { allRoutes.LogoutLink = path.Join(opts.Basepath, "/oauth/logout") // Create middleware that redirects to the appropriate provider logout - router.GET("/oauth/logout", Logout("/", basepath, allRoutes.AuthRoutes)) + router.GET("/oauth/logout", Logout("/", opts.Basepath, allRoutes.AuthRoutes)) out = Logger(opts.Logger, PrefixedRedirect(opts.Basepath, auth)) } else { out = Logger(opts.Logger, PrefixedRedirect(opts.Basepath, router)) @@ -363,13 +357,8 @@ func AuthAPI(opts MuxOpts, router chronograf.Router) (http.Handler, AuthRoutes) }) } - rootPath := "/chronograf/v1" - logoutPath := "/oauth/logout" - - if opts.PrefixRoutes { - rootPath = path.Join(opts.Basepath, rootPath) - logoutPath = path.Join(opts.Basepath, logoutPath) - } + rootPath := path.Join(opts.Basepath, "/chronograf/v1") + logoutPath := path.Join(opts.Basepath, "/oauth/logout") tokenMiddleware := AuthorizedToken(opts.Auth, opts.Logger, router) // Wrap the API with token validation middleware. diff --git a/server/server.go b/server/server.go index 7bff45f21..bc463f600 100644 --- a/server/server.go +++ b/server/server.go @@ -29,7 +29,6 @@ import ( var ( startTime time.Time - basepath string ) func init() { @@ -98,8 +97,7 @@ type Server struct { ReportingDisabled bool `short:"r" long:"reporting-disabled" description:"Disable reporting of usage stats (os,arch,version,cluster_id,uptime) once every 24hr" env:"REPORTING_DISABLED"` LogLevel string `short:"l" long:"log-level" value-name:"choice" choice:"debug" choice:"info" choice:"error" default:"info" description:"Set the logging level" env:"LOG_LEVEL"` - Basepath string `short:"p" long:"basepath" description:"A URL path prefix under which all chronograf routes will be mounted" env:"BASE_PATH"` - PrefixRoutes bool `long:"prefix-routes" description:"Force chronograf server to require that all requests to it are prefixed with the value set in --basepath" env:"PREFIX_ROUTES"` + Basepath string `short:"p" long:"basepath" description:"A URL path prefix under which all chronograf routes will be mounted. (Note: PREFIX_ROUTES has been deprecated. Now, if basepath is set, all routes will be prefixed with it.)" env:"BASE_PATH"` ShowVersion bool `short:"v" long:"version" description:"Show Chronograf version info"` BuildInfo chronograf.BuildInfo Listener net.Listener @@ -355,12 +353,6 @@ func (s *Server) Serve(ctx context.Context) error { Error(err) return err } - if s.Basepath != "" && s.PrefixRoutes == false { - logger. - WithField("component", "server"). - Info("Note: you may want to use --prefix-routes with --basepath. Try `./chronograf --help` for more info.") - } - basepath = s.Basepath providerFuncs := []func(func(oauth2.Provider, oauth2.Mux)){} @@ -377,8 +369,7 @@ func (s *Server) Serve(ctx context.Context) error { Logger: logger, UseAuth: s.useAuth(), ProviderFuncs: providerFuncs, - Basepath: basepath, - PrefixRoutes: s.PrefixRoutes, + Basepath: s.Basepath, StatusFeedURL: s.StatusFeedURL, CustomLinks: s.CustomLinks, }, service) From a5adbdfc8d6f8ebbcc0330d6db93d3288eddd582 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 20 Apr 2018 16:48:50 -0700 Subject: [PATCH 05/18] Remove basepath var & arg from PrefixedRedirect --- server/mux.go | 4 ++-- server/prefixing_redirector.go | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/server/mux.go b/server/mux.go index af1722e9d..6f7415385 100644 --- a/server/mux.go +++ b/server/mux.go @@ -321,9 +321,9 @@ func NewMux(opts MuxOpts, service Service) http.Handler { // Create middleware that redirects to the appropriate provider logout router.GET("/oauth/logout", Logout("/", opts.Basepath, allRoutes.AuthRoutes)) - out = Logger(opts.Logger, PrefixedRedirect(opts.Basepath, auth)) + out = Logger(opts.Logger, PrefixedRedirect(auth)) } else { - out = Logger(opts.Logger, PrefixedRedirect(opts.Basepath, router)) + out = Logger(opts.Logger, PrefixedRedirect(router)) } return out diff --git a/server/prefixing_redirector.go b/server/prefixing_redirector.go index 14f4611d3..9d5d633ce 100644 --- a/server/prefixing_redirector.go +++ b/server/prefixing_redirector.go @@ -7,7 +7,6 @@ import ( type interceptingResponseWriter struct { http.ResponseWriter Flusher http.Flusher - Prefix string } func (i *interceptingResponseWriter) WriteHeader(status int) { @@ -25,11 +24,10 @@ func (i *interceptingResponseWriter) Flush() { // PrefixedRedirect alters the Location header of downstream http.Handlers // to include a specified prefix -func PrefixedRedirect(prefix string, next http.Handler) http.Handler { +func PrefixedRedirect(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { iw := &interceptingResponseWriter{ ResponseWriter: w, - Prefix: prefix, } if flusher, ok := w.(http.Flusher); ok { iw.Flusher = flusher From c23d75396fb786f27bf59336d35e97039c6006be Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 20 Apr 2018 16:52:48 -0700 Subject: [PATCH 06/18] Refactor interceptingResponseWrite Flusher for clarity Co-authored-by: Daniel Nelson --- server/prefixing_redirector.go | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/server/prefixing_redirector.go b/server/prefixing_redirector.go index 9d5d633ce..30884cdcf 100644 --- a/server/prefixing_redirector.go +++ b/server/prefixing_redirector.go @@ -6,7 +6,6 @@ import ( type interceptingResponseWriter struct { http.ResponseWriter - Flusher http.Flusher } func (i *interceptingResponseWriter) WriteHeader(status int) { @@ -17,8 +16,8 @@ func (i *interceptingResponseWriter) WriteHeader(status int) { // to implement http.Flusher. Without it data is silently buffered. This // was discovered when proxying kapacitor chunked logs. func (i *interceptingResponseWriter) Flush() { - if i.Flusher != nil { - i.Flusher.Flush() + if flusher, ok := i.ResponseWriter.(http.Flusher); ok { + flusher.Flush() } } @@ -29,9 +28,6 @@ func PrefixedRedirect(next http.Handler) http.Handler { iw := &interceptingResponseWriter{ ResponseWriter: w, } - if flusher, ok := w.(http.Flusher); ok { - iw.Flusher = flusher - } next.ServeHTTP(iw, r) }) } From 990457568082ee8c7fb43952a2b29e1b609ebd51 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 20 Apr 2018 17:11:32 -0700 Subject: [PATCH 07/18] Rename PrefixedRedirect to FlushingHandler & comment It's not clear whether this code is necessary, but investigating this was outside of the scope of this PR. --- server/mux.go | 4 ++-- server/prefixing_redirector.go | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/server/mux.go b/server/mux.go index 6f7415385..cecf7a99b 100644 --- a/server/mux.go +++ b/server/mux.go @@ -321,9 +321,9 @@ func NewMux(opts MuxOpts, service Service) http.Handler { // Create middleware that redirects to the appropriate provider logout router.GET("/oauth/logout", Logout("/", opts.Basepath, allRoutes.AuthRoutes)) - out = Logger(opts.Logger, PrefixedRedirect(auth)) + out = Logger(opts.Logger, FlushingHandler(auth)) } else { - out = Logger(opts.Logger, PrefixedRedirect(router)) + out = Logger(opts.Logger, FlushingHandler(router)) } return out diff --git a/server/prefixing_redirector.go b/server/prefixing_redirector.go index 30884cdcf..0317ceb39 100644 --- a/server/prefixing_redirector.go +++ b/server/prefixing_redirector.go @@ -4,28 +4,29 @@ import ( "net/http" ) -type interceptingResponseWriter struct { +type flushingResponseWriter struct { http.ResponseWriter } -func (i *interceptingResponseWriter) WriteHeader(status int) { - i.ResponseWriter.WriteHeader(status) +func (f *flushingResponseWriter) WriteHeader(status int) { + f.ResponseWriter.WriteHeader(status) } // Flush is here because the underlying HTTP chunked transfer response writer // to implement http.Flusher. Without it data is silently buffered. This // was discovered when proxying kapacitor chunked logs. -func (i *interceptingResponseWriter) Flush() { - if flusher, ok := i.ResponseWriter.(http.Flusher); ok { +func (f *flushingResponseWriter) Flush() { + if flusher, ok := f.ResponseWriter.(http.Flusher); ok { flusher.Flush() } } -// PrefixedRedirect alters the Location header of downstream http.Handlers -// to include a specified prefix -func PrefixedRedirect(next http.Handler) http.Handler { +// FlushingHandler may not actually do anything, but it was ostensibly +// implemented to flush response writers that can be flushed for the +// purposes in the comment above. +func FlushingHandler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - iw := &interceptingResponseWriter{ + iw := &flushingResponseWriter{ ResponseWriter: w, } next.ServeHTTP(iw, r) From 58559f3b71c15c281537bf4b07a432fedb93ae2f Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 20 Apr 2018 19:01:23 -0700 Subject: [PATCH 08/18] Clean up regexp guard logic for valid basepath --- server/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/server.go b/server/server.go index bc463f600..1cf18e94b 100644 --- a/server/server.go +++ b/server/server.go @@ -345,7 +345,7 @@ func (s *Server) Serve(ctx context.Context) error { } re := regexp.MustCompile(`(\/{1}\w+)+`) - if len(re.ReplaceAllLiteralString(s.Basepath, "")) > 0 { + if re.ReplaceAllLiteralString(s.Basepath, "") != "" { err := fmt.Errorf("Invalid basepath, must follow format \"/mybasepath\"") logger. WithField("component", "server"). From e78573e2b37fd3d01f0329be97bd24c1060ebcbe Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Fri, 20 Apr 2018 19:01:28 -0700 Subject: [PATCH 09/18] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 429fab90f..1dd0ff878 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ ### Bug Fixes 1. [#3252](https://github.com/influxdata/chronograf/pull/3252): Allows users to select tickscript editor with mouse +1. [#3284](https://github.com/influxdata/chronograf/pull/3284): Fix logout when using basepath & simplify basepath usage (deprecates `PREFIX_ROUTES`) ## v1.4.4.1 [2018-04-16] From ae80e1beec25ef2d8597f561f61b99dfac947502 Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Thu, 19 Apr 2018 15:58:15 -0700 Subject: [PATCH 10/18] WIP introduce handling of variables --- ui/src/ifql/ast/walker.ts | 27 +++++ ui/src/ifql/containers/IFQLPage.tsx | 2 +- ui/test/ifql/ast/variable.ts | 41 +++++++ ui/test/ifql/ast/variables.ts | 182 ++++++++++++++++++++++++++++ ui/test/ifql/ast/walker.test.ts | 52 +++++--- 5 files changed, 288 insertions(+), 16 deletions(-) create mode 100644 ui/test/ifql/ast/variable.ts create mode 100644 ui/test/ifql/ast/variables.ts diff --git a/ui/src/ifql/ast/walker.ts b/ui/src/ifql/ast/walker.ts index 6ec623ec3..0b7a67afa 100644 --- a/ui/src/ifql/ast/walker.ts +++ b/ui/src/ifql/ast/walker.ts @@ -44,6 +44,33 @@ export default class Walker { return this.buildFuncNodes(this.walk(this.baseExpression)) } + public get stuff() { + const body = _.get(this.ast, 'body', new Array()) + return body.map(b => { + if (b.type.includes('Expression')) { + return this.expression(b) + } else if (b.type.includes('Variable')) { + return this.variable(b) + } + }) + } + + private variable({type, location, declarations}) { + const dec = declarations.map(({init, id}) => { + return {name: id.name, type: init.type, value: init.value} + }) + return {source: location.source, declarations: dec, type} + } + + private expression({location, expression}): FlatExpression { + const funcs = this.buildFuncNodes(this.walk(expression)) + + return { + source: location.source, + funcs, + } + } + public get expressions(): FlatExpression[] { const body = _.get(this.ast, 'body', new Array()) return body.map(b => { diff --git a/ui/src/ifql/containers/IFQLPage.tsx b/ui/src/ifql/containers/IFQLPage.tsx index c4f827421..7c471ca2c 100644 --- a/ui/src/ifql/containers/IFQLPage.tsx +++ b/ui/src/ifql/containers/IFQLPage.tsx @@ -46,7 +46,7 @@ export class IFQLPage extends PureComponent { expressions: [], ast: null, script: - 'from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m) \n\t|> derivative(nonNegative: true)\n\nfrom(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m) \n\t|> derivative(nonNegative: true)', + 'from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\nfrom(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\n', } } diff --git a/ui/test/ifql/ast/variable.ts b/ui/test/ifql/ast/variable.ts new file mode 100644 index 000000000..9c2cb0e26 --- /dev/null +++ b/ui/test/ifql/ast/variable.ts @@ -0,0 +1,41 @@ +export default { + type: 'Program', + location: { + start: {line: 1, column: 1}, + end: {line: 1, column: 21}, + source: 'bux = "im a var"', + }, + body: [ + { + type: 'VariableDeclaration', + location: { + start: {line: 1, column: 1}, + end: {line: 1, column: 21}, + source: 'bux = "im a var"', + }, + declarations: [ + { + type: 'VariableDeclarator', + id: { + type: 'Identifier', + location: { + start: {line: 1, column: 1}, + end: {line: 1, column: 4}, + source: 'bux', + }, + name: 'bux', + }, + init: { + type: 'StringLiteral', + location: { + start: {line: 1, column: 7}, + end: {line: 1, column: 21}, + source: '"im a var"', + }, + value: 'im a var', + }, + }, + ], + }, + ], +} diff --git a/ui/test/ifql/ast/variables.ts b/ui/test/ifql/ast/variables.ts new file mode 100644 index 000000000..fda08f3c1 --- /dev/null +++ b/ui/test/ifql/ast/variables.ts @@ -0,0 +1,182 @@ +export default { + type: 'Program', + location: { + start: {line: 1, column: 1}, + end: {line: 1, column: 61}, + source: + 'bux = "ASDFASDFASDF"\nfoo = from(db: "foo")\t\nfrom(db: bux)\n\n\n', + }, + body: [ + { + type: 'VariableDeclaration', + location: { + start: {line: 1, column: 1}, + end: {line: 1, column: 21}, + source: 'bux = "ASDFASDFASDF"', + }, + declarations: [ + { + type: 'VariableDeclarator', + id: { + type: 'Identifier', + location: { + start: {line: 1, column: 1}, + end: {line: 1, column: 4}, + source: 'bux', + }, + name: 'bux', + }, + init: { + type: 'StringLiteral', + location: { + start: {line: 1, column: 7}, + end: {line: 1, column: 21}, + source: '"ASDFASDFASDF"', + }, + value: 'ASDFASDFASDF', + }, + }, + ], + }, + { + type: 'VariableDeclaration', + location: { + start: {line: 2, column: 1}, + end: {line: 2, column: 22}, + source: 'foo = from(db: "foo")', + }, + declarations: [ + { + type: 'VariableDeclarator', + id: { + type: 'Identifier', + location: { + start: {line: 2, column: 1}, + end: {line: 2, column: 4}, + source: 'foo', + }, + name: 'foo', + }, + init: { + type: 'CallExpression', + location: { + start: {line: 2, column: 7}, + end: {line: 2, column: 22}, + source: 'from(db: "foo")', + }, + callee: { + type: 'Identifier', + location: { + start: {line: 2, column: 7}, + end: {line: 2, column: 11}, + source: 'from', + }, + name: 'from', + }, + arguments: [ + { + type: 'ObjectExpression', + location: { + start: {line: 2, column: 12}, + end: {line: 2, column: 21}, + source: 'db: "foo"', + }, + properties: [ + { + type: 'Property', + location: { + start: {line: 2, column: 12}, + end: {line: 2, column: 21}, + source: 'db: "foo"', + }, + key: { + type: 'Identifier', + location: { + start: {line: 2, column: 12}, + end: {line: 2, column: 14}, + source: 'db', + }, + name: 'db', + }, + value: { + type: 'StringLiteral', + location: { + start: {line: 2, column: 16}, + end: {line: 2, column: 21}, + source: '"foo"', + }, + value: 'foo', + }, + }, + ], + }, + ], + }, + }, + ], + }, + { + type: 'ExpressionStatement', + location: { + start: {line: 3, column: 1}, + end: {line: 3, column: 14}, + source: 'from(db: bux)', + }, + expression: { + type: 'CallExpression', + location: { + start: {line: 3, column: 1}, + end: {line: 3, column: 14}, + source: 'from(db: bux)', + }, + callee: { + type: 'Identifier', + location: { + start: {line: 3, column: 1}, + end: {line: 3, column: 5}, + source: 'from', + }, + name: 'from', + }, + arguments: [ + { + type: 'ObjectExpression', + location: { + start: {line: 3, column: 6}, + end: {line: 3, column: 13}, + source: 'db: bux', + }, + properties: [ + { + type: 'Property', + location: { + start: {line: 3, column: 6}, + end: {line: 3, column: 13}, + source: 'db: bux', + }, + key: { + type: 'Identifier', + location: { + start: {line: 3, column: 6}, + end: {line: 3, column: 8}, + source: 'db', + }, + name: 'db', + }, + value: { + type: 'Identifier', + location: { + start: {line: 3, column: 10}, + end: {line: 3, column: 13}, + source: 'bux', + }, + name: 'bux', + }, + }, + ], + }, + ], + }, + }, + ], +} diff --git a/ui/test/ifql/ast/walker.test.ts b/ui/test/ifql/ast/walker.test.ts index cab26f1c3..7eac21d93 100644 --- a/ui/test/ifql/ast/walker.test.ts +++ b/ui/test/ifql/ast/walker.test.ts @@ -1,36 +1,58 @@ import Walker from 'src/ifql/ast/walker' import From from 'test/ifql/ast/from' import Complex from 'test/ifql/ast/complex' +import Variable from 'test/ifql/ast/variable' describe('IFQL.AST.Walker', () => { describe('Walker#functions', () => { describe('simple example', () => { - it('returns a flattened ordered list of from and its arguments', () => { - const walker = new Walker(From) - expect(walker.expressions).toEqual([ - { - source: 'from(db: "telegraf")', - funcs: [ + describe('a single expression', () => { + it('returns a flattened ordered list of from and its arguments', () => { + const walker = new Walker(From) + expect(walker.stuff).toEqual([ + { + source: 'from(db: "telegraf")', + funcs: [ + { + name: 'from', + source: 'from(db: "telegraf")', + arguments: [ + { + key: 'db', + value: 'telegraf', + }, + ], + }, + ], + }, + ]) + }) + + describe('a single variable declaration', () => { + it('returns a variable declaration for a string literal', () => { + const walker = new Walker(Variable) + expect(walker.stuff).toEqual([ { - name: 'from', - source: 'from(db: "telegraf")', - arguments: [ + type: 'VariableDeclaration', + source: 'bux = "im a var"', + declarations: [ { - key: 'db', - value: 'telegraf', + name: 'bux', + type: 'StringLiteral', + value: 'im a var', }, ], }, - ], - }, - ]) + ]) + }) + }) }) }) describe('complex example', () => { it('returns a flattened ordered list of all funcs and their arguments', () => { const walker = new Walker(Complex) - expect(walker.expressions).toEqual([ + expect(walker.stuff).toEqual([ { source: 'from(db: "telegraf") |> filter(fn: (r) => r["_measurement"] == "cpu") |> range(start: -1m)', From eddcac95a41f442626c0862855af56053a7c41be Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Thu, 19 Apr 2018 17:09:47 -0700 Subject: [PATCH 11/18] Add ability to handle literal and expression variables --- ui/src/ifql/ast/walker.ts | 20 +++++--- ui/test/ifql/ast/variable.ts | 90 ++++++++++++++++++++++++++++++++- ui/test/ifql/ast/walker.test.ts | 67 +++++++++++++++++------- 3 files changed, 153 insertions(+), 24 deletions(-) diff --git a/ui/src/ifql/ast/walker.ts b/ui/src/ifql/ast/walker.ts index 0b7a67afa..1ae9dc598 100644 --- a/ui/src/ifql/ast/walker.ts +++ b/ui/src/ifql/ast/walker.ts @@ -48,21 +48,29 @@ export default class Walker { const body = _.get(this.ast, 'body', new Array()) return body.map(b => { if (b.type.includes('Expression')) { - return this.expression(b) + return this.expression(b.expression, b.location) } else if (b.type.includes('Variable')) { return this.variable(b) } }) } - private variable({type, location, declarations}) { - const dec = declarations.map(({init, id}) => { - return {name: id.name, type: init.type, value: init.value} + private variable(variable) { + const {location} = variable + const declarations = variable.declarations.map(({init, id}) => { + const {type} = init + if (type.includes('Expression')) { + const {source, funcs} = this.expression(init, location) + return {name: id.name, type, source, funcs} + } + + return {name: id.name, type, value: init.value} }) - return {source: location.source, declarations: dec, type} + + return {source: location.source, declarations, type: variable.type} } - private expression({location, expression}): FlatExpression { + private expression(expression, location): FlatExpression { const funcs = this.buildFuncNodes(this.walk(expression)) return { diff --git a/ui/test/ifql/ast/variable.ts b/ui/test/ifql/ast/variable.ts index 9c2cb0e26..20c9951a4 100644 --- a/ui/test/ifql/ast/variable.ts +++ b/ui/test/ifql/ast/variable.ts @@ -1,4 +1,4 @@ -export default { +export const StringLiteral = { type: 'Program', location: { start: {line: 1, column: 1}, @@ -39,3 +39,91 @@ export default { }, ], } + +export const Expression = { + type: 'Program', + location: { + start: {line: 1, column: 1}, + end: {line: 1, column: 28}, + source: 'tele = from(db: "telegraf")', + }, + body: [ + { + type: 'VariableDeclaration', + location: { + start: {line: 1, column: 1}, + end: {line: 1, column: 28}, + source: 'tele = from(db: "telegraf")', + }, + declarations: [ + { + type: 'VariableDeclarator', + id: { + type: 'Identifier', + location: { + start: {line: 1, column: 1}, + end: {line: 1, column: 5}, + source: 'tele', + }, + name: 'tele', + }, + init: { + type: 'CallExpression', + location: { + start: {line: 1, column: 8}, + end: {line: 1, column: 28}, + source: 'from(db: "telegraf")', + }, + callee: { + type: 'Identifier', + location: { + start: {line: 1, column: 8}, + end: {line: 1, column: 12}, + source: 'from', + }, + name: 'from', + }, + arguments: [ + { + type: 'ObjectExpression', + location: { + start: {line: 1, column: 13}, + end: {line: 1, column: 27}, + source: 'db: "telegraf"', + }, + properties: [ + { + type: 'Property', + location: { + start: {line: 1, column: 13}, + end: {line: 1, column: 27}, + source: 'db: "telegraf"', + }, + key: { + type: 'Identifier', + location: { + start: {line: 1, column: 13}, + end: {line: 1, column: 15}, + source: 'db', + }, + name: 'db', + }, + value: { + type: 'StringLiteral', + location: { + start: {line: 1, column: 17}, + end: {line: 1, column: 27}, + source: '"telegraf"', + }, + value: 'telegraf', + }, + }, + ], + }, + ], + }, + }, + ], + }, + ], +} diff --git a/ui/test/ifql/ast/walker.test.ts b/ui/test/ifql/ast/walker.test.ts index 7eac21d93..87d6f45d0 100644 --- a/ui/test/ifql/ast/walker.test.ts +++ b/ui/test/ifql/ast/walker.test.ts @@ -1,7 +1,7 @@ import Walker from 'src/ifql/ast/walker' import From from 'test/ifql/ast/from' import Complex from 'test/ifql/ast/complex' -import Variable from 'test/ifql/ast/variable' +import {StringLiteral, Expression} from 'test/ifql/ast/variable' describe('IFQL.AST.Walker', () => { describe('Walker#functions', () => { @@ -28,22 +28,55 @@ describe('IFQL.AST.Walker', () => { ]) }) - describe('a single variable declaration', () => { - it('returns a variable declaration for a string literal', () => { - const walker = new Walker(Variable) - expect(walker.stuff).toEqual([ - { - type: 'VariableDeclaration', - source: 'bux = "im a var"', - declarations: [ - { - name: 'bux', - type: 'StringLiteral', - value: 'im a var', - }, - ], - }, - ]) + describe('variables', () => { + describe('a single string literal variable', () => { + it('returns the expected list', () => { + const walker = new Walker(StringLiteral) + expect(walker.stuff).toEqual([ + { + type: 'VariableDeclaration', + source: 'bux = "im a var"', + declarations: [ + { + name: 'bux', + type: 'StringLiteral', + value: 'im a var', + }, + ], + }, + ]) + }) + }) + + describe('a single expression variable', () => { + it('returns the expected list', () => { + const walker = new Walker(Expression) + expect(walker.stuff).toEqual([ + { + type: 'VariableDeclaration', + source: 'tele = from(db: "telegraf")', + declarations: [ + { + name: 'tele', + type: 'CallExpression', + source: 'tele = from(db: "telegraf")', + funcs: [ + { + name: 'from', + source: 'from(db: "telegraf")', + arguments: [ + { + key: 'db', + value: 'telegraf', + }, + ], + }, + ], + }, + ], + }, + ]) + }) }) }) }) From c217560afe0cbeb676a08285ba15e278ecb733d7 Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Mon, 23 Apr 2018 15:27:19 -0700 Subject: [PATCH 12/18] WIP move / change shape of body function --- ui/src/ifql/ast/walker.ts | 18 +- ui/src/ifql/components/BodyBuilder.tsx | 101 ++++++ ui/src/ifql/components/FuncArgs.tsx | 20 +- ui/src/ifql/components/TimeMachine.tsx | 69 ++-- ui/src/ifql/containers/IFQLPage.tsx | 81 +---- ui/src/ifql/helpers/index.ts | 72 +++++ ui/src/types/ifql.ts | 43 +++ ui/test/ifql/ast/varsAndExpressions.ts | 352 +++++++++++++++++++++ ui/test/ifql/ast/walker.test.ts | 24 +- ui/test/ifql/helpers/bodyNodes.test.ts | 148 +++++++++ ui/test/ifql/semantic_graph/suggestions.ts | 93 ++++++ 11 files changed, 874 insertions(+), 147 deletions(-) create mode 100644 ui/src/ifql/components/BodyBuilder.tsx create mode 100644 ui/src/ifql/helpers/index.ts create mode 100644 ui/test/ifql/ast/varsAndExpressions.ts create mode 100644 ui/test/ifql/helpers/bodyNodes.test.ts create mode 100644 ui/test/ifql/semantic_graph/suggestions.ts diff --git a/ui/src/ifql/ast/walker.ts b/ui/src/ifql/ast/walker.ts index 1ae9dc598..332a2a078 100644 --- a/ui/src/ifql/ast/walker.ts +++ b/ui/src/ifql/ast/walker.ts @@ -1,5 +1,6 @@ // Texas Ranger import _ from 'lodash' +import {FlatBody, Func} from 'src/types/ifql' interface Expression { argument: object @@ -19,14 +20,9 @@ interface Body { } interface FlatExpression { + type: string source: string - funcs: FuncNode[] -} - -interface FuncNode { - name: string - arguments: any[] - source: string + funcs: Func[] } interface AST { @@ -44,7 +40,7 @@ export default class Walker { return this.buildFuncNodes(this.walk(this.baseExpression)) } - public get stuff() { + public get body(): FlatBody[] { const body = _.get(this.ast, 'body', new Array()) return body.map(b => { if (b.type.includes('Expression')) { @@ -74,6 +70,7 @@ export default class Walker { const funcs = this.buildFuncNodes(this.walk(expression)) return { + type: expression.type, source: location.source, funcs, } @@ -86,6 +83,7 @@ export default class Walker { const funcs = this.buildFuncNodes(this.walk(expression)) return { + type: expression.type, source: location.source, funcs, } @@ -122,11 +120,11 @@ export default class Walker { return [{name, args, source}] } - private buildFuncNodes = (nodes): FuncNode[] => { + private buildFuncNodes = (nodes): Func[] => { return nodes.map(({name, args, source}) => { return { name, - arguments: this.reduceArgs(args), + args: this.reduceArgs(args), source, } }) diff --git a/ui/src/ifql/components/BodyBuilder.tsx b/ui/src/ifql/components/BodyBuilder.tsx new file mode 100644 index 000000000..a0ca545bd --- /dev/null +++ b/ui/src/ifql/components/BodyBuilder.tsx @@ -0,0 +1,101 @@ +import React, {PureComponent} from 'react' +import _ from 'lodash' + +import FuncSelector from 'src/ifql/components/FuncSelector' +import FuncNode from 'src/ifql/components/FuncNode' +import { + FlatBody, + OnAddNode, + Suggestion, + OnChangeArg, + OnDeleteFuncNode, +} from 'src/types/ifql' + +interface Props { + body: Body[] + onAddNode: OnAddNode + onChangeArg: OnChangeArg + onDeleteFuncNode: OnDeleteFuncNode + suggestions: Suggestion[] + onGenerateScript: () => void +} + +interface Body extends FlatBody { + id: string +} + +class BodyBuilder extends PureComponent { + public render() { + const { + body, + onAddNode, + onChangeArg, + onDeleteFuncNode, + onGenerateScript, + } = this.props + + const bodybuilder = body.map(b => { + if (b.declarations.length) { + return b.declarations.map(d => { + if (d.funcs) { + return ( +
+

+ {d.name} + +

+ {d.funcs.map(func => ( + + ))} +
+ ) + } + + return
{b.source}
+ }) + } + + return ( +
+

+ Expression + +

+ {b.funcs.map(func => ( + + ))} +
+ ) + }) + + return _.flatten(bodybuilder) + } + + private get funcNames() { + return this.props.suggestions.map(f => f.name) + } +} + +export default BodyBuilder diff --git a/ui/src/ifql/components/FuncArgs.tsx b/ui/src/ifql/components/FuncArgs.tsx index ddc8c2345..95ecfbd8a 100644 --- a/ui/src/ifql/components/FuncArgs.tsx +++ b/ui/src/ifql/components/FuncArgs.tsx @@ -2,21 +2,7 @@ import React, {PureComponent} from 'react' import FuncArg from 'src/ifql/components/FuncArg' import {OnChangeArg} from 'src/types/ifql' import {ErrorHandling} from 'src/shared/decorators/errors' - -type Value = string | boolean - -interface Arg { - key: string - value: Value - type: string -} - -export interface Func { - name: string - args: Arg[] - source: string - id: string -} +import {Func} from 'src/types/ifql' interface Props { func: Func @@ -30,6 +16,10 @@ export default class FuncArgs extends PureComponent { public render() { const {expressionID, func, onChangeArg, onGenerateScript} = this.props + if (!func.args) { + debugger + } + return (
{func.args.map(({key, value, type}) => { diff --git a/ui/src/ifql/components/TimeMachine.tsx b/ui/src/ifql/components/TimeMachine.tsx index 68d9301b6..a66f06a67 100644 --- a/ui/src/ifql/components/TimeMachine.tsx +++ b/ui/src/ifql/components/TimeMachine.tsx @@ -1,28 +1,20 @@ import React, {PureComponent} from 'react' -import FuncSelector from 'src/ifql/components/FuncSelector' -import FuncNode from 'src/ifql/components/FuncNode' +import BodyBuilder from 'src/ifql/components/BodyBuilder' import TimeMachineEditor from 'src/ifql/components/TimeMachineEditor' -import {Func} from 'src/ifql/components/FuncArgs' -import {OnChangeArg, OnDeleteFuncNode, OnAddNode} from 'src/types/ifql' +import { + FlatBody, + Suggestion, + OnChangeArg, + OnDeleteFuncNode, + OnAddNode, +} from 'src/types/ifql' import {ErrorHandling} from 'src/shared/decorators/errors' -export interface Suggestion { - name: string - params: { - [key: string]: string - } -} - -interface Expression { - id: string - funcs: Func[] -} - interface Props { script: string suggestions: Suggestion[] - expressions: Expression[] + body: Body[] onSubmitScript: () => void onChangeScript: (script: string) => void onAddNode: OnAddNode @@ -31,18 +23,23 @@ interface Props { onGenerateScript: () => void } +interface Body extends FlatBody { + id: string +} + @ErrorHandling class TimeMachine extends PureComponent { public render() { const { + body, script, onAddNode, - expressions, onChangeArg, onChangeScript, onSubmitScript, onDeleteFuncNode, onGenerateScript, + suggestions, } = this.props return ( @@ -53,38 +50,18 @@ class TimeMachine extends PureComponent { onSubmitScript={onSubmitScript} />
- {expressions.map(({funcs, id}, i) => { - return ( -
-

- Expression {i} - -

- {funcs.map(func => ( - - ))} -
- ) - })} +
) } - - private get funcNames() { - return this.props.suggestions.map(f => f.name) - } } export default TimeMachine diff --git a/ui/src/ifql/containers/IFQLPage.tsx b/ui/src/ifql/containers/IFQLPage.tsx index 7c471ca2c..b212cf42d 100644 --- a/ui/src/ifql/containers/IFQLPage.tsx +++ b/ui/src/ifql/containers/IFQLPage.tsx @@ -4,12 +4,13 @@ import {connect} from 'react-redux' import uuid from 'uuid' import _ from 'lodash' -import TimeMachine, {Suggestion} from 'src/ifql/components/TimeMachine' +import TimeMachine from 'src/ifql/components/TimeMachine' import KeyboardShortcuts from 'src/shared/components/KeyboardShortcuts' import Walker from 'src/ifql/ast/walker' -import {Func} from 'src/ifql/components/FuncArgs' +import {Func, Suggestion, FlatBody} from 'src/types/ifql' import {InputArg} from 'src/types/ifql' +import {bodyNodes} from 'src/ifql/helpers' import {getSuggestions, getAST} from 'src/ifql/apis' import * as argTypes from 'src/ifql/constants/argumentTypes' import {ErrorHandling} from 'src/shared/decorators/errors' @@ -24,17 +25,15 @@ interface Props { links: Links } -interface State { - suggestions: Suggestion[] - expressions: Expression[] - ast: object - script: string +interface Body extends FlatBody { + id: string } -interface Expression { - id: string - funcs: Func[] - source: string +interface State { + body: Body[] + ast: object + script: string + suggestions: Suggestion[] } @ErrorHandling @@ -42,11 +41,11 @@ export class IFQLPage extends PureComponent { constructor(props) { super(props) this.state = { - suggestions: [], - expressions: [], + body: [], ast: null, + suggestions: [], script: - 'from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\nfrom(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\n', + 'foo = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\nfrom(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\n', } } @@ -80,7 +79,7 @@ export class IFQLPage extends PureComponent {
{ this.getASTResponse(script) } - private expressions = (ast, suggestions): Expression[] => { - if (!ast) { - return [] - } - - const walker = new Walker(ast) - - const expressions = walker.expressions.map(({funcs, source}) => { - const id = uuid.v4() - return { - id, - funcs: this.functions(funcs, suggestions), - source, - } - }) - - return expressions - } - - private functions = (funcs, suggestions): Func[] => { - const functions = funcs.map(func => { - const {params, name} = suggestions.find(f => f.name === func.name) - - const args = Object.entries(params).map(([key, type]) => { - const value = _.get( - func.arguments.find(arg => arg.key === key), - 'value', - '' - ) - - return { - key, - value, - type, - } - }) - - return { - id: uuid.v4(), - source: func.source, - name, - args, - } - }) - - return functions - } - private getASTResponse = async (script: string) => { const {links} = this.props try { const ast = await getAST({url: links.ast, body: script}) - const expressions = this.expressions(ast, this.state.suggestions) - this.setState({ast, script, expressions}) + const body = bodyNodes(ast, this.state.suggestions) + this.setState({ast, script, body}) } catch (error) { console.error('Could not parse AST', error) } diff --git a/ui/src/ifql/helpers/index.ts b/ui/src/ifql/helpers/index.ts new file mode 100644 index 000000000..00354c52a --- /dev/null +++ b/ui/src/ifql/helpers/index.ts @@ -0,0 +1,72 @@ +import uuid from 'uuid' +import _ from 'lodash' +import Walker from 'src/ifql/ast/walker' +import {FlatBody, Func} from 'src/types/ifql' + +interface Body extends FlatBody { + id: string +} + +export const bodyNodes = (ast, suggestions): Body[] => { + if (!ast) { + return [] + } + + const walker = new Walker(ast) + + const body = walker.body.map(b => { + const {type} = b + const id = uuid.v4() + if (type.includes('Variable')) { + const declarations = b.declarations.map(d => { + if (!d.funcs) { + return {...d, id: uuid.v4()} + } + + return { + ...d, + id: uuid.v4(), + funcs: functions(d.funcs, suggestions), + } + }) + + return {...b, type, id, declarations} + } + + const {funcs, source} = b + + return { + id, + funcs: functions(funcs, suggestions), + declarations: [], + type, + source, + } + }) + + return body +} + +const functions = (funcs, suggestions): Func[] => { + const funcList = funcs.map(func => { + const {params, name} = suggestions.find(f => f.name === func.name) + const args = Object.entries(params).map(([key, type]) => { + const value = _.get(func.args.find(arg => arg.key === key), 'value', '') + + return { + key, + value, + type, + } + }) + + return { + id: uuid.v4(), + source: func.source, + name, + args, + } + }) + + return funcList +} diff --git a/ui/src/types/ifql.ts b/ui/src/types/ifql.ts index d6028dc1a..5de7708fa 100644 --- a/ui/src/types/ifql.ts +++ b/ui/src/types/ifql.ts @@ -9,3 +9,46 @@ export interface InputArg { value: string | boolean generate?: boolean } + +// Flattened AST +export interface FlatBody { + type: string + source: string + funcs?: Func[] + declarations?: FlatDeclaration[] +} + +export interface Func { + type: string + name: string + args: Arg[] + source: string + id: string +} + +type Value = string | boolean + +interface Arg { + key: string + value: Value + type: string +} + +interface FlatExpression { + id: string + funcs?: Func[] +} + +interface FlatDeclaration extends FlatExpression { + name: string + value: string + type: string +} + +// Semantic Graph list of available functions for ifql queries +export interface Suggestion { + name: string + params: { + [key: string]: string + } +} diff --git a/ui/test/ifql/ast/varsAndExpressions.ts b/ui/test/ifql/ast/varsAndExpressions.ts new file mode 100644 index 000000000..b8c720fb0 --- /dev/null +++ b/ui/test/ifql/ast/varsAndExpressions.ts @@ -0,0 +1,352 @@ +export default { + type: 'Program', + location: { + start: {line: 1, column: 1}, + end: {line: 1, column: 129}, + source: + 'literal = "foo"\n\ntele = from(db: "telegraf")\n\t|\u003e range(start: -15m)\n\nfrom(db: "telegraf")\n\t|\u003e filter() \n\t|\u003e range(start: -15m)\n\n', + }, + body: [ + { + type: 'VariableDeclaration', + location: { + start: {line: 1, column: 1}, + end: {line: 1, column: 16}, + source: 'literal = "foo"', + }, + declarations: [ + { + type: 'VariableDeclarator', + id: { + type: 'Identifier', + location: { + start: {line: 1, column: 1}, + end: {line: 1, column: 8}, + source: 'literal', + }, + name: 'literal', + }, + init: { + type: 'StringLiteral', + location: { + start: {line: 1, column: 11}, + end: {line: 1, column: 16}, + source: '"foo"', + }, + value: 'foo', + }, + }, + ], + }, + { + type: 'VariableDeclaration', + location: { + start: {line: 3, column: 1}, + end: {line: 3, column: 53}, + source: 'tele = from(db: "telegraf")\n\t|\u003e range(start: -15m)\n\n', + }, + declarations: [ + { + type: 'VariableDeclarator', + id: { + type: 'Identifier', + location: { + start: {line: 3, column: 1}, + end: {line: 3, column: 5}, + source: 'tele', + }, + name: 'tele', + }, + init: { + type: 'PipeExpression', + location: { + start: {line: 4, column: 2}, + end: {line: 4, column: 23}, + source: '|\u003e range(start: -15m)', + }, + argument: { + type: 'CallExpression', + location: { + start: {line: 3, column: 8}, + end: {line: 3, column: 28}, + source: 'from(db: "telegraf")', + }, + callee: { + type: 'Identifier', + location: { + start: {line: 3, column: 8}, + end: {line: 3, column: 12}, + source: 'from', + }, + name: 'from', + }, + arguments: [ + { + type: 'ObjectExpression', + location: { + start: {line: 3, column: 13}, + end: {line: 3, column: 27}, + source: 'db: "telegraf"', + }, + properties: [ + { + type: 'Property', + location: { + start: {line: 3, column: 13}, + end: {line: 3, column: 27}, + source: 'db: "telegraf"', + }, + key: { + type: 'Identifier', + location: { + start: {line: 3, column: 13}, + end: {line: 3, column: 15}, + source: 'db', + }, + name: 'db', + }, + value: { + type: 'StringLiteral', + location: { + start: {line: 3, column: 17}, + end: {line: 3, column: 27}, + source: '"telegraf"', + }, + value: 'telegraf', + }, + }, + ], + }, + ], + }, + call: { + type: 'CallExpression', + location: { + start: {line: 4, column: 5}, + end: {line: 4, column: 23}, + source: 'range(start: -15m)', + }, + callee: { + type: 'Identifier', + location: { + start: {line: 4, column: 5}, + end: {line: 4, column: 10}, + source: 'range', + }, + name: 'range', + }, + arguments: [ + { + type: 'ObjectExpression', + location: { + start: {line: 4, column: 11}, + end: {line: 4, column: 22}, + source: 'start: -15m', + }, + properties: [ + { + type: 'Property', + location: { + start: {line: 4, column: 11}, + end: {line: 4, column: 22}, + source: 'start: -15m', + }, + key: { + type: 'Identifier', + location: { + start: {line: 4, column: 11}, + end: {line: 4, column: 16}, + source: 'start', + }, + name: 'start', + }, + value: { + type: 'UnaryExpression', + location: { + start: {line: 4, column: 18}, + end: {line: 4, column: 22}, + source: '-15m', + }, + operator: '-', + argument: { + type: 'DurationLiteral', + location: { + start: {line: 4, column: 19}, + end: {line: 4, column: 22}, + source: '15m', + }, + value: '15m0s', + }, + }, + }, + ], + }, + ], + }, + }, + }, + ], + }, + { + type: 'ExpressionStatement', + location: { + start: {line: 6, column: 1}, + end: {line: 6, column: 60}, + source: + 'from(db: "telegraf")\n\t|\u003e filter() \n\t|\u003e range(start: -15m)\n\n', + }, + expression: { + type: 'PipeExpression', + location: { + start: {line: 8, column: 2}, + end: {line: 8, column: 23}, + source: '|\u003e range(start: -15m)', + }, + argument: { + type: 'PipeExpression', + location: { + start: {line: 7, column: 2}, + end: {line: 7, column: 13}, + source: '|\u003e filter()', + }, + argument: { + type: 'CallExpression', + location: { + start: {line: 6, column: 1}, + end: {line: 6, column: 21}, + source: 'from(db: "telegraf")', + }, + callee: { + type: 'Identifier', + location: { + start: {line: 6, column: 1}, + end: {line: 6, column: 5}, + source: 'from', + }, + name: 'from', + }, + arguments: [ + { + type: 'ObjectExpression', + location: { + start: {line: 6, column: 6}, + end: {line: 6, column: 20}, + source: 'db: "telegraf"', + }, + properties: [ + { + type: 'Property', + location: { + start: {line: 6, column: 6}, + end: {line: 6, column: 20}, + source: 'db: "telegraf"', + }, + key: { + type: 'Identifier', + location: { + start: {line: 6, column: 6}, + end: {line: 6, column: 8}, + source: 'db', + }, + name: 'db', + }, + value: { + type: 'StringLiteral', + location: { + start: {line: 6, column: 10}, + end: {line: 6, column: 20}, + source: '"telegraf"', + }, + value: 'telegraf', + }, + }, + ], + }, + ], + }, + call: { + type: 'CallExpression', + location: { + start: {line: 7, column: 5}, + end: {line: 7, column: 13}, + source: 'filter()', + }, + callee: { + type: 'Identifier', + location: { + start: {line: 7, column: 5}, + end: {line: 7, column: 11}, + source: 'filter', + }, + name: 'filter', + }, + }, + }, + call: { + type: 'CallExpression', + location: { + start: {line: 8, column: 5}, + end: {line: 8, column: 23}, + source: 'range(start: -15m)', + }, + callee: { + type: 'Identifier', + location: { + start: {line: 8, column: 5}, + end: {line: 8, column: 10}, + source: 'range', + }, + name: 'range', + }, + arguments: [ + { + type: 'ObjectExpression', + location: { + start: {line: 8, column: 11}, + end: {line: 8, column: 22}, + source: 'start: -15m', + }, + properties: [ + { + type: 'Property', + location: { + start: {line: 8, column: 11}, + end: {line: 8, column: 22}, + source: 'start: -15m', + }, + key: { + type: 'Identifier', + location: { + start: {line: 8, column: 11}, + end: {line: 8, column: 16}, + source: 'start', + }, + name: 'start', + }, + value: { + type: 'UnaryExpression', + location: { + start: {line: 8, column: 18}, + end: {line: 8, column: 22}, + source: '-15m', + }, + operator: '-', + argument: { + type: 'DurationLiteral', + location: { + start: {line: 8, column: 19}, + end: {line: 8, column: 22}, + source: '15m', + }, + value: '15m0s', + }, + }, + }, + ], + }, + ], + }, + }, + }, + ], +} diff --git a/ui/test/ifql/ast/walker.test.ts b/ui/test/ifql/ast/walker.test.ts index 87d6f45d0..5dfb7cf5e 100644 --- a/ui/test/ifql/ast/walker.test.ts +++ b/ui/test/ifql/ast/walker.test.ts @@ -7,16 +7,17 @@ describe('IFQL.AST.Walker', () => { describe('Walker#functions', () => { describe('simple example', () => { describe('a single expression', () => { - it('returns a flattened ordered list of from and its arguments', () => { + it('returns a flattened ordered list of from and its args', () => { const walker = new Walker(From) - expect(walker.stuff).toEqual([ + expect(walker.body).toEqual([ { + type: 'CallExpression', source: 'from(db: "telegraf")', funcs: [ { name: 'from', source: 'from(db: "telegraf")', - arguments: [ + args: [ { key: 'db', value: 'telegraf', @@ -32,7 +33,7 @@ describe('IFQL.AST.Walker', () => { describe('a single string literal variable', () => { it('returns the expected list', () => { const walker = new Walker(StringLiteral) - expect(walker.stuff).toEqual([ + expect(walker.body).toEqual([ { type: 'VariableDeclaration', source: 'bux = "im a var"', @@ -51,7 +52,7 @@ describe('IFQL.AST.Walker', () => { describe('a single expression variable', () => { it('returns the expected list', () => { const walker = new Walker(Expression) - expect(walker.stuff).toEqual([ + expect(walker.body).toEqual([ { type: 'VariableDeclaration', source: 'tele = from(db: "telegraf")', @@ -64,7 +65,7 @@ describe('IFQL.AST.Walker', () => { { name: 'from', source: 'from(db: "telegraf")', - arguments: [ + args: [ { key: 'db', value: 'telegraf', @@ -83,22 +84,23 @@ describe('IFQL.AST.Walker', () => { }) describe('complex example', () => { - it('returns a flattened ordered list of all funcs and their arguments', () => { + it('returns a flattened ordered list of all funcs and their args', () => { const walker = new Walker(Complex) - expect(walker.stuff).toEqual([ + expect(walker.body).toEqual([ { + type: 'PipeExpression', source: 'from(db: "telegraf") |> filter(fn: (r) => r["_measurement"] == "cpu") |> range(start: -1m)', funcs: [ { name: 'from', source: 'from(db: "telegraf")', - arguments: [{key: 'db', value: 'telegraf'}], + args: [{key: 'db', value: 'telegraf'}], }, { name: 'filter', source: '|> filter(fn: (r) => r["_measurement"] == "cpu")', - arguments: [ + args: [ { key: 'fn', value: '(r) => r["_measurement"] == "cpu"', @@ -108,7 +110,7 @@ describe('IFQL.AST.Walker', () => { { name: 'range', source: '|> range(start: -1m)', - arguments: [{key: 'start', value: '-1m'}], + args: [{key: 'start', value: '-1m'}], }, ], }, diff --git a/ui/test/ifql/helpers/bodyNodes.test.ts b/ui/test/ifql/helpers/bodyNodes.test.ts new file mode 100644 index 000000000..9e13ce3fd --- /dev/null +++ b/ui/test/ifql/helpers/bodyNodes.test.ts @@ -0,0 +1,148 @@ +import {bodyNodes} from 'src/ifql/helpers' +import suggestions from 'test/ifql/semantic_graph/suggestions' +import Variables from 'test/ifql/ast/variables' +import {Expression, StringLiteral} from 'test/ifql/ast/variable' +import From from 'test/ifql/ast/from' + +const id = expect.any(String) + +describe('IFQL.helpers', () => { + describe('bodyNodes', () => { + describe('bodyNodes for Expressions assigned to a variable', () => { + it('can parse an Expression assigned to a Variable', () => { + const actual = bodyNodes(Expression, suggestions) + const expected = [ + { + declarations: [ + { + funcs: [ + { + args: [{key: 'db', type: 'string', value: 'telegraf'}], + id, + name: 'from', + source: 'from(db: "telegraf")', + }, + ], + id, + name: 'tele', + source: 'tele = from(db: "telegraf")', + type: 'CallExpression', + }, + ], + id, + source: 'tele = from(db: "telegraf")', + type: 'VariableDeclaration', + }, + ] + + expect(actual).toEqual(expected) + }) + }) + + describe('bodyNodes for a Literal assigned to a Variable', () => { + it('can parse an Expression assigned to a Variable', () => { + const actual = bodyNodes(StringLiteral, suggestions) + const expected = [ + { + id, + source: 'bux = "im a var"', + type: 'VariableDeclaration', + declarations: [ + { + id, + name: 'bux', + type: 'StringLiteral', + value: 'im a var', + }, + ], + }, + ] + + expect(actual).toEqual(expected) + }) + }) + + describe('bodyNodes for an Expression', () => { + it('can parse an Expression into bodyNodes', () => { + const actual = bodyNodes(From, suggestions) + + const expected = [ + { + declarations: [], + funcs: [ + { + args: [{key: 'db', type: 'string', value: 'telegraf'}], + id, + name: 'from', + source: 'from(db: "telegraf")', + }, + ], + id, + source: 'from(db: "telegraf")', + type: 'CallExpression', + }, + ] + + expect(actual).toEqual(expected) + }) + }) + }) + + describe('multiple bodyNodes', () => { + it('can parse variables and expressions together', () => { + const actual = bodyNodes(Variables, suggestions) + const expected = [ + { + declarations: [ + { + id, + name: 'bux', + type: 'StringLiteral', + value: 'ASDFASDFASDF', + }, + ], + id, + source: 'bux = "ASDFASDFASDF"', + type: 'VariableDeclaration', + }, + { + declarations: [ + { + funcs: [ + { + args: [{key: 'db', type: 'string', value: 'foo'}], + id, + name: 'from', + source: 'from(db: "foo")', + }, + ], + id, + name: 'foo', + source: 'foo = from(db: "foo")', + type: 'CallExpression', + }, + ], + id, + source: 'foo = from(db: "foo")', + type: 'VariableDeclaration', + }, + { + declarations: [], + funcs: [ + { + args: [{key: 'db', type: 'string', value: 'bux'}], + id, + name: 'from', + source: 'from(db: bux)', + }, + ], + id, + source: 'from(db: bux)', + type: 'CallExpression', + }, + ] + + expect(actual).toEqual(expected) + }) + }) +}) diff --git a/ui/test/ifql/semantic_graph/suggestions.ts b/ui/test/ifql/semantic_graph/suggestions.ts new file mode 100644 index 000000000..f0ad0999f --- /dev/null +++ b/ui/test/ifql/semantic_graph/suggestions.ts @@ -0,0 +1,93 @@ +export default [ + { + name: '_highestOrLowest', + params: { + _sortLimit: 'invalid', + by: 'invalid', + cols: 'array', + n: 'invalid', + reducer: 'function', + }, + }, + { + name: '_sortLimit', + params: {cols: 'array', desc: 'invalid', n: 'invalid'}, + }, + {name: 'bottom', params: {cols: 'array', n: 'invalid'}}, + {name: 'count', params: {}}, + { + name: 'cov', + params: {on: 'invalid', pearsonr: 'bool', x: 'invalid', y: 'invalid'}, + }, + {name: 'covariance', params: {pearsonr: 'bool'}}, + {name: 'derivative', params: {nonNegative: 'bool', unit: 'duration'}}, + {name: 'difference', params: {nonNegative: 'bool'}}, + {name: 'distinct', params: {column: 'string'}}, + {name: 'filter', params: {fn: 'function'}}, + {name: 'first', params: {column: 'string', useRowTime: 'bool'}}, + {name: 'from', params: {db: 'string'}}, + {name: 'group', params: {by: 'array', except: 'array', keep: 'array'}}, + { + name: 'highestAverage', + params: {by: 'invalid', cols: 'array', n: 'invalid'}, + }, + { + name: 'highestCurrent', + params: {by: 'invalid', cols: 'array', n: 'invalid'}, + }, + {name: 'highestMax', params: {by: 'invalid', cols: 'array', n: 'invalid'}}, + {name: 'integral', params: {unit: 'duration'}}, + {name: 'join', params: {}}, + {name: 'last', params: {column: 'string', useRowTime: 'bool'}}, + {name: 'limit', params: {}}, + { + name: 'lowestAverage', + params: {by: 'invalid', cols: 'array', n: 'invalid'}, + }, + { + name: 'lowestCurrent', + params: {by: 'invalid', cols: 'array', n: 'invalid'}, + }, + {name: 'lowestMin', params: {by: 'invalid', cols: 'array', n: 'invalid'}}, + {name: 'map', params: {fn: 'function'}}, + {name: 'max', params: {column: 'string', useRowTime: 'bool'}}, + {name: 'mean', params: {}}, + {name: 'median', params: {compression: 'float', exact: 'bool'}}, + {name: 'min', params: {column: 'string', useRowTime: 'bool'}}, + {name: 'pearsonr', params: {on: 'invalid', x: 'invalid', y: 'invalid'}}, + {name: 'percentile', params: {p: 'float'}}, + {name: 'range', params: {start: 'time', stop: 'time'}}, + {name: 'sample', params: {column: 'string', useRowTime: 'bool'}}, + {name: 'set', params: {key: 'string', value: 'string'}}, + {name: 'shift', params: {shift: 'duration'}}, + {name: 'skew', params: {}}, + {name: 'sort', params: {cols: 'array'}}, + {name: 'spread', params: {}}, + {name: 'stateCount', params: {fn: 'invalid', label: 'string'}}, + { + name: 'stateDuration', + params: {fn: 'invalid', label: 'string', unit: 'duration'}, + }, + { + name: 'stateTracking', + params: { + countLabel: 'string', + durationLabel: 'string', + durationUnit: 'duration', + fn: 'function', + }, + }, + {name: 'stddev', params: {}}, + {name: 'sum', params: {}}, + {name: 'top', params: {cols: 'array', n: 'invalid'}}, + { + name: 'window', + params: { + every: 'duration', + period: 'duration', + round: 'duration', + start: 'time', + }, + }, + {name: 'yield', params: {name: 'string'}}, +] From 88f1d7cd854492813ffc0bb8ea370674efaf8f25 Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Mon, 23 Apr 2018 15:32:06 -0700 Subject: [PATCH 13/18] WIP clear up errors and warnings --- ui/src/ifql/containers/IFQLPage.tsx | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/ui/src/ifql/containers/IFQLPage.tsx b/ui/src/ifql/containers/IFQLPage.tsx index b212cf42d..87c7de377 100644 --- a/ui/src/ifql/containers/IFQLPage.tsx +++ b/ui/src/ifql/containers/IFQLPage.tsx @@ -1,13 +1,10 @@ import React, {PureComponent} from 'react' import {connect} from 'react-redux' -import uuid from 'uuid' -import _ from 'lodash' import TimeMachine from 'src/ifql/components/TimeMachine' import KeyboardShortcuts from 'src/shared/components/KeyboardShortcuts' -import Walker from 'src/ifql/ast/walker' -import {Func, Suggestion, FlatBody} from 'src/types/ifql' +import {Suggestion, FlatBody} from 'src/types/ifql' import {InputArg} from 'src/types/ifql' import {bodyNodes} from 'src/ifql/helpers' @@ -110,7 +107,7 @@ export class IFQLPage extends PureComponent { funcID, expressionID, }: InputArg): void => { - const expressions = this.state.expressions.map(expression => { + const body = this.state.body.map(expression => { if (expression.id !== expressionID) { return expression } @@ -134,7 +131,7 @@ export class IFQLPage extends PureComponent { return {...expression, funcs} }) - this.setState({expressions}, () => { + this.setState({body}, () => { if (generate) { this.handleGenerateScript() } @@ -142,7 +139,7 @@ export class IFQLPage extends PureComponent { } private get expressionsToScript(): string { - return this.state.expressions.reduce((acc, expression) => { + return this.state.body.reduce((acc, expression) => { return `${acc + this.funcsToScript(expression.funcs)}\n\n` }, '') } @@ -176,7 +173,7 @@ export class IFQLPage extends PureComponent { } private handleAddNode = (name: string, expressionID: string): void => { - const script = this.state.expressions.reduce((acc, expression) => { + const script = this.state.body.reduce((acc, expression) => { if (expression.id === expressionID) { const {funcs} = expression return `${acc}${this.funcsToScript(funcs)}\n\t|> ${name}()\n\n` @@ -193,7 +190,7 @@ export class IFQLPage extends PureComponent { expressionID: string ): void => { // TODO: export this and test functionality - const script = this.state.expressions + const script = this.state.body .map((expression, expressionIndex) => { if (expression.id !== expressionID) { return expression.source @@ -208,7 +205,7 @@ export class IFQLPage extends PureComponent { return `${acc}\n\t${f.source}` }, '') - const isLast = expressionIndex === this.state.expressions.length - 1 + const isLast = expressionIndex === this.state.body.length - 1 if (isLast) { return `${source}` } From 42d912397b68f085b6829c351ad6ae7eda70c1d1 Mon Sep 17 00:00:00 2001 From: Jared Scheib Date: Mon, 23 Apr 2018 16:46:16 -0700 Subject: [PATCH 14/18] Comment WithContext fn for context --- server/server_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/server/server_test.go b/server/server_test.go index 3f6c11b16..e832d4b85 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -7,6 +7,7 @@ import ( "github.com/bouk/httprouter" ) +// WithContext is a helper function to cut down on boilerplate in server test files func WithContext(ctx context.Context, r *http.Request, kv map[string]string) *http.Request { params := make(httprouter.Params, 0, len(kv)) for k, v := range kv { From 2ce7d8e3eea9e2319271df34118647bf3826186f Mon Sep 17 00:00:00 2001 From: Brandon Farmer Date: Mon, 23 Apr 2018 17:02:00 -0700 Subject: [PATCH 15/18] Test & refactor basepath validation into dedicated fn --- server/server.go | 8 ++++++-- server/server_test.go | 48 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/server/server.go b/server/server.go index 1cf18e94b..9d7f44e5a 100644 --- a/server/server.go +++ b/server/server.go @@ -344,8 +344,7 @@ func (s *Server) Serve(ctx context.Context) error { return err } - re := regexp.MustCompile(`(\/{1}\w+)+`) - if re.ReplaceAllLiteralString(s.Basepath, "") != "" { + if !validBasepath(s.Basepath) { err := fmt.Errorf("Invalid basepath, must follow format \"/mybasepath\"") logger. WithField("component", "server"). @@ -539,3 +538,8 @@ func clientUsage(values client.Values) *client.Usage { }, } } + +func validBasepath(basepath string) bool { + re := regexp.MustCompile(`(\/{1}\w+)+`) + return re.ReplaceAllLiteralString(basepath, "") == "" +} diff --git a/server/server_test.go b/server/server_test.go index e832d4b85..f6dd40c42 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -3,6 +3,7 @@ package server import ( "context" "net/http" + "testing" "github.com/bouk/httprouter" ) @@ -18,3 +19,50 @@ func WithContext(ctx context.Context, r *http.Request, kv map[string]string) *ht } return r.WithContext(httprouter.WithParams(ctx, params)) } + +func Test_validBasepath(t *testing.T) { + type args struct { + basepath string + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "Basepath can be empty", + args: args{ + basepath: "", + }, + want: true, + }, + { + name: "Basepath is not empty and valid", + args: args{ + basepath: "/russ", + }, + want: true, + }, + { + name: "Basepath is not empty and invalid - no slashes", + args: args{ + basepath: "russ", + }, + want: false, + }, + { + name: "Basepath is not empty and invalid - extra slashes", + args: args{ + basepath: "//russ//", + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := validBasepath(tt.args.basepath); got != tt.want { + t.Errorf("validBasepath() = %v, want %v", got, tt.want) + } + }) + } +} From e52b552b33a0360ce07c9928a687c166b63d599d Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Mon, 23 Apr 2018 17:12:14 -0700 Subject: [PATCH 16/18] Introduce new context and ExpressionNode component --- ui/package.json | 1 - ui/src/ifql/components/BodyBuilder.tsx | 78 +++++------------------ ui/src/ifql/components/ExpressionNode.tsx | 48 ++++++++++++++ ui/src/ifql/components/TimeMachine.tsx | 16 ++--- ui/src/ifql/containers/IFQLPage.tsx | 61 +++++++++++------- ui/yarn.lock | 31 ++++----- 6 files changed, 117 insertions(+), 118 deletions(-) create mode 100644 ui/src/ifql/components/ExpressionNode.tsx diff --git a/ui/package.json b/ui/package.json index e8e0957d4..87321ea69 100644 --- a/ui/package.json +++ b/ui/package.json @@ -133,7 +133,6 @@ "query-string": "^5.0.0", "react": "^16.3.1", "react-addons-shallow-compare": "^15.0.2", - "react-codemirror": "^1.0.0", "react-codemirror2": "^4.2.1", "react-custom-scrollbars": "^4.1.1", "react-dimensions": "^1.2.0", diff --git a/ui/src/ifql/components/BodyBuilder.tsx b/ui/src/ifql/components/BodyBuilder.tsx index a0ca545bd..b1602438e 100644 --- a/ui/src/ifql/components/BodyBuilder.tsx +++ b/ui/src/ifql/components/BodyBuilder.tsx @@ -1,23 +1,13 @@ import React, {PureComponent} from 'react' import _ from 'lodash' -import FuncSelector from 'src/ifql/components/FuncSelector' -import FuncNode from 'src/ifql/components/FuncNode' -import { - FlatBody, - OnAddNode, - Suggestion, - OnChangeArg, - OnDeleteFuncNode, -} from 'src/types/ifql' +import ExpressionNode from 'src/ifql/components/ExpressionNode' + +import {FlatBody, Suggestion} from 'src/types/ifql' interface Props { body: Body[] - onAddNode: OnAddNode - onChangeArg: OnChangeArg - onDeleteFuncNode: OnDeleteFuncNode suggestions: Suggestion[] - onGenerateScript: () => void } interface Body extends FlatBody { @@ -26,39 +16,17 @@ interface Body extends FlatBody { class BodyBuilder extends PureComponent { public render() { - const { - body, - onAddNode, - onChangeArg, - onDeleteFuncNode, - onGenerateScript, - } = this.props - - const bodybuilder = body.map(b => { + const bodybuilder = this.props.body.map(b => { if (b.declarations.length) { return b.declarations.map(d => { if (d.funcs) { return ( -
-

- {d.name} - -

- {d.funcs.map(func => ( - - ))} -
+ ) } @@ -67,26 +35,12 @@ class BodyBuilder extends PureComponent { } return ( -
-

- Expression - -

- {b.funcs.map(func => ( - - ))} -
+ ) }) diff --git a/ui/src/ifql/components/ExpressionNode.tsx b/ui/src/ifql/components/ExpressionNode.tsx new file mode 100644 index 000000000..68422b3df --- /dev/null +++ b/ui/src/ifql/components/ExpressionNode.tsx @@ -0,0 +1,48 @@ +import React, {PureComponent} from 'react' + +import {IFQLContext} from 'src/ifql/containers/IFQLPage' +import FuncSelector from 'src/ifql/components/FuncSelector' +import FuncNode from 'src/ifql/components/FuncNode' + +import {Func} from 'src/types/ifql' + +interface Props { + funcNames: any[] + id: string + funcs: Func[] +} +// an expression is a group of one or more functions +class ExpressionNode extends PureComponent { + public render() { + const {id, funcNames, funcs} = this.props + return ( + + {({onDeleteFuncNode, onAddNode, onChangeArg, onGenerateScript}) => { + return ( +
+

+ +

+ {funcs.map(func => ( + + ))} +
+ ) + }} +
+ ) + } +} + +export default ExpressionNode diff --git a/ui/src/ifql/components/TimeMachine.tsx b/ui/src/ifql/components/TimeMachine.tsx index a66f06a67..d8302e1d5 100644 --- a/ui/src/ifql/components/TimeMachine.tsx +++ b/ui/src/ifql/components/TimeMachine.tsx @@ -1,6 +1,7 @@ import React, {PureComponent} from 'react' import BodyBuilder from 'src/ifql/components/BodyBuilder' import TimeMachineEditor from 'src/ifql/components/TimeMachineEditor' +import {IFQLContext} from 'src/ifql/containers/IFQLPage' import { FlatBody, @@ -33,12 +34,8 @@ class TimeMachine extends PureComponent { const { body, script, - onAddNode, - onChangeArg, onChangeScript, onSubmitScript, - onDeleteFuncNode, - onGenerateScript, suggestions, } = this.props @@ -50,14 +47,9 @@ class TimeMachine extends PureComponent { onSubmitScript={onSubmitScript} />
- + return ( + + ) }}
) diff --git a/ui/src/ifql/containers/IFQLPage.tsx b/ui/src/ifql/containers/IFQLPage.tsx index 87c7de377..af76f8297 100644 --- a/ui/src/ifql/containers/IFQLPage.tsx +++ b/ui/src/ifql/containers/IFQLPage.tsx @@ -33,6 +33,8 @@ interface State { suggestions: Suggestion[] } +export const IFQLContext = React.createContext(() => {}) + @ErrorHandling export class IFQLPage extends PureComponent { constructor(props) { @@ -63,35 +65,48 @@ export class IFQLPage extends PureComponent { const {suggestions, script} = this.state return ( - -
-
-
-
-

Time Machine

+ + +
+
+
+
+

Time Machine

+
+
+
+
+
+
-
-
- -
-
-
- + + ) } + private get handlers() { + return { + onAddNode: this.handleAddNode, + onChangeArg: this.handleChangeArg, + onSubmitScript: this.handleSubmitScript, + onChangeScript: this.handleChangeScript, + onDeleteFuncNode: this.handleDeleteFuncNode, + onGenerateScript: this.handleGenerateScript, + } + } + private handleSubmitScript = () => { this.getASTResponse(this.state.script) } diff --git a/ui/yarn.lock b/ui/yarn.lock index 9c4ff9555..c5cb29322 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -80,12 +80,18 @@ "@types/history" "^3" "@types/react" "*" -"@types/react@*", "@types/react@^16.0.38": +"@types/react@*": version "16.3.9" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.3.9.tgz#15be16b53c89aac558cf6445774502b2792555ff" dependencies: csstype "^2.2.0" +"@types/react@^16.0.38": + version "16.3.12" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.3.12.tgz#68d9146f3e9797e38ffbf22f7ed1dde91a2cfd2e" + dependencies: + csstype "^2.2.0" + "@types/text-encoding@^0.0.32": version "0.0.32" resolved "https://registry.yarnpkg.com/@types/text-encoding/-/text-encoding-0.0.32.tgz#52289b320a406850b14f08f48b475ca021218048" @@ -1830,7 +1836,7 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" -codemirror@^5.18.2, codemirror@^5.36.0: +codemirror@^5.36.0: version "5.36.0" resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.36.0.tgz#1172ad9dc298056c06e0b34e5ccd23825ca15b40" @@ -2334,8 +2340,8 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": cssom "0.3.x" csstype@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.2.0.tgz#1656ef97553ac53b77090844a2531c6660ebd902" + version "2.3.0" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.3.0.tgz#062e141c78345cf814da0e0b716ad777931b08af" currently-unhandled@^0.4.1: version "0.4.1" @@ -5354,10 +5360,6 @@ lodash.create@3.1.1: lodash._basecreate "^3.0.0" lodash._isiterateecall "^3.0.0" -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - lodash.deburr@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash.deburr/-/lodash.deburr-3.2.0.tgz#6da8f54334a366a7cf4c4c76ef8d80aa1b365ed5" @@ -5395,7 +5397,7 @@ lodash.isempty@4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" -lodash.isequal@^4.0.0, lodash.isequal@^4.5.0: +lodash.isequal@^4.0.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" @@ -7109,17 +7111,6 @@ react-codemirror2@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/react-codemirror2/-/react-codemirror2-4.2.1.tgz#4ad3c5c60ebbcb34880f961721b51527324ec021" -react-codemirror@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/react-codemirror/-/react-codemirror-1.0.0.tgz#91467b53b1f5d80d916a2fd0b4c7adb85a9001ba" - dependencies: - classnames "^2.2.5" - codemirror "^5.18.2" - create-react-class "^15.5.1" - lodash.debounce "^4.0.8" - lodash.isequal "^4.5.0" - prop-types "^15.5.4" - react-custom-scrollbars@^4.1.1: version "4.2.1" resolved "https://registry.yarnpkg.com/react-custom-scrollbars/-/react-custom-scrollbars-4.2.1.tgz#830fd9502927e97e8a78c2086813899b2a8b66db" From ba9655af3af9b5b4eef2f67b8971d0cb0c0d6b07 Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Mon, 23 Apr 2018 19:32:07 -0700 Subject: [PATCH 17/18] Linter --- ui/package.json | 13 +- ui/src/CheckSources.tsx | 10 +- ui/src/admin/actions/influxdb.js | 4 +- .../admin/containers/DatabaseManagerPage.js | 12 +- .../containers/chronograf/AllUsersPage.tsx | 22 +- .../chronograf/OrganizationsPage.js | 22 +- .../admin/containers/chronograf/UsersPage.js | 13 +- ui/src/alerts/components/AlertsTable.js | 9 +- ui/src/dashboards/actions/index.js | 8 +- ui/src/dashboards/components/AxesOptions.js | 22 +- .../components/CellEditorOverlay.tsx | 13 +- .../dashboards/components/DisplayOptions.js | 7 +- ui/src/dashboards/components/GaugeOptions.js | 14 +- .../components/GraphTypeSelector.js | 6 +- .../components/MeasurementDropdown.js | 6 +- ui/src/dashboards/components/QueryTextArea.js | 4 +- .../components/SingleStatOptions.js | 13 +- ui/src/dashboards/components/TableOptions.tsx | 10 +- .../dashboards/components/TagKeyDropdown.js | 6 +- ui/src/dashboards/components/Threshold.tsx | 4 +- ui/src/dashboards/components/Visualization.js | 6 +- .../components/VisualizationName.js | 6 +- .../components/template_variables/Row.js | 10 +- ui/src/dashboards/containers/DashboardPage.js | 6 +- .../dashboards/containers/DashboardsPage.js | 10 +- .../dashboards/reducers/cellEditorOverlay.js | 5 +- .../data_explorer/components/QueryEditor.js | 4 +- .../data_explorer/components/Visualization.js | 6 +- .../data_explorer/containers/DataExplorer.tsx | 4 +- ui/src/hosts/containers/HostPage.js | 9 +- ui/src/hosts/containers/HostsPage.js | 7 +- ui/src/ifql/components/ExpressionNode.tsx | 3 +- ui/src/ifql/components/FuncArgs.tsx | 4 - ui/src/ifql/components/TimeMachine.tsx | 1 - ui/src/ifql/containers/IFQLPage.tsx | 6 +- ui/src/kapacitor/actions/view/index.js | 4 +- ui/src/kapacitor/components/AlertTabs.js | 8 +- ui/src/kapacitor/components/KapacitorForm.tsx | 4 +- ui/src/kapacitor/components/KapacitorRule.js | 10 +- ui/src/kapacitor/components/Relative.js | 4 +- ui/src/kapacitor/components/Threshold.js | 4 +- ui/src/kapacitor/containers/KapacitorPage.tsx | 6 +- .../kapacitor/containers/TickscriptPage.tsx | 5 +- ui/src/shared/actions/sources.js | 8 +- ui/src/shared/apis/index.js | 8 +- .../components/CustomTimeRangeDropdown.tsx | 8 +- ui/src/shared/components/Dygraph.js | 17 +- ui/src/shared/components/DygraphLegend.tsx | 4 +- .../components/MultiSelectDBDropdown.js | 6 +- ui/src/shared/components/Notification.js | 13 +- ui/src/shared/components/Notifications.js | 4 +- ui/src/shared/components/TableGraph.js | 9 +- ui/src/shared/middleware/errors.js | 11 +- .../shared/parsing/parseHandlersFromConfig.js | 4 +- ui/src/shared/reducers/auth.js | 4 +- ui/src/side_nav/components/UserNavBlock.js | 4 +- ui/src/side_nav/containers/SideNav.tsx | 4 +- ui/src/status/components/NewsFeed.js | 4 +- ui/src/types/ifql.ts | 23 +- ui/yarn.lock | 388 +++++++++--------- 60 files changed, 565 insertions(+), 304 deletions(-) diff --git a/ui/package.json b/ui/package.json index 87321ea69..de8f74f90 100644 --- a/ui/package.json +++ b/ui/package.json @@ -12,7 +12,8 @@ "build": "yarn run clean && webpack --config ./webpack/prod.config.js", "build:dev": "webpack --config ./webpack/dev.config.js", "build:vendor": "webpack --config webpack/vendor.config.js", - "start": "yarn run clean && yarn run build:vendor && webpack --watch --config ./webpack/dev.config.js --progress", + "start": + "yarn run clean && yarn run build:vendor && webpack --watch --config ./webpack/dev.config.js --progress", "start:fast": "webpack --watch --config ./webpack/dev.config.js", "start:hmr": "webpack-dev-server --open --config ./webpack/dev.config.js", "lint": "esw src/", @@ -22,9 +23,12 @@ "clean": "rm -rf ./build/*", "eslint:fix": "eslint src --fix", "tslint:fix": "tslint --fix -c ./tslint.json '{src,test}/**/*.ts?(x)'", - "prettier": "prettier --single-quote --trailing-comma es5 --bracket-spacing false --semi false --write \"{src,spec}/**/*.js\"", - "lint:fix": "yarn run prettier && yarn run eslint:fix && yarn run tslint:fix", - "eslint-check": "eslint --print-config .eslintrc | eslint-config-prettier-check" + "prettier": + "prettier --single-quote --trailing-comma es5 --bracket-spacing false --semi false --write \"{src,spec}/**/*.js\"", + "lint:fix": + "yarn run prettier && yarn run eslint:fix && yarn run tslint:fix", + "eslint-check": + "eslint --print-config .eslintrc | eslint-config-prettier-check" }, "author": "", "eslintConfig": { @@ -133,6 +137,7 @@ "query-string": "^5.0.0", "react": "^16.3.1", "react-addons-shallow-compare": "^15.0.2", + "react-codemirror": "^1.0.0", "react-codemirror2": "^4.2.1", "react-custom-scrollbars": "^4.1.1", "react-dimensions": "^1.2.0", diff --git a/ui/src/CheckSources.tsx b/ui/src/CheckSources.tsx index c6213ff2b..1e56ec371 100644 --- a/ui/src/CheckSources.tsx +++ b/ui/src/CheckSources.tsx @@ -84,7 +84,10 @@ export class CheckSources extends Component { } public async componentWillMount() { - const {router, auth: {isUsingAuth, me}} = this.props + const { + router, + auth: {isUsingAuth, me}, + } = this.props if (!isUsingAuth || isUserAuthorized(me.role, VIEWER_ROLE)) { await this.props.getSources() this.setState({isFetching: false}) @@ -189,7 +192,10 @@ export class CheckSources extends Component { const { params, sources, - auth: {isUsingAuth, me: {currentOrganization}}, + auth: { + isUsingAuth, + me: {currentOrganization}, + }, } = this.props const {isFetching} = this.state const source = sources.find(s => s.id === params.sourceID) diff --git a/ui/src/admin/actions/influxdb.js b/ui/src/admin/actions/influxdb.js index ce4d9b183..cf899ac48 100644 --- a/ui/src/admin/actions/influxdb.js +++ b/ui/src/admin/actions/influxdb.js @@ -298,7 +298,9 @@ export const loadPermissionsAsync = url => async dispatch => { export const loadDBsAndRPsAsync = url => async dispatch => { try { - const {data: {databases}} = await getDbsAndRpsAJAX(url) + const { + data: {databases}, + } = await getDbsAndRpsAJAX(url) dispatch(loadDatabases(_.sortBy(databases, ({name}) => name.toLowerCase()))) } catch (error) { dispatch(errorThrown(error)) diff --git a/ui/src/admin/containers/DatabaseManagerPage.js b/ui/src/admin/containers/DatabaseManagerPage.js index 5ea3ca6f8..8b50a67fa 100644 --- a/ui/src/admin/containers/DatabaseManagerPage.js +++ b/ui/src/admin/containers/DatabaseManagerPage.js @@ -23,7 +23,12 @@ class DatabaseManagerPage extends Component { } componentDidMount() { - const {source: {links: {databases}}, actions} = this.props + const { + source: { + links: {databases}, + }, + actions, + } = this.props actions.loadDBsAndRPsAsync(databases) } @@ -80,7 +85,10 @@ class DatabaseManagerPage extends Component { } handleDatabaseDeleteConfirm = database => e => { - const {key, target: {value}} = e + const { + key, + target: {value}, + } = e const {actions, notify} = this.props if (key === 'Escape') { diff --git a/ui/src/admin/containers/chronograf/AllUsersPage.tsx b/ui/src/admin/containers/chronograf/AllUsersPage.tsx index edb33285d..4f74b6683 100644 --- a/ui/src/admin/containers/chronograf/AllUsersPage.tsx +++ b/ui/src/admin/containers/chronograf/AllUsersPage.tsx @@ -50,7 +50,10 @@ export class AllUsersPage extends PureComponent { } public componentDidMount() { - const {links, actionsConfig: {getAuthConfigAsync}} = this.props + const { + links, + actionsConfig: {getAuthConfigAsync}, + } = this.props getAuthConfigAsync(links.config.auth) } @@ -71,7 +74,10 @@ export class AllUsersPage extends PureComponent { } public handleCreateUser = (user: User) => { - const {links, actionsAdmin: {createUserAsync}} = this.props + const { + links, + actionsAdmin: {createUserAsync}, + } = this.props createUserAsync(links.allUsers, user) } @@ -80,13 +86,17 @@ export class AllUsersPage extends PureComponent { roles: Role[], successMessage: string ) => { - const {actionsAdmin: {updateUserAsync}} = this.props + const { + actionsAdmin: {updateUserAsync}, + } = this.props const updatedUser = {...user, roles} updateUserAsync(user, updatedUser, successMessage) } public handleUpdateUserSuperAdmin = (user: User, superAdmin: boolean) => { - const {actionsAdmin: {updateUserAsync}} = this.props + const { + actionsAdmin: {updateUserAsync}, + } = this.props const updatedUser = {...user, superAdmin} updateUserAsync( user, @@ -96,7 +106,9 @@ export class AllUsersPage extends PureComponent { } public handleDeleteUser = (user: User) => { - const {actionsAdmin: {deleteUserAsync}} = this.props + const { + actionsAdmin: {deleteUserAsync}, + } = this.props deleteUserAsync(user, {isAbsoluteDelete: true}) } diff --git a/ui/src/admin/containers/chronograf/OrganizationsPage.js b/ui/src/admin/containers/chronograf/OrganizationsPage.js index 491cf1845..a9910a6bf 100644 --- a/ui/src/admin/containers/chronograf/OrganizationsPage.js +++ b/ui/src/admin/containers/chronograf/OrganizationsPage.js @@ -12,24 +12,34 @@ import OrganizationsTable from 'src/admin/components/chronograf/OrganizationsTab @ErrorHandling class OrganizationsPage extends Component { componentDidMount() { - const {links, actionsAdmin: {loadOrganizationsAsync}} = this.props + const { + links, + actionsAdmin: {loadOrganizationsAsync}, + } = this.props loadOrganizationsAsync(links.organizations) } handleCreateOrganization = async organization => { - const {links, actionsAdmin: {createOrganizationAsync}} = this.props + const { + links, + actionsAdmin: {createOrganizationAsync}, + } = this.props await createOrganizationAsync(links.organizations, organization) this.refreshMe() } handleRenameOrganization = async (organization, name) => { - const {actionsAdmin: {updateOrganizationAsync}} = this.props + const { + actionsAdmin: {updateOrganizationAsync}, + } = this.props await updateOrganizationAsync(organization, {...organization, name}) this.refreshMe() } handleDeleteOrganization = organization => { - const {actionsAdmin: {deleteOrganizationAsync}} = this.props + const { + actionsAdmin: {deleteOrganizationAsync}, + } = this.props deleteOrganizationAsync(organization) this.refreshMe() } @@ -40,7 +50,9 @@ class OrganizationsPage extends Component { } handleChooseDefaultRole = (organization, defaultRole) => { - const {actionsAdmin: {updateOrganizationAsync}} = this.props + const { + actionsAdmin: {updateOrganizationAsync}, + } = this.props updateOrganizationAsync(organization, {...organization, defaultRole}) // refreshMe is here to update the org's defaultRole in `me.organizations` this.refreshMe() diff --git a/ui/src/admin/containers/chronograf/UsersPage.js b/ui/src/admin/containers/chronograf/UsersPage.js index d2fb10219..a53ab8b5f 100644 --- a/ui/src/admin/containers/chronograf/UsersPage.js +++ b/ui/src/admin/containers/chronograf/UsersPage.js @@ -20,12 +20,17 @@ class UsersPage extends PureComponent { } handleCreateUser = user => { - const {links, actions: {createUserAsync}} = this.props + const { + links, + actions: {createUserAsync}, + } = this.props createUserAsync(links.users, user) } handleUpdateUserRole = (user, currentRole, {name}) => { - const {actions: {updateUserAsync}} = this.props + const { + actions: {updateUserAsync}, + } = this.props const updatedRole = {...currentRole, name} const newRoles = user.roles.map( r => (r.organization === currentRole.organization ? updatedRole : r) @@ -38,7 +43,9 @@ class UsersPage extends PureComponent { } handleDeleteUser = user => { - const {actions: {deleteUserAsync}} = this.props + const { + actions: {deleteUserAsync}, + } = this.props deleteUserAsync(user, {isAbsoluteDelete: false}) } diff --git a/ui/src/alerts/components/AlertsTable.js b/ui/src/alerts/components/AlertsTable.js index 82e0297b9..72e7fd3c1 100644 --- a/ui/src/alerts/components/AlertsTable.js +++ b/ui/src/alerts/components/AlertsTable.js @@ -74,7 +74,9 @@ class AlertsTable extends Component { } renderTable() { - const {source: {id}} = this.props + const { + source: {id}, + } = this.props const alerts = this.sort( this.state.filteredAlerts, this.state.sortKey, @@ -175,7 +177,10 @@ class AlertsTable extends Component { } renderTableEmpty() { - const {source: {id}, shouldNotBeFilterable} = this.props + const { + source: {id}, + shouldNotBeFilterable, + } = this.props return shouldNotBeFilterable ? (
diff --git a/ui/src/dashboards/actions/index.js b/ui/src/dashboards/actions/index.js index e7c565fef..ce5c9678d 100644 --- a/ui/src/dashboards/actions/index.js +++ b/ui/src/dashboards/actions/index.js @@ -210,7 +210,9 @@ export const setActiveCell = activeCellID => ({ export const getDashboardsAsync = () => async dispatch => { try { - const {data: {dashboards}} = await getDashboardsAJAX() + const { + data: {dashboards}, + } = await getDashboardsAJAX() dispatch(loadDashboards(dashboards)) return dashboards } catch (error) { @@ -260,7 +262,9 @@ export const putDashboard = dashboard => async dispatch => { export const putDashboardByID = dashboardID => async (dispatch, getState) => { try { - const {dashboardUI: {dashboards}} = getState() + const { + dashboardUI: {dashboards}, + } = getState() const dashboard = dashboards.find(d => d.id === +dashboardID) const templates = removeUnselectedTemplateValues(dashboard) await updateDashboardAJAX({...dashboard, templates}) diff --git a/ui/src/dashboards/components/AxesOptions.js b/ui/src/dashboards/components/AxesOptions.js index 6d1f95698..a621b14fc 100644 --- a/ui/src/dashboards/components/AxesOptions.js +++ b/ui/src/dashboards/components/AxesOptions.js @@ -41,7 +41,11 @@ class AxesOptions extends Component { handleSetYAxisBoundMin = min => { const {handleUpdateAxes, axes} = this.props - const {y: {bounds: [, max]}} = this.props.axes + const { + y: { + bounds: [, max], + }, + } = this.props.axes const newAxes = {...axes, y: {...axes.y, bounds: [min, max]}} handleUpdateAxes(newAxes) @@ -49,7 +53,11 @@ class AxesOptions extends Component { handleSetYAxisBoundMax = max => { const {handleUpdateAxes, axes} = this.props - const {y: {bounds: [min]}} = axes + const { + y: { + bounds: [min], + }, + } = axes const newAxes = {...axes, y: {...axes.y, bounds: [min, max]}} handleUpdateAxes(newAxes) @@ -78,7 +86,9 @@ class AxesOptions extends Component { render() { const { - axes: {y: {bounds, label, prefix, suffix, base, scale, defaultYLabel}}, + axes: { + y: {bounds, label, prefix, suffix, base, scale, defaultYLabel}, + }, type, staticLegend, onToggleStaticLegend, @@ -218,7 +228,11 @@ AxesOptions.propTypes = { handleUpdateAxes: func.isRequired, } -const mapStateToProps = ({cellEditorOverlay: {cell: {axes, type}}}) => ({ +const mapStateToProps = ({ + cellEditorOverlay: { + cell: {axes, type}, + }, +}) => ({ axes, type, }) diff --git a/ui/src/dashboards/components/CellEditorOverlay.tsx b/ui/src/dashboards/components/CellEditorOverlay.tsx index ce0127473..b49c7f711 100644 --- a/ui/src/dashboards/components/CellEditorOverlay.tsx +++ b/ui/src/dashboards/components/CellEditorOverlay.tsx @@ -99,8 +99,12 @@ class CellEditorOverlay extends Component { constructor(props) { super(props) - const {cell: {legend}} = props - let {cell: {queries}} = props + const { + cell: {legend}, + } = props + let { + cell: {queries}, + } = props // Always have at least one query if (_.isEmpty(queries)) { @@ -395,7 +399,10 @@ class CellEditorOverlay extends Component { } private get sourceLink(): string { - const {cell: {queries}, source: {links}} = this.props + const { + cell: {queries}, + source: {links}, + } = this.props return _.get(queries, '0.source.links.self', links.self) } diff --git a/ui/src/dashboards/components/DisplayOptions.js b/ui/src/dashboards/components/DisplayOptions.js index ec3c47cf3..8bc04102b 100644 --- a/ui/src/dashboards/components/DisplayOptions.js +++ b/ui/src/dashboards/components/DisplayOptions.js @@ -97,7 +97,12 @@ DisplayOptions.propTypes = { onResetFocus: func.isRequired, } -const mapStateToProps = ({cellEditorOverlay: {cell, cell: {axes}}}) => ({ +const mapStateToProps = ({ + cellEditorOverlay: { + cell, + cell: {axes}, + }, +}) => ({ cell, axes, }) diff --git a/ui/src/dashboards/components/GaugeOptions.js b/ui/src/dashboards/components/GaugeOptions.js index 2a6c29b0b..0145c366a 100644 --- a/ui/src/dashboards/components/GaugeOptions.js +++ b/ui/src/dashboards/components/GaugeOptions.js @@ -156,7 +156,12 @@ class GaugeOptions extends Component { } render() { - const {gaugeColors, axes: {y: {prefix, suffix}}} = this.props + const { + gaugeColors, + axes: { + y: {prefix, suffix}, + }, + } = this.props const disableMaxColor = gaugeColors.length > MIN_THRESHOLDS const disableAddThreshold = gaugeColors.length > MAX_THRESHOLDS @@ -229,7 +234,12 @@ GaugeOptions.propTypes = { onResetFocus: func.isRequired, } -const mapStateToProps = ({cellEditorOverlay: {gaugeColors, cell: {axes}}}) => ({ +const mapStateToProps = ({ + cellEditorOverlay: { + gaugeColors, + cell: {axes}, + }, +}) => ({ gaugeColors, axes, }) diff --git a/ui/src/dashboards/components/GraphTypeSelector.js b/ui/src/dashboards/components/GraphTypeSelector.js index 162361ff7..4e6e04f73 100644 --- a/ui/src/dashboards/components/GraphTypeSelector.js +++ b/ui/src/dashboards/components/GraphTypeSelector.js @@ -49,7 +49,11 @@ GraphTypeSelector.propTypes = { handleChangeCellType: func.isRequired, } -const mapStateToProps = ({cellEditorOverlay: {cell: {type}}}) => ({ +const mapStateToProps = ({ + cellEditorOverlay: { + cell: {type}, + }, +}) => ({ type, }) diff --git a/ui/src/dashboards/components/MeasurementDropdown.js b/ui/src/dashboards/components/MeasurementDropdown.js index 0ab2d9c86..3df2f0a0f 100644 --- a/ui/src/dashboards/components/MeasurementDropdown.js +++ b/ui/src/dashboards/components/MeasurementDropdown.js @@ -42,7 +42,11 @@ class MeasurementDropdown extends Component { } _getMeasurements = async () => { - const {source: {links: {proxy}}} = this.context + const { + source: { + links: {proxy}, + }, + } = this.context const { measurement, database, diff --git a/ui/src/dashboards/components/QueryTextArea.js b/ui/src/dashboards/components/QueryTextArea.js index 1e94bd83f..ea152f8cd 100644 --- a/ui/src/dashboards/components/QueryTextArea.js +++ b/ui/src/dashboards/components/QueryTextArea.js @@ -187,7 +187,9 @@ class QueryTextArea extends Component { } render() { - const {config: {status}} = this.props + const { + config: {status}, + } = this.props const { value, isTemplating, diff --git a/ui/src/dashboards/components/SingleStatOptions.js b/ui/src/dashboards/components/SingleStatOptions.js index c1beac6e6..c67ea1e82 100644 --- a/ui/src/dashboards/components/SingleStatOptions.js +++ b/ui/src/dashboards/components/SingleStatOptions.js @@ -27,7 +27,12 @@ class SingleStatOptions extends Component { } render() { - const {axes: {y: {prefix, suffix}}, onResetFocus} = this.props + const { + axes: { + y: {prefix, suffix}, + }, + onResetFocus, + } = this.props return ( ({ +const mapStateToProps = ({ + cellEditorOverlay: { + cell: {axes}, + }, +}) => ({ axes, }) diff --git a/ui/src/dashboards/components/TableOptions.tsx b/ui/src/dashboards/components/TableOptions.tsx index c1056766c..12a034f1d 100644 --- a/ui/src/dashboards/components/TableOptions.tsx +++ b/ui/src/dashboards/components/TableOptions.tsx @@ -123,7 +123,9 @@ export class TableOptions extends Component { } private get fieldNames() { - const {tableOptions: {fieldNames}} = this.props + const { + tableOptions: {fieldNames}, + } = this.props return fieldNames || [] } @@ -217,7 +219,11 @@ export class TableOptions extends Component { } } -const mapStateToProps = ({cellEditorOverlay: {cell: {tableOptions}}}) => ({ +const mapStateToProps = ({ + cellEditorOverlay: { + cell: {tableOptions}, + }, +}) => ({ tableOptions, }) diff --git a/ui/src/dashboards/components/TagKeyDropdown.js b/ui/src/dashboards/components/TagKeyDropdown.js index afa71a3a3..8838c2686 100644 --- a/ui/src/dashboards/components/TagKeyDropdown.js +++ b/ui/src/dashboards/components/TagKeyDropdown.js @@ -54,7 +54,11 @@ class TagKeyDropdown extends Component { onSelectTagKey, onErrorThrown, } = this.props - const {source: {links: {proxy}}} = this.context + const { + source: { + links: {proxy}, + }, + } = this.context try { const {data} = await showTagKeys({source: proxy, database, measurement}) diff --git a/ui/src/dashboards/components/Threshold.tsx b/ui/src/dashboards/components/Threshold.tsx index 28d650943..e74061d4e 100644 --- a/ui/src/dashboards/components/Threshold.tsx +++ b/ui/src/dashboards/components/Threshold.tsx @@ -84,7 +84,9 @@ class Threshold extends PureComponent { } private get selectedColor(): SelectedColor { - const {threshold: {hex, name}} = this.props + const { + threshold: {hex, name}, + } = this.props return {hex, name} } diff --git a/ui/src/dashboards/components/Visualization.js b/ui/src/dashboards/components/Visualization.js index 82cf5ce83..96606fa22 100644 --- a/ui/src/dashboards/components/Visualization.js +++ b/ui/src/dashboards/components/Visualization.js @@ -25,7 +25,11 @@ const DashVisualization = ( thresholdsListColors, tableOptions, }, - {source: {links: {proxy}}} + { + source: { + links: {proxy}, + }, + } ) => { const colors = getCellTypeColors({ cellType: type, diff --git a/ui/src/dashboards/components/VisualizationName.js b/ui/src/dashboards/components/VisualizationName.js index 34928e36d..399836382 100644 --- a/ui/src/dashboards/components/VisualizationName.js +++ b/ui/src/dashboards/components/VisualizationName.js @@ -64,7 +64,11 @@ VisualizationName.propTypes = { handleRenameCell: func, } -const mapStateToProps = ({cellEditorOverlay: {cell: {name}}}) => ({ +const mapStateToProps = ({ + cellEditorOverlay: { + cell: {name}, + }, +}) => ({ name, }) diff --git a/ui/src/dashboards/components/template_variables/Row.js b/ui/src/dashboards/components/template_variables/Row.js index e4aa07731..4760990f4 100644 --- a/ui/src/dashboards/components/template_variables/Row.js +++ b/ui/src/dashboards/components/template_variables/Row.js @@ -129,7 +129,9 @@ const TemplateVariableRow = ({ class RowWrapper extends Component { constructor(props) { super(props) - const {template: {type, query, isNew}} = this.props + const { + template: {type, query, isNew}, + } = this.props this.state = { isEditing: !!isNew, @@ -218,7 +220,11 @@ class RowWrapper extends Component { handleCancelEdit = () => { const { - template: {type, query: {db, measurement, tagKey}, id}, + template: { + type, + query: {db, measurement, tagKey}, + id, + }, onDelete, } = this.props const {hasBeenSavedToComponentStateOnce} = this.state diff --git a/ui/src/dashboards/containers/DashboardPage.js b/ui/src/dashboards/containers/DashboardPage.js index d0a27bf02..a0976bfe2 100644 --- a/ui/src/dashboards/containers/DashboardPage.js +++ b/ui/src/dashboards/containers/DashboardPage.js @@ -239,7 +239,11 @@ class DashboardPage extends Component { } handleSelectTemplate = templateID => values => { - const {dashboardActions, dashboard, params: {dashboardID}} = this.props + const { + dashboardActions, + dashboard, + params: {dashboardID}, + } = this.props dashboardActions.templateVariableSelected(dashboard.id, templateID, [ values, ]) diff --git a/ui/src/dashboards/containers/DashboardsPage.js b/ui/src/dashboards/containers/DashboardsPage.js index 4e5589ad5..163ead9dd 100644 --- a/ui/src/dashboards/containers/DashboardsPage.js +++ b/ui/src/dashboards/containers/DashboardsPage.js @@ -20,13 +20,19 @@ class DashboardsPage extends Component { } handleCreateDashboard = async () => { - const {source: {id}, router: {push}} = this.props + const { + source: {id}, + router: {push}, + } = this.props const {data} = await createDashboard(NEW_DASHBOARD) push(`/sources/${id}/dashboards/${data.id}`) } handleCloneDashboard = dashboard => async () => { - const {source: {id}, router: {push}} = this.props + const { + source: {id}, + router: {push}, + } = this.props const {data} = await createDashboard({ ...dashboard, name: `${dashboard.name} (clone)`, diff --git a/ui/src/dashboards/reducers/cellEditorOverlay.js b/ui/src/dashboards/reducers/cellEditorOverlay.js index d51d2c503..01f8692cf 100644 --- a/ui/src/dashboards/reducers/cellEditorOverlay.js +++ b/ui/src/dashboards/reducers/cellEditorOverlay.js @@ -27,7 +27,10 @@ export const initialState = { export default function cellEditorOverlay(state = initialState, action) { switch (action.type) { case 'SHOW_CELL_EDITOR_OVERLAY': { - const {cell, cell: {colors}} = action.payload + const { + cell, + cell: {colors}, + } = action.payload const thresholdsListType = getThresholdsListType(colors) const thresholdsListColors = validateThresholdsListColors( diff --git a/ui/src/data_explorer/components/QueryEditor.js b/ui/src/data_explorer/components/QueryEditor.js index abc6a4b4d..220f5b609 100644 --- a/ui/src/data_explorer/components/QueryEditor.js +++ b/ui/src/data_explorer/components/QueryEditor.js @@ -48,7 +48,9 @@ class QueryEditor extends Component { } render() { - const {config: {status}} = this.props + const { + config: {status}, + } = this.props const {value} = this.state return ( diff --git a/ui/src/data_explorer/components/Visualization.js b/ui/src/data_explorer/components/Visualization.js index 4c07702b9..b9ddc7354 100644 --- a/ui/src/data_explorer/components/Visualization.js +++ b/ui/src/data_explorer/components/Visualization.js @@ -64,7 +64,11 @@ class Visualization extends Component { errorThrown, } = this.props - const {source: {links: {proxy}}} = this.context + const { + source: { + links: {proxy}, + }, + } = this.context const {view} = this.state const queries = buildQueries(proxy, queryConfigs, timeRange) diff --git a/ui/src/data_explorer/containers/DataExplorer.tsx b/ui/src/data_explorer/containers/DataExplorer.tsx index 3c1e0ca78..57ae430f9 100644 --- a/ui/src/data_explorer/containers/DataExplorer.tsx +++ b/ui/src/data_explorer/containers/DataExplorer.tsx @@ -199,7 +199,9 @@ export class DataExplorer extends PureComponent { const mapStateToProps = state => { const { - app: {persisted: {autoRefresh}}, + app: { + persisted: {autoRefresh}, + }, dataExplorer, dataExplorerQueryConfigs: queryConfigs, timeRange, diff --git a/ui/src/hosts/containers/HostPage.js b/ui/src/hosts/containers/HostPage.js index a0bc77045..8f81f52bc 100644 --- a/ui/src/hosts/containers/HostPage.js +++ b/ui/src/hosts/containers/HostPage.js @@ -39,7 +39,9 @@ class HostPage extends Component { const {source, params, location} = this.props // fetching layouts and mappings can be done at the same time - const {data: {layouts}} = await getLayouts() + const { + data: {layouts}, + } = await getLayouts() const hosts = await getAllHosts(source.links.proxy, source.telegraf) const newHosts = await getAppsForHosts( source.links.proxy, @@ -220,7 +222,10 @@ HostPage.propTypes = { } const mapStateToProps = ({ - app: {ephemeral: {inPresentationMode}, persisted: {autoRefresh}}, + app: { + ephemeral: {inPresentationMode}, + persisted: {autoRefresh}, + }, }) => ({ inPresentationMode, autoRefresh, diff --git a/ui/src/hosts/containers/HostsPage.js b/ui/src/hosts/containers/HostsPage.js index e083202bf..bcc8ae73d 100644 --- a/ui/src/hosts/containers/HostsPage.js +++ b/ui/src/hosts/containers/HostsPage.js @@ -162,7 +162,12 @@ export class HostsPage extends Component { const {func, shape, string, number} = PropTypes const mapStateToProps = state => { - const {app: {persisted: {autoRefresh}}, links} = state + const { + app: { + persisted: {autoRefresh}, + }, + links, + } = state return { links, autoRefresh, diff --git a/ui/src/ifql/components/ExpressionNode.tsx b/ui/src/ifql/components/ExpressionNode.tsx index 68422b3df..5f6fabe91 100644 --- a/ui/src/ifql/components/ExpressionNode.tsx +++ b/ui/src/ifql/components/ExpressionNode.tsx @@ -11,7 +11,8 @@ interface Props { id: string funcs: Func[] } -// an expression is a group of one or more functions + +// an Expression is a group of one or more functions class ExpressionNode extends PureComponent { public render() { const {id, funcNames, funcs} = this.props diff --git a/ui/src/ifql/components/FuncArgs.tsx b/ui/src/ifql/components/FuncArgs.tsx index 95ecfbd8a..c8be0ac3c 100644 --- a/ui/src/ifql/components/FuncArgs.tsx +++ b/ui/src/ifql/components/FuncArgs.tsx @@ -16,10 +16,6 @@ export default class FuncArgs extends PureComponent { public render() { const {expressionID, func, onChangeArg, onGenerateScript} = this.props - if (!func.args) { - debugger - } - return (
{func.args.map(({key, value, type}) => { diff --git a/ui/src/ifql/components/TimeMachine.tsx b/ui/src/ifql/components/TimeMachine.tsx index d8302e1d5..3c8d45ce1 100644 --- a/ui/src/ifql/components/TimeMachine.tsx +++ b/ui/src/ifql/components/TimeMachine.tsx @@ -1,7 +1,6 @@ import React, {PureComponent} from 'react' import BodyBuilder from 'src/ifql/components/BodyBuilder' import TimeMachineEditor from 'src/ifql/components/TimeMachineEditor' -import {IFQLContext} from 'src/ifql/containers/IFQLPage' import { FlatBody, diff --git a/ui/src/ifql/containers/IFQLPage.tsx b/ui/src/ifql/containers/IFQLPage.tsx index af76f8297..49b970302 100644 --- a/ui/src/ifql/containers/IFQLPage.tsx +++ b/ui/src/ifql/containers/IFQLPage.tsx @@ -5,7 +5,7 @@ import {connect} from 'react-redux' import TimeMachine from 'src/ifql/components/TimeMachine' import KeyboardShortcuts from 'src/shared/components/KeyboardShortcuts' import {Suggestion, FlatBody} from 'src/types/ifql' -import {InputArg} from 'src/types/ifql' +import {InputArg, Handlers} from 'src/types/ifql' import {bodyNodes} from 'src/ifql/helpers' import {getSuggestions, getAST} from 'src/ifql/apis' @@ -33,7 +33,7 @@ interface State { suggestions: Suggestion[] } -export const IFQLContext = React.createContext(() => {}) +export const IFQLContext = React.createContext() @ErrorHandling export class IFQLPage extends PureComponent { @@ -96,7 +96,7 @@ export class IFQLPage extends PureComponent { ) } - private get handlers() { + private get handlers(): Handlers { return { onAddNode: this.handleAddNode, onChangeArg: this.handleChangeArg, diff --git a/ui/src/kapacitor/actions/view/index.js b/ui/src/kapacitor/actions/view/index.js index 657367146..a0d928837 100644 --- a/ui/src/kapacitor/actions/view/index.js +++ b/ui/src/kapacitor/actions/view/index.js @@ -92,7 +92,9 @@ export const loadDefaultRule = () => { export const fetchRules = kapacitor => async dispatch => { try { - const {data: {rules}} = await getRules(kapacitor) + const { + data: {rules}, + } = await getRules(kapacitor) dispatch({type: 'LOAD_RULES', payload: {rules}}) } catch (error) { dispatch(errorThrown(error)) diff --git a/ui/src/kapacitor/components/AlertTabs.js b/ui/src/kapacitor/components/AlertTabs.js index 841cfce38..4e81cc4fd 100644 --- a/ui/src/kapacitor/components/AlertTabs.js +++ b/ui/src/kapacitor/components/AlertTabs.js @@ -55,7 +55,9 @@ class AlertTabs extends Component { refreshKapacitorConfig = async kapacitor => { try { - const {data: {sections}} = await getKapacitorConfig(kapacitor) + const { + data: {sections}, + } = await getKapacitorConfig(kapacitor) this.setState({configSections: sections}) } catch (error) { this.setState({configSections: null}) @@ -91,7 +93,9 @@ class AlertTabs extends Component { this.refreshKapacitorConfig(this.props.kapacitor) this.props.notify(notifyAlertEndpointSaved(section)) return true - } catch ({data: {error}}) { + } catch ({ + data: {error}, + }) { const errorMsg = _.join(_.drop(_.split(error, ': '), 2), ': ') this.props.notify(notifyAlertEndpointSaveFailed(section, errorMsg)) return false diff --git a/ui/src/kapacitor/components/KapacitorForm.tsx b/ui/src/kapacitor/components/KapacitorForm.tsx index 01f24472b..3bbbb95a1 100644 --- a/ui/src/kapacitor/components/KapacitorForm.tsx +++ b/ui/src/kapacitor/components/KapacitorForm.tsx @@ -162,7 +162,9 @@ class KapacitorForm extends PureComponent { } private get url(): string { - const {kapacitor: {url}} = this.props + const { + kapacitor: {url}, + } = this.props if (url) { return url } diff --git a/ui/src/kapacitor/components/KapacitorRule.js b/ui/src/kapacitor/components/KapacitorRule.js index 3248f9673..08892424c 100644 --- a/ui/src/kapacitor/components/KapacitorRule.js +++ b/ui/src/kapacitor/components/KapacitorRule.js @@ -101,12 +101,18 @@ class KapacitorRule extends Component { } handleAddEvery = frequency => { - const {rule: {id: ruleID}, ruleActions: {addEvery}} = this.props + const { + rule: {id: ruleID}, + ruleActions: {addEvery}, + } = this.props addEvery(ruleID, frequency) } handleRemoveEvery = () => { - const {rule: {id: ruleID}, ruleActions: {removeEvery}} = this.props + const { + rule: {id: ruleID}, + ruleActions: {removeEvery}, + } = this.props removeEvery(ruleID) } diff --git a/ui/src/kapacitor/components/Relative.js b/ui/src/kapacitor/components/Relative.js index fd89960bd..6b483f01e 100644 --- a/ui/src/kapacitor/components/Relative.js +++ b/ui/src/kapacitor/components/Relative.js @@ -11,7 +11,9 @@ const operators = mapToItems(RELATIVE_OPERATORS, 'operator') const Relative = ({ onRuleTypeInputChange, onDropdownChange, - rule: {values: {change, shift, operator, value}}, + rule: { + values: {change, shift, operator, value}, + }, }) => (

Send Alert when

diff --git a/ui/src/kapacitor/components/Threshold.js b/ui/src/kapacitor/components/Threshold.js index cc1ecb294..1c3ba10a3 100644 --- a/ui/src/kapacitor/components/Threshold.js +++ b/ui/src/kapacitor/components/Threshold.js @@ -17,7 +17,9 @@ const getField = ({fields}) => { } const Threshold = ({ - rule: {values: {operator, value, rangeValue}}, + rule: { + values: {operator, value, rangeValue}, + }, query, onDropdownChange, onRuleTypeInputChange, diff --git a/ui/src/kapacitor/containers/KapacitorPage.tsx b/ui/src/kapacitor/containers/KapacitorPage.tsx index 63de5f327..54953b6d6 100644 --- a/ui/src/kapacitor/containers/KapacitorPage.tsx +++ b/ui/src/kapacitor/containers/KapacitorPage.tsx @@ -78,7 +78,11 @@ export class KapacitorPage extends PureComponent { } public async componentDidMount() { - const {source, params: {id}, notify} = this.props + const { + source, + params: {id}, + notify, + } = this.props if (!id) { return } diff --git a/ui/src/kapacitor/containers/TickscriptPage.tsx b/ui/src/kapacitor/containers/TickscriptPage.tsx index 723b0429e..83e54d74c 100644 --- a/ui/src/kapacitor/containers/TickscriptPage.tsx +++ b/ui/src/kapacitor/containers/TickscriptPage.tsx @@ -201,7 +201,10 @@ export class TickscriptPage extends PureComponent { } private handleExit = () => { - const {source: {id: sourceID}, router} = this.props + const { + source: {id: sourceID}, + router, + } = this.props return router.push(`/sources/${sourceID}/alert-rules`) } diff --git a/ui/src/shared/actions/sources.js b/ui/src/shared/actions/sources.js index 4a3968b34..f218ae11c 100644 --- a/ui/src/shared/actions/sources.js +++ b/ui/src/shared/actions/sources.js @@ -73,7 +73,9 @@ export const removeAndLoadSources = source => async dispatch => { } } - const {data: {sources: newSources}} = await getSourcesAJAX() + const { + data: {sources: newSources}, + } = await getSourcesAJAX() dispatch(loadSources(newSources)) } catch (err) { dispatch(notify(notifyServerError())) @@ -107,7 +109,9 @@ export const deleteKapacitorAsync = kapacitor => async dispatch => { export const getSourcesAsync = () => async dispatch => { try { - const {data: {sources}} = await getSourcesAJAX() + const { + data: {sources}, + } = await getSourcesAJAX() dispatch(loadSources(sources)) return sources } catch (error) { diff --git a/ui/src/shared/apis/index.js b/ui/src/shared/apis/index.js index 18ec7d602..436dea75a 100644 --- a/ui/src/shared/apis/index.js +++ b/ui/src/shared/apis/index.js @@ -173,11 +173,9 @@ export function updateKapacitorConfigSection(kapacitor, section, properties) { export const testAlertOutput = async (kapacitor, outputName) => { try { - const {data: {services}} = await kapacitorProxy( - kapacitor, - 'GET', - '/kapacitor/v1/service-tests' - ) + const { + data: {services}, + } = await kapacitorProxy(kapacitor, 'GET', '/kapacitor/v1/service-tests') const service = services.find(s => s.name === outputName) return kapacitorProxy(kapacitor, 'POST', service.link.href, {}) } catch (error) { diff --git a/ui/src/shared/components/CustomTimeRangeDropdown.tsx b/ui/src/shared/components/CustomTimeRangeDropdown.tsx index 2031b4b9e..c32a19cda 100644 --- a/ui/src/shared/components/CustomTimeRangeDropdown.tsx +++ b/ui/src/shared/components/CustomTimeRangeDropdown.tsx @@ -61,7 +61,9 @@ class CustomTimeRangeDropdown extends PureComponent { } private get upperTimeRange(): string { - const {timeRange: {upper}} = this.props + const { + timeRange: {upper}, + } = this.props if (upper === 'now()') { return moment().format(this.timeFormat) @@ -71,7 +73,9 @@ class CustomTimeRangeDropdown extends PureComponent { } private get lowerTimeRange(): string { - const {timeRange: {lower}} = this.props + const { + timeRange: {lower}, + } = this.props return moment(lower).format(this.timeFormat) } diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index a495f85d5..9c6917126 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -101,7 +101,12 @@ class Dygraph extends Component { } componentDidUpdate(prevProps) { - const {labels, axes: {y, y2}, options, isBarGraph} = this.props + const { + labels, + axes: {y, y2}, + options, + isBarGraph, + } = this.props const dygraph = this.dygraph @@ -154,7 +159,11 @@ class Dygraph extends Component { } getYRange = timeSeries => { - const {options, axes: {y}, ruleValues} = this.props + const { + options, + axes: {y}, + ruleValues, + } = this.props if (options.stackedGraph) { return getStackedRange(y.bounds) @@ -224,7 +233,9 @@ class Dygraph extends Component { } get labelWidth() { - const {axes: {y}} = this.props + const { + axes: {y}, + } = this.props return ( LABEL_WIDTH + y.prefix.length * CHAR_PIXELS + diff --git a/ui/src/shared/components/DygraphLegend.tsx b/ui/src/shared/components/DygraphLegend.tsx index 9bf7edae3..e3f38b436 100644 --- a/ui/src/shared/components/DygraphLegend.tsx +++ b/ui/src/shared/components/DygraphLegend.tsx @@ -280,7 +280,9 @@ class DygraphLegend extends PureComponent { } private get styles() { - const {dygraph: {graphDiv}} = this.props + const { + dygraph: {graphDiv}, + } = this.props const {pageX} = this.state return makeLegendStyles(graphDiv, this.legendRef, pageX) } diff --git a/ui/src/shared/components/MultiSelectDBDropdown.js b/ui/src/shared/components/MultiSelectDBDropdown.js index 4ac82c5aa..08d5fbc12 100644 --- a/ui/src/shared/components/MultiSelectDBDropdown.js +++ b/ui/src/shared/components/MultiSelectDBDropdown.js @@ -37,7 +37,11 @@ class MultiSelectDBDropdown extends Component { } _getDbRps = async () => { - const {source: {links: {proxy}}} = this.context + const { + source: { + links: {proxy}, + }, + } = this.context const {onErrorThrown} = this.props try { diff --git a/ui/src/shared/components/Notification.js b/ui/src/shared/components/Notification.js index 62c85ede1..e185e6d53 100644 --- a/ui/src/shared/components/Notification.js +++ b/ui/src/shared/components/Notification.js @@ -23,7 +23,9 @@ class Notification extends Component { } componentDidMount() { - const {notification: {duration}} = this.props + const { + notification: {duration}, + } = this.props this.updateHeight() @@ -46,7 +48,10 @@ class Notification extends Component { } handleDismiss = () => { - const {notification: {id}, dismissNotification} = this.props + const { + notification: {id}, + dismissNotification, + } = this.props this.setState({dismissed: true}) this.deleteTimer = setTimeout( @@ -61,7 +66,9 @@ class Notification extends Component { } render() { - const {notification: {type, message, icon}} = this.props + const { + notification: {type, message, icon}, + } = this.props const {height, dismissed} = this.state const notificationContainerClass = classnames('notification-container', { diff --git a/ui/src/shared/components/Notifications.js b/ui/src/shared/components/Notifications.js index 8d20a00ea..f08bec624 100644 --- a/ui/src/shared/components/Notifications.js +++ b/ui/src/shared/components/Notifications.js @@ -33,7 +33,9 @@ Notifications.propTypes = { const mapStateToProps = ({ notifications, - app: {ephemeral: {inPresentationMode}}, + app: { + ephemeral: {inPresentationMode}, + }, }) => ({ notifications, inPresentationMode, diff --git a/ui/src/shared/components/TableGraph.js b/ui/src/shared/components/TableGraph.js index 9a1db53e4..8ec929f07 100644 --- a/ui/src/shared/components/TableGraph.js +++ b/ui/src/shared/components/TableGraph.js @@ -135,7 +135,10 @@ class TableGraph extends Component { } handleHover = (columnIndex, rowIndex) => () => { - const {handleSetHoverTime, tableOptions: {verticalTimeAxis}} = this.props + const { + handleSetHoverTime, + tableOptions: {verticalTimeAxis}, + } = this.props const {sortedTimeVals} = this.state if (verticalTimeAxis && rowIndex === 0) { return @@ -193,7 +196,9 @@ class TableGraph extends Component { calculateColumnWidth = columnSizerWidth => column => { const {index} = column - const {tableOptions: {fixFirstColumn}} = this.props + const { + tableOptions: {fixFirstColumn}, + } = this.props const {processedData, columnWidths, totalColumnWidths} = this.state const columnCount = _.get(processedData, ['0', 'length'], 0) const columnLabel = processedData[0][index] diff --git a/ui/src/shared/middleware/errors.js b/ui/src/shared/middleware/errors.js index ee1fd5f72..3dbc4c22b 100644 --- a/ui/src/shared/middleware/errors.js +++ b/ui/src/shared/middleware/errors.js @@ -23,10 +23,17 @@ const notificationsBlackoutDuration = 5000 let allowNotifications = true // eslint-disable-line const errorsMiddleware = store => next => action => { - const {auth: {me}} = store.getState() + const { + auth: {me}, + } = store.getState() if (action.type === 'ERROR_THROWN') { - const {error, error: {status, auth}, altText, alertType = 'info'} = action + const { + error, + error: {status, auth}, + altText, + alertType = 'info', + } = action if (status === HTTP_FORBIDDEN) { const message = _.get(error, 'data.message', '') diff --git a/ui/src/shared/parsing/parseHandlersFromConfig.js b/ui/src/shared/parsing/parseHandlersFromConfig.js index 48b14be43..cb72415e4 100644 --- a/ui/src/shared/parsing/parseHandlersFromConfig.js +++ b/ui/src/shared/parsing/parseHandlersFromConfig.js @@ -6,7 +6,9 @@ import { } from 'src/kapacitor/constants' const parseHandlersFromConfig = config => { - const {data: {sections}} = config + const { + data: {sections}, + } = config const allHandlers = _.map(sections, (v, k) => { const fromConfig = _.get(v, ['elements', '0', 'options'], {}) diff --git a/ui/src/shared/reducers/auth.js b/ui/src/shared/reducers/auth.js index 4bb128118..35fd5c2e5 100644 --- a/ui/src/shared/reducers/auth.js +++ b/ui/src/shared/reducers/auth.js @@ -43,7 +43,9 @@ const logoutLinkReceived = (state, {logoutLink}, isUsingAuth) => ({ const authReducer = (state = initialState, action) => { switch (action.type) { case 'AUTH_EXPIRED': { - const {auth: {links}} = action.payload + const { + auth: {links}, + } = action.payload return {...initialState, links} } case 'AUTH_REQUESTED': { diff --git a/ui/src/side_nav/components/UserNavBlock.js b/ui/src/side_nav/components/UserNavBlock.js index 274674437..631607a96 100644 --- a/ui/src/side_nav/components/UserNavBlock.js +++ b/ui/src/side_nav/components/UserNavBlock.js @@ -24,7 +24,9 @@ class UserNavBlock extends Component { render() { const { logoutLink, - links: {external: {custom: customLinks}}, + links: { + external: {custom: customLinks}, + }, me, me: {currentOrganization, organizations, roles}, me: {role}, diff --git a/ui/src/side_nav/containers/SideNav.tsx b/ui/src/side_nav/containers/SideNav.tsx index dc17ddbb0..1e62e6160 100644 --- a/ui/src/side_nav/containers/SideNav.tsx +++ b/ui/src/side_nav/containers/SideNav.tsx @@ -153,7 +153,9 @@ class SideNav extends PureComponent { const mapStateToProps = ({ auth: {isUsingAuth, logoutLink, me}, - app: {ephemeral: {inPresentationMode}}, + app: { + ephemeral: {inPresentationMode}, + }, links, }) => ({ isHidden: inPresentationMode, diff --git a/ui/src/status/components/NewsFeed.js b/ui/src/status/components/NewsFeed.js index e2dbb325f..8aa84fb77 100644 --- a/ui/src/status/components/NewsFeed.js +++ b/ui/src/status/components/NewsFeed.js @@ -73,7 +73,9 @@ NewsFeed.propTypes = { } const mapStateToProps = ({ - links: {external: {statusFeed: statusFeedURL}}, + links: { + external: {statusFeed: statusFeedURL}, + }, JSONFeed: {hasCompletedFetchOnce, isFetching, isFailed, data}, }) => ({ hasCompletedFetchOnce, diff --git a/ui/src/types/ifql.ts b/ui/src/types/ifql.ts index 5de7708fa..41d0cff52 100644 --- a/ui/src/types/ifql.ts +++ b/ui/src/types/ifql.ts @@ -1,7 +1,23 @@ // function definitions -export type OnDeleteFuncNode = (funcID: string, expressionID: string) => void -export type OnChangeArg = (inputArg: InputArg) => void -export type OnAddNode = (expressionID: string, funcName: string) => void +type noop = () => void +export type OnDeleteFuncNode = ( + funcID: string, + expressionID: string +) => void | noop +export type OnChangeArg = (inputArg: InputArg) => void | noop +export type OnAddNode = (expressionID: string, funcName: string) => void | noop +export type OnGenerateScript = (script: string) => void | noop +export type OnChangeScript = (script: string) => void | noop + +export interface Handlers { + onAddNode: OnAddNode + onChangeArg: OnChangeArg + onSubmitScript: () => void + onChangeScript: OnChangeScript + onDeleteFuncNode: OnDeleteFuncNode + onGenerateScript: OnGenerateScript +} + export interface InputArg { funcID: string expressionID: string @@ -9,7 +25,6 @@ export interface InputArg { value: string | boolean generate?: boolean } - // Flattened AST export interface FlatBody { type: string diff --git a/ui/yarn.lock b/ui/yarn.lock index c5cb29322..aa367c686 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -3,22 +3,22 @@ "@babel/code-frame@^7.0.0-beta.35": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9" + version "7.0.0-beta.46" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.46.tgz#e0d002100805daab1461c0fcb32a07e304f3a4f4" dependencies: - "@babel/highlight" "7.0.0-beta.44" + "@babel/highlight" "7.0.0-beta.46" -"@babel/highlight@7.0.0-beta.44": - version "7.0.0-beta.44" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5" +"@babel/highlight@7.0.0-beta.46": + version "7.0.0-beta.46" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.46.tgz#c553c51e65f572bdedd6eff66fc0bb563016645e" dependencies: chalk "^2.0.0" esutils "^2.0.2" js-tokens "^3.0.0" "@types/chai@^4.1.2": - version "4.1.2" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.2.tgz#f1af664769cfb50af805431c407425ed619daa21" + version "4.1.3" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.3.tgz#b8a74352977a23b604c01aa784f5b793443fb7dc" "@types/cheerio@*": version "0.22.7" @@ -31,8 +31,8 @@ "@types/google.visualization" "*" "@types/enzyme@^3.1.9": - version "3.1.9" - resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-3.1.9.tgz#fbd97f3beb7cad76fc9c6f04c97d77f4834522ef" + version "3.1.10" + resolved "https://registry.yarnpkg.com/@types/enzyme/-/enzyme-3.1.10.tgz#28108a9864e65699751469551a803a35d2e26160" dependencies: "@types/cheerio" "*" "@types/react" "*" @@ -50,12 +50,12 @@ resolved "https://registry.yarnpkg.com/@types/jest/-/jest-22.2.3.tgz#0157c0316dc3722c43a7b71de3fdf3acbccef10d" "@types/lodash@^4.14.104": - version "4.14.106" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.106.tgz#6093e9a02aa567ddecfe9afadca89e53e5dce4dd" + version "4.14.107" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.107.tgz#b2d2ae3958bfb8ff828495cbe12214af9e4d035e" "@types/node@*", "@types/node@^9.4.6": - version "9.6.4" - resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.4.tgz#0ef7b4cfc3499881c81e0ea1ce61a23f6f4f5b42" + version "9.6.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.6.tgz#439b91f9caf3983cad2eef1e11f6bedcbf9431d2" "@types/prop-types@^15.5.2": version "15.5.2" @@ -80,13 +80,7 @@ "@types/history" "^3" "@types/react" "*" -"@types/react@*": - version "16.3.9" - resolved "https://registry.yarnpkg.com/@types/react/-/react-16.3.9.tgz#15be16b53c89aac558cf6445774502b2792555ff" - dependencies: - csstype "^2.2.0" - -"@types/react@^16.0.38": +"@types/react@*", "@types/react@^16.0.38": version "16.3.12" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.3.12.tgz#68d9146f3e9797e38ffbf22f7ed1dde91a2cfd2e" dependencies: @@ -175,7 +169,7 @@ ajv-keywords@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be" -ajv@^4.7.0, ajv@^4.9.1: +ajv@^4.7.0: version "4.11.8" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" dependencies: @@ -513,7 +507,7 @@ babel-core@^6.0.0, babel-core@^6.26.0, babel-core@^6.5.1: babel-eslint@6.1.2: version "6.1.2" - resolved "http://registry.npmjs.org/babel-eslint/-/babel-eslint-6.1.2.tgz#5293419fe3672d66598d327da9694567ba6a5f2f" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-6.1.2.tgz#5293419fe3672d66598d327da9694567ba6a5f2f" dependencies: babel-traverse "^6.0.20" babel-types "^6.0.19" @@ -1262,8 +1256,8 @@ base62@^1.1.0: resolved "https://registry.yarnpkg.com/base62/-/base62-1.2.8.tgz#1264cb0fb848d875792877479dbe8bae6bae3428" base64-js@^1.0.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.3.tgz#fb13668233d9614cf5fb4bce95a9ba4096cdf801" + version "1.3.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3" base@^0.11.1: version "0.11.2" @@ -1619,12 +1613,12 @@ caniuse-api@^1.5.2: lodash.uniq "^4.5.0" caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: - version "1.0.30000827" - resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000827.tgz#bd2839dd196093b44c28c17f93513140c9d92588" + version "1.0.30000830" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000830.tgz#6e45255b345649fd15ff59072da1e12bb3de2f13" caniuse-lite@^1.0.30000792: - version "1.0.30000827" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000827.tgz#2dad2354e4810c3c9bb1cfc57f655c270c25fa52" + version "1.0.30000830" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000830.tgz#cb96b8a2dd3cbfe04acea2af3c4e894249095328" caseless@~0.11.0: version "0.11.0" @@ -1662,8 +1656,8 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: supports-color "^2.0.0" chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" + version "2.4.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.0.tgz#a060a297a6b57e15b61ca63ce84995daa0fe6e52" dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" @@ -1802,8 +1796,8 @@ cliui@^3.2.0: wrap-ansi "^2.0.0" cliui@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.0.0.tgz#743d4650e05f36d1ed2575b59638d87322bfbbcc" + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" dependencies: string-width "^2.1.1" strip-ansi "^4.0.0" @@ -1836,9 +1830,9 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" -codemirror@^5.36.0: - version "5.36.0" - resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.36.0.tgz#1172ad9dc298056c06e0b34e5ccd23825ca15b40" +codemirror@^5.18.2, codemirror@^5.36.0: + version "5.37.0" + resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.37.0.tgz#c349b584e158f590277f26d37c2469a6bc538036" collection-visit@^1.0.0: version "1.0.0" @@ -2395,7 +2389,7 @@ debug@2.6.8: dependencies: ms "2.0.0" -debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8: +debug@2.6.9, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -2704,8 +2698,8 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" ejs@^2.5.7: - version "2.5.8" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.8.tgz#2ab6954619f225e6193b7ac5f7c39c48fefe4380" + version "2.5.9" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.9.tgz#7ba254582a560d267437109a68354112475b0ce5" electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.30: version "1.3.42" @@ -2940,8 +2934,8 @@ eslint-plugin-babel@^4.1.2: resolved "https://registry.yarnpkg.com/eslint-plugin-babel/-/eslint-plugin-babel-4.1.2.tgz#79202a0e35757dd92780919b2336f1fa2fe53c1e" eslint-plugin-jest@^21.12.2: - version "21.15.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-21.15.0.tgz#645a3f560d3e61d99611b215adc80b4f31e6d896" + version "21.15.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-21.15.1.tgz#662a3f0888002878f0f388efd09c190a95c33d82" eslint-plugin-prettier@^2.2.0, eslint-plugin-prettier@^2.6.0: version "2.6.0" @@ -3122,9 +3116,9 @@ event-emitter@~0.3.5: d "1" es5-ext "~0.10.14" -eventemitter3@1.x.x: - version "1.2.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" +eventemitter3@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.0.1.tgz#4ce66c3fc5b5a6b9f2245e359e1938f1ab10f960" events@^1.0.0: version "1.1.1" @@ -3494,6 +3488,12 @@ follow-redirects@0.0.7: debug "^2.2.0" stream-consume "^0.1.0" +follow-redirects@^1.0.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.4.1.tgz#d8120f4518190f55aac65bb6fc7b85fcd666d6aa" + dependencies: + debug "^3.1.0" + for-in@^0.1.3: version "0.1.8" resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" @@ -3591,6 +3591,12 @@ fs-extra@^0.24.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + dependencies: + minipass "^2.2.1" + fs-promise@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/fs-promise/-/fs-promise-0.3.1.tgz#bf34050368f24d6dc9dfc6688ab5cead8f86842a" @@ -3611,21 +3617,13 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" fsevents@^1.0.0, fsevents@^1.1.1, fsevents@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.3.tgz#11f82318f5fe7bb2cd22965a108e9306208216d8" + version "1.2.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.2.tgz#4f598f0f69b273188ef4a62ca4e9e08ace314bbf" dependencies: - nan "^2.3.0" - node-pre-gyp "^0.6.39" + nan "^2.9.2" + node-pre-gyp "^0.9.0" -fstream-ignore@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - dependencies: - fstream "^1.0.0" - inherits "2" - minimatch "^3.0.0" - -fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: +fstream@^1.0.0, fstream@^1.0.2: version "1.0.11" resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" dependencies: @@ -3862,10 +3860,6 @@ hanson@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/hanson/-/hanson-1.2.0.tgz#2d198d5ca03ebccdcaeb7c9d9c492e18405be002" -har-schema@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" - har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" @@ -3879,13 +3873,6 @@ har-validator@~2.0.6: is-my-json-valid "^2.12.4" pinkie-promise "^2.0.0" -har-validator@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" - dependencies: - ajv "^4.9.1" - har-schema "^1.0.5" - har-validator@~5.0.3: version "5.0.3" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd" @@ -3958,12 +3945,6 @@ has@^1.0.1: dependencies: function-bind "^1.0.2" -hash-base@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" - dependencies: - inherits "^2.0.1" - hash-base@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" @@ -3978,7 +3959,7 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.0" -hawk@3.1.3, hawk@~3.1.3: +hawk@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" dependencies: @@ -4068,8 +4049,8 @@ html-entities@^1.2.0: resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" html-minifier@^3.2.3: - version "3.5.14" - resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.14.tgz#88653b24b344274e3e3d7052f1541ebea054ac60" + version "3.5.15" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.15.tgz#f869848d4543cbfd84f26d5514a2a87cbf9a05e0" dependencies: camel-case "3.0.x" clean-css "4.1.x" @@ -4154,11 +4135,12 @@ http-proxy-middleware@~0.17.4: micromatch "^2.3.11" http-proxy@^1.16.2: - version "1.16.2" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" + version "1.17.0" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a" dependencies: - eventemitter3 "1.x.x" - requires-port "1.x.x" + eventemitter3 "^3.0.0" + follow-redirects "^1.0.0" + requires-port "^1.0.0" http-signature@~1.1.0: version "1.1.1" @@ -4184,7 +4166,7 @@ iconv-lite@0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" -iconv-lite@^0.4.17, iconv-lite@^0.4.5, iconv-lite@~0.4.13: +iconv-lite@^0.4.17, iconv-lite@^0.4.4, iconv-lite@^0.4.5, iconv-lite@~0.4.13: version "0.4.21" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.21.tgz#c47f8733d02171189ebc4a400f3218d348094798" dependencies: @@ -4202,6 +4184,12 @@ iferr@^0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" +ignore-walk@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8" + dependencies: + minimatch "^3.0.4" + ignore@^3.2.0, ignore@^3.3.3: version "3.3.7" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" @@ -5030,8 +5018,8 @@ jsbn@~0.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" jsdom@^11.5.1: - version "11.7.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.7.0.tgz#8b45b657dae90d6d2d3a5f5d1126bb7102d0a172" + version "11.9.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.9.0.tgz#58ac6dfd248d560d736b0202d74eedad55590cd9" dependencies: abab "^1.0.4" acorn "^5.3.0" @@ -5360,6 +5348,10 @@ lodash.create@3.1.1: lodash._basecreate "^3.0.0" lodash._isiterateecall "^3.0.0" +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + lodash.deburr@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash.deburr/-/lodash.deburr-3.2.0.tgz#6da8f54334a366a7cf4c4c76ef8d80aa1b365ed5" @@ -5397,7 +5389,7 @@ lodash.isempty@4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" -lodash.isequal@^4.0.0: +lodash.isequal@^4.0.0, lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" @@ -5675,7 +5667,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" -"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2: +"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: @@ -5693,6 +5685,19 @@ minimist@~0.0.1: version "0.0.10" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf" +minipass@^2.2.1, minipass@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.2.4.tgz#03c824d84551ec38a8d1bb5bc350a5a30a354a40" + dependencies: + safe-buffer "^5.1.1" + yallist "^3.0.0" + +minizlib@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.1.0.tgz#11e13658ce46bc3a70a267aac58359d1e0c29ceb" + dependencies: + minipass "^2.2.1" + mississippi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-2.0.0.tgz#3442a508fafc28500486feea99409676e4ee5a6f" @@ -5745,8 +5750,8 @@ mocha@3.5.0: supports-color "3.1.2" moment@^2.13.0, moment@^2.8.2: - version "2.22.0" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.0.tgz#7921ade01017dd45186e7fee5f424f0b8663a730" + version "2.22.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.1.tgz#529a2e9bf973f259c9643d237fda84de3a26e8ad" move-concurrently@^1.0.1: version "1.0.1" @@ -5782,7 +5787,7 @@ mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" -nan@^2.10.0, nan@^2.3.0: +nan@^2.10.0, nan@^2.9.2: version "2.10.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" @@ -5824,6 +5829,14 @@ nearley@^2.7.10: randexp "0.4.6" semver "^5.4.1" +needle@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.0.tgz#f14efc69cee1024b72c8b21c7bdf94a731dc12fa" + dependencies: + debug "^2.1.2" + iconv-lite "^0.4.4" + sax "^1.2.4" + negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" @@ -5912,21 +5925,20 @@ node-notifier@^5.2.1: shellwords "^0.1.1" which "^1.3.0" -node-pre-gyp@^0.6.39: - version "0.6.39" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.39.tgz#c00e96860b23c0e1420ac7befc5044e1d78d8649" +node-pre-gyp@^0.9.0: + version "0.9.1" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.9.1.tgz#f11c07516dd92f87199dbc7e1838eab7cd56c9e0" dependencies: detect-libc "^1.0.2" - hawk "3.1.3" mkdirp "^0.5.1" + needle "^2.2.0" nopt "^4.0.1" + npm-packlist "^1.1.6" npmlog "^4.0.2" rc "^1.1.7" - request "2.81.0" rimraf "^2.6.1" semver "^5.3.0" - tar "^2.2.1" - tar-pack "^3.4.0" + tar "^4" node-sass@^4.5.3: version "4.8.3" @@ -6000,6 +6012,17 @@ normalize-url@^1.4.0: query-string "^4.1.0" sort-keys "^1.0.0" +npm-bundled@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.3.tgz#7e71703d973af3370a9591bafe3a63aca0be2308" + +npm-packlist@^1.1.6: + version "1.1.10" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.1.10.tgz#1039db9e985727e464df066f4cf0ab6ef85c398a" + dependencies: + ignore-walk "^3.0.1" + npm-bundled "^1.0.1" + npm-run-path@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" @@ -6144,7 +6167,7 @@ on-headers@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7" -once@^1.3.0, once@^1.3.1, once@^1.3.3, once@^1.4.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: @@ -6382,8 +6405,8 @@ path-type@^2.0.0: pify "^2.0.0" pbkdf2@^3.0.3: - version "3.0.14" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.14.tgz#a35e13c64799b06ce15320f459c230e68e73bade" + version "3.0.16" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.16.tgz#7404208ec6b01b62d85bf83853a8064f8d9c2a5c" dependencies: create-hash "^1.1.2" create-hmac "^1.1.4" @@ -6391,10 +6414,6 @@ pbkdf2@^3.0.3: safe-buffer "^5.0.1" sha.js "^2.4.8" -performance-now@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" - performance-now@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" @@ -6881,8 +6900,8 @@ preserve@^0.2.0: resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" prettier@^1.11.1: - version "1.11.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.11.1.tgz#61e43fc4cd44e68f2b0dfc2c38cd4bb0fccdcc75" + version "1.12.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.12.1.tgz#c1ad20e803e7749faf905a409d2367e06bbe7325" pretty-error@^2.0.2: version "2.1.1" @@ -7006,10 +7025,6 @@ qs@~6.3.0: version "6.3.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" -qs@~6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" - query-string@^4.1.0, query-string@^4.2.2: version "4.3.4" resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" @@ -7037,9 +7052,9 @@ querystringify@0.0.x: version "0.0.4" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-0.0.4.tgz#0cf7f84f9463ff0ae51c4c4b142d95be37724d9c" -querystringify@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb" +querystringify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.0.0.tgz#fa3ed6e68eb15159457c89b37bc6472833195755" raf@^3.1.0, raf@^3.4.0: version "3.4.0" @@ -7108,8 +7123,19 @@ react-addons-shallow-compare@^15.0.2: object-assign "^4.1.0" react-codemirror2@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/react-codemirror2/-/react-codemirror2-4.2.1.tgz#4ad3c5c60ebbcb34880f961721b51527324ec021" + version "4.3.0" + resolved "https://registry.yarnpkg.com/react-codemirror2/-/react-codemirror2-4.3.0.tgz#e79aedca4da60d22402d2cd74f2885a3e5c009fd" + +react-codemirror@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/react-codemirror/-/react-codemirror-1.0.0.tgz#91467b53b1f5d80d916a2fd0b4c7adb85a9001ba" + dependencies: + classnames "^2.2.5" + codemirror "^5.18.2" + create-react-class "^15.5.1" + lodash.debounce "^4.0.8" + lodash.isequal "^4.5.0" + prop-types "^15.5.4" react-custom-scrollbars@^4.1.1: version "4.2.1" @@ -7286,7 +7312,7 @@ read-pkg@^2.0.0: normalize-package-data "^2.3.2" path-type "^2.0.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.3: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.9, readable-stream@^2.3.3: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" dependencies: @@ -7527,33 +7553,6 @@ request@2, request@^2.79.0, request@^2.83.0: tunnel-agent "^0.6.0" uuid "^3.1.0" -request@2.81.0: - version "2.81.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.12.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~4.2.1" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - performance-now "^0.2.0" - qs "~6.4.0" - safe-buffer "^5.0.1" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "^0.6.0" - uuid "^3.0.0" - request@~2.79.0: version "2.79.0" resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" @@ -7598,7 +7597,7 @@ require-uncached@^1.0.2, require-uncached@^1.0.3: caller-path "^0.1.0" resolve-from "^1.0.0" -requires-port@1.0.x, requires-port@1.x.x, requires-port@~1.0.0: +requires-port@1.0.x, requires-port@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" @@ -7639,8 +7638,8 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" resolve@^1.1.6, resolve@^1.1.7, resolve@^1.3.2, resolve@^1.5.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.7.0.tgz#2bdf5374811207285df0df652b78f118ab8f3c5e" + version "1.7.1" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.7.1.tgz#aadd656374fd298aee895bc026b8297418677fd3" dependencies: path-parse "^1.0.5" @@ -7683,17 +7682,17 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2, rimraf@^2.2.8, rimraf@^2.4.4, rimraf@^2.5.1, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: +rimraf@2, rimraf@^2.2.8, rimraf@^2.4.4, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" dependencies: glob "^7.0.5" ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" dependencies: - hash-base "^2.0.0" + hash-base "^3.0.0" inherits "^2.0.1" rome@^2.1.22: @@ -7864,8 +7863,8 @@ send@0.16.2: statuses "~1.4.0" serialize-javascript@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.4.0.tgz#7c958514db6ac2443a8abc062dc9f7886a7f6005" + version "1.5.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.5.0.tgz#1aa336162c88a890ddad5384baebc93a655161fe" serve-index@^1.7.2: version "1.9.1" @@ -8385,8 +8384,8 @@ supports-color@^4.2.1: has-flag "^2.0.0" supports-color@^5.1.0, supports-color@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0" + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" dependencies: has-flag "^3.0.0" @@ -8436,20 +8435,7 @@ tapable@^0.2.7: version "0.2.8" resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22" -tar-pack@^3.4.0: - version "3.4.1" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.1.tgz#e1dbc03a9b9d3ba07e896ad027317eb679a10a1f" - dependencies: - debug "^2.2.0" - fstream "^1.0.10" - fstream-ignore "^1.0.5" - once "^1.3.3" - readable-stream "^2.1.4" - rimraf "^2.5.1" - tar "^2.2.1" - uid-number "^0.0.6" - -tar@^2.0.0, tar@^2.2.1: +tar@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" dependencies: @@ -8457,6 +8443,18 @@ tar@^2.0.0, tar@^2.2.1: fstream "^1.0.2" inherits "2" +tar@^4: + version "4.4.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.1.tgz#b25d5a8470c976fd7a9a8a350f42c59e9fa81749" + dependencies: + chownr "^1.0.1" + fs-minipass "^1.2.5" + minipass "^2.2.4" + minizlib "^1.1.0" + mkdirp "^0.5.0" + safe-buffer "^5.1.1" + yallist "^3.0.2" + tcomb@^2.5.1: version "2.7.0" resolved "https://registry.yarnpkg.com/tcomb/-/tcomb-2.7.0.tgz#10d62958041669a5d53567b9a4ee8cde22b1c2b0" @@ -8511,8 +8509,8 @@ time-stamp@^2.0.0: resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-2.0.0.tgz#95c6a44530e15ba8d6f4a3ecb8c3a3fac46da357" timers-browserify@^2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.6.tgz#241e76927d9ca05f4d959819022f5b3664b64bae" + version "2.0.10" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae" dependencies: setimmediate "^1.0.4" @@ -8582,7 +8580,7 @@ tough-cookie@>=2.3.3, tough-cookie@^2.3.2, tough-cookie@^2.3.3, tough-cookie@~2. dependencies: punycode "^1.4.1" -tr46@^1.0.0: +tr46@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" dependencies: @@ -8615,8 +8613,8 @@ tryer@^1.0.0: resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.0.tgz#027b69fa823225e551cace3ef03b11f6ab37c1d7" ts-jest@^22.4.1: - version "22.4.2" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-22.4.2.tgz#2137bc0899b14dfb1d58257ee10b18ab8a2d92c5" + version "22.4.4" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-22.4.4.tgz#7b5c0abb2188fe7170840df9f80e78659aaf8a24" dependencies: babel-core "^6.26.0" babel-plugin-istanbul "^4.1.4" @@ -8643,8 +8641,8 @@ tslib@^1.7.1, tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" tslint-config-prettier@^1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/tslint-config-prettier/-/tslint-config-prettier-1.10.0.tgz#5063c413d43de4f6988c73727f65ecfc239054ec" + version "1.12.0" + resolved "https://registry.yarnpkg.com/tslint-config-prettier/-/tslint-config-prettier-1.12.0.tgz#bc8504f286ecf42b906f3d1126a093114f5729cc" tslint-loader@^3.6.0: version "3.6.0" @@ -8728,8 +8726,8 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" typescript@^2.7.2: - version "2.8.1" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.1.tgz#6160e4f8f195d5ba81d4876f9c0cc1fbc0820624" + version "2.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.3.tgz#5d817f9b6f31bb871835f4edf0089f21abe6c170" ua-parser-js@^0.7.9: version "0.7.17" @@ -8743,8 +8741,8 @@ uglify-es@^3.3.4: source-map "~0.6.1" uglify-js@3.3.x: - version "3.3.20" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.3.20.tgz#dc8bdee7d454c7d31dddc36f922d170bfcee3a0a" + version "3.3.22" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.3.22.tgz#e5f0e50ddd386b7e35b728b51600bf7a7ad0b0dc" dependencies: commander "~2.15.0" source-map "~0.6.1" @@ -8771,8 +8769,8 @@ uglifyjs-webpack-plugin@^0.4.6: webpack-sources "^1.0.1" uglifyjs-webpack-plugin@^1.2.2: - version "1.2.4" - resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.4.tgz#5eec941b2e9b8538be0a20fc6eda25b14c7c1043" + version "1.2.5" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.5.tgz#2ef8387c8f1a903ec5e44fa36f9f3cbdcea67641" dependencies: cacache "^10.0.4" find-cache-dir "^1.0.0" @@ -8783,10 +8781,6 @@ uglifyjs-webpack-plugin@^1.2.2: webpack-sources "^1.1.0" worker-farm "^1.5.2" -uid-number@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - underscore@~1.4.4: version "1.4.4" resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.4.4.tgz#61a6a32010622afa07963bf325203cf12239d604" @@ -8871,11 +8865,11 @@ url-parse@1.0.x: requires-port "1.0.x" url-parse@^1.1.8: - version "1.3.0" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.3.0.tgz#04a06c420d22beb9804f7ada2d57ad13160a4258" + version "1.4.0" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.0.tgz#6bfdaad60098c7fe06f623e42b22de62de0d3d75" dependencies: - querystringify "~1.0.0" - requires-port "~1.0.0" + querystringify "^2.0.0" + requires-port "^1.0.0" url@^0.11.0: version "0.11.0" @@ -8941,8 +8935,8 @@ vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" vendors@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22" + version "1.0.2" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.2.tgz#7fcb5eef9f5623b156bcea89ec37d63676f21801" verror@1.10.0: version "1.10.0" @@ -9007,7 +9001,7 @@ webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" -webidl-conversions@^4.0.0, webidl-conversions@^4.0.1, webidl-conversions@^4.0.2: +webidl-conversions@^4.0.0, webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" @@ -9137,12 +9131,12 @@ whatwg-url@^4.3.0: webidl-conversions "^3.0.0" whatwg-url@^6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.4.0.tgz#08fdf2b9e872783a7a1f6216260a1d66cc722e08" + version "6.4.1" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.4.1.tgz#fdb94b440fd4ad836202c16e9737d511f012fd67" dependencies: lodash.sortby "^4.7.0" - tr46 "^1.0.0" - webidl-conversions "^4.0.1" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" whet.extend@~0.9.9: version "0.9.9" @@ -9253,6 +9247,10 @@ yallist@^2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" + yargs-parser@^4.2.0: version "4.2.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" From 1e3a036cd99ee11638b333fa66df80bb0c849c4e Mon Sep 17 00:00:00 2001 From: Andrew Watkins Date: Mon, 23 Apr 2018 19:45:50 -0700 Subject: [PATCH 18/18] Fix errors and warnings --- ui/package.json | 2 +- ui/src/ifql/components/FuncNode.tsx | 3 +-- ui/src/ifql/components/TimeMachine.tsx | 17 +++++---------- ui/src/ifql/components/TimeMachineEditor.tsx | 8 +++++-- ui/src/ifql/containers/IFQLPage.tsx | 4 ---- ui/src/types/ifql.ts | 17 ++++++--------- ui/src/types/kapacitor.ts | 2 +- ui/test/ifql/components/TimeMachine.test.tsx | 8 ++----- ui/yarn.lock | 23 +++++--------------- 9 files changed, 29 insertions(+), 55 deletions(-) diff --git a/ui/package.json b/ui/package.json index de8f74f90..62c4e0d5c 100644 --- a/ui/package.json +++ b/ui/package.json @@ -49,6 +49,7 @@ "@types/react-dnd-html5-backend": "^2.1.9", "@types/react-router": "^3.0.15", "@types/text-encoding": "^0.0.32", + "@types/codemirror": "^0.0.56", "autoprefixer": "^6.3.1", "babel-core": "^6.5.1", "babel-eslint": "6.1.2", @@ -137,7 +138,6 @@ "query-string": "^5.0.0", "react": "^16.3.1", "react-addons-shallow-compare": "^15.0.2", - "react-codemirror": "^1.0.0", "react-codemirror2": "^4.2.1", "react-custom-scrollbars": "^4.1.1", "react-dimensions": "^1.2.0", diff --git a/ui/src/ifql/components/FuncNode.tsx b/ui/src/ifql/components/FuncNode.tsx index 4a51db4d9..7d83005ce 100644 --- a/ui/src/ifql/components/FuncNode.tsx +++ b/ui/src/ifql/components/FuncNode.tsx @@ -1,7 +1,6 @@ import React, {PureComponent, MouseEvent} from 'react' import FuncArgs from 'src/ifql/components/FuncArgs' -import {Func} from 'src/ifql/components/FuncArgs' -import {OnChangeArg} from 'src/types/ifql' +import {OnChangeArg, Func} from 'src/types/ifql' import {ErrorHandling} from 'src/shared/decorators/errors' interface Props { diff --git a/ui/src/ifql/components/TimeMachine.tsx b/ui/src/ifql/components/TimeMachine.tsx index 3c8d45ce1..716c09994 100644 --- a/ui/src/ifql/components/TimeMachine.tsx +++ b/ui/src/ifql/components/TimeMachine.tsx @@ -3,11 +3,10 @@ import BodyBuilder from 'src/ifql/components/BodyBuilder' import TimeMachineEditor from 'src/ifql/components/TimeMachineEditor' import { - FlatBody, Suggestion, - OnChangeArg, - OnDeleteFuncNode, - OnAddNode, + OnChangeScript, + OnSubmitScript, + FlatBody, } from 'src/types/ifql' import {ErrorHandling} from 'src/shared/decorators/errors' @@ -15,12 +14,8 @@ interface Props { script: string suggestions: Suggestion[] body: Body[] - onSubmitScript: () => void - onChangeScript: (script: string) => void - onAddNode: OnAddNode - onChangeArg: OnChangeArg - onDeleteFuncNode: OnDeleteFuncNode - onGenerateScript: () => void + onSubmitScript: OnSubmitScript + onChangeScript: OnChangeScript } interface Body extends FlatBody { @@ -46,9 +41,7 @@ class TimeMachine extends PureComponent { onSubmitScript={onSubmitScript} />
- return ( - ) }}
) diff --git a/ui/src/ifql/components/TimeMachineEditor.tsx b/ui/src/ifql/components/TimeMachineEditor.tsx index 6c51e89e1..e448f3e49 100644 --- a/ui/src/ifql/components/TimeMachineEditor.tsx +++ b/ui/src/ifql/components/TimeMachineEditor.tsx @@ -3,11 +3,12 @@ import {Controlled as CodeMirror, IInstance} from 'react-codemirror2' import {EditorChange} from 'codemirror' import 'src/external/codemirror' import {ErrorHandling} from 'src/shared/decorators/errors' +import {OnSubmitScript, OnChangeScript} from 'src/types/ifql' interface Props { script: string - onChangeScript: (script: string) => void - onSubmitScript: () => void + onChangeScript: OnChangeScript + onSubmitScript: OnSubmitScript } @ErrorHandling @@ -35,6 +36,7 @@ class TimeMachineEditor extends PureComponent { value={script} options={options} onBeforeChange={this.updateCode} + onTouchStart={this.onTouchStart} />
diff --git a/ui/src/types/ifql.ts b/ui/src/types/ifql.ts index 41d0cff52..4cf3326e8 100644 --- a/ui/src/types/ifql.ts +++ b/ui/src/types/ifql.ts @@ -1,18 +1,15 @@ // function definitions -type noop = () => void -export type OnDeleteFuncNode = ( - funcID: string, - expressionID: string -) => void | noop -export type OnChangeArg = (inputArg: InputArg) => void | noop -export type OnAddNode = (expressionID: string, funcName: string) => void | noop -export type OnGenerateScript = (script: string) => void | noop -export type OnChangeScript = (script: string) => void | noop +export type OnDeleteFuncNode = (funcID: string, expressionID: string) => void +export type OnChangeArg = (inputArg: InputArg) => void +export type OnAddNode = (expressionID: string, funcName: string) => void +export type OnGenerateScript = (script: string) => void +export type OnChangeScript = (script: string) => void +export type OnSubmitScript = () => void export interface Handlers { onAddNode: OnAddNode onChangeArg: OnChangeArg - onSubmitScript: () => void + onSubmitScript: OnSubmitScript onChangeScript: OnChangeScript onDeleteFuncNode: OnDeleteFuncNode onGenerateScript: OnGenerateScript diff --git a/ui/src/types/kapacitor.ts b/ui/src/types/kapacitor.ts index 7b9520941..dfe832a0c 100644 --- a/ui/src/types/kapacitor.ts +++ b/ui/src/types/kapacitor.ts @@ -178,7 +178,7 @@ interface OpsGenie { } // Talk sends alerts to Jane Talk (https://jianliao.com/site) -interface Talk {} +interface Talk {} // tslint:disable-line // TriggerValues specifies the alerting logic for a specific trigger type interface TriggerValues { diff --git a/ui/test/ifql/components/TimeMachine.test.tsx b/ui/test/ifql/components/TimeMachine.test.tsx index 1b714751b..3fb702d80 100644 --- a/ui/test/ifql/components/TimeMachine.test.tsx +++ b/ui/test/ifql/components/TimeMachine.test.tsx @@ -5,14 +5,10 @@ import TimeMachine from 'src/ifql/components/TimeMachine' const setup = () => { const props = { script: '', + body: [], suggestions: [], - expressions: [], - onAddNode: () => {}, - onChangeScript: () => {}, onSubmitScript: () => {}, - onDeleteFuncNode: () => {}, - onChangeArg: () => {}, - onGenerateScript: () => {}, + onChangeScript: () => {}, } const wrapper = shallow() diff --git a/ui/yarn.lock b/ui/yarn.lock index aa367c686..8b3d253a9 100644 --- a/ui/yarn.lock +++ b/ui/yarn.lock @@ -24,6 +24,10 @@ version "0.22.7" resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.7.tgz#4a92eafedfb2b9f4437d3a4410006d81114c66ce" +"@types/codemirror@^0.0.56": + version "0.0.56" + resolved "https://registry.yarnpkg.com/@types/codemirror/-/codemirror-0.0.56.tgz#1fcf68df0d0a49791d843dadda7d94891ac88669" + "@types/dygraphs@^1.1.6": version "1.1.6" resolved "https://registry.yarnpkg.com/@types/dygraphs/-/dygraphs-1.1.6.tgz#20ff1a01e353e813ff97898c0fee5defc66626be" @@ -1830,7 +1834,7 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" -codemirror@^5.18.2, codemirror@^5.36.0: +codemirror@^5.36.0: version "5.37.0" resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.37.0.tgz#c349b584e158f590277f26d37c2469a6bc538036" @@ -5348,10 +5352,6 @@ lodash.create@3.1.1: lodash._basecreate "^3.0.0" lodash._isiterateecall "^3.0.0" -lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - lodash.deburr@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash.deburr/-/lodash.deburr-3.2.0.tgz#6da8f54334a366a7cf4c4c76ef8d80aa1b365ed5" @@ -5389,7 +5389,7 @@ lodash.isempty@4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" -lodash.isequal@^4.0.0, lodash.isequal@^4.5.0: +lodash.isequal@^4.0.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" @@ -7126,17 +7126,6 @@ react-codemirror2@^4.2.1: version "4.3.0" resolved "https://registry.yarnpkg.com/react-codemirror2/-/react-codemirror2-4.3.0.tgz#e79aedca4da60d22402d2cd74f2885a3e5c009fd" -react-codemirror@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/react-codemirror/-/react-codemirror-1.0.0.tgz#91467b53b1f5d80d916a2fd0b4c7adb85a9001ba" - dependencies: - classnames "^2.2.5" - codemirror "^5.18.2" - create-react-class "^15.5.1" - lodash.debounce "^4.0.8" - lodash.isequal "^4.5.0" - prop-types "^15.5.4" - react-custom-scrollbars@^4.1.1: version "4.2.1" resolved "https://registry.yarnpkg.com/react-custom-scrollbars/-/react-custom-scrollbars-4.2.1.tgz#830fd9502927e97e8a78c2086813899b2a8b66db"