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
a9a06ad5
Commit
a9a06ad5
authored
Sep 19, 2014
by
Torkel Ödegaard
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Working on collaborators
parent
17057344
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
174 additions
and
98 deletions
+174
-98
grafana
+1
-1
pkg/api/api.go
+4
-12
pkg/api/api_account.go
+17
-11
pkg/api/api_auth.go
+48
-0
pkg/api/api_dashboard.go
+13
-17
pkg/api/api_login.go
+3
-20
pkg/api/api_routing.go
+36
-0
pkg/models/account.go
+43
-0
pkg/models/dashboards.go
+0
-34
pkg/stores/rethinkdb_accounts.go
+1
-0
views/index.html
+8
-3
No files found.
grafana
@
c65b7d15
Subproject commit
e5fd35db343109feec09d339d5d770dd1de1808a
Subproject commit
c65b7d159189f81b0d87ecc5b64be3ffbe332393
pkg/api/api.go
View file @
a9a06ad5
...
@@ -7,6 +7,7 @@ import (
...
@@ -7,6 +7,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin"
"github.com/gorilla/sessions"
"github.com/gorilla/sessions"
"github.com/torkelo/grafana-pro/pkg/components"
"github.com/torkelo/grafana-pro/pkg/components"
"github.com/torkelo/grafana-pro/pkg/models"
"github.com/torkelo/grafana-pro/pkg/stores"
"github.com/torkelo/grafana-pro/pkg/stores"
)
)
...
@@ -61,9 +62,9 @@ func (self *HttpServer) ListenAndServe() {
...
@@ -61,9 +62,9 @@ func (self *HttpServer) ListenAndServe() {
func
(
self
*
HttpServer
)
index
(
c
*
gin
.
Context
)
{
func
(
self
*
HttpServer
)
index
(
c
*
gin
.
Context
)
{
viewModel
:=
&
IndexDto
{}
viewModel
:=
&
IndexDto
{}
login
,
_
:=
c
.
Get
(
"login
"
)
userAccount
,
_
:=
c
.
Get
(
"userAccount
"
)
if
login
!=
nil
{
if
userAccount
!=
nil
{
viewModel
.
User
.
Login
=
login
.
(
string
)
viewModel
.
User
.
Login
=
userAccount
.
(
*
models
.
UserAccount
)
.
Login
}
}
c
.
HTML
(
200
,
"index.html"
,
viewModel
)
c
.
HTML
(
200
,
"index.html"
,
viewModel
)
...
@@ -74,12 +75,3 @@ func CacheHeadersMiddleware() gin.HandlerFunc {
...
@@ -74,12 +75,3 @@ func CacheHeadersMiddleware() gin.HandlerFunc {
c
.
Writer
.
Header
()
.
Add
(
"Cache-Control"
,
"max-age=0, public, must-revalidate, proxy-revalidate"
)
c
.
Writer
.
Header
()
.
Add
(
"Cache-Control"
,
"max-age=0, public, must-revalidate, proxy-revalidate"
)
}
}
}
}
// Api Handler Registration
var
routeHandlers
=
make
([]
routeHandlerRegisterFn
,
0
)
type
routeHandlerRegisterFn
func
(
self
*
HttpServer
)
func
addRoutes
(
fn
routeHandlerRegisterFn
)
{
routeHandlers
=
append
(
routeHandlers
,
fn
)
}
pkg/api/api_account.go
View file @
a9a06ad5
...
@@ -4,7 +4,7 @@ import "github.com/gin-gonic/gin"
...
@@ -4,7 +4,7 @@ import "github.com/gin-gonic/gin"
func
init
()
{
func
init
()
{
addRoutes
(
func
(
self
*
HttpServer
)
{
addRoutes
(
func
(
self
*
HttpServer
)
{
self
.
router
.
POST
(
"/api/account/collaborators/add"
,
self
.
auth
()
,
self
.
addCollaborator
)
self
.
addRoute
(
"POST"
,
"/api/account/collaborators/add"
,
self
.
addCollaborator
)
})
})
}
}
...
@@ -12,28 +12,34 @@ type addCollaboratorDto struct {
...
@@ -12,28 +12,34 @@ type addCollaboratorDto struct {
Email
string
`json:"email" binding:"required"`
Email
string
`json:"email" binding:"required"`
}
}
func
(
self
*
HttpServer
)
addCollaborator
(
c
*
gin
.
Context
)
{
func
(
self
*
HttpServer
)
addCollaborator
(
c
*
gin
.
Context
,
auth
*
authContext
)
{
var
model
addCollaboratorDto
var
model
addCollaboratorDto
if
!
c
.
EnsureBody
(
&
model
)
{
if
!
c
.
EnsureBody
(
&
model
)
{
c
.
JSON
(
400
,
gin
.
H
{
"status"
:
"
bad request
"
})
c
.
JSON
(
400
,
gin
.
H
{
"status"
:
"
Collaborator not found
"
})
return
return
}
}
accountId
,
_
:=
c
.
Get
(
"accountId"
)
account
,
err
:=
self
.
store
.
GetAccount
(
accountId
.
(
int
))
if
err
!=
nil
{
c
.
JSON
(
401
,
gin
.
H
{
"status"
:
"Authentication error"
})
}
collaborator
,
err
:=
self
.
store
.
GetUserAccountLogin
(
model
.
Email
)
collaborator
,
err
:=
self
.
store
.
GetUserAccountLogin
(
model
.
Email
)
if
err
!=
nil
{
if
err
!=
nil
{
c
.
JSON
(
404
,
gin
.
H
{
"status"
:
"Collaborator not found"
})
c
.
JSON
(
404
,
gin
.
H
{
"status"
:
"Collaborator not found"
})
return
}
}
account
.
AddCollaborator
(
collaborator
.
Id
)
userAccount
:=
auth
.
userAccount
if
collaborator
.
Id
==
userAccount
.
Id
{
c
.
JSON
(
400
,
gin
.
H
{
"status"
:
"Cannot add yourself as collaborator"
})
return
}
err
=
userAccount
.
AddCollaborator
(
collaborator
.
Id
)
if
err
!=
nil
{
c
.
JSON
(
400
,
gin
.
H
{
"status"
:
err
.
Error
()})
return
}
self
.
store
.
SaveUserAccount
(
a
ccount
)
self
.
store
.
SaveUserAccount
(
userA
ccount
)
c
.
JSON
(
200
,
gin
.
H
{
"status"
:
"Collaborator added"
})
c
.
JSON
(
200
,
gin
.
H
{
"status"
:
"Collaborator added"
})
}
}
pkg/api/api_auth.go
0 → 100644
View file @
a9a06ad5
package
api
import
(
"github.com/gin-gonic/gin"
"github.com/torkelo/grafana-pro/pkg/models"
)
type
authContext
struct
{
account
*
models
.
UserAccount
userAccount
*
models
.
UserAccount
}
func
(
auth
*
authContext
)
getAccountId
()
int
{
return
auth
.
account
.
Id
}
func
(
self
*
HttpServer
)
authDenied
(
c
*
gin
.
Context
)
{
c
.
Writer
.
Header
()
.
Set
(
"Location"
,
"/login"
)
c
.
Abort
(
302
)
}
func
(
self
*
HttpServer
)
auth
()
gin
.
HandlerFunc
{
return
func
(
c
*
gin
.
Context
)
{
session
,
_
:=
sessionStore
.
Get
(
c
.
Request
,
"grafana-session"
)
if
c
.
Request
.
URL
.
Path
!=
"/login"
&&
session
.
Values
[
"userAccountId"
]
==
nil
{
self
.
authDenied
(
c
)
return
}
account
,
err
:=
self
.
store
.
GetAccount
(
session
.
Values
[
"userAccountId"
]
.
(
int
))
if
err
!=
nil
{
self
.
authDenied
(
c
)
return
}
usingAccount
,
err
:=
self
.
store
.
GetAccount
(
session
.
Values
[
"usingAccountId"
]
.
(
int
))
if
err
!=
nil
{
self
.
authDenied
(
c
)
return
}
c
.
Set
(
"userAccount"
,
account
)
c
.
Set
(
"usingAccount"
,
usingAccount
)
session
.
Save
(
c
.
Request
,
c
.
Writer
)
}
}
pkg/api/api_dashboard.go
View file @
a9a06ad5
...
@@ -8,18 +8,17 @@ import (
...
@@ -8,18 +8,17 @@ import (
func
init
()
{
func
init
()
{
addRoutes
(
func
(
self
*
HttpServer
)
{
addRoutes
(
func
(
self
*
HttpServer
)
{
self
.
router
.
GET
(
"/api/dashboards/:slug"
,
self
.
auth
()
,
self
.
getDashboard
)
self
.
addRoute
(
"GET"
,
"/api/dashboards/:slug"
,
self
.
getDashboard
)
self
.
router
.
GET
(
"/api/search/"
,
self
.
auth
()
,
self
.
search
)
self
.
addRoute
(
"GET"
,
"/api/search/"
,
self
.
search
)
self
.
router
.
POST
(
"/api/dashboard"
,
self
.
auth
()
,
self
.
postDashboard
)
self
.
addRoute
(
"POST"
,
"/api/dashboard/"
,
self
.
postDashboard
)
self
.
router
.
DELETE
(
"/api/dashboard/:slug"
,
self
.
auth
()
,
self
.
deleteDashboard
)
self
.
addRoute
(
"DELETE"
,
"/api/dashboard/:slug"
,
self
.
deleteDashboard
)
})
})
}
}
func
(
self
*
HttpServer
)
getDashboard
(
c
*
gin
.
Context
)
{
func
(
self
*
HttpServer
)
getDashboard
(
c
*
gin
.
Context
,
auth
*
authContext
)
{
slug
:=
c
.
Params
.
ByName
(
"slug"
)
slug
:=
c
.
Params
.
ByName
(
"slug"
)
accountId
,
err
:=
c
.
Get
(
"accountId"
)
dash
,
err
:=
self
.
store
.
GetDashboard
(
slug
,
a
ccountId
.
(
int
))
dash
,
err
:=
self
.
store
.
GetDashboard
(
slug
,
a
uth
.
getAccountId
(
))
if
err
!=
nil
{
if
err
!=
nil
{
c
.
JSON
(
404
,
newErrorResponse
(
"Dashboard not found"
))
c
.
JSON
(
404
,
newErrorResponse
(
"Dashboard not found"
))
return
return
...
@@ -30,17 +29,16 @@ func (self *HttpServer) getDashboard(c *gin.Context) {
...
@@ -30,17 +29,16 @@ func (self *HttpServer) getDashboard(c *gin.Context) {
c
.
JSON
(
200
,
dash
.
Data
)
c
.
JSON
(
200
,
dash
.
Data
)
}
}
func
(
self
*
HttpServer
)
deleteDashboard
(
c
*
gin
.
Context
)
{
func
(
self
*
HttpServer
)
deleteDashboard
(
c
*
gin
.
Context
,
auth
*
authContext
)
{
slug
:=
c
.
Params
.
ByName
(
"slug"
)
slug
:=
c
.
Params
.
ByName
(
"slug"
)
accountId
,
err
:=
c
.
Get
(
"accountId"
)
dash
,
err
:=
self
.
store
.
GetDashboard
(
slug
,
a
ccountId
.
(
int
))
dash
,
err
:=
self
.
store
.
GetDashboard
(
slug
,
a
uth
.
getAccountId
(
))
if
err
!=
nil
{
if
err
!=
nil
{
c
.
JSON
(
404
,
newErrorResponse
(
"Dashboard not found"
))
c
.
JSON
(
404
,
newErrorResponse
(
"Dashboard not found"
))
return
return
}
}
err
=
self
.
store
.
DeleteDashboard
(
slug
,
a
ccountId
.
(
int
))
err
=
self
.
store
.
DeleteDashboard
(
slug
,
a
uth
.
getAccountId
(
))
if
err
!=
nil
{
if
err
!=
nil
{
c
.
JSON
(
500
,
newErrorResponse
(
"Failed to delete dashboard: "
+
err
.
Error
()))
c
.
JSON
(
500
,
newErrorResponse
(
"Failed to delete dashboard: "
+
err
.
Error
()))
return
return
...
@@ -51,11 +49,10 @@ func (self *HttpServer) deleteDashboard(c *gin.Context) {
...
@@ -51,11 +49,10 @@ func (self *HttpServer) deleteDashboard(c *gin.Context) {
c
.
JSON
(
200
,
resp
)
c
.
JSON
(
200
,
resp
)
}
}
func
(
self
*
HttpServer
)
search
(
c
*
gin
.
Context
)
{
func
(
self
*
HttpServer
)
search
(
c
*
gin
.
Context
,
auth
*
authContext
)
{
query
:=
c
.
Params
.
ByName
(
"q"
)
query
:=
c
.
Params
.
ByName
(
"q"
)
accountId
,
err
:=
c
.
Get
(
"accountId"
)
results
,
err
:=
self
.
store
.
Query
(
query
,
a
ccountId
.
(
int
))
results
,
err
:=
self
.
store
.
Query
(
query
,
a
uth
.
getAccountId
(
))
if
err
!=
nil
{
if
err
!=
nil
{
log
.
Error
(
"Store query error: %v"
,
err
)
log
.
Error
(
"Store query error: %v"
,
err
)
c
.
JSON
(
500
,
newErrorResponse
(
"Failed"
))
c
.
JSON
(
500
,
newErrorResponse
(
"Failed"
))
...
@@ -65,15 +62,14 @@ func (self *HttpServer) search(c *gin.Context) {
...
@@ -65,15 +62,14 @@ func (self *HttpServer) search(c *gin.Context) {
c
.
JSON
(
200
,
results
)
c
.
JSON
(
200
,
results
)
}
}
func
(
self
*
HttpServer
)
postDashboard
(
c
*
gin
.
Context
)
{
func
(
self
*
HttpServer
)
postDashboard
(
c
*
gin
.
Context
,
auth
*
authContext
)
{
var
command
saveDashboardCommand
var
command
saveDashboardCommand
accountId
,
_
:=
c
.
Get
(
"accountId"
)
if
c
.
EnsureBody
(
&
command
)
{
if
c
.
EnsureBody
(
&
command
)
{
dashboard
:=
models
.
NewDashboard
(
"test"
)
dashboard
:=
models
.
NewDashboard
(
"test"
)
dashboard
.
Data
=
command
.
Dashboard
dashboard
.
Data
=
command
.
Dashboard
dashboard
.
Title
=
dashboard
.
Data
[
"title"
]
.
(
string
)
dashboard
.
Title
=
dashboard
.
Data
[
"title"
]
.
(
string
)
dashboard
.
AccountId
=
a
ccountId
.
(
int
)
dashboard
.
AccountId
=
a
uth
.
getAccountId
(
)
dashboard
.
UpdateSlug
()
dashboard
.
UpdateSlug
()
if
dashboard
.
Data
[
"id"
]
!=
nil
{
if
dashboard
.
Data
[
"id"
]
!=
nil
{
...
...
pkg/api/api_login.go
View file @
a9a06ad5
...
@@ -35,8 +35,8 @@ func (self *HttpServer) loginPost(c *gin.Context) {
...
@@ -35,8 +35,8 @@ func (self *HttpServer) loginPost(c *gin.Context) {
}
}
session
,
_
:=
sessionStore
.
Get
(
c
.
Request
,
"grafana-session"
)
session
,
_
:=
sessionStore
.
Get
(
c
.
Request
,
"grafana-session"
)
session
.
Values
[
"
login"
]
=
loginModel
.
Email
session
.
Values
[
"
userAccountId"
]
=
account
.
Id
session
.
Values
[
"
accountId"
]
=
account
.
Id
session
.
Values
[
"
usingAccountId"
]
=
account
.
UsingAccount
Id
session
.
Save
(
c
.
Request
,
c
.
Writer
)
session
.
Save
(
c
.
Request
,
c
.
Writer
)
var
resp
=
&
LoginResultDto
{}
var
resp
=
&
LoginResultDto
{}
...
@@ -48,25 +48,8 @@ func (self *HttpServer) loginPost(c *gin.Context) {
...
@@ -48,25 +48,8 @@ func (self *HttpServer) loginPost(c *gin.Context) {
func
(
self
*
HttpServer
)
logoutPost
(
c
*
gin
.
Context
)
{
func
(
self
*
HttpServer
)
logoutPost
(
c
*
gin
.
Context
)
{
session
,
_
:=
sessionStore
.
Get
(
c
.
Request
,
"grafana-session"
)
session
,
_
:=
sessionStore
.
Get
(
c
.
Request
,
"grafana-session"
)
session
.
Values
[
"login"
]
=
nil
session
.
Values
=
nil
session
.
Save
(
c
.
Request
,
c
.
Writer
)
session
.
Save
(
c
.
Request
,
c
.
Writer
)
c
.
JSON
(
200
,
gin
.
H
{
"status"
:
"logged out"
})
c
.
JSON
(
200
,
gin
.
H
{
"status"
:
"logged out"
})
}
}
func
(
self
*
HttpServer
)
auth
()
gin
.
HandlerFunc
{
return
func
(
c
*
gin
.
Context
)
{
session
,
_
:=
sessionStore
.
Get
(
c
.
Request
,
"grafana-session"
)
if
c
.
Request
.
URL
.
Path
!=
"/login"
&&
session
.
Values
[
"login"
]
==
nil
{
c
.
Writer
.
Header
()
.
Set
(
"Location"
,
"/login"
)
c
.
Abort
(
302
)
return
}
c
.
Set
(
"accountId"
,
session
.
Values
[
"accountId"
])
c
.
Set
(
"login"
,
session
.
Values
[
"login"
])
session
.
Save
(
c
.
Request
,
c
.
Writer
)
}
}
pkg/api/api_routing.go
0 → 100644
View file @
a9a06ad5
package
api
import
(
"github.com/gin-gonic/gin"
"github.com/torkelo/grafana-pro/pkg/models"
)
type
routeHandlerRegisterFn
func
(
self
*
HttpServer
)
type
routeHandlerFn
func
(
c
*
gin
.
Context
,
auth
*
authContext
)
var
routeHandlers
=
make
([]
routeHandlerRegisterFn
,
0
)
func
getRouteHandlerWrapper
(
handler
routeHandlerFn
)
gin
.
HandlerFunc
{
return
func
(
c
*
gin
.
Context
)
{
authContext
:=
authContext
{
account
:
c
.
MustGet
(
"usingAccount"
)
.
(
*
models
.
UserAccount
),
userAccount
:
c
.
MustGet
(
"userAccount"
)
.
(
*
models
.
UserAccount
),
}
handler
(
c
,
&
authContext
)
}
}
func
(
self
*
HttpServer
)
addRoute
(
method
string
,
path
string
,
handler
routeHandlerFn
)
{
switch
method
{
case
"GET"
:
self
.
router
.
GET
(
path
,
self
.
auth
(),
getRouteHandlerWrapper
(
handler
))
case
"POST"
:
self
.
router
.
POST
(
path
,
self
.
auth
(),
getRouteHandlerWrapper
(
handler
))
case
"DELETE"
:
self
.
router
.
DELETE
(
path
,
self
.
auth
(),
getRouteHandlerWrapper
(
handler
))
}
}
func
addRoutes
(
fn
routeHandlerRegisterFn
)
{
routeHandlers
=
append
(
routeHandlers
,
fn
)
}
pkg/models/account.go
0 → 100644
View file @
a9a06ad5
package
models
import
(
"errors"
"time"
)
type
CollaboratorLink
struct
{
AccountId
int
Role
string
ModifiedOn
time
.
Time
CreatedOn
time
.
Time
}
type
UserAccount
struct
{
Id
int
`gorethink:"id"`
UserName
string
Login
string
Email
string
Password
string
NextDashboardId
int
UsingAccountId
int
Collaborators
[]
CollaboratorLink
CreatedOn
time
.
Time
ModifiedOn
time
.
Time
}
func
(
account
*
UserAccount
)
AddCollaborator
(
accountId
int
)
error
{
for
_
,
collaborator
:=
range
account
.
Collaborators
{
if
collaborator
.
AccountId
==
accountId
{
return
errors
.
New
(
"Collaborator already exists"
)
}
}
account
.
Collaborators
=
append
(
account
.
Collaborators
,
CollaboratorLink
{
AccountId
:
accountId
,
Role
:
"admin"
,
CreatedOn
:
time
.
Now
(),
ModifiedOn
:
time
.
Now
(),
})
return
nil
}
pkg/models/dashboards.go
View file @
a9a06ad5
...
@@ -21,31 +21,6 @@ type Dashboard struct {
...
@@ -21,31 +21,6 @@ type Dashboard struct {
Data
map
[
string
]
interface
{}
Data
map
[
string
]
interface
{}
}
}
type
CollaboratorLink
struct
{
AccountId
int
Role
string
ModifiedOn
time
.
Time
CreatedOn
time
.
Time
}
type
UserAccount
struct
{
Id
int
`gorethink:"id"`
UserName
string
Login
string
Email
string
Password
string
NextDashboardId
int
UsingAccountId
int
Collaborators
[]
CollaboratorLink
CreatedOn
time
.
Time
ModifiedOn
time
.
Time
}
type
UserContext
struct
{
UserId
string
AccountId
string
}
type
SearchResult
struct
{
type
SearchResult
struct
{
Id
string
`json:"id"`
Id
string
`json:"id"`
Title
string
`json:"title"`
Title
string
`json:"title"`
...
@@ -87,12 +62,3 @@ func (dash *Dashboard) UpdateSlug() {
...
@@ -87,12 +62,3 @@ func (dash *Dashboard) UpdateSlug() {
re2
:=
regexp
.
MustCompile
(
"
\\
s"
)
re2
:=
regexp
.
MustCompile
(
"
\\
s"
)
dash
.
Slug
=
re2
.
ReplaceAllString
(
re
.
ReplaceAllString
(
title
,
""
),
"-"
)
dash
.
Slug
=
re2
.
ReplaceAllString
(
re
.
ReplaceAllString
(
title
,
""
),
"-"
)
}
}
func
(
account
*
UserAccount
)
AddCollaborator
(
accountId
int
)
{
account
.
Collaborators
=
append
(
account
.
Collaborators
,
CollaboratorLink
{
AccountId
:
accountId
,
Role
:
"admin"
,
CreatedOn
:
time
.
Now
(),
ModifiedOn
:
time
.
Now
(),
})
}
pkg/stores/rethinkdb_accounts.go
View file @
a9a06ad5
...
@@ -32,6 +32,7 @@ func (self *rethinkStore) SaveUserAccount(account *models.UserAccount) error {
...
@@ -32,6 +32,7 @@ func (self *rethinkStore) SaveUserAccount(account *models.UserAccount) error {
}
}
account
.
Id
=
accountId
account
.
Id
=
accountId
account
.
UsingAccountId
=
accountId
resp
,
err
:=
r
.
Table
(
"accounts"
)
.
Insert
(
account
)
.
RunWrite
(
self
.
session
)
resp
,
err
:=
r
.
Table
(
"accounts"
)
.
Insert
(
account
)
.
RunWrite
(
self
.
session
)
if
err
!=
nil
{
if
err
!=
nil
{
...
...
views/index.html
View file @
a9a06ad5
...
@@ -28,9 +28,14 @@
...
@@ -28,9 +28,14 @@
<div
ng-include=
"'app/partials/pro/sidemenu.html'"
></div>
<div
ng-include=
"'app/partials/pro/sidemenu.html'"
></div>
</aside>
</aside>
<div
ng-repeat=
'alert in dashAlerts.list'
class=
"alert-{{alert.severity}} dashboard-notice"
ng-show=
"$last"
>
<div
class=
"page-alert-list"
>
<button
type=
"button"
class=
"close"
ng-click=
"dashAlerts.clear(alert)"
style=
"padding-right:50px"
>
×
</button>
<div
ng-repeat=
'alert in dashAlerts.list'
class=
"alert-{{alert.severity}} alert"
>
<strong>
{{alert.title}}
</strong>
<span
ng-bind-html=
'alert.text'
></span>
<div
style=
"padding-right:10px"
class=
'pull-right small'
>
{{$index + 1}} alert(s)
</div>
<button
type=
"button"
class=
"alert-close"
ng-click=
"dashAlerts.clear(alert)"
>
<i
class=
"icon-remove-sign"
></i>
</button>
<div
class=
"alert-title"
>
{{alert.title}}
</div>
<div
ng-bind-html=
'alert.text'
></div>
</div>
</div>
</div>
<div
ng-view
class=
"pro-main-view"
ng-class=
"{'dashboard-fullscreen': fullscreen}"
></div>
<div
ng-view
class=
"pro-main-view"
ng-class=
"{'dashboard-fullscreen': fullscreen}"
></div>
...
...
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