Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
668cb3c1
Commit
668cb3c1
authored
Aug 09, 2017
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'v4.4.x'
parents
eac0d30e
e8a20643
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
248 additions
and
83 deletions
+248
-83
pkg/metrics/publish.go
+11
-9
pkg/middleware/middleware.go
+10
-1
pkg/models/org_user.go
+7
-5
pkg/models/stats.go
+17
-14
pkg/models/user.go
+20
-7
pkg/services/sqlstore/migrations/user_mig.go
+4
-0
pkg/services/sqlstore/org_users.go
+11
-3
pkg/services/sqlstore/sqlstore.go
+1
-1
pkg/services/sqlstore/stats.go
+35
-18
pkg/services/sqlstore/user.go
+56
-14
pkg/util/strings.go
+34
-0
pkg/util/strings_test.go
+13
-0
public/app/features/admin/partials/stats.html
+13
-9
public/app/features/admin/partials/users.html
+11
-2
public/app/features/org/partials/orgUsers.html
+5
-0
No files found.
pkg/metrics/publish.go
View file @
668cb3c1
...
...
@@ -67,10 +67,10 @@ func updateTotalStats() {
return
}
M_StatTotal_Dashboards
.
Update
(
statsQuery
.
Result
.
Dashboard
Count
)
M_StatTotal_Users
.
Update
(
statsQuery
.
Result
.
User
Count
)
M_StatTotal_Playlists
.
Update
(
statsQuery
.
Result
.
Playlist
Count
)
M_StatTotal_Orgs
.
Update
(
statsQuery
.
Result
.
Org
Count
)
M_StatTotal_Dashboards
.
Update
(
statsQuery
.
Result
.
Dashboard
s
)
M_StatTotal_Users
.
Update
(
statsQuery
.
Result
.
User
s
)
M_StatTotal_Playlists
.
Update
(
statsQuery
.
Result
.
Playlist
s
)
M_StatTotal_Orgs
.
Update
(
statsQuery
.
Result
.
Org
s
)
}
}
...
...
@@ -97,14 +97,16 @@ func sendUsageStats() {
return
}
metrics
[
"stats.dashboards.count"
]
=
statsQuery
.
Result
.
Dashboard
Count
metrics
[
"stats.users.count"
]
=
statsQuery
.
Result
.
User
Count
metrics
[
"stats.orgs.count"
]
=
statsQuery
.
Result
.
Org
Count
metrics
[
"stats.playlist.count"
]
=
statsQuery
.
Result
.
Playlist
Count
metrics
[
"stats.dashboards.count"
]
=
statsQuery
.
Result
.
Dashboard
s
metrics
[
"stats.users.count"
]
=
statsQuery
.
Result
.
User
s
metrics
[
"stats.orgs.count"
]
=
statsQuery
.
Result
.
Org
s
metrics
[
"stats.playlist.count"
]
=
statsQuery
.
Result
.
Playlist
s
metrics
[
"stats.plugins.apps.count"
]
=
len
(
plugins
.
Apps
)
metrics
[
"stats.plugins.panels.count"
]
=
len
(
plugins
.
Panels
)
metrics
[
"stats.plugins.datasources.count"
]
=
len
(
plugins
.
DataSources
)
metrics
[
"stats.alerts.count"
]
=
statsQuery
.
Result
.
AlertCount
metrics
[
"stats.alerts.count"
]
=
statsQuery
.
Result
.
Alerts
metrics
[
"stats.active_users.count"
]
=
statsQuery
.
Result
.
ActiveUsers
metrics
[
"stats.datasources.count"
]
=
statsQuery
.
Result
.
Datasources
dsStats
:=
m
.
GetDataSourceStatsQuery
{}
if
err
:=
bus
.
Dispatch
(
&
dsStats
);
err
!=
nil
{
...
...
pkg/middleware/middleware.go
View file @
668cb3c1
...
...
@@ -62,6 +62,15 @@ func GetContextHandler() macaron.Handler {
ctx
.
Data
[
"ctx"
]
=
ctx
c
.
Map
(
ctx
)
// update last seen at
// update last seen every 5min
if
ctx
.
ShouldUpdateLastSeenAt
()
{
ctx
.
Logger
.
Debug
(
"Updating last user_seen_at"
,
"user_id"
,
ctx
.
UserId
)
if
err
:=
bus
.
Dispatch
(
&
m
.
UpdateUserLastSeenAtCommand
{
UserId
:
ctx
.
UserId
});
err
!=
nil
{
ctx
.
Logger
.
Error
(
"Failed to update last_seen_at"
,
"error"
,
err
)
}
}
}
}
...
...
@@ -99,7 +108,7 @@ func initContextWithUserSessionCookie(ctx *Context, orgId int64) bool {
query
:=
m
.
GetSignedInUserQuery
{
UserId
:
userId
,
OrgId
:
orgId
}
if
err
:=
bus
.
Dispatch
(
&
query
);
err
!=
nil
{
ctx
.
Logger
.
Error
(
"Failed to get user with id"
,
"userId"
,
userId
)
ctx
.
Logger
.
Error
(
"Failed to get user with id"
,
"userId"
,
userId
,
"error"
,
err
)
return
false
}
...
...
pkg/models/org_user.go
View file @
668cb3c1
...
...
@@ -103,9 +103,11 @@ type GetOrgUsersQuery struct {
// Projections and DTOs
type
OrgUserDTO
struct
{
OrgId
int64
`json:"orgId"`
UserId
int64
`json:"userId"`
Email
string
`json:"email"`
Login
string
`json:"login"`
Role
string
`json:"role"`
OrgId
int64
`json:"orgId"`
UserId
int64
`json:"userId"`
Email
string
`json:"email"`
Login
string
`json:"login"`
Role
string
`json:"role"`
LastSeenAt
time
.
Time
`json:"lastSeenAt"`
LastSeenAtAge
string
`json:"lastSeenAtAge"`
}
pkg/models/stats.go
View file @
668cb3c1
package
models
type
SystemStats
struct
{
DashboardCount
int64
UserCount
int64
OrgCount
int64
PlaylistCount
int64
AlertCount
int64
Dashboards
int64
Datasources
int64
Users
int64
ActiveUsers
int64
Orgs
int64
Playlists
int64
Alerts
int64
}
type
DataSourceStats
struct
{
...
...
@@ -22,15 +24,16 @@ type GetDataSourceStatsQuery struct {
}
type
AdminStats
struct
{
UserCount
int
`json:"user_count"`
OrgCount
int
`json:"org_count"`
DashboardCount
int
`json:"dashboard_count"`
DbSnapshotCount
int
`json:"db_snapshot_count"`
DbTagCount
int
`json:"db_tag_count"`
DataSourceCount
int
`json:"data_source_count"`
PlaylistCount
int
`json:"playlist_count"`
StarredDbCount
int
`json:"starred_db_count"`
AlertCount
int
`json:"alert_count"`
Users
int
`json:"users"`
Orgs
int
`json:"orgs"`
Dashboards
int
`json:"dashboards"`
Snapshots
int
`json:"snapshots"`
Tags
int
`json:"tags"`
Datasources
int
`json:"datasources"`
Playlists
int
`json:"playlists"`
Stars
int
`json:"stars"`
Alerts
int
`json:"alerts"`
ActiveUsers
int
`json:"activeUsers"`
}
type
GetAdminStatsQuery
struct
{
...
...
pkg/models/user.go
View file @
668cb3c1
...
...
@@ -33,8 +33,9 @@ type User struct {
IsAdmin
bool
OrgId
int64
Created
time
.
Time
Updated
time
.
Time
Created
time
.
Time
Updated
time
.
Time
LastSeenAt
time
.
Time
}
func
(
u
*
User
)
NameOrFallback
()
string
{
...
...
@@ -127,6 +128,7 @@ type GetUserProfileQuery struct {
}
type
SearchUsersQuery
struct
{
OrgId
int64
Query
string
Page
int
Limit
int
...
...
@@ -160,6 +162,15 @@ type SignedInUser struct {
ApiKeyId
int64
IsGrafanaAdmin
bool
HelpFlags1
HelpFlags1
LastSeenAt
time
.
Time
}
func
(
u
*
SignedInUser
)
ShouldUpdateLastSeenAt
()
bool
{
return
u
.
UserId
>
0
&&
time
.
Since
(
u
.
LastSeenAt
)
>
time
.
Minute
*
5
}
type
UpdateUserLastSeenAtCommand
struct
{
UserId
int64
}
type
UserProfileDTO
struct
{
...
...
@@ -173,11 +184,13 @@ type UserProfileDTO struct {
}
type
UserSearchHitDTO
struct
{
Id
int64
`json:"id"`
Name
string
`json:"name"`
Login
string
`json:"login"`
Email
string
`json:"email"`
IsAdmin
bool
`json:"isAdmin"`
Id
int64
`json:"id"`
Name
string
`json:"name"`
Login
string
`json:"login"`
Email
string
`json:"email"`
IsAdmin
bool
`json:"isAdmin"`
LastSeenAt
time
.
Time
`json:"lastSeenAt"`
LastSeenAtAge
string
`json:"lastSeenAtAge"`
}
type
UserIdDTO
struct
{
...
...
pkg/services/sqlstore/migrations/user_mig.go
View file @
668cb3c1
...
...
@@ -103,4 +103,8 @@ func addUserMigrations(mg *Migrator) {
{
Name
:
"company"
,
Type
:
DB_NVarchar
,
Length
:
255
,
Nullable
:
true
},
{
Name
:
"theme"
,
Type
:
DB_NVarchar
,
Length
:
255
,
Nullable
:
true
},
}))
mg
.
AddMigration
(
"Add last_seen_at column to user"
,
NewAddColumnMigration
(
userV2
,
&
Column
{
Name
:
"last_seen_at"
,
Type
:
DB_DateTime
,
Nullable
:
true
,
}))
}
pkg/services/sqlstore/org_users.go
View file @
668cb3c1
...
...
@@ -6,6 +6,7 @@ import (
"github.com/grafana/grafana/pkg/bus"
m
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/util"
)
func
init
()
{
...
...
@@ -71,11 +72,18 @@ func GetOrgUsers(query *m.GetOrgUsersQuery) error {
sess
:=
x
.
Table
(
"org_user"
)
sess
.
Join
(
"INNER"
,
"user"
,
fmt
.
Sprintf
(
"org_user.user_id=%s.id"
,
x
.
Dialect
()
.
Quote
(
"user"
)))
sess
.
Where
(
"org_user.org_id=?"
,
query
.
OrgId
)
sess
.
Cols
(
"org_user.org_id"
,
"org_user.user_id"
,
"user.email"
,
"user.login"
,
"org_user.role"
)
sess
.
Cols
(
"org_user.org_id"
,
"org_user.user_id"
,
"user.email"
,
"user.login"
,
"org_user.role"
,
"user.last_seen_at"
)
sess
.
Asc
(
"user.email"
,
"user.login"
)
err
:=
sess
.
Find
(
&
query
.
Result
)
return
err
if
err
:=
sess
.
Find
(
&
query
.
Result
);
err
!=
nil
{
return
err
}
for
_
,
user
:=
range
query
.
Result
{
user
.
LastSeenAtAge
=
util
.
GetAgeString
(
user
.
LastSeenAt
)
}
return
nil
}
func
RemoveOrgUser
(
cmd
*
m
.
RemoveOrgUserCommand
)
error
{
...
...
pkg/services/sqlstore/sqlstore.go
View file @
668cb3c1
...
...
@@ -53,7 +53,7 @@ func EnsureAdminUser() {
return
}
if
statsQuery
.
Result
.
User
Count
>
0
{
if
statsQuery
.
Result
.
User
s
>
0
{
return
}
...
...
pkg/services/sqlstore/stats.go
View file @
668cb3c1
package
sqlstore
import
(
"time"
"github.com/grafana/grafana/pkg/bus"
m
"github.com/grafana/grafana/pkg/models"
)
...
...
@@ -11,6 +13,8 @@ func init() {
bus
.
AddHandler
(
"sql"
,
GetAdminStats
)
}
var
activeUserTimeLimit
time
.
Duration
=
time
.
Hour
*
24
*
14
func
GetDataSourceStats
(
query
*
m
.
GetDataSourceStatsQuery
)
error
{
var
rawSql
=
`SELECT COUNT(*) as count, type FROM data_source GROUP BY type`
query
.
Result
=
make
([]
*
m
.
DataSourceStats
,
0
)
...
...
@@ -27,27 +31,35 @@ func GetSystemStats(query *m.GetSystemStatsQuery) error {
(
SELECT COUNT(*)
FROM `
+
dialect
.
Quote
(
"user"
)
+
`
) AS user
_count
,
) AS user
s
,
(
SELECT COUNT(*)
FROM `
+
dialect
.
Quote
(
"org"
)
+
`
) AS org
_count
,
) AS org
s
,
(
SELECT COUNT(*)
FROM `
+
dialect
.
Quote
(
"dashboard"
)
+
`
) AS dashboard_count,
) AS dashboards,
(
SELECT COUNT(*)
FROM `
+
dialect
.
Quote
(
"data_source"
)
+
`
) AS datasources,
(
SELECT COUNT(*)
FROM `
+
dialect
.
Quote
(
"playlist"
)
+
`
) AS playlist
_count
,
) AS playlist
s
,
(
SELECT COUNT(*)
FROM `
+
dialect
.
Quote
(
"alert"
)
+
`
) AS alert_count
) AS alerts,
(
SELECT COUNT(*) FROM `
+
dialect
.
Quote
(
"user"
)
+
` where last_seen_at > ?
) as active_users
`
activeUserDeadlineDate
:=
time
.
Now
()
.
Add
(
-
activeUserTimeLimit
)
var
stats
m
.
SystemStats
_
,
err
:=
x
.
Sql
(
rawSql
)
.
Get
(
&
stats
)
_
,
err
:=
x
.
Sql
(
rawSql
,
activeUserDeadlineDate
)
.
Get
(
&
stats
)
if
err
!=
nil
{
return
err
}
...
...
@@ -61,43 +73,48 @@ func GetAdminStats(query *m.GetAdminStatsQuery) error {
(
SELECT COUNT(*)
FROM `
+
dialect
.
Quote
(
"user"
)
+
`
) AS user
_count
,
) AS user
s
,
(
SELECT COUNT(*)
FROM `
+
dialect
.
Quote
(
"org"
)
+
`
) AS org
_count
,
) AS org
s
,
(
SELECT COUNT(*)
FROM `
+
dialect
.
Quote
(
"dashboard"
)
+
`
) AS dashboard
_count
,
) AS dashboard
s
,
(
SELECT COUNT(*)
FROM `
+
dialect
.
Quote
(
"dashboard_snapshot"
)
+
`
) AS
db_snapshot_count
,
) AS
snapshots
,
(
SELECT COUNT( DISTINCT ( `
+
dialect
.
Quote
(
"term"
)
+
` ))
FROM `
+
dialect
.
Quote
(
"dashboard_tag"
)
+
`
) AS
db_tag_count
,
) AS
tags
,
(
SELECT COUNT(*)
FROM `
+
dialect
.
Quote
(
"data_source"
)
+
`
) AS data
_source_count
,
) AS data
sources
,
(
SELECT COUNT(*)
FROM `
+
dialect
.
Quote
(
"playlist"
)
+
`
) AS playlist
_count
,
) AS playlist
s
,
(
SELECT COUNT(DISTINCT `
+
dialect
.
Quote
(
"dashboard_id"
)
+
` )
FROM `
+
dialect
.
Quote
(
"star"
)
+
`
) AS starred_db_count,
SELECT COUNT(*) FROM `
+
dialect
.
Quote
(
"star"
)
+
`
) AS stars,
(
SELECT COUNT(*)
FROM `
+
dialect
.
Quote
(
"alert"
)
+
`
) AS alert_count
) AS alerts,
(
SELECT COUNT(*)
from `
+
dialect
.
Quote
(
"user"
)
+
` where last_seen_at > ?
) as active_users
`
activeUserDeadlineDate
:=
time
.
Now
()
.
Add
(
-
activeUserTimeLimit
)
var
stats
m
.
AdminStats
_
,
err
:=
x
.
Sql
(
rawSql
)
.
Get
(
&
stats
)
_
,
err
:=
x
.
Sql
(
rawSql
,
activeUserDeadlineDate
)
.
Get
(
&
stats
)
if
err
!=
nil
{
return
err
}
...
...
pkg/services/sqlstore/user.go
View file @
668cb3c1
...
...
@@ -22,6 +22,7 @@ func init() {
bus
.
AddHandler
(
"sql"
,
GetUserByLogin
)
bus
.
AddHandler
(
"sql"
,
GetUserByEmail
)
bus
.
AddHandler
(
"sql"
,
SetUsingOrg
)
bus
.
AddHandler
(
"sql"
,
UpdateUserLastSeenAt
)
bus
.
AddHandler
(
"sql"
,
GetUserProfile
)
bus
.
AddHandler
(
"sql"
,
GetSignedInUser
)
bus
.
AddHandler
(
"sql"
,
SearchUsers
)
...
...
@@ -260,6 +261,24 @@ func ChangeUserPassword(cmd *m.ChangeUserPasswordCommand) error {
})
}
func
UpdateUserLastSeenAt
(
cmd
*
m
.
UpdateUserLastSeenAtCommand
)
error
{
return
inTransaction
(
func
(
sess
*
DBSession
)
error
{
if
cmd
.
UserId
<=
0
{
}
user
:=
m
.
User
{
Id
:
cmd
.
UserId
,
LastSeenAt
:
time
.
Now
(),
}
if
_
,
err
:=
sess
.
Id
(
cmd
.
UserId
)
.
Update
(
&
user
);
err
!=
nil
{
return
err
}
return
nil
})
}
func
SetUsingOrg
(
cmd
*
m
.
SetUsingOrgCommand
)
error
{
getOrgsForUserCmd
:=
&
m
.
GetUserOrgListQuery
{
UserId
:
cmd
.
UserId
}
GetUserOrgList
(
getOrgsForUserCmd
)
...
...
@@ -324,15 +343,16 @@ func GetSignedInUser(query *m.GetSignedInUserQuery) error {
}
var
rawSql
=
`SELECT
u.id as user_id,
u.is_admin as is_grafana_admin,
u.email as email,
u.login as login,
u.name as name,
u.help_flags1 as help_flags1,
org.name as org_name,
org_user.role as org_role,
org.id as org_id
u.id as user_id,
u.is_admin as is_grafana_admin,
u.email as email,
u.login as login,
u.name as name,
u.help_flags1 as help_flags1,
u.last_seen_at as last_seen_at,
org.name as org_name,
org_user.role as org_role,
org.id as org_id
FROM `
+
dialect
.
Quote
(
"user"
)
+
` as u
LEFT OUTER JOIN org_user on org_user.org_id = `
+
orgId
+
` and org_user.user_id = u.id
LEFT OUTER JOIN org on org.id = org_user.org_id `
...
...
@@ -367,27 +387,49 @@ func SearchUsers(query *m.SearchUsersQuery) error {
query
.
Result
=
m
.
SearchUserQueryResult
{
Users
:
make
([]
*
m
.
UserSearchHitDTO
,
0
),
}
queryWithWildcards
:=
"%"
+
query
.
Query
+
"%"
whereConditions
:=
make
([]
string
,
0
)
whereParams
:=
make
([]
interface
{},
0
)
sess
:=
x
.
Table
(
"user"
)
if
query
.
OrgId
>
0
{
whereConditions
=
append
(
whereConditions
,
"org_id = ?"
)
whereParams
=
append
(
whereParams
,
query
.
OrgId
)
}
if
query
.
Query
!=
""
{
sess
.
Where
(
"email LIKE ? OR name LIKE ? OR login like ?"
,
queryWithWildcards
,
queryWithWildcards
,
queryWithWildcards
)
whereConditions
=
append
(
whereConditions
,
"(email LIKE ? OR name LIKE ? OR login like ?)"
)
whereParams
=
append
(
whereParams
,
queryWithWildcards
,
queryWithWildcards
,
queryWithWildcards
)
}
if
len
(
whereConditions
)
>
0
{
sess
.
Where
(
strings
.
Join
(
whereConditions
,
" AND "
),
whereParams
...
)
}
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"
,
"last_seen_at"
)
if
err
:=
sess
.
Find
(
&
query
.
Result
.
Users
);
err
!=
nil
{
return
err
}
// get total
user
:=
m
.
User
{}
countSess
:=
x
.
Table
(
"user"
)
if
query
.
Query
!=
""
{
countSess
.
Where
(
"email LIKE ? OR name LIKE ? OR login like ?"
,
queryWithWildcards
,
queryWithWildcards
,
queryWithWildcards
)
if
len
(
whereConditions
)
>
0
{
countSess
.
Where
(
strings
.
Join
(
whereConditions
,
" AND "
),
whereParams
...
)
}
count
,
err
:=
countSess
.
Count
(
&
user
)
query
.
Result
.
TotalCount
=
count
for
_
,
user
:=
range
query
.
Result
.
Users
{
user
.
LastSeenAtAge
=
util
.
GetAgeString
(
user
.
LastSeenAt
)
}
return
err
}
...
...
pkg/util/strings.go
View file @
668cb3c1
package
util
import
(
"fmt"
"math"
"regexp"
"time"
)
func
StringsFallback2
(
val1
string
,
val2
string
)
string
{
...
...
@@ -28,3 +31,34 @@ func SplitString(str string) []string {
return
regexp
.
MustCompile
(
"[, ]+"
)
.
Split
(
str
,
-
1
)
}
func
GetAgeString
(
t
time
.
Time
)
string
{
if
t
.
IsZero
()
{
return
"?"
}
sinceNow
:=
time
.
Since
(
t
)
minutes
:=
sinceNow
.
Minutes
()
years
:=
int
(
math
.
Floor
(
minutes
/
525600
))
months
:=
int
(
math
.
Floor
(
minutes
/
43800
))
days
:=
int
(
math
.
Floor
(
minutes
/
1440
))
hours
:=
int
(
math
.
Floor
(
minutes
/
60
))
if
years
>
0
{
return
fmt
.
Sprintf
(
"%dy"
,
years
)
}
if
months
>
0
{
return
fmt
.
Sprintf
(
"%dM"
,
months
)
}
if
days
>
0
{
return
fmt
.
Sprintf
(
"%dd"
,
days
)
}
if
hours
>
0
{
return
fmt
.
Sprintf
(
"%dh"
,
hours
)
}
if
int
(
minutes
)
>
0
{
return
fmt
.
Sprintf
(
"%dm"
,
int
(
minutes
))
}
return
"< 1m"
}
pkg/util/strings_test.go
View file @
668cb3c1
...
...
@@ -2,6 +2,7 @@ package util
import
(
"testing"
"time"
.
"github.com/smartystreets/goconvey/convey"
)
...
...
@@ -24,3 +25,15 @@ func TestSplitString(t *testing.T) {
So
(
SplitString
(
"test1 , test2 test3"
),
ShouldResemble
,
[]
string
{
"test1"
,
"test2"
,
"test3"
})
})
}
func
TestDateAge
(
t
*
testing
.
T
)
{
Convey
(
"GetAgeString"
,
t
,
func
()
{
So
(
GetAgeString
(
time
.
Time
{}),
ShouldEqual
,
"?"
)
So
(
GetAgeString
(
time
.
Now
()
.
Add
(
-
time
.
Second
*
2
)),
ShouldEqual
,
"< 1m"
)
So
(
GetAgeString
(
time
.
Now
()
.
Add
(
-
time
.
Minute
*
2
)),
ShouldEqual
,
"2m"
)
So
(
GetAgeString
(
time
.
Now
()
.
Add
(
-
time
.
Hour
*
2
)),
ShouldEqual
,
"2h"
)
So
(
GetAgeString
(
time
.
Now
()
.
Add
(
-
time
.
Hour
*
24
*
3
)),
ShouldEqual
,
"3d"
)
So
(
GetAgeString
(
time
.
Now
()
.
Add
(
-
time
.
Hour
*
24
*
67
)),
ShouldEqual
,
"2M"
)
So
(
GetAgeString
(
time
.
Now
()
.
Add
(
-
time
.
Hour
*
24
*
409
)),
ShouldEqual
,
"1y"
)
})
}
public/app/features/admin/partials/stats.html
View file @
668cb3c1
...
...
@@ -15,39 +15,43 @@
<tbody>
<tr>
<td>
Total dashboards
</td>
<td>
{{ctrl.stats.dashboard
_count
}}
</td>
<td>
{{ctrl.stats.dashboard
s
}}
</td>
</tr>
<tr>
<td>
Total users
</td>
<td>
{{ctrl.stats.user_count}}
</td>
<td>
{{ctrl.stats.users}}
</td>
</tr>
<tr>
<td>
Active users (seen last 14 days)
</td>
<td>
{{ctrl.stats.activeUsers}}
</td>
</tr>
<tr>
<td>
Total organizations
</td>
<td>
{{ctrl.stats.org
_count
}}
</td>
<td>
{{ctrl.stats.org
s
}}
</td>
</tr>
<tr>
<td>
Total datasources
</td>
<td>
{{ctrl.stats.data
_source_count
}}
</td>
<td>
{{ctrl.stats.data
sources
}}
</td>
</tr>
<tr>
<td>
Total playlists
</td>
<td>
{{ctrl.stats.playlist
_count
}}
</td>
<td>
{{ctrl.stats.playlist
s
}}
</td>
</tr>
<tr>
<td>
Total snapshots
</td>
<td>
{{ctrl.stats.
db_snapshot_count
}}
</td>
<td>
{{ctrl.stats.
snapshots
}}
</td>
</tr>
<tr>
<td>
Total dashboard tags
</td>
<td>
{{ctrl.stats.
db_tag_count
}}
</td>
<td>
{{ctrl.stats.
tags
}}
</td>
</tr>
<tr>
<td>
Total starred dashboards
</td>
<td>
{{ctrl.stats.star
red_db_count
}}
</td>
<td>
{{ctrl.stats.star
s
}}
</td>
</tr>
<tr>
<td>
Total alerts
</td>
<td>
{{ctrl.stats.alert
_count
}}
</td>
<td>
{{ctrl.stats.alert
s
}}
</td>
</tr>
</tbody>
</table>
...
...
public/app/features/admin/partials/users.html
View file @
668cb3c1
...
...
@@ -25,7 +25,11 @@
<th>
Name
</th>
<th>
Login
</th>
<th>
Email
</th>
<th
style=
"white-space: nowrap"
>
Grafana Admin
</th>
<th>
Seen
<tip>
Time since user was seen using Grafana
</tip>
</th>
<th></th>
<th></th>
</tr>
</thead>
...
...
@@ -35,7 +39,12 @@
<td>
{{user.name}}
</td>
<td>
{{user.login}}
</td>
<td>
{{user.email}}
</td>
<td>
{{user.isAdmin}}
</td>
<td>
{{user.lastSeenAtAge}}
</td>
<td>
<i
class=
"fa fa-shield"
ng-show=
"user.isAdmin"
bs-tooltip=
"'Grafana Admin'"
></i>
</td>
<td
class=
"text-right"
>
<a
href=
"admin/users/edit/{{user.id}}"
class=
"btn btn-inverse btn-small"
>
<i
class=
"fa fa-edit"
></i>
...
...
public/app/features/org/partials/orgUsers.html
View file @
668cb3c1
...
...
@@ -41,6 +41,10 @@
<tr>
<th>
Login
</th>
<th>
Email
</th>
<th>
Seen
<tip>
Time since user was seen using Grafana
</tip>
</th>
<th>
Role
</th>
<th
style=
"width: 34px;"
></th>
</tr>
...
...
@@ -48,6 +52,7 @@
<tr
ng-repeat=
"user in ctrl.users"
>
<td>
{{user.login}}
</td>
<td><span
class=
"ellipsis"
>
{{user.email}}
</span></td>
<td>
{{user.lastSeenAtAge}}
</td>
<td>
<select
type=
"text"
ng-model=
"user.role"
class=
"input-medium"
ng-options=
"f for f in ['Viewer', 'Editor', 'Read Only Editor', 'Admin']"
ng-change=
"ctrl.updateOrgUser(user)"
>
</select>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment