mirror of
https://github.com/grafana/grafana.git
synced 2025-12-22 04:34:27 +08:00
Compare commits
16 Commits
docs/add-d
...
v4.1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3b510b7581 | ||
|
|
0c7d101a97 | ||
|
|
4c192714e4 | ||
|
|
d01cf16dea | ||
|
|
9f0b6f5aca | ||
|
|
46c1f72c03 | ||
|
|
ec033840bc | ||
|
|
f09c114019 | ||
|
|
225bf094b2 | ||
|
|
98b648dabe | ||
|
|
da7f1f29de | ||
|
|
0719a66d47 | ||
|
|
65ac0bc68b | ||
|
|
8862ee1ae6 | ||
|
|
3205d1e754 | ||
|
|
eac75ec303 |
@@ -5,7 +5,7 @@ os: Windows Server 2012 R2
|
|||||||
clone_folder: c:\gopath\src\github.com\grafana\grafana
|
clone_folder: c:\gopath\src\github.com\grafana\grafana
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
nodejs_version: "5"
|
nodejs_version: "6"
|
||||||
GOPATH: c:\gopath
|
GOPATH: c:\gopath
|
||||||
|
|
||||||
install:
|
install:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"company": "Coding Instinct AB"
|
"company": "Coding Instinct AB"
|
||||||
},
|
},
|
||||||
"name": "grafana",
|
"name": "grafana",
|
||||||
"version": "4.1.0-beta1",
|
"version": "4.1.2",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "http://github.com/grafana/grafana.git"
|
"url": "http://github.com/grafana/grafana.git"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#! /usr/bin/env bash
|
#! /usr/bin/env bash
|
||||||
deb_ver=4.0.2-1481203731
|
deb_ver=4.1.1-1484211277
|
||||||
rpm_ver=4.0.2-1481203731
|
rpm_ver=4.1.1-1484211277
|
||||||
|
|
||||||
wget https://grafanarel.s3.amazonaws.com/builds/grafana_${deb_ver}_amd64.deb
|
wget https://grafanarel.s3.amazonaws.com/builds/grafana_${deb_ver}_amd64.deb
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ func Register(r *macaron.Macaron) {
|
|||||||
// users (admin permission required)
|
// users (admin permission required)
|
||||||
r.Group("/users", func() {
|
r.Group("/users", func() {
|
||||||
r.Get("/", wrap(SearchUsers))
|
r.Get("/", wrap(SearchUsers))
|
||||||
|
r.Get("/search", wrap(SearchUsersWithPaging))
|
||||||
r.Get("/:id", wrap(GetUserById))
|
r.Get("/:id", wrap(GetUserById))
|
||||||
r.Get("/:id/orgs", wrap(GetUserOrgList))
|
r.Get("/:id/orgs", wrap(GetUserOrgList))
|
||||||
r.Put("/:id", bind(m.UpdateUserCommand{}), wrap(UpdateUser))
|
r.Put("/:id", bind(m.UpdateUserCommand{}), wrap(UpdateUser))
|
||||||
@@ -194,7 +195,7 @@ func Register(r *macaron.Macaron) {
|
|||||||
|
|
||||||
// Data sources
|
// Data sources
|
||||||
r.Group("/datasources", func() {
|
r.Group("/datasources", func() {
|
||||||
r.Get("/", GetDataSources)
|
r.Get("/", wrap(GetDataSources))
|
||||||
r.Post("/", quota("data_source"), bind(m.AddDataSourceCommand{}), AddDataSource)
|
r.Post("/", quota("data_source"), bind(m.AddDataSourceCommand{}), AddDataSource)
|
||||||
r.Put("/:id", bind(m.UpdateDataSourceCommand{}), wrap(UpdateDataSource))
|
r.Put("/:id", bind(m.UpdateDataSourceCommand{}), wrap(UpdateDataSource))
|
||||||
r.Delete("/:id", DeleteDataSource)
|
r.Delete("/:id", DeleteDataSource)
|
||||||
|
|||||||
@@ -140,8 +140,8 @@ func init() {
|
|||||||
// Please update the region list in public/app/plugins/datasource/cloudwatch/partials/config.html
|
// Please update the region list in public/app/plugins/datasource/cloudwatch/partials/config.html
|
||||||
func handleGetRegions(req *cwRequest, c *middleware.Context) {
|
func handleGetRegions(req *cwRequest, c *middleware.Context) {
|
||||||
regions := []string{
|
regions := []string{
|
||||||
"ap-northeast-1", "ap-northeast-2", "ap-southeast-1", "ap-southeast-2", "ca-central-1", "cn-north-1",
|
"ap-northeast-1", "ap-northeast-2", "ap-southeast-1", "ap-southeast-2", "ap-south-1", "ca-central-1", "cn-north-1",
|
||||||
"eu-central-1", "eu-west-1", "eu-west-2", "sa-east-1", "us-east-1", "us-west-1", "us-west-2", "us-gov-west-1",
|
"eu-central-1", "eu-west-1", "eu-west-2", "sa-east-1", "us-east-1", "us-east-2", "us-gov-west-1", "us-west-1", "us-west-2",
|
||||||
}
|
}
|
||||||
|
|
||||||
result := []interface{}{}
|
result := []interface{}{}
|
||||||
|
|||||||
@@ -11,12 +11,11 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/util"
|
"github.com/grafana/grafana/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetDataSources(c *middleware.Context) {
|
func GetDataSources(c *middleware.Context) Response {
|
||||||
query := m.GetDataSourcesQuery{OrgId: c.OrgId}
|
query := m.GetDataSourcesQuery{OrgId: c.OrgId}
|
||||||
|
|
||||||
if err := bus.Dispatch(&query); err != nil {
|
if err := bus.Dispatch(&query); err != nil {
|
||||||
c.JsonApiErr(500, "Failed to query datasources", err)
|
return ApiError(500, "Failed to query datasources", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result := make(dtos.DataSourceList, 0)
|
result := make(dtos.DataSourceList, 0)
|
||||||
@@ -46,7 +45,8 @@ func GetDataSources(c *middleware.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sort.Sort(result)
|
sort.Sort(result)
|
||||||
c.JSON(200, result)
|
|
||||||
|
return Json(200, &result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDataSourceById(c *middleware.Context) Response {
|
func GetDataSourceById(c *middleware.Context) Response {
|
||||||
|
|||||||
132
pkg/api/datasources_test.go
Normal file
132
pkg/api/datasources_test.go
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
macaron "gopkg.in/macaron.v1"
|
||||||
|
|
||||||
|
"github.com/go-macaron/session"
|
||||||
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
"github.com/grafana/grafana/pkg/middleware"
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TestOrgID = 1
|
||||||
|
TestUserID = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDataSourcesProxy(t *testing.T) {
|
||||||
|
Convey("Given a user is logged in", t, func() {
|
||||||
|
loggedInUserScenario("When calling GET on", "/api/datasources/", func(sc *scenarioContext) {
|
||||||
|
|
||||||
|
// Stubs the database query
|
||||||
|
bus.AddHandler("test", func(query *models.GetDataSourcesQuery) error {
|
||||||
|
So(query.OrgId, ShouldEqual, TestOrgID)
|
||||||
|
query.Result = []*models.DataSource{
|
||||||
|
{Name: "mmm"},
|
||||||
|
{Name: "ZZZ"},
|
||||||
|
{Name: "BBB"},
|
||||||
|
{Name: "aaa"},
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
// handler func being tested
|
||||||
|
sc.handlerFunc = GetDataSources
|
||||||
|
sc.fakeReq("GET", "/api/datasources").exec()
|
||||||
|
|
||||||
|
respJSON := []map[string]interface{}{}
|
||||||
|
err := json.NewDecoder(sc.resp.Body).Decode(&respJSON)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
Convey("should return list of datasources for org sorted alphabetically and case insensitively", func() {
|
||||||
|
So(respJSON[0]["name"], ShouldEqual, "aaa")
|
||||||
|
So(respJSON[1]["name"], ShouldEqual, "BBB")
|
||||||
|
So(respJSON[2]["name"], ShouldEqual, "mmm")
|
||||||
|
So(respJSON[3]["name"], ShouldEqual, "ZZZ")
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func loggedInUserScenario(desc string, url string, fn scenarioFunc) {
|
||||||
|
Convey(desc+" "+url, func() {
|
||||||
|
defer bus.ClearBusHandlers()
|
||||||
|
|
||||||
|
sc := &scenarioContext{
|
||||||
|
url: url,
|
||||||
|
}
|
||||||
|
viewsPath, _ := filepath.Abs("../../public/views")
|
||||||
|
|
||||||
|
sc.m = macaron.New()
|
||||||
|
sc.m.Use(macaron.Renderer(macaron.RenderOptions{
|
||||||
|
Directory: viewsPath,
|
||||||
|
Delims: macaron.Delims{Left: "[[", Right: "]]"},
|
||||||
|
}))
|
||||||
|
|
||||||
|
sc.m.Use(middleware.GetContextHandler())
|
||||||
|
sc.m.Use(middleware.Sessioner(&session.Options{}))
|
||||||
|
|
||||||
|
sc.defaultHandler = wrap(func(c *middleware.Context) Response {
|
||||||
|
sc.context = c
|
||||||
|
sc.context.UserId = TestUserID
|
||||||
|
sc.context.OrgId = TestOrgID
|
||||||
|
sc.context.OrgRole = models.ROLE_EDITOR
|
||||||
|
if sc.handlerFunc != nil {
|
||||||
|
return sc.handlerFunc(sc.context)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
sc.m.Get(url, sc.defaultHandler)
|
||||||
|
|
||||||
|
fn(sc)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *scenarioContext) fakeReq(method, url string) *scenarioContext {
|
||||||
|
sc.resp = httptest.NewRecorder()
|
||||||
|
req, err := http.NewRequest(method, url, nil)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
sc.req = req
|
||||||
|
|
||||||
|
return sc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *scenarioContext) fakeReqWithParams(method, url string, queryParams map[string]string) *scenarioContext {
|
||||||
|
sc.resp = httptest.NewRecorder()
|
||||||
|
req, err := http.NewRequest(method, url, nil)
|
||||||
|
q := req.URL.Query()
|
||||||
|
for k, v := range queryParams {
|
||||||
|
q.Add(k, v)
|
||||||
|
}
|
||||||
|
req.URL.RawQuery = q.Encode()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
sc.req = req
|
||||||
|
|
||||||
|
return sc
|
||||||
|
}
|
||||||
|
|
||||||
|
type scenarioContext struct {
|
||||||
|
m *macaron.Macaron
|
||||||
|
context *middleware.Context
|
||||||
|
resp *httptest.ResponseRecorder
|
||||||
|
handlerFunc handlerFunc
|
||||||
|
defaultHandler macaron.Handler
|
||||||
|
req *http.Request
|
||||||
|
url string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *scenarioContext) exec() {
|
||||||
|
sc.m.ServeHTTP(sc.resp, sc.req)
|
||||||
|
}
|
||||||
|
|
||||||
|
type scenarioFunc func(c *scenarioContext)
|
||||||
|
type handlerFunc func(c *middleware.Context) Response
|
||||||
@@ -91,7 +91,7 @@ func (slice DataSourceList) Len() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (slice DataSourceList) Less(i, j int) bool {
|
func (slice DataSourceList) Less(i, j int) bool {
|
||||||
return slice[i].Name < slice[j].Name
|
return strings.ToLower(slice[i].Name) < strings.ToLower(slice[j].Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (slice DataSourceList) Swap(i, j int) {
|
func (slice DataSourceList) Swap(i, j int) {
|
||||||
|
|||||||
@@ -186,14 +186,46 @@ func ChangeUserPassword(c *middleware.Context, cmd m.ChangeUserPasswordCommand)
|
|||||||
|
|
||||||
// GET /api/users
|
// GET /api/users
|
||||||
func SearchUsers(c *middleware.Context) Response {
|
func SearchUsers(c *middleware.Context) Response {
|
||||||
query := m.SearchUsersQuery{Query: "", Page: 0, Limit: 1000}
|
query, err := searchUser(c)
|
||||||
if err := bus.Dispatch(&query); err != nil {
|
if err != nil {
|
||||||
|
return ApiError(500, "Failed to fetch users", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Json(200, query.Result.Users)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GET /api/paged-users
|
||||||
|
func SearchUsersWithPaging(c *middleware.Context) Response {
|
||||||
|
query, err := searchUser(c)
|
||||||
|
if err != nil {
|
||||||
return ApiError(500, "Failed to fetch users", err)
|
return ApiError(500, "Failed to fetch users", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return Json(200, query.Result)
|
return Json(200, query.Result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func searchUser(c *middleware.Context) (*m.SearchUsersQuery, error) {
|
||||||
|
perPage := c.QueryInt("perpage")
|
||||||
|
if perPage <= 0 {
|
||||||
|
perPage = 1000
|
||||||
|
}
|
||||||
|
page := c.QueryInt("page")
|
||||||
|
|
||||||
|
if page < 1 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
query := &m.SearchUsersQuery{Query: "", Page: page, Limit: perPage}
|
||||||
|
if err := bus.Dispatch(query); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
query.Result.Page = page
|
||||||
|
query.Result.PerPage = perPage
|
||||||
|
|
||||||
|
return query, nil
|
||||||
|
}
|
||||||
|
|
||||||
func SetHelpFlag(c *middleware.Context) Response {
|
func SetHelpFlag(c *middleware.Context) Response {
|
||||||
flag := c.ParamsInt64(":id")
|
flag := c.ParamsInt64(":id")
|
||||||
|
|
||||||
|
|||||||
109
pkg/api/user_test.go
Normal file
109
pkg/api/user_test.go
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/bus"
|
||||||
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUserApiEndpoint(t *testing.T) {
|
||||||
|
Convey("Given a user is logged in", t, func() {
|
||||||
|
mockResult := models.SearchUserQueryResult{
|
||||||
|
Users: []*models.UserSearchHitDTO{
|
||||||
|
{Name: "user1"},
|
||||||
|
{Name: "user2"},
|
||||||
|
},
|
||||||
|
TotalCount: 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
loggedInUserScenario("When calling GET on", "/api/users", func(sc *scenarioContext) {
|
||||||
|
var sentLimit int
|
||||||
|
var sendPage int
|
||||||
|
bus.AddHandler("test", func(query *models.SearchUsersQuery) error {
|
||||||
|
query.Result = mockResult
|
||||||
|
|
||||||
|
sentLimit = query.Limit
|
||||||
|
sendPage = query.Page
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
sc.handlerFunc = SearchUsers
|
||||||
|
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||||
|
|
||||||
|
So(sentLimit, ShouldEqual, 1000)
|
||||||
|
So(sendPage, ShouldEqual, 1)
|
||||||
|
|
||||||
|
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(len(respJSON.MustArray()), ShouldEqual, 2)
|
||||||
|
})
|
||||||
|
|
||||||
|
loggedInUserScenario("When calling GET with page and limit querystring parameters on", "/api/users", func(sc *scenarioContext) {
|
||||||
|
var sentLimit int
|
||||||
|
var sendPage int
|
||||||
|
bus.AddHandler("test", func(query *models.SearchUsersQuery) error {
|
||||||
|
query.Result = mockResult
|
||||||
|
|
||||||
|
sentLimit = query.Limit
|
||||||
|
sendPage = query.Page
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
sc.handlerFunc = SearchUsers
|
||||||
|
sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "10", "page": "2"}).exec()
|
||||||
|
|
||||||
|
So(sentLimit, ShouldEqual, 10)
|
||||||
|
So(sendPage, ShouldEqual, 2)
|
||||||
|
})
|
||||||
|
|
||||||
|
loggedInUserScenario("When calling GET on", "/api/users/search", func(sc *scenarioContext) {
|
||||||
|
var sentLimit int
|
||||||
|
var sendPage int
|
||||||
|
bus.AddHandler("test", func(query *models.SearchUsersQuery) error {
|
||||||
|
query.Result = mockResult
|
||||||
|
|
||||||
|
sentLimit = query.Limit
|
||||||
|
sendPage = query.Page
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
sc.handlerFunc = SearchUsersWithPaging
|
||||||
|
sc.fakeReqWithParams("GET", sc.url, map[string]string{}).exec()
|
||||||
|
|
||||||
|
So(sentLimit, ShouldEqual, 1000)
|
||||||
|
So(sendPage, ShouldEqual, 1)
|
||||||
|
|
||||||
|
respJSON, err := simplejson.NewJson(sc.resp.Body.Bytes())
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
So(respJSON.Get("totalCount").MustInt(), ShouldEqual, 2)
|
||||||
|
So(len(respJSON.Get("users").MustArray()), ShouldEqual, 2)
|
||||||
|
})
|
||||||
|
|
||||||
|
loggedInUserScenario("When calling GET with page and perpage querystring parameters on", "/api/users/search", func(sc *scenarioContext) {
|
||||||
|
var sentLimit int
|
||||||
|
var sendPage int
|
||||||
|
bus.AddHandler("test", func(query *models.SearchUsersQuery) error {
|
||||||
|
query.Result = mockResult
|
||||||
|
|
||||||
|
sentLimit = query.Limit
|
||||||
|
sendPage = query.Page
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
sc.handlerFunc = SearchUsersWithPaging
|
||||||
|
sc.fakeReqWithParams("GET", sc.url, map[string]string{"perpage": "10", "page": "2"}).exec()
|
||||||
|
|
||||||
|
So(sentLimit, ShouldEqual, 10)
|
||||||
|
So(sendPage, ShouldEqual, 2)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -130,7 +130,14 @@ type SearchUsersQuery struct {
|
|||||||
Page int
|
Page int
|
||||||
Limit int
|
Limit int
|
||||||
|
|
||||||
Result []*UserSearchHitDTO
|
Result SearchUserQueryResult
|
||||||
|
}
|
||||||
|
|
||||||
|
type SearchUserQueryResult struct {
|
||||||
|
TotalCount int64 `json:"totalCount"`
|
||||||
|
Users []*UserSearchHitDTO `json:"users"`
|
||||||
|
Page int `json:"page"`
|
||||||
|
PerPage int `json:"perPage"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GetUserOrgListQuery struct {
|
type GetUserOrgListQuery struct {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ func NewWebHookNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
|
|||||||
return &WebhookNotifier{
|
return &WebhookNotifier{
|
||||||
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
|
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
|
||||||
Url: url,
|
Url: url,
|
||||||
User: model.Settings.Get("user").MustString(),
|
User: model.Settings.Get("username").MustString(),
|
||||||
Password: model.Settings.Get("password").MustString(),
|
Password: model.Settings.Get("password").MustString(),
|
||||||
HttpMethod: model.Settings.Get("httpMethod").MustString("POST"),
|
HttpMethod: model.Settings.Get("httpMethod").MustString("POST"),
|
||||||
log: log.New("alerting.notifier.webhook"),
|
log: log.New("alerting.notifier.webhook"),
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ func TestAccountDataAccess(t *testing.T) {
|
|||||||
err := SearchUsers(&query)
|
err := SearchUsers(&query)
|
||||||
|
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(query.Result[0].Email, ShouldEqual, "ac1@test.com")
|
So(query.Result.Users[0].Email, ShouldEqual, "ac1@test.com")
|
||||||
So(query.Result[1].Email, ShouldEqual, "ac2@test.com")
|
So(query.Result.Users[1].Email, ShouldEqual, "ac2@test.com")
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Given an added org user", func() {
|
Convey("Given an added org user", func() {
|
||||||
|
|||||||
@@ -344,12 +344,21 @@ func GetSignedInUser(query *m.GetSignedInUserQuery) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SearchUsers(query *m.SearchUsersQuery) error {
|
func SearchUsers(query *m.SearchUsersQuery) error {
|
||||||
query.Result = make([]*m.UserSearchHitDTO, 0)
|
query.Result = m.SearchUserQueryResult{
|
||||||
|
Users: make([]*m.UserSearchHitDTO, 0),
|
||||||
|
}
|
||||||
sess := x.Table("user")
|
sess := x.Table("user")
|
||||||
sess.Where("email LIKE ?", query.Query+"%")
|
sess.Where("email LIKE ?", query.Query+"%")
|
||||||
sess.Limit(query.Limit, query.Limit*query.Page)
|
offset := query.Limit * (query.Page - 1)
|
||||||
|
sess.Limit(query.Limit, offset)
|
||||||
sess.Cols("id", "email", "name", "login", "is_admin")
|
sess.Cols("id", "email", "name", "login", "is_admin")
|
||||||
err := sess.Find(&query.Result)
|
if err := sess.Find(&query.Result.Users); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
user := m.User{}
|
||||||
|
count, err := x.Count(&user)
|
||||||
|
query.Result.TotalCount = count
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
45
pkg/services/sqlstore/user_test.go
Normal file
45
pkg/services/sqlstore/user_test.go
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package sqlstore
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/smartystreets/goconvey/convey"
|
||||||
|
|
||||||
|
"github.com/grafana/grafana/pkg/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUserDataAccess(t *testing.T) {
|
||||||
|
|
||||||
|
Convey("Testing DB", t, func() {
|
||||||
|
InitTestDB(t)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
err = CreateUser(&models.CreateUserCommand{
|
||||||
|
Email: fmt.Sprint("user", i, "@test.com"),
|
||||||
|
Name: fmt.Sprint("user", i),
|
||||||
|
Login: fmt.Sprint("user", i),
|
||||||
|
})
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
}
|
||||||
|
|
||||||
|
Convey("Can return the first page of users and a total count", func() {
|
||||||
|
query := models.SearchUsersQuery{Query: "", Page: 1, Limit: 3}
|
||||||
|
err = SearchUsers(&query)
|
||||||
|
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(len(query.Result.Users), ShouldEqual, 3)
|
||||||
|
So(query.Result.TotalCount, ShouldEqual, 5)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Can return the second page of users and a total count", func() {
|
||||||
|
query := models.SearchUsersQuery{Query: "", Page: 2, Limit: 3}
|
||||||
|
err = SearchUsers(&query)
|
||||||
|
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(len(query.Result.Users), ShouldEqual, 2)
|
||||||
|
So(query.Result.TotalCount, ShouldEqual, 5)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -113,6 +113,7 @@ function setupAngularRoutes($routeProvider, $locationProvider) {
|
|||||||
.when('/admin/users', {
|
.when('/admin/users', {
|
||||||
templateUrl: 'public/app/features/admin/partials/users.html',
|
templateUrl: 'public/app/features/admin/partials/users.html',
|
||||||
controller : 'AdminListUsersCtrl',
|
controller : 'AdminListUsersCtrl',
|
||||||
|
controllerAs: 'ctrl',
|
||||||
resolve: loadAdminBundle,
|
resolve: loadAdminBundle,
|
||||||
})
|
})
|
||||||
.when('/admin/users/create', {
|
.when('/admin/users/create', {
|
||||||
|
|||||||
@@ -97,10 +97,19 @@ function (angular, _, coreModule, config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
metricSources.sort(function(a, b) {
|
metricSources.sort(function(a, b) {
|
||||||
if (a.meta.builtIn || a.name > b.name) {
|
if (a.meta.builtIn) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (a.name < b.name) {
|
|
||||||
|
if (b.meta.builtIn) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.name.toLowerCase() > b.name.toLowerCase()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.name.toLowerCase() < b.name.toLowerCase()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import './adminListUsersCtrl';
|
import AdminListUsersCtrl from './admin_list_users_ctrl';
|
||||||
import './adminListOrgsCtrl';
|
import './adminListOrgsCtrl';
|
||||||
import './adminEditOrgCtrl';
|
import './adminEditOrgCtrl';
|
||||||
import './adminEditUserCtrl';
|
import './adminEditUserCtrl';
|
||||||
@@ -37,3 +37,4 @@ export class AdminStatsCtrl {
|
|||||||
coreModule.controller('AdminSettingsCtrl', AdminSettingsCtrl);
|
coreModule.controller('AdminSettingsCtrl', AdminSettingsCtrl);
|
||||||
coreModule.controller('AdminHomeCtrl', AdminHomeCtrl);
|
coreModule.controller('AdminHomeCtrl', AdminHomeCtrl);
|
||||||
coreModule.controller('AdminStatsCtrl', AdminStatsCtrl);
|
coreModule.controller('AdminStatsCtrl', AdminStatsCtrl);
|
||||||
|
coreModule.controller('AdminListUsersCtrl', AdminListUsersCtrl);
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
define([
|
|
||||||
'angular',
|
|
||||||
],
|
|
||||||
function (angular) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var module = angular.module('grafana.controllers');
|
|
||||||
|
|
||||||
module.controller('AdminListUsersCtrl', function($scope, backendSrv) {
|
|
||||||
|
|
||||||
$scope.init = function() {
|
|
||||||
$scope.getUsers();
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.getUsers = function() {
|
|
||||||
backendSrv.get('/api/users').then(function(users) {
|
|
||||||
$scope.users = users;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.deleteUser = function(user) {
|
|
||||||
$scope.appEvent('confirm-modal', {
|
|
||||||
title: 'Delete',
|
|
||||||
text: 'Do you want to delete ' + user.login + '?',
|
|
||||||
icon: 'fa-trash',
|
|
||||||
yesText: 'Delete',
|
|
||||||
onConfirm: function() {
|
|
||||||
backendSrv.delete('/api/admin/users/' + user.id).then(function() {
|
|
||||||
$scope.getUsers();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.init();
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
49
public/app/features/admin/admin_list_users_ctrl.ts
Normal file
49
public/app/features/admin/admin_list_users_ctrl.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
///<reference path="../../headers/common.d.ts" />
|
||||||
|
|
||||||
|
export default class AdminListUsersCtrl {
|
||||||
|
users: any;
|
||||||
|
pages = [];
|
||||||
|
perPage = 1000;
|
||||||
|
page = 1;
|
||||||
|
totalPages: number;
|
||||||
|
showPaging = false;
|
||||||
|
|
||||||
|
/** @ngInject */
|
||||||
|
constructor(private $scope, private backendSrv) {
|
||||||
|
this.getUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
getUsers() {
|
||||||
|
this.backendSrv.get(`/api/users/search?perpage=${this.perPage}&page=${this.page}`).then((result) => {
|
||||||
|
this.users = result.users;
|
||||||
|
this.page = result.page;
|
||||||
|
this.perPage = result.perPage;
|
||||||
|
this.totalPages = Math.ceil(result.totalCount / result.perPage);
|
||||||
|
this.showPaging = this.totalPages > 1;
|
||||||
|
this.pages = [];
|
||||||
|
|
||||||
|
for (var i = 1; i < this.totalPages+1; i++) {
|
||||||
|
this.pages.push({ page: i, current: i === this.page});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
navigateToPage(page) {
|
||||||
|
this.page = page.page;
|
||||||
|
this.getUsers();
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteUser(user) {
|
||||||
|
this.$scope.appEvent('confirm-modal', {
|
||||||
|
title: 'Delete',
|
||||||
|
text: 'Do you want to delete ' + user.login + '?',
|
||||||
|
icon: 'fa-trash',
|
||||||
|
yesText: 'Delete',
|
||||||
|
onConfirm: () => {
|
||||||
|
this.backendSrv.delete('/api/admin/users/' + user.id).then(() => {
|
||||||
|
this.getUsers();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,49 +1,62 @@
|
|||||||
<navbar icon="fa fa-fw fa-cogs" title="Admin" title-url="admin">
|
<navbar icon="fa fa-fw fa-cogs" title="Admin" title-url="admin">
|
||||||
<a href="admin/users" class="navbar-page-btn">
|
<a href="admin/users" class="navbar-page-btn">
|
||||||
<i class="icon-gf icon-gf-users"></i>
|
<i class="icon-gf icon-gf-users"></i>
|
||||||
Users
|
Users
|
||||||
</a>
|
</a>
|
||||||
</navbar>
|
</navbar>
|
||||||
|
|
||||||
<div class="page-container">
|
<div class="page-container">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1>Users</h1>
|
<h1>Users</h1>
|
||||||
|
|
||||||
<a class="btn btn-success" href="admin/users/create">
|
<a class="btn btn-success" href="admin/users/create">
|
||||||
<i class="fa fa-plus"></i>
|
<i class="fa fa-plus"></i>
|
||||||
Add new user
|
Add new user
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="admin-list-table">
|
||||||
|
<table class="filter-table form-inline">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Id</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Login</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th style="white-space: nowrap">Grafana Admin</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr ng-repeat="user in ctrl.users">
|
||||||
|
<td>{{user.id}}</td>
|
||||||
|
<td>{{user.name}}</td>
|
||||||
|
<td>{{user.login}}</td>
|
||||||
|
<td>{{user.email}}</td>
|
||||||
|
<td>{{user.isAdmin}}</td>
|
||||||
|
<td class="text-right">
|
||||||
|
<a href="admin/users/edit/{{user.id}}" class="btn btn-inverse btn-small">
|
||||||
|
<i class="fa fa-edit"></i>
|
||||||
|
Edit
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a ng-click="ctrl.deleteUser(user)" class="btn btn-danger btn-small">
|
||||||
|
<i class="fa fa-remove"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
|
||||||
<table class="filter-table form-inline">
|
</table>
|
||||||
<thead>
|
</div>
|
||||||
<tr>
|
|
||||||
<th>Id</th>
|
<div class="admin-list-paging" ng-if="ctrl.showPaging">
|
||||||
<th>Name</th>
|
<ol>
|
||||||
<th>Login</th>
|
<li ng-repeat="page in ctrl.pages">
|
||||||
<th>Email</th>
|
<button
|
||||||
<th style="white-space: nowrap">Grafana Admin</th>
|
class="btn btn-small"
|
||||||
<th></th>
|
ng-class="{'btn-secondary': page.current, 'btn-inverse': !page.current}"
|
||||||
</tr>
|
ng-click="ctrl.navigateToPage(page)">{{page.page}}</button>
|
||||||
</thead>
|
</li>
|
||||||
<tbody>
|
</ol>
|
||||||
<tr ng-repeat="user in users">
|
</div>
|
||||||
<td>{{user.id}}</td>
|
|
||||||
<td>{{user.name}}</td>
|
|
||||||
<td>{{user.login}}</td>
|
|
||||||
<td>{{user.email}}</td>
|
|
||||||
<td>{{user.isAdmin}}</td>
|
|
||||||
<td class="text-right">
|
|
||||||
<a href="admin/users/edit/{{user.id}}" class="btn btn-inverse btn-small">
|
|
||||||
<i class="fa fa-edit"></i>
|
|
||||||
Edit
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a ng-click="deleteUser(user)" class="btn btn-danger btn-small">
|
|
||||||
<i class="fa fa-remove"></i>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,58 +1,17 @@
|
|||||||
{
|
{
|
||||||
"revision": 6,
|
|
||||||
"title": "TestData - Graph Panel Last 1h",
|
|
||||||
"tags": [
|
|
||||||
"grafana-test"
|
|
||||||
],
|
|
||||||
"style": "dark",
|
|
||||||
"timezone": "browser",
|
|
||||||
"editable": true,
|
|
||||||
"sharedCrosshair": false,
|
|
||||||
"hideControls": false,
|
|
||||||
"time": {
|
|
||||||
"from": "2016-11-16T16:59:38.294Z",
|
|
||||||
"to": "2016-11-16T17:09:01.532Z"
|
|
||||||
},
|
|
||||||
"timepicker": {
|
|
||||||
"refresh_intervals": [
|
|
||||||
"5s",
|
|
||||||
"10s",
|
|
||||||
"30s",
|
|
||||||
"1m",
|
|
||||||
"5m",
|
|
||||||
"15m",
|
|
||||||
"30m",
|
|
||||||
"1h",
|
|
||||||
"2h",
|
|
||||||
"1d"
|
|
||||||
],
|
|
||||||
"time_options": [
|
|
||||||
"5m",
|
|
||||||
"15m",
|
|
||||||
"1h",
|
|
||||||
"6h",
|
|
||||||
"12h",
|
|
||||||
"24h",
|
|
||||||
"2d",
|
|
||||||
"7d",
|
|
||||||
"30d"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"templating": {
|
|
||||||
"list": []
|
|
||||||
},
|
|
||||||
"annotations": {
|
"annotations": {
|
||||||
"list": []
|
"list": []
|
||||||
},
|
},
|
||||||
"refresh": false,
|
"editable": true,
|
||||||
"schemaVersion": 13,
|
|
||||||
"version": 4,
|
|
||||||
"links": [],
|
|
||||||
"gnetId": null,
|
"gnetId": null,
|
||||||
|
"graphTooltip": 0,
|
||||||
|
"hideControls": false,
|
||||||
|
"links": [],
|
||||||
|
"refresh": false,
|
||||||
|
"revision": 8,
|
||||||
"rows": [
|
"rows": [
|
||||||
{
|
{
|
||||||
"collapse": false,
|
"collapse": false,
|
||||||
"editable": true,
|
|
||||||
"height": "250px",
|
"height": "250px",
|
||||||
"panels": [
|
"panels": [
|
||||||
{
|
{
|
||||||
@@ -63,7 +22,6 @@
|
|||||||
"error": false,
|
"error": false,
|
||||||
"fill": 1,
|
"fill": 1,
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"isNew": true,
|
|
||||||
"legend": {
|
"legend": {
|
||||||
"avg": false,
|
"avg": false,
|
||||||
"current": false,
|
"current": false,
|
||||||
@@ -137,7 +95,6 @@
|
|||||||
"error": false,
|
"error": false,
|
||||||
"fill": 1,
|
"fill": 1,
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"isNew": true,
|
|
||||||
"legend": {
|
"legend": {
|
||||||
"avg": false,
|
"avg": false,
|
||||||
"current": false,
|
"current": false,
|
||||||
@@ -211,7 +168,6 @@
|
|||||||
"error": false,
|
"error": false,
|
||||||
"fill": 1,
|
"fill": 1,
|
||||||
"id": 3,
|
"id": 3,
|
||||||
"isNew": true,
|
|
||||||
"legend": {
|
"legend": {
|
||||||
"avg": false,
|
"avg": false,
|
||||||
"current": false,
|
"current": false,
|
||||||
@@ -278,17 +234,15 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "New row",
|
|
||||||
"showTitle": false,
|
|
||||||
"titleSize": "h6",
|
|
||||||
"isNew": false,
|
|
||||||
"repeat": null,
|
"repeat": null,
|
||||||
|
"repeatIteration": null,
|
||||||
"repeatRowId": null,
|
"repeatRowId": null,
|
||||||
"repeatIteration": null
|
"showTitle": false,
|
||||||
|
"title": "New row",
|
||||||
|
"titleSize": "h6"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"collapse": false,
|
"collapse": false,
|
||||||
"editable": true,
|
|
||||||
"height": "250px",
|
"height": "250px",
|
||||||
"panels": [
|
"panels": [
|
||||||
{
|
{
|
||||||
@@ -299,7 +253,6 @@
|
|||||||
"error": false,
|
"error": false,
|
||||||
"fill": 1,
|
"fill": 1,
|
||||||
"id": 4,
|
"id": 4,
|
||||||
"isNew": true,
|
|
||||||
"legend": {
|
"legend": {
|
||||||
"avg": false,
|
"avg": false,
|
||||||
"current": false,
|
"current": false,
|
||||||
@@ -370,7 +323,6 @@
|
|||||||
"editable": true,
|
"editable": true,
|
||||||
"error": false,
|
"error": false,
|
||||||
"id": 6,
|
"id": 6,
|
||||||
"isNew": true,
|
|
||||||
"links": [],
|
"links": [],
|
||||||
"mode": "markdown",
|
"mode": "markdown",
|
||||||
"span": 4,
|
"span": 4,
|
||||||
@@ -378,17 +330,15 @@
|
|||||||
"type": "text"
|
"type": "text"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "New row",
|
|
||||||
"showTitle": false,
|
|
||||||
"titleSize": "h6",
|
|
||||||
"isNew": false,
|
|
||||||
"repeat": null,
|
"repeat": null,
|
||||||
|
"repeatIteration": null,
|
||||||
"repeatRowId": null,
|
"repeatRowId": null,
|
||||||
"repeatIteration": null
|
"showTitle": false,
|
||||||
|
"title": "New row",
|
||||||
|
"titleSize": "h6"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"collapse": false,
|
"collapse": false,
|
||||||
"editable": true,
|
|
||||||
"height": 336,
|
"height": 336,
|
||||||
"panels": [
|
"panels": [
|
||||||
{
|
{
|
||||||
@@ -399,7 +349,6 @@
|
|||||||
"error": false,
|
"error": false,
|
||||||
"fill": 1,
|
"fill": 1,
|
||||||
"id": 5,
|
"id": 5,
|
||||||
"isNew": true,
|
|
||||||
"legend": {
|
"legend": {
|
||||||
"avg": false,
|
"avg": false,
|
||||||
"current": false,
|
"current": false,
|
||||||
@@ -481,7 +430,6 @@
|
|||||||
"editable": true,
|
"editable": true,
|
||||||
"error": false,
|
"error": false,
|
||||||
"id": 7,
|
"id": 7,
|
||||||
"isNew": true,
|
|
||||||
"links": [],
|
"links": [],
|
||||||
"mode": "markdown",
|
"mode": "markdown",
|
||||||
"span": 4,
|
"span": 4,
|
||||||
@@ -489,17 +437,15 @@
|
|||||||
"type": "text"
|
"type": "text"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "New row",
|
|
||||||
"showTitle": false,
|
|
||||||
"titleSize": "h6",
|
|
||||||
"isNew": false,
|
|
||||||
"repeat": null,
|
"repeat": null,
|
||||||
|
"repeatIteration": null,
|
||||||
"repeatRowId": null,
|
"repeatRowId": null,
|
||||||
"repeatIteration": null
|
"showTitle": false,
|
||||||
|
"title": "New row",
|
||||||
|
"titleSize": "h6"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"collapse": false,
|
"collapse": false,
|
||||||
"editable": true,
|
|
||||||
"height": "250px",
|
"height": "250px",
|
||||||
"panels": [
|
"panels": [
|
||||||
{
|
{
|
||||||
@@ -510,7 +456,6 @@
|
|||||||
"error": false,
|
"error": false,
|
||||||
"fill": 1,
|
"fill": 1,
|
||||||
"id": 8,
|
"id": 8,
|
||||||
"isNew": true,
|
|
||||||
"legend": {
|
"legend": {
|
||||||
"avg": false,
|
"avg": false,
|
||||||
"current": false,
|
"current": false,
|
||||||
@@ -584,7 +529,6 @@
|
|||||||
"error": false,
|
"error": false,
|
||||||
"fill": 1,
|
"fill": 1,
|
||||||
"id": 10,
|
"id": 10,
|
||||||
"isNew": true,
|
|
||||||
"legend": {
|
"legend": {
|
||||||
"avg": false,
|
"avg": false,
|
||||||
"current": false,
|
"current": false,
|
||||||
@@ -655,7 +599,6 @@
|
|||||||
"editable": true,
|
"editable": true,
|
||||||
"error": false,
|
"error": false,
|
||||||
"id": 13,
|
"id": 13,
|
||||||
"isNew": true,
|
|
||||||
"links": [],
|
"links": [],
|
||||||
"mode": "markdown",
|
"mode": "markdown",
|
||||||
"span": 4,
|
"span": 4,
|
||||||
@@ -663,17 +606,16 @@
|
|||||||
"type": "text"
|
"type": "text"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"title": "New row",
|
|
||||||
"showTitle": false,
|
|
||||||
"titleSize": "h6",
|
|
||||||
"isNew": false,
|
|
||||||
"repeat": null,
|
"repeat": null,
|
||||||
|
"repeatIteration": null,
|
||||||
"repeatRowId": null,
|
"repeatRowId": null,
|
||||||
"repeatIteration": null
|
"showTitle": false,
|
||||||
|
"title": "New row",
|
||||||
|
"titleSize": "h6"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"isNew": false,
|
"collapse": false,
|
||||||
"title": "Dashboard Row",
|
"height": 250,
|
||||||
"panels": [
|
"panels": [
|
||||||
{
|
{
|
||||||
"aliasColors": {},
|
"aliasColors": {},
|
||||||
@@ -683,7 +625,6 @@
|
|||||||
"error": false,
|
"error": false,
|
||||||
"fill": 1,
|
"fill": 1,
|
||||||
"id": 9,
|
"id": 9,
|
||||||
"isNew": true,
|
|
||||||
"legend": {
|
"legend": {
|
||||||
"avg": false,
|
"avg": false,
|
||||||
"current": false,
|
"current": false,
|
||||||
@@ -776,7 +717,6 @@
|
|||||||
"editable": true,
|
"editable": true,
|
||||||
"error": false,
|
"error": false,
|
||||||
"id": 14,
|
"id": 14,
|
||||||
"isNew": true,
|
|
||||||
"links": [],
|
"links": [],
|
||||||
"mode": "markdown",
|
"mode": "markdown",
|
||||||
"span": 4,
|
"span": 4,
|
||||||
@@ -784,17 +724,16 @@
|
|||||||
"type": "text"
|
"type": "text"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"showTitle": false,
|
|
||||||
"titleSize": "h6",
|
|
||||||
"height": 250,
|
|
||||||
"repeat": null,
|
"repeat": null,
|
||||||
"repeatRowId": null,
|
|
||||||
"repeatIteration": null,
|
"repeatIteration": null,
|
||||||
"collapse": false
|
"repeatRowId": null,
|
||||||
|
"showTitle": false,
|
||||||
|
"title": "Dashboard Row",
|
||||||
|
"titleSize": "h6"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"isNew": false,
|
"collapse": false,
|
||||||
"title": "Dashboard Row",
|
"height": 250,
|
||||||
"panels": [
|
"panels": [
|
||||||
{
|
{
|
||||||
"aliasColors": {},
|
"aliasColors": {},
|
||||||
@@ -804,7 +743,6 @@
|
|||||||
"error": false,
|
"error": false,
|
||||||
"fill": 1,
|
"fill": 1,
|
||||||
"id": 12,
|
"id": 12,
|
||||||
"isNew": true,
|
|
||||||
"legend": {
|
"legend": {
|
||||||
"avg": false,
|
"avg": false,
|
||||||
"current": false,
|
"current": false,
|
||||||
@@ -833,12 +771,12 @@
|
|||||||
"steppedLine": false,
|
"steppedLine": false,
|
||||||
"targets": [
|
"targets": [
|
||||||
{
|
{
|
||||||
|
"alias": "",
|
||||||
"hide": false,
|
"hide": false,
|
||||||
"refId": "B",
|
"refId": "B",
|
||||||
"scenarioId": "csv_metric_values",
|
"scenarioId": "csv_metric_values",
|
||||||
"stringInput": "1,20,40,null,null,null,null,null,null,100,10,10,20,30,40,10",
|
"stringInput": "1,20,40,null,null,null,null,null,null,100,10,10,20,30,40,10",
|
||||||
"target": "",
|
"target": ""
|
||||||
"alias": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"alias": "",
|
"alias": "",
|
||||||
@@ -898,7 +836,6 @@
|
|||||||
"editable": true,
|
"editable": true,
|
||||||
"error": false,
|
"error": false,
|
||||||
"id": 15,
|
"id": 15,
|
||||||
"isNew": true,
|
|
||||||
"links": [],
|
"links": [],
|
||||||
"mode": "markdown",
|
"mode": "markdown",
|
||||||
"span": 4,
|
"span": 4,
|
||||||
@@ -906,13 +843,606 @@
|
|||||||
"type": "text"
|
"type": "text"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"showTitle": false,
|
|
||||||
"titleSize": "h6",
|
|
||||||
"height": 250,
|
|
||||||
"repeat": null,
|
"repeat": null,
|
||||||
"repeatRowId": null,
|
|
||||||
"repeatIteration": null,
|
"repeatIteration": null,
|
||||||
"collapse": false
|
"repeatRowId": null,
|
||||||
|
"showTitle": false,
|
||||||
|
"title": "Dashboard Row",
|
||||||
|
"titleSize": "h6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapse": false,
|
||||||
|
"height": 250,
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"aliasColors": {},
|
||||||
|
"bars": false,
|
||||||
|
"datasource": "Grafana TestData",
|
||||||
|
"decimals": 3,
|
||||||
|
"fill": 1,
|
||||||
|
"id": 20,
|
||||||
|
"legend": {
|
||||||
|
"alignAsTable": true,
|
||||||
|
"avg": true,
|
||||||
|
"current": true,
|
||||||
|
"max": true,
|
||||||
|
"min": true,
|
||||||
|
"show": true,
|
||||||
|
"total": true,
|
||||||
|
"values": true
|
||||||
|
},
|
||||||
|
"lines": true,
|
||||||
|
"linewidth": 1,
|
||||||
|
"links": [],
|
||||||
|
"nullPointMode": "null",
|
||||||
|
"percentage": false,
|
||||||
|
"pointradius": 5,
|
||||||
|
"points": false,
|
||||||
|
"renderer": "flot",
|
||||||
|
"seriesOverrides": [],
|
||||||
|
"span": 12,
|
||||||
|
"stack": false,
|
||||||
|
"steppedLine": false,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thresholds": [],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "Legend Table Single Series Should Take Minium Height",
|
||||||
|
"tooltip": {
|
||||||
|
"shared": true,
|
||||||
|
"sort": 0,
|
||||||
|
"value_type": "individual"
|
||||||
|
},
|
||||||
|
"type": "graph",
|
||||||
|
"xaxis": {
|
||||||
|
"mode": "time",
|
||||||
|
"name": null,
|
||||||
|
"show": true,
|
||||||
|
"values": []
|
||||||
|
},
|
||||||
|
"yaxes": [
|
||||||
|
{
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"repeat": null,
|
||||||
|
"repeatIteration": null,
|
||||||
|
"repeatRowId": null,
|
||||||
|
"showTitle": false,
|
||||||
|
"title": "Dashboard Row",
|
||||||
|
"titleSize": "h6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapse": false,
|
||||||
|
"height": 250,
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"aliasColors": {},
|
||||||
|
"bars": false,
|
||||||
|
"datasource": "Grafana TestData",
|
||||||
|
"decimals": 3,
|
||||||
|
"fill": 1,
|
||||||
|
"id": 16,
|
||||||
|
"legend": {
|
||||||
|
"alignAsTable": true,
|
||||||
|
"avg": true,
|
||||||
|
"current": true,
|
||||||
|
"max": true,
|
||||||
|
"min": true,
|
||||||
|
"show": true,
|
||||||
|
"total": true,
|
||||||
|
"values": true
|
||||||
|
},
|
||||||
|
"lines": true,
|
||||||
|
"linewidth": 1,
|
||||||
|
"links": [],
|
||||||
|
"nullPointMode": "null",
|
||||||
|
"percentage": false,
|
||||||
|
"pointradius": 5,
|
||||||
|
"points": false,
|
||||||
|
"renderer": "flot",
|
||||||
|
"seriesOverrides": [],
|
||||||
|
"span": 6,
|
||||||
|
"stack": false,
|
||||||
|
"steppedLine": false,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "B",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "C",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "D",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thresholds": [],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "Legend Table No Scroll Visible",
|
||||||
|
"tooltip": {
|
||||||
|
"shared": true,
|
||||||
|
"sort": 0,
|
||||||
|
"value_type": "individual"
|
||||||
|
},
|
||||||
|
"type": "graph",
|
||||||
|
"xaxis": {
|
||||||
|
"mode": "time",
|
||||||
|
"name": null,
|
||||||
|
"show": true,
|
||||||
|
"values": []
|
||||||
|
},
|
||||||
|
"yaxes": [
|
||||||
|
{
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aliasColors": {},
|
||||||
|
"bars": false,
|
||||||
|
"datasource": "Grafana TestData",
|
||||||
|
"decimals": 3,
|
||||||
|
"fill": 1,
|
||||||
|
"id": 17,
|
||||||
|
"legend": {
|
||||||
|
"alignAsTable": true,
|
||||||
|
"avg": true,
|
||||||
|
"current": true,
|
||||||
|
"max": true,
|
||||||
|
"min": true,
|
||||||
|
"show": true,
|
||||||
|
"total": true,
|
||||||
|
"values": true
|
||||||
|
},
|
||||||
|
"lines": true,
|
||||||
|
"linewidth": 1,
|
||||||
|
"links": [],
|
||||||
|
"nullPointMode": "null",
|
||||||
|
"percentage": false,
|
||||||
|
"pointradius": 5,
|
||||||
|
"points": false,
|
||||||
|
"renderer": "flot",
|
||||||
|
"seriesOverrides": [],
|
||||||
|
"span": 6,
|
||||||
|
"stack": false,
|
||||||
|
"steppedLine": false,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "B",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "C",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "D",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "E",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "F",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "G",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "H",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "I",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "J",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thresholds": [],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "Legend Table Should Scroll",
|
||||||
|
"tooltip": {
|
||||||
|
"shared": true,
|
||||||
|
"sort": 0,
|
||||||
|
"value_type": "individual"
|
||||||
|
},
|
||||||
|
"type": "graph",
|
||||||
|
"xaxis": {
|
||||||
|
"mode": "time",
|
||||||
|
"name": null,
|
||||||
|
"show": true,
|
||||||
|
"values": []
|
||||||
|
},
|
||||||
|
"yaxes": [
|
||||||
|
{
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"repeat": null,
|
||||||
|
"repeatIteration": null,
|
||||||
|
"repeatRowId": null,
|
||||||
|
"showTitle": false,
|
||||||
|
"title": "Dashboard Row",
|
||||||
|
"titleSize": "h6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"collapse": false,
|
||||||
|
"height": 250,
|
||||||
|
"panels": [
|
||||||
|
{
|
||||||
|
"aliasColors": {},
|
||||||
|
"bars": false,
|
||||||
|
"datasource": "Grafana TestData",
|
||||||
|
"decimals": 3,
|
||||||
|
"fill": 1,
|
||||||
|
"id": 18,
|
||||||
|
"legend": {
|
||||||
|
"alignAsTable": true,
|
||||||
|
"avg": true,
|
||||||
|
"current": true,
|
||||||
|
"max": true,
|
||||||
|
"min": true,
|
||||||
|
"rightSide": true,
|
||||||
|
"show": true,
|
||||||
|
"total": true,
|
||||||
|
"values": true
|
||||||
|
},
|
||||||
|
"lines": true,
|
||||||
|
"linewidth": 1,
|
||||||
|
"links": [],
|
||||||
|
"nullPointMode": "null",
|
||||||
|
"percentage": false,
|
||||||
|
"pointradius": 5,
|
||||||
|
"points": false,
|
||||||
|
"renderer": "flot",
|
||||||
|
"seriesOverrides": [],
|
||||||
|
"span": 6,
|
||||||
|
"stack": false,
|
||||||
|
"steppedLine": false,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "B",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "C",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "D",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thresholds": [],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "Legend Table No Scroll Visible",
|
||||||
|
"tooltip": {
|
||||||
|
"shared": true,
|
||||||
|
"sort": 0,
|
||||||
|
"value_type": "individual"
|
||||||
|
},
|
||||||
|
"type": "graph",
|
||||||
|
"xaxis": {
|
||||||
|
"mode": "time",
|
||||||
|
"name": null,
|
||||||
|
"show": true,
|
||||||
|
"values": []
|
||||||
|
},
|
||||||
|
"yaxes": [
|
||||||
|
{
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"aliasColors": {},
|
||||||
|
"bars": false,
|
||||||
|
"datasource": "Grafana TestData",
|
||||||
|
"decimals": 3,
|
||||||
|
"fill": 1,
|
||||||
|
"id": 19,
|
||||||
|
"legend": {
|
||||||
|
"alignAsTable": true,
|
||||||
|
"avg": true,
|
||||||
|
"current": true,
|
||||||
|
"max": true,
|
||||||
|
"min": true,
|
||||||
|
"rightSide": true,
|
||||||
|
"show": true,
|
||||||
|
"total": true,
|
||||||
|
"values": true
|
||||||
|
},
|
||||||
|
"lines": true,
|
||||||
|
"linewidth": 1,
|
||||||
|
"links": [],
|
||||||
|
"nullPointMode": "null",
|
||||||
|
"percentage": false,
|
||||||
|
"pointradius": 5,
|
||||||
|
"points": false,
|
||||||
|
"renderer": "flot",
|
||||||
|
"seriesOverrides": [],
|
||||||
|
"span": 6,
|
||||||
|
"stack": false,
|
||||||
|
"steppedLine": false,
|
||||||
|
"targets": [
|
||||||
|
{
|
||||||
|
"refId": "A",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "B",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "C",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "D",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "E",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "F",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "G",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "H",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "I",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "J",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "K",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"refId": "L",
|
||||||
|
"scenarioId": "csv_metric_values",
|
||||||
|
"stringInput": "1,20,90,30,5,0",
|
||||||
|
"target": ""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thresholds": [],
|
||||||
|
"timeFrom": null,
|
||||||
|
"timeShift": null,
|
||||||
|
"title": "Legend Table No Scroll Visible",
|
||||||
|
"tooltip": {
|
||||||
|
"shared": true,
|
||||||
|
"sort": 0,
|
||||||
|
"value_type": "individual"
|
||||||
|
},
|
||||||
|
"type": "graph",
|
||||||
|
"xaxis": {
|
||||||
|
"mode": "time",
|
||||||
|
"name": null,
|
||||||
|
"show": true,
|
||||||
|
"values": []
|
||||||
|
},
|
||||||
|
"yaxes": [
|
||||||
|
{
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"format": "short",
|
||||||
|
"label": null,
|
||||||
|
"logBase": 1,
|
||||||
|
"max": null,
|
||||||
|
"min": null,
|
||||||
|
"show": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"repeat": null,
|
||||||
|
"repeatIteration": null,
|
||||||
|
"repeatRowId": null,
|
||||||
|
"showTitle": false,
|
||||||
|
"title": "Dashboard Row",
|
||||||
|
"titleSize": "h6"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"schemaVersion": 14,
|
||||||
|
"style": "dark",
|
||||||
|
"tags": [
|
||||||
|
"grafana-test"
|
||||||
|
],
|
||||||
|
"templating": {
|
||||||
|
"list": []
|
||||||
|
},
|
||||||
|
"time": {
|
||||||
|
"from": "now-1h",
|
||||||
|
"to": "now"
|
||||||
|
},
|
||||||
|
"timepicker": {
|
||||||
|
"refresh_intervals": [
|
||||||
|
"5s",
|
||||||
|
"10s",
|
||||||
|
"30s",
|
||||||
|
"1m",
|
||||||
|
"5m",
|
||||||
|
"15m",
|
||||||
|
"30m",
|
||||||
|
"1h",
|
||||||
|
"2h",
|
||||||
|
"1d"
|
||||||
|
],
|
||||||
|
"time_options": [
|
||||||
|
"5m",
|
||||||
|
"15m",
|
||||||
|
"1h",
|
||||||
|
"6h",
|
||||||
|
"12h",
|
||||||
|
"24h",
|
||||||
|
"2d",
|
||||||
|
"7d",
|
||||||
|
"30d"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"timezone": "browser",
|
||||||
|
"title": "TestData - Graph Panel Last 1h",
|
||||||
|
"version": 2
|
||||||
}
|
}
|
||||||
|
|||||||
2
public/app/plugins/app/testdata/plugin.json
vendored
2
public/app/plugins/app/testdata/plugin.json
vendored
@@ -9,7 +9,7 @@
|
|||||||
"name": "Grafana Project",
|
"name": "Grafana Project",
|
||||||
"url": "http://grafana.org"
|
"url": "http://grafana.org"
|
||||||
},
|
},
|
||||||
"version": "1.0.15",
|
"version": "1.0.17",
|
||||||
"updated": "2016-09-26"
|
"updated": "2016-09-26"
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ function (angular, _, $) {
|
|||||||
|
|
||||||
$container.toggleClass('graph-legend-table', panel.legend.alignAsTable === true);
|
$container.toggleClass('graph-legend-table', panel.legend.alignAsTable === true);
|
||||||
|
|
||||||
|
var tableHeaderElem;
|
||||||
if (panel.legend.alignAsTable) {
|
if (panel.legend.alignAsTable) {
|
||||||
var header = '<tr>';
|
var header = '<tr>';
|
||||||
header += '<th colspan="2" style="text-align:left"></th>';
|
header += '<th colspan="2" style="text-align:left"></th>';
|
||||||
@@ -135,7 +136,7 @@ function (angular, _, $) {
|
|||||||
header += getTableHeaderHtml('total');
|
header += getTableHeaderHtml('total');
|
||||||
}
|
}
|
||||||
header += '</tr>';
|
header += '</tr>';
|
||||||
$container.append($(header));
|
tableHeaderElem = $(header);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (panel.legend.sort) {
|
if (panel.legend.sort) {
|
||||||
@@ -148,6 +149,8 @@ function (angular, _, $) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var seriesShown = 0;
|
var seriesShown = 0;
|
||||||
|
var seriesElements = [];
|
||||||
|
|
||||||
for (i = 0; i < seriesList.length; i++) {
|
for (i = 0; i < seriesList.length; i++) {
|
||||||
var series = seriesList[i];
|
var series = seriesList[i];
|
||||||
|
|
||||||
@@ -156,6 +159,7 @@ function (angular, _, $) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var html = '<div class="graph-legend-series';
|
var html = '<div class="graph-legend-series';
|
||||||
|
|
||||||
if (series.yaxis === 2) { html += ' graph-legend-series--right-y'; }
|
if (series.yaxis === 2) { html += ' graph-legend-series--right-y'; }
|
||||||
if (ctrl.hiddenSeries[series.alias]) { html += ' graph-legend-series-hidden'; }
|
if (ctrl.hiddenSeries[series.alias]) { html += ' graph-legend-series-hidden'; }
|
||||||
html += '" data-series-index="' + i + '">';
|
html += '" data-series-index="' + i + '">';
|
||||||
@@ -180,7 +184,7 @@ function (angular, _, $) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
$container.append($(html));
|
seriesElements.push($(html));
|
||||||
|
|
||||||
seriesShown++;
|
seriesShown++;
|
||||||
}
|
}
|
||||||
@@ -193,9 +197,13 @@ function (angular, _, $) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var topPadding = 6;
|
var topPadding = 6;
|
||||||
$container.css("max-height", maxHeight - topPadding);
|
var tbodyElem = $('<tbody></tbody>');
|
||||||
|
tbodyElem.css("max-height", maxHeight - topPadding);
|
||||||
|
tbodyElem.append(tableHeaderElem);
|
||||||
|
tbodyElem.append(seriesElements);
|
||||||
|
$container.append(tbodyElem);
|
||||||
} else {
|
} else {
|
||||||
$container.css("max-height", "");
|
$container.append(seriesElements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,14 +153,16 @@ describe('when transforming time series table', () => {
|
|||||||
|
|
||||||
describe('Annnotations', () => {
|
describe('Annnotations', () => {
|
||||||
var panel = {transform: 'annotations'};
|
var panel = {transform: 'annotations'};
|
||||||
var rawData = [
|
var rawData = {
|
||||||
{
|
annotations: [
|
||||||
min: 1000,
|
{
|
||||||
text: 'hej',
|
min: 1000,
|
||||||
tags: ['tags', 'asd'],
|
text: 'hej',
|
||||||
title: 'title',
|
tags: ['tags', 'asd'],
|
||||||
}
|
title: 'title',
|
||||||
];
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
table = transformDataToTable(rawData, panel);
|
table = transformDataToTable(rawData, panel);
|
||||||
|
|||||||
@@ -125,12 +125,12 @@ transformers['annotations'] = {
|
|||||||
model.columns.push({text: 'Text'});
|
model.columns.push({text: 'Text'});
|
||||||
model.columns.push({text: 'Tags'});
|
model.columns.push({text: 'Tags'});
|
||||||
|
|
||||||
if (!data || data.length === 0) {
|
if (!data || !data.annotations || data.annotations.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < data.length; i++) {
|
for (var i = 0; i < data.annotations.length; i++) {
|
||||||
var evt = data[i];
|
var evt = data.annotations[i];
|
||||||
model.rows.push([evt.min, evt.title, evt.text, evt.tags]);
|
model.rows.push([evt.min, evt.title, evt.text, evt.tags]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,9 +85,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.graph-legend-table {
|
.graph-legend-table {
|
||||||
overflow-y: auto;
|
tbody {
|
||||||
overflow-x: hidden;
|
display: block;
|
||||||
display: table;
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
.graph-legend-series {
|
.graph-legend-series {
|
||||||
display: table-row;
|
display: table-row;
|
||||||
|
|||||||
@@ -8,3 +8,15 @@ td.admin-settings-key {
|
|||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.admin-list-table {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-list-paging {
|
||||||
|
float: right;
|
||||||
|
li {
|
||||||
|
display: inline-block;
|
||||||
|
padding-left: 10px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
58
public/test/specs/datasource_srv_specs.js
Normal file
58
public/test/specs/datasource_srv_specs.js
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
define([
|
||||||
|
'app/core/config',
|
||||||
|
'app/core/services/datasource_srv'
|
||||||
|
], function(config) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
describe('datasource_srv', function() {
|
||||||
|
var _datasourceSrv;
|
||||||
|
var metricSources;
|
||||||
|
var templateSrv = {};
|
||||||
|
|
||||||
|
beforeEach(module('grafana.core'));
|
||||||
|
beforeEach(module(function($provide) {
|
||||||
|
$provide.value('templateSrv', templateSrv);
|
||||||
|
}));
|
||||||
|
beforeEach(module('grafana.services'));
|
||||||
|
beforeEach(inject(function(datasourceSrv) {
|
||||||
|
_datasourceSrv = datasourceSrv;
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('when loading metric sources', function() {
|
||||||
|
var unsortedDatasources = {
|
||||||
|
'mmm': {
|
||||||
|
type: 'test-db',
|
||||||
|
meta: { metrics: {m: 1} }
|
||||||
|
},
|
||||||
|
'--Mixed--': {
|
||||||
|
type: 'test-db',
|
||||||
|
meta: {builtIn: true, metrics: {m: 1} }
|
||||||
|
},
|
||||||
|
'ZZZ': {
|
||||||
|
type: 'test-db',
|
||||||
|
meta: {metrics: {m: 1} }
|
||||||
|
},
|
||||||
|
'aaa': {
|
||||||
|
type: 'test-db',
|
||||||
|
meta: { metrics: {m: 1} }
|
||||||
|
},
|
||||||
|
'BBB': {
|
||||||
|
type: 'test-db',
|
||||||
|
meta: { metrics: {m: 1} }
|
||||||
|
},
|
||||||
|
};
|
||||||
|
beforeEach(function() {
|
||||||
|
config.datasources = unsortedDatasources;
|
||||||
|
metricSources = _datasourceSrv.getMetricSources({skipVariables: true});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return a list of sources sorted case insensitively with builtin sources last', function() {
|
||||||
|
expect(metricSources[0].name).to.be('aaa');
|
||||||
|
expect(metricSources[1].name).to.be('BBB');
|
||||||
|
expect(metricSources[2].name).to.be('mmm');
|
||||||
|
expect(metricSources[3].name).to.be('ZZZ');
|
||||||
|
expect(metricSources[4].name).to.be('--Mixed--');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -2,9 +2,31 @@
|
|||||||
|
|
||||||
_circle_token=$1
|
_circle_token=$1
|
||||||
|
|
||||||
trigger_build_url=https://circleci.com/api/v1/project/grafana/grafana-packer/tree/master?circle-token=${_circle_token}
|
trigger_build_url=https://circleci.com/api/v1/project/grafana/grafana-packer/tree/v4.1.x?circle-token=${_circle_token}
|
||||||
|
|
||||||
|
post_data=$(cat <<EOF
|
||||||
|
{
|
||||||
|
"build_parameters": {
|
||||||
|
"BRANCH": "v4.1.x"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
)
|
||||||
|
|
||||||
|
echo ${post_data}
|
||||||
|
|
||||||
curl \
|
curl \
|
||||||
--header "Accept: application/json" \
|
--header "Accept: application/json" \
|
||||||
--header "Content-Type: application/json" \
|
--header "Content-Type: application/json" \
|
||||||
--request POST ${trigger_build_url}
|
--data "${post_data}" \
|
||||||
|
--request POST ${trigger_build_url}
|
||||||
|
|
||||||
|
#curl \
|
||||||
|
#--header "Accept: application/json" \
|
||||||
|
#--header "Content-Type: application/json" \
|
||||||
|
#-X POST -d '{ "build_parameters": { "BRANCH": "v4.1.x"} }' \
|
||||||
|
#${trigger_build_url}
|
||||||
|
|
||||||
|
#--request POST ${trigger_build_url}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ _token=$1
|
|||||||
curl \
|
curl \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-H "Authorization: Bearer ${_token}" \
|
-H "Authorization: Bearer ${_token}" \
|
||||||
-X POST -d '{ "accountName": "Torkeldegaard", "projectSlug": "grafana","branch": "master","environmentVariables": {}}' \
|
-X POST -d '{ "accountName": "Torkeldegaard", "projectSlug": "grafana","branch": "v4.1.x","environmentVariables": {}}' \
|
||||||
https://ci.appveyor.com/api/builds
|
https://ci.appveyor.com/api/builds
|
||||||
|
|||||||
Reference in New Issue
Block a user