mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'develop' into template_var_multi_select
This commit is contained in:
commit
01148ac1b9
@ -7,6 +7,7 @@
|
||||
- [Issue #171](https://github.com/grafana/grafana/issues/171). Panel: Different time periods, panels can override dashboard relative time and/or add a time shift
|
||||
- [Issue #1488](https://github.com/grafana/grafana/issues/1488). Dashboard: Clone dashboard / Save as
|
||||
- [Issue #1458](https://github.com/grafana/grafana/issues/1458). User: persisted user option for dark or light theme (no longer an option on a dashboard)
|
||||
- [Issue #452](https://github.com/grafana/grafana/issues/452). Graph: Adds logarithmic scale option (log base 10)
|
||||
|
||||
**Enhancements**
|
||||
- [Issue #1366](https://github.com/grafana/grafana/issues/1366). Graph & Singlestat: Support for additional units, Fahrenheit (°F) and Celsius (°C), Humidity (%H), kW, watt-hour (Wh), kilowatt-hour (kWh), velocities (m/s, km/h, mpg, knot)
|
||||
|
6
Godeps/Godeps.json
generated
6
Godeps/Godeps.json
generated
@ -11,7 +11,7 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/Unknwon/macaron",
|
||||
"Rev": "da7cbddc50b9d33e076fb1eabff13b55c3b85fc5"
|
||||
"Rev": "93de4f3fad97bf246b838f828e2348f46f21f20a"
|
||||
},
|
||||
{
|
||||
"ImportPath": "github.com/codegangsta/cli",
|
||||
@ -72,8 +72,8 @@
|
||||
},
|
||||
{
|
||||
"ImportPath": "gopkg.in/ini.v1",
|
||||
"Comment": "v0-10-g28ad8c4",
|
||||
"Rev": "28ad8c408ba20e5c86b06d64cd2cc9248f640a83"
|
||||
"Comment": "v0-16-g1772191",
|
||||
"Rev": "177219109c97e7920c933e21c9b25f874357b237"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
7
Godeps/_workspace/src/github.com/Unknwon/macaron/README.md
generated
vendored
7
Godeps/_workspace/src/github.com/Unknwon/macaron/README.md
generated
vendored
@ -1,11 +1,11 @@
|
||||
Macaron [](https://drone.io/github.com/Unknwon/macaron/latest) [](http://gocover.io/github.com/Unknwon/macaron)
|
||||
=======================
|
||||
|
||||

|
||||

|
||||
|
||||
Package macaron is a high productive and modular design web framework in Go.
|
||||
|
||||
##### Current version: 0.5.0
|
||||
##### Current version: 0.5.4
|
||||
|
||||
## Getting Started
|
||||
|
||||
@ -70,15 +70,18 @@ There are already many [middlewares](https://github.com/macaron-contrib) to simp
|
||||
|
||||
- [Gogs](https://github.com/gogits/gogs): Go Git Service
|
||||
- [Gogs Web](https://github.com/gogits/gogsweb): Gogs official website
|
||||
- [Go Walker](https://gowalker.org): Go online API documentation
|
||||
- [Switch](https://github.com/gpmgo/switch): Gopm registry
|
||||
- [YouGam](http://yougam.com): Online Forum
|
||||
- [Car Girl](http://qcnl.gzsy.com/): Online campaign
|
||||
- [Critical Stack Intel](https://intel.criticalstack.com/): A 100% free intel marketplace from Critical Stack, Inc.
|
||||
|
||||
## Getting Help
|
||||
|
||||
- [API Reference](https://gowalker.org/github.com/Unknwon/macaron)
|
||||
- [Documentation](http://macaron.gogs.io)
|
||||
- [FAQs](http://macaron.gogs.io/docs/faqs)
|
||||
- [](https://gitter.im/Unknwon/macaron?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
## Credits
|
||||
|
||||
|
37
Godeps/_workspace/src/github.com/Unknwon/macaron/bpool/README.md
generated
vendored
37
Godeps/_workspace/src/github.com/Unknwon/macaron/bpool/README.md
generated
vendored
@ -1,37 +0,0 @@
|
||||
# bpool [](https://godoc.org/github.com/oxtoacart/bpool)
|
||||
|
||||
Package bpool implements leaky pools of byte arrays and Buffers as bounded channels. It is based on the leaky buffer example from the Effective Go documentation: http://golang.org/doc/effective_go.html#leaky_buffer
|
||||
|
||||
## Install
|
||||
|
||||
`go get github.com/oxtoacart/bpool`
|
||||
|
||||
## Documentation
|
||||
|
||||
See [godoc.org](http://godoc.org/github.com/oxtoacart/bpool) or use `godoc github.com/oxtoacart/bpool`
|
||||
|
||||
## Example
|
||||
|
||||
```go
|
||||
|
||||
var bufpool *bpol.BufferPool
|
||||
|
||||
func main() {
|
||||
|
||||
bufpool = bpool.NewBufferPool(48)
|
||||
|
||||
}
|
||||
|
||||
func someFunction() error {
|
||||
|
||||
// Get a buffer from the pool
|
||||
buf := bufpool.Get()
|
||||
...
|
||||
...
|
||||
...
|
||||
// Return the buffer to the pool
|
||||
bufpool.Put(buf)
|
||||
|
||||
return nil
|
||||
}
|
||||
```
|
45
Godeps/_workspace/src/github.com/Unknwon/macaron/bpool/bufferpool.go
generated
vendored
45
Godeps/_workspace/src/github.com/Unknwon/macaron/bpool/bufferpool.go
generated
vendored
@ -1,45 +0,0 @@
|
||||
package bpool
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
/*
|
||||
BufferPool implements a pool of bytes.Buffers in the form of a bounded
|
||||
channel.
|
||||
*/
|
||||
type BufferPool struct {
|
||||
c chan *bytes.Buffer
|
||||
}
|
||||
|
||||
/*
|
||||
NewBufferPool creates a new BufferPool bounded to the given size.
|
||||
*/
|
||||
func NewBufferPool(size int) (bp *BufferPool) {
|
||||
return &BufferPool{
|
||||
c: make(chan *bytes.Buffer, size),
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Get gets a Buffer from the BufferPool, or creates a new one if none are available
|
||||
in the pool.
|
||||
*/
|
||||
func (bp *BufferPool) Get() (b *bytes.Buffer) {
|
||||
select {
|
||||
case b = <-bp.c:
|
||||
// reuse existing buffer
|
||||
default:
|
||||
// create new buffer
|
||||
b = bytes.NewBuffer([]byte{})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
Put returns the given Buffer to the BufferPool.
|
||||
*/
|
||||
func (bp *BufferPool) Put(b *bytes.Buffer) {
|
||||
b.Reset()
|
||||
bp.c <- b
|
||||
}
|
81
Godeps/_workspace/src/github.com/Unknwon/macaron/context.go
generated
vendored
81
Godeps/_workspace/src/github.com/Unknwon/macaron/context.go
generated
vendored
@ -23,9 +23,11 @@ import (
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -182,6 +184,11 @@ func (ctx *Context) Query(name string) string {
|
||||
return ctx.Req.Form.Get(name)
|
||||
}
|
||||
|
||||
// QueryTrim querys and trims spaces form parameter.
|
||||
func (ctx *Context) QueryTrim(name string) string {
|
||||
return strings.TrimSpace(ctx.Query(name))
|
||||
}
|
||||
|
||||
// QueryStrings returns a list of results by given query name.
|
||||
func (ctx *Context) QueryStrings(name string) []string {
|
||||
if ctx.Req.Form == nil {
|
||||
@ -210,9 +217,21 @@ func (ctx *Context) QueryInt64(name string) int64 {
|
||||
return com.StrTo(ctx.Query(name)).MustInt64()
|
||||
}
|
||||
|
||||
// QueryFloat64 returns query result in float64 type.
|
||||
func (ctx *Context) QueryFloat64(name string) float64 {
|
||||
v, _ := strconv.ParseFloat(ctx.Query(name), 64)
|
||||
return v
|
||||
}
|
||||
|
||||
// Params returns value of given param name.
|
||||
// e.g. ctx.Params(":uid")
|
||||
// e.g. ctx.Params(":uid") or ctx.Params("uid")
|
||||
func (ctx *Context) Params(name string) string {
|
||||
if len(name) == 0 {
|
||||
return ""
|
||||
}
|
||||
if name[0] != '*' && name[0] != ':' {
|
||||
name = ":" + name
|
||||
}
|
||||
return ctx.params[name]
|
||||
}
|
||||
|
||||
@ -242,12 +261,20 @@ func (ctx *Context) ParamsInt64(name string) int64 {
|
||||
return com.StrTo(ctx.Params(name)).MustInt64()
|
||||
}
|
||||
|
||||
// ParamsFloat64 returns params result in int64 type.
|
||||
// e.g. ctx.ParamsFloat64(":uid")
|
||||
func (ctx *Context) ParamsFloat64(name string) float64 {
|
||||
v, _ := strconv.ParseFloat(ctx.Params(name), 64)
|
||||
return v
|
||||
}
|
||||
|
||||
// GetFile returns information about user upload file by given form field name.
|
||||
func (ctx *Context) GetFile(name string) (multipart.File, *multipart.FileHeader, error) {
|
||||
return ctx.Req.FormFile(name)
|
||||
}
|
||||
|
||||
// SetCookie sets given cookie value to response header.
|
||||
// FIXME: IE support? http://golanghome.com/post/620#reply2
|
||||
func (ctx *Context) SetCookie(name string, value string, others ...interface{}) {
|
||||
cookie := http.Cookie{}
|
||||
cookie.Name = name
|
||||
@ -264,23 +291,19 @@ func (ctx *Context) SetCookie(name string, value string, others ...interface{})
|
||||
}
|
||||
}
|
||||
|
||||
// default "/"
|
||||
cookie.Path = "/"
|
||||
if len(others) > 1 {
|
||||
if v, ok := others[1].(string); ok && len(v) > 0 {
|
||||
cookie.Path = v
|
||||
}
|
||||
} else {
|
||||
cookie.Path = "/"
|
||||
}
|
||||
|
||||
// default empty
|
||||
if len(others) > 2 {
|
||||
if v, ok := others[2].(string); ok && len(v) > 0 {
|
||||
cookie.Domain = v
|
||||
}
|
||||
}
|
||||
|
||||
// default empty
|
||||
if len(others) > 3 {
|
||||
switch v := others[3].(type) {
|
||||
case bool:
|
||||
@ -292,7 +315,6 @@ func (ctx *Context) SetCookie(name string, value string, others ...interface{})
|
||||
}
|
||||
}
|
||||
|
||||
// default false. for session cookie default true
|
||||
if len(others) > 4 {
|
||||
if v, ok := others[4].(bool); ok && v {
|
||||
cookie.HttpOnly = true
|
||||
@ -322,6 +344,12 @@ func (ctx *Context) GetCookieInt64(name string) int64 {
|
||||
return com.StrTo(ctx.GetCookie(name)).MustInt64()
|
||||
}
|
||||
|
||||
// GetCookieFloat64 returns cookie result in float64 type.
|
||||
func (ctx *Context) GetCookieFloat64(name string) float64 {
|
||||
v, _ := strconv.ParseFloat(ctx.GetCookie(name), 64)
|
||||
return v
|
||||
}
|
||||
|
||||
var defaultCookieSecret string
|
||||
|
||||
// SetDefaultCookieSecret sets global default secure cookie secret.
|
||||
@ -368,6 +396,14 @@ func (ctx *Context) GetSuperSecureCookie(secret, key string) (string, bool) {
|
||||
return string(text), err == nil
|
||||
}
|
||||
|
||||
func (ctx *Context) setRawContentHeader() {
|
||||
ctx.Resp.Header().Set("Content-Description", "Raw content")
|
||||
ctx.Resp.Header().Set("Content-Type", "text/plain")
|
||||
ctx.Resp.Header().Set("Expires", "0")
|
||||
ctx.Resp.Header().Set("Cache-Control", "must-revalidate")
|
||||
ctx.Resp.Header().Set("Pragma", "public")
|
||||
}
|
||||
|
||||
// ServeContent serves given content to response.
|
||||
func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interface{}) {
|
||||
modtime := time.Now()
|
||||
@ -377,14 +413,35 @@ func (ctx *Context) ServeContent(name string, r io.ReadSeeker, params ...interfa
|
||||
modtime = v
|
||||
}
|
||||
}
|
||||
ctx.Resp.Header().Set("Content-Description", "Raw content")
|
||||
ctx.Resp.Header().Set("Content-Type", "text/plain")
|
||||
ctx.Resp.Header().Set("Expires", "0")
|
||||
ctx.Resp.Header().Set("Cache-Control", "must-revalidate")
|
||||
ctx.Resp.Header().Set("Pragma", "public")
|
||||
|
||||
ctx.setRawContentHeader()
|
||||
http.ServeContent(ctx.Resp, ctx.Req.Request, name, modtime, r)
|
||||
}
|
||||
|
||||
// ServeFileContent serves given file as content to response.
|
||||
func (ctx *Context) ServeFileContent(file string, names ...string) {
|
||||
var name string
|
||||
if len(names) > 0 {
|
||||
name = names[0]
|
||||
} else {
|
||||
name = path.Base(file)
|
||||
}
|
||||
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
if Env == PROD {
|
||||
http.Error(ctx.Resp, "Internal Server Error", 500)
|
||||
} else {
|
||||
http.Error(ctx.Resp, err.Error(), 500)
|
||||
}
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
ctx.setRawContentHeader()
|
||||
http.ServeContent(ctx.Resp, ctx.Req.Request, name, time.Now(), f)
|
||||
}
|
||||
|
||||
// ServeFile serves given file to response.
|
||||
func (ctx *Context) ServeFile(file string, names ...string) {
|
||||
var name string
|
||||
|
106
Godeps/_workspace/src/github.com/Unknwon/macaron/context_test.go
generated
vendored
106
Godeps/_workspace/src/github.com/Unknwon/macaron/context_test.go
generated
vendored
@ -76,35 +76,53 @@ func Test_Context(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Render HTML", func() {
|
||||
m.Get("/html", func(ctx *Context) {
|
||||
ctx.HTML(304, "hello", "Unknwon") // 304 for logger test.
|
||||
|
||||
Convey("Normal HTML", func() {
|
||||
m.Get("/html", func(ctx *Context) {
|
||||
ctx.HTML(304, "hello", "Unknwon") // 304 for logger test.
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/html", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "<h1>Hello Unknwon</h1>")
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/html", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "<h1>Hello Unknwon</h1>")
|
||||
Convey("HTML template set", func() {
|
||||
m.Get("/html2", func(ctx *Context) {
|
||||
ctx.Data["Name"] = "Unknwon"
|
||||
ctx.HTMLSet(200, "basic2", "hello2")
|
||||
})
|
||||
|
||||
m.Get("/html2", func(ctx *Context) {
|
||||
ctx.Data["Name"] = "Unknwon"
|
||||
ctx.HTMLSet(200, "basic2", "hello2")
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/html2", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "<h1>Hello Unknwon</h1>")
|
||||
})
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/html2", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "<h1>Hello Unknwon</h1>")
|
||||
Convey("With layout", func() {
|
||||
m.Get("/layout", func(ctx *Context) {
|
||||
ctx.HTML(200, "hello", "Unknwon", HTMLOptions{"layout"})
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/layout", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "head<h1>Hello Unknwon</h1>foot")
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Parse from and query", func() {
|
||||
m.Get("/query", func(ctx *Context) string {
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString(ctx.Query("name") + " ")
|
||||
buf.WriteString(ctx.QueryTrim("name") + " ")
|
||||
buf.WriteString(ctx.QueryEscape("name") + " ")
|
||||
buf.WriteString(com.ToStr(ctx.QueryInt("int")) + " ")
|
||||
buf.WriteString(com.ToStr(ctx.QueryInt64("int64")) + " ")
|
||||
buf.WriteString(com.ToStr(ctx.QueryFloat64("float64")) + " ")
|
||||
return buf.String()
|
||||
})
|
||||
m.Get("/query2", func(ctx *Context) string {
|
||||
@ -115,10 +133,10 @@ func Test_Context(t *testing.T) {
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/query?name=Unknwon&int=12&int64=123", nil)
|
||||
req, err := http.NewRequest("GET", "/query?name=Unknwon&int=12&int64=123&float64=1.25", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "Unknwon Unknwon 12 123 ")
|
||||
So(resp.Body.String(), ShouldEqual, "Unknwon Unknwon 12 123 1.25 ")
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/query2?list=item1&list=item2", nil)
|
||||
@ -128,21 +146,23 @@ func Test_Context(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("URL parameter", func() {
|
||||
m.Get("/:name/:int/:int64", func(ctx *Context) string {
|
||||
m.Get("/:name/:int/:int64/:float64", func(ctx *Context) string {
|
||||
var buf bytes.Buffer
|
||||
ctx.SetParams(":name", ctx.Params(":name"))
|
||||
ctx.SetParams("name", ctx.Params("name"))
|
||||
buf.WriteString(ctx.Params(""))
|
||||
buf.WriteString(ctx.Params(":name") + " ")
|
||||
buf.WriteString(ctx.ParamsEscape(":name") + " ")
|
||||
buf.WriteString(com.ToStr(ctx.ParamsInt(":int")) + " ")
|
||||
buf.WriteString(com.ToStr(ctx.ParamsInt64(":int64")) + " ")
|
||||
buf.WriteString(com.ToStr(ctx.ParamsFloat64(":float64")) + " ")
|
||||
return buf.String()
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/user/1/13", nil)
|
||||
req, err := http.NewRequest("GET", "/user/1/13/1.24", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "user user 1 13 ")
|
||||
So(resp.Body.String(), ShouldEqual, "user user 1 13 1.24 ")
|
||||
})
|
||||
|
||||
Convey("Get file", func() {
|
||||
@ -158,26 +178,29 @@ func Test_Context(t *testing.T) {
|
||||
|
||||
Convey("Set and get cookie", func() {
|
||||
m.Get("/set", func(ctx *Context) {
|
||||
ctx.SetCookie("user", "Unknwon", 1)
|
||||
ctx.SetCookie("user", "Unknwon", 1, "/", "localhost", true, true)
|
||||
ctx.SetCookie("user", "Unknwon", int32(1), "/", "localhost", 1)
|
||||
ctx.SetCookie("user", "Unknwon", int64(1))
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/set", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Header().Get("Set-Cookie"), ShouldEqual, "user=Unknwon; Path=/; Max-Age=1")
|
||||
So(resp.Header().Get("Set-Cookie"), ShouldEqual, "user=Unknwon; Path=/; Domain=localhost; Max-Age=1; HttpOnly; Secure")
|
||||
|
||||
m.Get("/get", func(ctx *Context) string {
|
||||
ctx.GetCookie("404")
|
||||
So(ctx.GetCookieInt("uid"), ShouldEqual, 1)
|
||||
So(ctx.GetCookieInt64("uid"), ShouldEqual, 1)
|
||||
So(ctx.GetCookieFloat64("balance"), ShouldEqual, 1.25)
|
||||
return ctx.GetCookie("user")
|
||||
})
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/get", nil)
|
||||
So(err, ShouldBeNil)
|
||||
req.Header.Set("Cookie", "user=Unknwon; uid=1")
|
||||
req.Header.Set("Cookie", "user=Unknwon; uid=1; balance=1.25")
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "Unknwon")
|
||||
})
|
||||
@ -231,6 +254,39 @@ func Test_Context(t *testing.T) {
|
||||
So(resp.Body.String(), ShouldEqual, "{{ myCustomFunc }}")
|
||||
})
|
||||
|
||||
Convey("Serve file content", func() {
|
||||
m.Get("/file", func(ctx *Context) {
|
||||
ctx.ServeFileContent("fixtures/custom_funcs/index.tmpl")
|
||||
})
|
||||
|
||||
resp := httptest.NewRecorder()
|
||||
req, err := http.NewRequest("GET", "/file", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "{{ myCustomFunc }}")
|
||||
|
||||
m.Get("/file2", func(ctx *Context) {
|
||||
ctx.ServeFileContent("fixtures/custom_funcs/index.tmpl", "ok.tmpl")
|
||||
})
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/file2", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "{{ myCustomFunc }}")
|
||||
|
||||
m.Get("/file3", func(ctx *Context) {
|
||||
ctx.ServeFileContent("404.tmpl")
|
||||
})
|
||||
|
||||
resp = httptest.NewRecorder()
|
||||
req, err = http.NewRequest("GET", "/file3", nil)
|
||||
So(err, ShouldBeNil)
|
||||
m.ServeHTTP(resp, req)
|
||||
So(resp.Body.String(), ShouldEqual, "open 404.tmpl: no such file or directory\n")
|
||||
So(resp.Code, ShouldEqual, 500)
|
||||
})
|
||||
|
||||
Convey("Serve content", func() {
|
||||
m.Get("/content", func(ctx *Context) {
|
||||
ctx.ServeContent("content1", bytes.NewReader([]byte("Hello world!")))
|
||||
|
2
Godeps/_workspace/src/github.com/Unknwon/macaron/inject/inject_test.go
generated
vendored
2
Godeps/_workspace/src/github.com/Unknwon/macaron/inject/inject_test.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
// Copyright 2013 Martini Authors
|
||||
// Copyright 2014 Unknown
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
|
2
Godeps/_workspace/src/github.com/Unknwon/macaron/logger_test.go
generated
vendored
2
Godeps/_workspace/src/github.com/Unknwon/macaron/logger_test.go
generated
vendored
@ -46,7 +46,7 @@ func Test_Logger(t *testing.T) {
|
||||
So(len(buf.String()), ShouldBeGreaterThan, 0)
|
||||
})
|
||||
|
||||
if !isWindows {
|
||||
if ColorLog {
|
||||
Convey("Color console output", t, func() {
|
||||
m := Classic()
|
||||
m.Get("/:code:int", func(ctx *Context) (int, string) {
|
||||
|
4
Godeps/_workspace/src/github.com/Unknwon/macaron/macaron.go
generated
vendored
4
Godeps/_workspace/src/github.com/Unknwon/macaron/macaron.go
generated
vendored
@ -29,7 +29,7 @@ import (
|
||||
"github.com/Unknwon/macaron/inject"
|
||||
)
|
||||
|
||||
const _VERSION = "0.5.0.0116"
|
||||
const _VERSION = "0.5.4.0318"
|
||||
|
||||
func Version() string {
|
||||
return _VERSION
|
||||
@ -267,7 +267,7 @@ func SetConfig(source interface{}, others ...interface{}) (_ *ini.File, err erro
|
||||
// It returns an empty object if there is no one available.
|
||||
func Config() *ini.File {
|
||||
if cfg == nil {
|
||||
return &ini.File{}
|
||||
return ini.Empty()
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
42
Godeps/_workspace/src/github.com/Unknwon/macaron/render.go
generated
vendored
42
Godeps/_workspace/src/github.com/Unknwon/macaron/render.go
generated
vendored
@ -1,4 +1,5 @@
|
||||
// Copyright 2013 Martini Authors
|
||||
// Copyright 2013 oxtoacart
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
@ -32,10 +33,39 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/com"
|
||||
|
||||
"github.com/Unknwon/macaron/bpool"
|
||||
)
|
||||
|
||||
// BufferPool implements a pool of bytes.Buffers in the form of a bounded channel.
|
||||
type BufferPool struct {
|
||||
c chan *bytes.Buffer
|
||||
}
|
||||
|
||||
// NewBufferPool creates a new BufferPool bounded to the given size.
|
||||
func NewBufferPool(size int) (bp *BufferPool) {
|
||||
return &BufferPool{
|
||||
c: make(chan *bytes.Buffer, size),
|
||||
}
|
||||
}
|
||||
|
||||
// Get gets a Buffer from the BufferPool, or creates a new one if none are available
|
||||
// in the pool.
|
||||
func (bp *BufferPool) Get() (b *bytes.Buffer) {
|
||||
select {
|
||||
case b = <-bp.c:
|
||||
// reuse existing buffer
|
||||
default:
|
||||
// create new buffer
|
||||
b = bytes.NewBuffer([]byte{})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Put returns the given Buffer to the BufferPool.
|
||||
func (bp *BufferPool) Put(b *bytes.Buffer) {
|
||||
b.Reset()
|
||||
bp.c <- b
|
||||
}
|
||||
|
||||
const (
|
||||
ContentType = "Content-Type"
|
||||
ContentLength = "Content-Length"
|
||||
@ -50,7 +80,7 @@ const (
|
||||
|
||||
var (
|
||||
// Provides a temporary buffer to execute templates into and catch errors.
|
||||
bufpool = bpool.NewBufferPool(64)
|
||||
bufpool = NewBufferPool(64)
|
||||
|
||||
// Included helper functions for use when rendering html
|
||||
helperFuncs = template.FuncMap{
|
||||
@ -392,8 +422,10 @@ func (r *TplRender) RW() http.ResponseWriter {
|
||||
}
|
||||
|
||||
func (r *TplRender) JSON(status int, v interface{}) {
|
||||
var result []byte
|
||||
var err error
|
||||
var (
|
||||
result []byte
|
||||
err error
|
||||
)
|
||||
if r.Opt.IndentJSON {
|
||||
result, err = json.MarshalIndent(v, "", " ")
|
||||
} else {
|
||||
|
46
Godeps/_workspace/src/github.com/Unknwon/macaron/return_handler.go
generated
vendored
46
Godeps/_workspace/src/github.com/Unknwon/macaron/return_handler.go
generated
vendored
@ -1,5 +1,5 @@
|
||||
// Copyright 2013 Martini Authors
|
||||
// Copyright 2014 Unknown
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
@ -28,32 +28,32 @@ import (
|
||||
// that are passed into this function.
|
||||
type ReturnHandler func(*Context, []reflect.Value)
|
||||
|
||||
func defaultReturnHandler() ReturnHandler {
|
||||
return func(ctx *Context, vals []reflect.Value) {
|
||||
rv := ctx.GetVal(inject.InterfaceOf((*http.ResponseWriter)(nil)))
|
||||
res := rv.Interface().(http.ResponseWriter)
|
||||
var responseVal reflect.Value
|
||||
if len(vals) > 1 && vals[0].Kind() == reflect.Int {
|
||||
res.WriteHeader(int(vals[0].Int()))
|
||||
responseVal = vals[1]
|
||||
} else if len(vals) > 0 {
|
||||
responseVal = vals[0]
|
||||
}
|
||||
if canDeref(responseVal) {
|
||||
responseVal = responseVal.Elem()
|
||||
}
|
||||
if isByteSlice(responseVal) {
|
||||
res.Write(responseVal.Bytes())
|
||||
} else {
|
||||
res.Write([]byte(responseVal.String()))
|
||||
}
|
||||
}
|
||||
func canDeref(val reflect.Value) bool {
|
||||
return val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr
|
||||
}
|
||||
|
||||
func isByteSlice(val reflect.Value) bool {
|
||||
return val.Kind() == reflect.Slice && val.Type().Elem().Kind() == reflect.Uint8
|
||||
}
|
||||
|
||||
func canDeref(val reflect.Value) bool {
|
||||
return val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr
|
||||
func defaultReturnHandler() ReturnHandler {
|
||||
return func(ctx *Context, vals []reflect.Value) {
|
||||
rv := ctx.GetVal(inject.InterfaceOf((*http.ResponseWriter)(nil)))
|
||||
res := rv.Interface().(http.ResponseWriter)
|
||||
var respVal reflect.Value
|
||||
if len(vals) > 1 && vals[0].Kind() == reflect.Int {
|
||||
res.WriteHeader(int(vals[0].Int()))
|
||||
respVal = vals[1]
|
||||
} else if len(vals) > 0 {
|
||||
respVal = vals[0]
|
||||
}
|
||||
if canDeref(respVal) {
|
||||
respVal = respVal.Elem()
|
||||
}
|
||||
if isByteSlice(respVal) {
|
||||
res.Write(respVal.Bytes())
|
||||
} else {
|
||||
res.Write([]byte(respVal.String()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
2
Godeps/_workspace/src/github.com/Unknwon/macaron/return_handler_test.go
generated
vendored
2
Godeps/_workspace/src/github.com/Unknwon/macaron/return_handler_test.go
generated
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright 2014 Unknown
|
||||
// Copyright 2014 Unknwon
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
|
2
Godeps/_workspace/src/gopkg.in/ini.v1/.gitignore
generated
vendored
2
Godeps/_workspace/src/gopkg.in/ini.v1/.gitignore
generated
vendored
@ -1 +1,3 @@
|
||||
testdata/conf_out.ini
|
||||
ini.sublime-project
|
||||
ini.sublime-workspace
|
||||
|
36
Godeps/_workspace/src/gopkg.in/ini.v1/README.md
generated
vendored
36
Godeps/_workspace/src/gopkg.in/ini.v1/README.md
generated
vendored
@ -32,6 +32,12 @@ A **Data Source** is either raw data in type `[]byte` or a file name with type `
|
||||
cfg, err := ini.Load([]byte("raw data"), "filename")
|
||||
```
|
||||
|
||||
Or start with an empty object:
|
||||
|
||||
```go
|
||||
cfg := ini.Empty()
|
||||
```
|
||||
|
||||
When you cannot decide how many data sources to load at the beginning, you still able to **Append()** them later.
|
||||
|
||||
```go
|
||||
@ -58,7 +64,7 @@ When you're pretty sure the section exists, following code could make your life
|
||||
section := cfg.Section("")
|
||||
```
|
||||
|
||||
What happens when the section somehow does not exists? Won't panic, it returns an empty section object.
|
||||
What happens when the section somehow does not exist? Don't panic, it automatically creates and returns a new section to you.
|
||||
|
||||
To create a new section:
|
||||
|
||||
@ -117,6 +123,9 @@ val := cfg.Section("").Key("key name").String()
|
||||
To get value with types:
|
||||
|
||||
```go
|
||||
// For boolean values:
|
||||
// true when value is: 1, t, T, TRUE, true, True, YES, yes, Yes, ON, on, On
|
||||
// false when value is: 0, f, F, FALSE, false, False, NO, no, No, OFF, off, Off
|
||||
v, err = cfg.Section("").Key("BOOL").Bool()
|
||||
v, err = cfg.Section("").Key("FLOAT64").Float64()
|
||||
v, err = cfg.Section("").Key("INT").Int()
|
||||
@ -176,11 +185,22 @@ v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"})
|
||||
v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75})
|
||||
v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30})
|
||||
v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30})
|
||||
v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3})
|
||||
v = cfg.Section("").Key("TIME").InTimeFormat(time.RFC3339, time.Now(), []time.Time{time1, time2, time3})
|
||||
v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3}) // RFC3339
|
||||
```
|
||||
|
||||
Default value will be presented if value of key is not in candidates you given, and default value does not need be one of candidates.
|
||||
|
||||
To validate value in a given range:
|
||||
|
||||
```go
|
||||
vals = cfg.Section("").Key("FLOAT64").RangeFloat64(0.0, 1.1, 2.2)
|
||||
vals = cfg.Section("").Key("INT").RangeInt(0, 10, 20)
|
||||
vals = cfg.Section("").Key("INT64").RangeInt64(0, 10, 20)
|
||||
vals = cfg.Section("").Key("TIME").RangeTimeFormat(time.RFC3339, time.Now(), minTime, maxTime)
|
||||
vals = cfg.Section("").Key("TIME").RangeTime(time.Now(), minTime, maxTime) // RFC3339
|
||||
```
|
||||
|
||||
To auto-split value into slice:
|
||||
|
||||
```go
|
||||
@ -295,6 +315,18 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
Can I have default value for field? Absolutely.
|
||||
|
||||
Assign it before you map to struct. It will keep the value as it is if the key is not presented or got wrong type.
|
||||
|
||||
```go
|
||||
// ...
|
||||
p := &Person{
|
||||
Name: "Joe",
|
||||
}
|
||||
// ...
|
||||
```
|
||||
|
||||
#### Name Mapper
|
||||
|
||||
To save your time and make your code cleaner, this library supports [`NameMapper`](https://gowalker.org/gopkg.in/ini.v1#NameMapper) between struct field and actual secion and key name.
|
||||
|
34
Godeps/_workspace/src/gopkg.in/ini.v1/README_ZH.md
generated
vendored
34
Godeps/_workspace/src/gopkg.in/ini.v1/README_ZH.md
generated
vendored
@ -27,6 +27,12 @@
|
||||
cfg, err := ini.Load([]byte("raw data"), "filename")
|
||||
```
|
||||
|
||||
或者从一个空白的文件开始:
|
||||
|
||||
```go
|
||||
cfg := ini.Empty()
|
||||
```
|
||||
|
||||
当您在一开始无法决定需要加载哪些数据源时,仍可以使用 **Append()** 在需要的时候加载它们。
|
||||
|
||||
```go
|
||||
@ -53,7 +59,7 @@ section, err := cfg.GetSection("")
|
||||
section := cfg.Section("")
|
||||
```
|
||||
|
||||
如果不小心判断错了,要获取的分区其实是不存在的,那会发生什么呢?没事的,它会返回一个空的分区对象。
|
||||
如果不小心判断错了,要获取的分区其实是不存在的,那会发生什么呢?没事的,它会自动创建并返回一个对应的分区对象给您。
|
||||
|
||||
创建一个分区:
|
||||
|
||||
@ -112,6 +118,9 @@ val := cfg.Section("").Key("key name").String()
|
||||
获取其它类型的值:
|
||||
|
||||
```go
|
||||
// 布尔值的规则:
|
||||
// true 当值为:1, t, T, TRUE, true, True, YES, yes, Yes, ON, on, On
|
||||
// false 当值为:0, f, F, FALSE, false, False, NO, no, No, OFF, off, Off
|
||||
v, err = cfg.Section("").Key("BOOL").Bool()
|
||||
v, err = cfg.Section("").Key("FLOAT64").Float64()
|
||||
v, err = cfg.Section("").Key("INT").Int()
|
||||
@ -171,11 +180,22 @@ v = cfg.Section("").Key("STRING").In("default", []string{"str", "arr", "types"})
|
||||
v = cfg.Section("").Key("FLOAT64").InFloat64(1.1, []float64{1.25, 2.5, 3.75})
|
||||
v = cfg.Section("").Key("INT").InInt(5, []int{10, 20, 30})
|
||||
v = cfg.Section("").Key("INT64").InInt64(10, []int64{10, 20, 30})
|
||||
v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3})
|
||||
v = cfg.Section("").Key("TIME").InTimeFormat(time.RFC3339, time.Now(), []time.Time{time1, time2, time3})
|
||||
v = cfg.Section("").Key("TIME").InTime(time.Now(), []time.Time{time1, time2, time3}) // RFC3339
|
||||
```
|
||||
|
||||
如果获取到的值不是候选值的任意一个,则会返回默认值,而默认值不需要是候选值中的一员。
|
||||
|
||||
验证获取的值是否在指定范围内:
|
||||
|
||||
```go
|
||||
vals = cfg.Section("").Key("FLOAT64").RangeFloat64(0.0, 1.1, 2.2)
|
||||
vals = cfg.Section("").Key("INT").RangeInt(0, 10, 20)
|
||||
vals = cfg.Section("").Key("INT64").RangeInt64(0, 10, 20)
|
||||
vals = cfg.Section("").Key("TIME").RangeTimeFormat(time.RFC3339, time.Now(), minTime, maxTime)
|
||||
vals = cfg.Section("").Key("TIME").RangeTime(time.Now(), minTime, maxTime) // RFC3339
|
||||
```
|
||||
|
||||
自动分割键值为切片(slice):
|
||||
|
||||
```go
|
||||
@ -290,6 +310,16 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
结构的字段怎么设置默认值呢?很简单,只要在映射之前对指定字段进行赋值就可以了。如果键未找到或者类型错误,该值不会发生改变。
|
||||
|
||||
```go
|
||||
// ...
|
||||
p := &Person{
|
||||
Name: "Joe",
|
||||
}
|
||||
// ...
|
||||
```
|
||||
|
||||
#### 名称映射器(Name Mapper)
|
||||
|
||||
为了节省您的时间并简化代码,本库支持类型为 [`NameMapper`](https://gowalker.org/gopkg.in/ini.v1#NameMapper) 的名称映射器,该映射器负责结构字段名与分区名和键名之间的映射。
|
||||
|
106
Godeps/_workspace/src/gopkg.in/ini.v1/ini.go
generated
vendored
106
Godeps/_workspace/src/gopkg.in/ini.v1/ini.go
generated
vendored
@ -35,7 +35,7 @@ const (
|
||||
// Maximum allowed depth when recursively substituing variable names.
|
||||
_DEPTH_VALUES = 99
|
||||
|
||||
_VERSION = "1.0.1"
|
||||
_VERSION = "1.2.6"
|
||||
)
|
||||
|
||||
func Version() string {
|
||||
@ -144,9 +144,24 @@ func (k *Key) String() string {
|
||||
return val
|
||||
}
|
||||
|
||||
// parseBool returns the boolean value represented by the string.
|
||||
//
|
||||
// It accepts 1, t, T, TRUE, true, True, YES, yes, Yes, ON, on, On,
|
||||
// 0, f, F, FALSE, false, False, NO, no, No, OFF, off, Off.
|
||||
// Any other value returns an error.
|
||||
func parseBool(str string) (value bool, err error) {
|
||||
switch str {
|
||||
case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "ON", "on", "On":
|
||||
return true, nil
|
||||
case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "OFF", "off", "Off":
|
||||
return false, nil
|
||||
}
|
||||
return false, fmt.Errorf("parsing \"%s\": invalid syntax", str)
|
||||
}
|
||||
|
||||
// Bool returns bool type value.
|
||||
func (k *Key) Bool() (bool, error) {
|
||||
return strconv.ParseBool(k.String())
|
||||
return parseBool(k.String())
|
||||
}
|
||||
|
||||
// Float64 returns float64 type value.
|
||||
@ -305,6 +320,52 @@ func (k *Key) InTime(defaultVal time.Time, candidates []time.Time) time.Time {
|
||||
return k.InTimeFormat(time.RFC3339, defaultVal, candidates)
|
||||
}
|
||||
|
||||
// RangeFloat64 checks if value is in given range inclusively,
|
||||
// and returns default value if it's not.
|
||||
func (k *Key) RangeFloat64(defaultVal, min, max float64) float64 {
|
||||
val := k.MustFloat64()
|
||||
if val < min || val > max {
|
||||
return defaultVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// RangeInt checks if value is in given range inclusively,
|
||||
// and returns default value if it's not.
|
||||
func (k *Key) RangeInt(defaultVal, min, max int) int {
|
||||
val := k.MustInt()
|
||||
if val < min || val > max {
|
||||
return defaultVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// RangeInt64 checks if value is in given range inclusively,
|
||||
// and returns default value if it's not.
|
||||
func (k *Key) RangeInt64(defaultVal, min, max int64) int64 {
|
||||
val := k.MustInt64()
|
||||
if val < min || val > max {
|
||||
return defaultVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// RangeTimeFormat checks if value with given format is in given range inclusively,
|
||||
// and returns default value if it's not.
|
||||
func (k *Key) RangeTimeFormat(format string, defaultVal, min, max time.Time) time.Time {
|
||||
val := k.MustTimeFormat(format)
|
||||
if val.Unix() < min.Unix() || val.Unix() > max.Unix() {
|
||||
return defaultVal
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// RangeTime checks if value with RFC3339 format is in given range inclusively,
|
||||
// and returns default value if it's not.
|
||||
func (k *Key) RangeTime(defaultVal, min, max time.Time) time.Time {
|
||||
return k.RangeTimeFormat(time.RFC3339, defaultVal, min, max)
|
||||
}
|
||||
|
||||
// Strings returns list of string devide by given delimiter.
|
||||
func (k *Key) Strings(delim string) []string {
|
||||
str := k.String()
|
||||
@ -440,7 +501,10 @@ func (s *Section) GetKey(name string) (*Key, error) {
|
||||
func (s *Section) Key(name string) *Key {
|
||||
key, err := s.GetKey(name)
|
||||
if err != nil {
|
||||
return &Key{}
|
||||
// It's OK here because the only possible error is empty key name,
|
||||
// but if it's empty, this piece of code won't be executed.
|
||||
key, _ = s.NewKey(name, "")
|
||||
return key
|
||||
}
|
||||
return key
|
||||
}
|
||||
@ -555,6 +619,13 @@ func Load(source interface{}, others ...interface{}) (_ *File, err error) {
|
||||
return f, f.Reload()
|
||||
}
|
||||
|
||||
// Empty returns an empty file object.
|
||||
func Empty() *File {
|
||||
// Ignore error here, we sure our data is good.
|
||||
f, _ := Load([]byte(""))
|
||||
return f
|
||||
}
|
||||
|
||||
// NewSection creates a new section.
|
||||
func (f *File) NewSection(name string) (*Section, error) {
|
||||
if len(name) == 0 {
|
||||
@ -575,6 +646,16 @@ func (f *File) NewSection(name string) (*Section, error) {
|
||||
return f.sections[name], nil
|
||||
}
|
||||
|
||||
// NewSections creates a list of sections.
|
||||
func (f *File) NewSections(names ...string) (err error) {
|
||||
for _, name := range names {
|
||||
if _, err = f.NewSection(name); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetSection returns section by given name.
|
||||
func (f *File) GetSection(name string) (*Section, error) {
|
||||
if len(name) == 0 {
|
||||
@ -597,7 +678,10 @@ func (f *File) GetSection(name string) (*Section, error) {
|
||||
func (f *File) Section(name string) *Section {
|
||||
sec, err := f.GetSection(name)
|
||||
if err != nil {
|
||||
return newSection(f, name)
|
||||
// It's OK here because the only possible error is empty section name,
|
||||
// but if it's empty, this piece of code won't be executed.
|
||||
sec, _ = f.NewSection(name)
|
||||
return sec
|
||||
}
|
||||
return sec
|
||||
}
|
||||
@ -638,6 +722,14 @@ func (f *File) DeleteSection(name string) {
|
||||
}
|
||||
}
|
||||
|
||||
func cutComment(str string) string {
|
||||
i := strings.Index(str, "#")
|
||||
if i == -1 {
|
||||
return str
|
||||
}
|
||||
return str[:i]
|
||||
}
|
||||
|
||||
// parse parses data through an io.Reader.
|
||||
func (f *File) parse(reader io.Reader) error {
|
||||
buf := bufio.NewReader(reader)
|
||||
@ -776,7 +868,6 @@ func (f *File) parse(reader io.Reader) error {
|
||||
val = lineRight[qLen:] + "\n"
|
||||
for {
|
||||
next, err := buf.ReadString('\n')
|
||||
val += next
|
||||
if err != nil {
|
||||
if err != io.EOF {
|
||||
return err
|
||||
@ -785,9 +876,10 @@ func (f *File) parse(reader io.Reader) error {
|
||||
}
|
||||
pos = strings.LastIndex(next, valQuote)
|
||||
if pos > -1 {
|
||||
val = val[:len(val)-len(valQuote)-1]
|
||||
val += next[:pos]
|
||||
break
|
||||
}
|
||||
val += next
|
||||
if isEnd {
|
||||
return fmt.Errorf("error parsing line: missing closing key quote from '%s' to '%s'", line, next)
|
||||
}
|
||||
@ -796,7 +888,7 @@ func (f *File) parse(reader io.Reader) error {
|
||||
val = lineRight[qLen : pos+qLen]
|
||||
}
|
||||
} else {
|
||||
val = strings.TrimSpace(lineRight[0:])
|
||||
val = strings.TrimSpace(cutComment(lineRight[0:]))
|
||||
}
|
||||
|
||||
k, err := section.NewKey(kname, val)
|
||||
|
51
Godeps/_workspace/src/gopkg.in/ini.v1/ini_test.go
generated
vendored
51
Godeps/_workspace/src/gopkg.in/ini.v1/ini_test.go
generated
vendored
@ -40,13 +40,13 @@ IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
|
||||
# Information about package author
|
||||
# Bio can be written in multiple lines.
|
||||
[author]
|
||||
NAME = Unknwon
|
||||
NAME = Unknwon # Succeeding comment
|
||||
E-MAIL = fake@localhost
|
||||
GITHUB = https://github.com/%(NAME)s
|
||||
BIO = """Gopher.
|
||||
Coding addict.
|
||||
Good man.
|
||||
"""
|
||||
""" # Succeeding comment
|
||||
|
||||
[package]
|
||||
CLONE_URL = https://%(IMPORT_PATH)s
|
||||
@ -62,6 +62,7 @@ UNUSED_KEY = should be deleted
|
||||
[types]
|
||||
STRING = str
|
||||
BOOL = true
|
||||
BOOL_FALSE = false
|
||||
FLOAT64 = 1.25
|
||||
INT = 10
|
||||
TIME = 2015-01-01T20:17:05Z
|
||||
@ -88,9 +89,7 @@ func Test_Load(t *testing.T) {
|
||||
Convey("Load from data sources", t, func() {
|
||||
|
||||
Convey("Load with empty data", func() {
|
||||
cfg, err := Load([]byte(""))
|
||||
So(err, ShouldBeNil)
|
||||
So(cfg, ShouldNotBeNil)
|
||||
So(Empty(), ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Load with multiple data sources", func() {
|
||||
@ -203,6 +202,10 @@ func Test_Values(t *testing.T) {
|
||||
So(err, ShouldBeNil)
|
||||
So(v1, ShouldBeTrue)
|
||||
|
||||
v1, err = sec.Key("BOOL_FALSE").Bool()
|
||||
So(err, ShouldBeNil)
|
||||
So(v1, ShouldBeFalse)
|
||||
|
||||
v2, err := sec.Key("FLOAT64").Float64()
|
||||
So(err, ShouldBeNil)
|
||||
So(v2, ShouldEqual, 1.25)
|
||||
@ -265,6 +268,30 @@ func Test_Values(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Get values in range", func() {
|
||||
sec := cfg.Section("types")
|
||||
So(sec.Key("FLOAT64").RangeFloat64(0, 1, 2), ShouldEqual, 1.25)
|
||||
So(sec.Key("INT").RangeInt(0, 10, 20), ShouldEqual, 10)
|
||||
So(sec.Key("INT").RangeInt64(0, 10, 20), ShouldEqual, 10)
|
||||
|
||||
minT, err := time.Parse(time.RFC3339, "0001-01-01T01:00:00Z")
|
||||
So(err, ShouldBeNil)
|
||||
midT, err := time.Parse(time.RFC3339, "2013-01-01T01:00:00Z")
|
||||
So(err, ShouldBeNil)
|
||||
maxT, err := time.Parse(time.RFC3339, "9999-01-01T01:00:00Z")
|
||||
So(err, ShouldBeNil)
|
||||
t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z")
|
||||
So(err, ShouldBeNil)
|
||||
So(sec.Key("TIME").RangeTime(t, minT, maxT).String(), ShouldEqual, t.String())
|
||||
|
||||
Convey("Get value in range with default value", func() {
|
||||
So(sec.Key("FLOAT64").RangeFloat64(5, 0, 1), ShouldEqual, 5)
|
||||
So(sec.Key("INT").RangeInt(7, 0, 5), ShouldEqual, 7)
|
||||
So(sec.Key("INT").RangeInt64(7, 0, 5), ShouldEqual, 7)
|
||||
So(sec.Key("TIME").RangeTime(t, minT, midT).String(), ShouldEqual, t.String())
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Get values into slice", func() {
|
||||
sec := cfg.Section("array")
|
||||
So(strings.Join(sec.Key("STRINGS").Strings(","), ","), ShouldEqual, "en,zh,de")
|
||||
@ -304,7 +331,7 @@ func Test_Values(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("Get key strings", func() {
|
||||
So(strings.Join(cfg.Section("types").KeyStrings(), ","), ShouldEqual, "STRING,BOOL,FLOAT64,INT,TIME")
|
||||
So(strings.Join(cfg.Section("types").KeyStrings(), ","), ShouldEqual, "STRING,BOOL,BOOL_FALSE,FLOAT64,INT,TIME")
|
||||
})
|
||||
|
||||
Convey("Delete a key", func() {
|
||||
@ -321,6 +348,14 @@ func Test_Values(t *testing.T) {
|
||||
cfg.DeleteSection("")
|
||||
So(cfg.SectionStrings()[0], ShouldNotEqual, DEFAULT_SECTION)
|
||||
})
|
||||
|
||||
Convey("Create new sections", func() {
|
||||
cfg.NewSections("test", "test2")
|
||||
_, err := cfg.GetSection("test")
|
||||
So(err, ShouldBeNil)
|
||||
_, err = cfg.GetSection("test2")
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Test getting and setting bad values", t, func() {
|
||||
@ -340,6 +375,10 @@ func Test_Values(t *testing.T) {
|
||||
So(s, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("Create new sections with empty name", func() {
|
||||
So(cfg.NewSections(""), ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Get section that not exists", func() {
|
||||
s, err := cfg.GetSection("404")
|
||||
So(err, ShouldNotBeNil)
|
||||
|
18
Godeps/_workspace/src/gopkg.in/ini.v1/struct.go
generated
vendored
18
Godeps/_workspace/src/gopkg.in/ini.v1/struct.go
generated
vendored
@ -29,7 +29,7 @@ type NameMapper func(string) string
|
||||
var (
|
||||
// AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE.
|
||||
AllCapsUnderscore NameMapper = func(raw string) string {
|
||||
newstr := make([]rune, 0, 10)
|
||||
newstr := make([]rune, 0, len(raw))
|
||||
for i, chr := range raw {
|
||||
if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
|
||||
if i > 0 {
|
||||
@ -42,7 +42,7 @@ var (
|
||||
}
|
||||
// TitleUnderscore converts to format title_underscore.
|
||||
TitleUnderscore NameMapper = func(raw string) string {
|
||||
newstr := make([]rune, 0, 10)
|
||||
newstr := make([]rune, 0, len(raw))
|
||||
for i, chr := range raw {
|
||||
if isUpper := 'A' <= chr && chr <= 'Z'; isUpper {
|
||||
if i > 0 {
|
||||
@ -75,32 +75,38 @@ func parseDelim(actual string) string {
|
||||
|
||||
var reflectTime = reflect.TypeOf(time.Now()).Kind()
|
||||
|
||||
// setWithProperType sets proper value to field based on its type,
|
||||
// but it does not return error for failing parsing,
|
||||
// because we want to use default value that is already assigned to strcut.
|
||||
func setWithProperType(kind reflect.Kind, key *Key, field reflect.Value, delim string) error {
|
||||
switch kind {
|
||||
case reflect.String:
|
||||
if len(key.String()) == 0 {
|
||||
return nil
|
||||
}
|
||||
field.SetString(key.String())
|
||||
case reflect.Bool:
|
||||
boolVal, err := key.Bool()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
field.SetBool(boolVal)
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
intVal, err := key.Int64()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
field.SetInt(intVal)
|
||||
case reflect.Float64:
|
||||
floatVal, err := key.Float64()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
field.SetFloat(floatVal)
|
||||
case reflectTime:
|
||||
timeVal, err := key.Time()
|
||||
if err != nil {
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
field.Set(reflect.ValueOf(timeVal))
|
||||
case reflect.Slice:
|
||||
|
44
Godeps/_workspace/src/gopkg.in/ini.v1/struct_test.go
generated
vendored
44
Godeps/_workspace/src/gopkg.in/ini.v1/struct_test.go
generated
vendored
@ -78,27 +78,17 @@ type unsupport4 struct {
|
||||
*unsupport3 `ini:"Others"`
|
||||
}
|
||||
|
||||
type invalidInt struct {
|
||||
Age int
|
||||
}
|
||||
|
||||
type invalidBool struct {
|
||||
Male bool
|
||||
}
|
||||
|
||||
type invalidFloat struct {
|
||||
Money float64
|
||||
}
|
||||
|
||||
type invalidTime struct {
|
||||
Born time.Time
|
||||
}
|
||||
|
||||
type emptySlice struct {
|
||||
type defaultValue struct {
|
||||
Name string
|
||||
Age int
|
||||
Male bool
|
||||
Money float64
|
||||
Born time.Time
|
||||
Cities []string
|
||||
}
|
||||
|
||||
const _INVALID_DATA_CONF_STRUCT = `
|
||||
Name =
|
||||
Age = age
|
||||
Male = 123
|
||||
Money = money
|
||||
@ -154,12 +144,20 @@ func Test_Struct(t *testing.T) {
|
||||
So(MapTo(&testStruct{}, "hi"), ShouldNotBeNil)
|
||||
})
|
||||
|
||||
Convey("Map to wrong types", t, func() {
|
||||
So(MapTo(&invalidInt{}, []byte(_INVALID_DATA_CONF_STRUCT)), ShouldNotBeNil)
|
||||
So(MapTo(&invalidBool{}, []byte(_INVALID_DATA_CONF_STRUCT)), ShouldNotBeNil)
|
||||
So(MapTo(&invalidFloat{}, []byte(_INVALID_DATA_CONF_STRUCT)), ShouldNotBeNil)
|
||||
So(MapTo(&invalidTime{}, []byte(_INVALID_DATA_CONF_STRUCT)), ShouldNotBeNil)
|
||||
So(MapTo(&emptySlice{}, []byte(_INVALID_DATA_CONF_STRUCT)), ShouldBeNil)
|
||||
Convey("Map to wrong types and gain default values", t, func() {
|
||||
cfg, err := Load([]byte(_INVALID_DATA_CONF_STRUCT))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
t, err := time.Parse(time.RFC3339, "1993-10-07T20:17:05Z")
|
||||
So(err, ShouldBeNil)
|
||||
dv := &defaultValue{"Joe", 10, true, 1.25, t, []string{"HangZhou", "Boston"}}
|
||||
So(cfg.MapTo(dv), ShouldBeNil)
|
||||
So(dv.Name, ShouldEqual, "Joe")
|
||||
So(dv.Age, ShouldEqual, 10)
|
||||
So(dv.Male, ShouldBeTrue)
|
||||
So(dv.Money, ShouldEqual, 1.25)
|
||||
So(dv.Born.String(), ShouldEqual, t.String())
|
||||
So(strings.Join(dv.Cities, ","), ShouldEqual, "HangZhou,Boston")
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/Unknwon/macaron"
|
||||
"github.com/codegangsta/cli"
|
||||
@ -68,6 +69,9 @@ func mapStatic(m *macaron.Macaron, dir string, prefix string) {
|
||||
macaron.StaticOptions{
|
||||
SkipLogging: true,
|
||||
Prefix: prefix,
|
||||
Expires: func() string {
|
||||
return time.Now().UTC().Format(http.TimeFormat)
|
||||
},
|
||||
},
|
||||
))
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ func addApiKeyMigrations(mg *Migrator) {
|
||||
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
|
||||
{Name: "org_id", Type: DB_BigInt, Nullable: false},
|
||||
{Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false},
|
||||
{Name: "key", Type: DB_Varchar, Length: 64, Nullable: false},
|
||||
{Name: "key", Type: DB_Varchar, Length: 255, Nullable: false},
|
||||
{Name: "role", Type: DB_NVarchar, Length: 255, Nullable: false},
|
||||
{Name: "created", Type: DB_DateTime, Nullable: false},
|
||||
{Name: "updated", Type: DB_DateTime, Nullable: false},
|
||||
|
@ -30,8 +30,8 @@ function (angular, $, config) {
|
||||
link: function(scope, elem) {
|
||||
var panelContainer = elem.find('.panel-container');
|
||||
|
||||
scope.$watchGroup(['fullscreen', 'panel.height', 'row.height'], function() {
|
||||
panelContainer.css({ minHeight: scope.panel.height || scope.row.height, display: 'block' });
|
||||
scope.$watchGroup(['fullscreen', 'height', 'panel.height', 'row.height'], function() {
|
||||
panelContainer.css({ minHeight: scope.height || scope.panel.height || scope.row.height, display: 'block' });
|
||||
elem.toggleClass('panel-fullscreen', scope.fullscreen ? true : false);
|
||||
});
|
||||
}
|
||||
|
@ -30,6 +30,12 @@
|
||||
empty-to-null ng-model="panel.grid.leftMin"
|
||||
ng-change="render()" ng-model-onblur>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Scale type
|
||||
</li>
|
||||
<li>
|
||||
<select class="input-small tight-form-input" style="width: 113px" ng-model="panel.grid.leftScale" ng-options="v as k for (k, v) in scaleTypes" ng-change="render()"></select>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Label
|
||||
</li>
|
||||
@ -69,6 +75,12 @@
|
||||
empty-to-null ng-model="panel.grid.rightMin"
|
||||
ng-change="render()" ng-model-onblur>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Scale type
|
||||
</li>
|
||||
<li>
|
||||
<select class="input-small tight-form-input" style="width: 113px" ng-model="panel.grid.rightScale" ng-options="v as k for (k, v) in scaleTypes" ng-change="render()"></select>
|
||||
</li>
|
||||
<li class="tight-form-item">
|
||||
Label
|
||||
</li>
|
||||
|
@ -27,6 +27,7 @@ function (angular, $, kbn, moment, _, GraphTooltip) {
|
||||
var dashboard = scope.dashboard;
|
||||
var data, annotations;
|
||||
var sortedSeries;
|
||||
var graphHeight;
|
||||
var legendSideLastValue = null;
|
||||
scope.crosshairEmiter = false;
|
||||
|
||||
@ -64,19 +65,19 @@ function (angular, $, kbn, moment, _, GraphTooltip) {
|
||||
|
||||
function setElementHeight() {
|
||||
try {
|
||||
var height = scope.height || scope.panel.height || scope.row.height;
|
||||
if (_.isString(height)) {
|
||||
height = parseInt(height.replace('px', ''), 10);
|
||||
graphHeight = scope.height || scope.panel.height || scope.row.height;
|
||||
if (_.isString(graphHeight)) {
|
||||
graphHeight = parseInt(graphHeight.replace('px', ''), 10);
|
||||
}
|
||||
|
||||
height -= 5; // padding
|
||||
height -= scope.panel.title ? 24 : 9; // subtract panel title bar
|
||||
graphHeight -= 5; // padding
|
||||
graphHeight -= scope.panel.title ? 24 : 9; // subtract panel title bar
|
||||
|
||||
if (scope.panel.legend.show && !scope.panel.legend.rightSide) {
|
||||
height = height - 26; // subtract one line legend
|
||||
graphHeight = graphHeight - 26; // subtract one line legend
|
||||
}
|
||||
|
||||
elem.css('height', height + 'px');
|
||||
elem.css('height', graphHeight + 'px');
|
||||
|
||||
return true;
|
||||
} catch(e) { // IE throws errors sometimes
|
||||
@ -349,6 +350,8 @@ function (angular, $, kbn, moment, _, GraphTooltip) {
|
||||
position: 'left',
|
||||
show: scope.panel['y-axis'],
|
||||
min: scope.panel.grid.leftMin,
|
||||
index: 1,
|
||||
scale: scope.panel.grid.leftScale,
|
||||
max: scope.panel.percentage && scope.panel.stack ? 100 : scope.panel.grid.leftMax,
|
||||
};
|
||||
|
||||
@ -356,16 +359,59 @@ function (angular, $, kbn, moment, _, GraphTooltip) {
|
||||
|
||||
if (_.findWhere(data, {yaxis: 2})) {
|
||||
var secondY = _.clone(defaults);
|
||||
secondY.index = 2,
|
||||
secondY.scale = scope.panel.grid.rightScale;
|
||||
secondY.position = 'right';
|
||||
secondY.min = scope.panel.grid.rightMin;
|
||||
secondY.max = scope.panel.percentage && scope.panel.stack ? 100 : scope.panel.grid.rightMax;
|
||||
options.yaxes.push(secondY);
|
||||
|
||||
applyLogScale(options.yaxes[1], data);
|
||||
configureAxisMode(options.yaxes[1], scope.panel.y_formats[1]);
|
||||
}
|
||||
|
||||
applyLogScale(options.yaxes[0], data);
|
||||
configureAxisMode(options.yaxes[0], scope.panel.y_formats[0]);
|
||||
}
|
||||
|
||||
function applyLogScale(axis, data) {
|
||||
if (axis.scale !== 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
var series, i;
|
||||
var max = axis.max;
|
||||
|
||||
if (max === null) {
|
||||
for (i = 0; i < data.length; i++) {
|
||||
series = data[i];
|
||||
if (series.yaxis === axis.index) {
|
||||
if (max < series.stats.max) {
|
||||
max = series.stats.max;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (max === null) {
|
||||
max = 10000000000;
|
||||
}
|
||||
}
|
||||
|
||||
axis.ticks = [0, 1];
|
||||
var tick = 1;
|
||||
|
||||
while (true) {
|
||||
tick = tick*10;
|
||||
axis.ticks.push(tick);
|
||||
if (tick > max) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
axis.transform = function(v) { return Math.log(v+0.1); };
|
||||
axis.inverseTransform = function (v) { return Math.pow(10,v); };
|
||||
}
|
||||
|
||||
function configureAxisMode(axis, format) {
|
||||
axis.tickFormatter = function(val, axis) {
|
||||
return kbn.valueFormats[format](val, axis.tickDecimals, axis.scaledDecimals);
|
||||
@ -411,44 +457,44 @@ function (angular, $, kbn, moment, _, GraphTooltip) {
|
||||
url += scope.panel['y-axis'] ? '' : '&hideYAxis=true';
|
||||
|
||||
switch(scope.panel.y_formats[0]) {
|
||||
case 'bytes':
|
||||
url += '&yUnitSystem=binary';
|
||||
break;
|
||||
case 'bits':
|
||||
url += '&yUnitSystem=binary';
|
||||
break;
|
||||
case 'bps':
|
||||
url += '&yUnitSystem=si';
|
||||
break;
|
||||
case 'Bps':
|
||||
url += '&yUnitSystem=si';
|
||||
break;
|
||||
case 'short':
|
||||
url += '&yUnitSystem=si';
|
||||
break;
|
||||
case 'joule':
|
||||
url += '&yUnitSystem=si';
|
||||
break;
|
||||
case 'watt':
|
||||
url += '&yUnitSystem=si';
|
||||
break;
|
||||
case 'ev':
|
||||
url += '&yUnitSystem=si';
|
||||
break;
|
||||
case 'none':
|
||||
url += '&yUnitSystem=none';
|
||||
break;
|
||||
case 'bytes':
|
||||
url += '&yUnitSystem=binary';
|
||||
break;
|
||||
case 'bits':
|
||||
url += '&yUnitSystem=binary';
|
||||
break;
|
||||
case 'bps':
|
||||
url += '&yUnitSystem=si';
|
||||
break;
|
||||
case 'Bps':
|
||||
url += '&yUnitSystem=si';
|
||||
break;
|
||||
case 'short':
|
||||
url += '&yUnitSystem=si';
|
||||
break;
|
||||
case 'joule':
|
||||
url += '&yUnitSystem=si';
|
||||
break;
|
||||
case 'watt':
|
||||
url += '&yUnitSystem=si';
|
||||
break;
|
||||
case 'ev':
|
||||
url += '&yUnitSystem=si';
|
||||
break;
|
||||
case 'none':
|
||||
url += '&yUnitSystem=none';
|
||||
break;
|
||||
}
|
||||
|
||||
switch(scope.panel.nullPointMode) {
|
||||
case 'connected':
|
||||
url += '&lineMode=connected';
|
||||
break;
|
||||
case 'null':
|
||||
break; // graphite default lineMode
|
||||
case 'null as zero':
|
||||
url += "&drawNullAsZero=true";
|
||||
break;
|
||||
case 'connected':
|
||||
url += '&lineMode=connected';
|
||||
break;
|
||||
case 'null':
|
||||
break; // graphite default lineMode
|
||||
case 'null as zero':
|
||||
url += "&drawNullAsZero=true";
|
||||
break;
|
||||
}
|
||||
|
||||
url += scope.panel.steppedLine ? '&lineMode=staircase' : '';
|
||||
|
@ -99,7 +99,7 @@ function ($) {
|
||||
var group, value, timestamp, hoverInfo, i, series, seriesHtml;
|
||||
|
||||
if(dashboard.sharedCrosshair){
|
||||
scope.appEvent('setCrosshair', { pos: pos, scope: scope });
|
||||
scope.appEvent('setCrosshair', { pos: pos, scope: scope });
|
||||
}
|
||||
|
||||
if (seriesList.length === 0) {
|
||||
|
@ -53,10 +53,12 @@ function (angular, app, $, _, kbn, moment, TimeSeries, PanelMeta) {
|
||||
y_formats : ['short', 'short'],
|
||||
// grid options
|
||||
grid : {
|
||||
leftScale: 1,
|
||||
leftMax: null,
|
||||
rightMax: null,
|
||||
leftMin: null,
|
||||
rightMin: null,
|
||||
rightScale: 1,
|
||||
threshold1: null,
|
||||
threshold2: null,
|
||||
threshold1Color: 'rgba(216, 200, 27, 0.27)',
|
||||
@ -95,7 +97,7 @@ function (angular, app, $, _, kbn, moment, TimeSeries, PanelMeta) {
|
||||
// tooltip options
|
||||
tooltip : {
|
||||
value_type: 'cumulative',
|
||||
shared: false,
|
||||
shared: true,
|
||||
},
|
||||
// time overrides
|
||||
timeFrom: null,
|
||||
@ -114,6 +116,8 @@ function (angular, app, $, _, kbn, moment, TimeSeries, PanelMeta) {
|
||||
_.defaults($scope.panel.grid, _d.grid);
|
||||
_.defaults($scope.panel.legend, _d.legend);
|
||||
|
||||
$scope.scaleTypes = {'linear': 1, 'log (base 10)': 2};
|
||||
|
||||
$scope.hiddenSeries = {};
|
||||
$scope.seriesList = [];
|
||||
$scope.unitFormats = kbn.getUnitFormats();
|
||||
|
@ -31,7 +31,6 @@
|
||||
</div>
|
||||
<editor-opt-bool text="Hide controls (CTRL+H)" model="dashboard.hideControls"></editor-opt-bool>
|
||||
<editor-opt-bool text="Shared Crosshair (CTRL+O)" model="dashboard.sharedCrosshair"></editor-opt-bool>
|
||||
<editor-opt-bool text="Editable" model="dashboard.editable"></editor-opt-bool>
|
||||
</div>
|
||||
</div>
|
||||
<div class="editor-row">
|
||||
|
@ -62,6 +62,7 @@
|
||||
.main-view-container {
|
||||
overflow: hidden;
|
||||
height: 0;
|
||||
padding: 0;
|
||||
.row-control-inner {
|
||||
display: none;
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
// grafana Variables
|
||||
// -------------------------
|
||||
@grafanaPanelBackground: @grayDarker;
|
||||
@grafanaPanelBorder: solid 1px @grayDark;
|
||||
@grafanaPanelBorder: solid 1px @grayDark;
|
||||
@grafanaTriggerBorder: solid 1px #555;
|
||||
|
||||
// Graphite Target Editor
|
||||
|
Loading…
Reference in New Issue
Block a user