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
c1204154
Unverified
Commit
c1204154
authored
Apr 17, 2018
by
Marcus Efraimsson
Committed by
GitHub
Apr 17, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #11398 from bergquist/readonly_dashboards
improved workflow for provisioned dashboards
parents
d9b5ef8f
d7688241
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
357 additions
and
34 deletions
+357
-34
pkg/api/dashboard.go
+12
-1
pkg/api/dashboard_test.go
+21
-0
pkg/api/dtos/dashboard.go
+1
-0
pkg/models/dashboards.go
+27
-20
pkg/services/dashboards/dashboard_service.go
+18
-5
pkg/services/dashboards/dashboard_service_test.go
+113
-2
pkg/services/dashboards/folder_service.go
+2
-2
pkg/services/dashboards/folder_service_test.go
+9
-0
pkg/services/provisioning/dashboards/types.go
+0
-3
pkg/services/sqlstore/dashboard_provisioning.go
+14
-0
pkg/services/sqlstore/dashboard_provisioning_test.go
+17
-0
pkg/services/sqlstore/dashboard_service_integration_test.go
+5
-1
public/app/features/dashboard/all.ts
+1
-0
public/app/features/dashboard/dashboard_srv.ts
+10
-0
public/app/features/dashboard/save_provisioned_modal.ts
+77
-0
public/app/features/dashboard/specs/save_provisioned_modal.jest.ts
+30
-0
No files found.
pkg/api/dashboard.go
View file @
c1204154
...
...
@@ -102,6 +102,16 @@ func GetDashboard(c *m.ReqContext) Response {
meta
.
FolderUrl
=
query
.
Result
.
GetUrl
()
}
isDashboardProvisioned
:=
&
m
.
IsDashboardProvisionedQuery
{
DashboardId
:
dash
.
Id
}
err
=
bus
.
Dispatch
(
isDashboardProvisioned
)
if
err
!=
nil
{
return
Error
(
500
,
"Error while checking if dashboard is provisioned"
,
err
)
}
if
isDashboardProvisioned
.
Result
{
meta
.
Provisioned
=
true
}
// make sure db version is in sync with json model version
dash
.
Data
.
Set
(
"version"
,
dash
.
Version
)
...
...
@@ -228,7 +238,8 @@ func PostDashboard(c *m.ReqContext, cmd m.SaveDashboardCommand) Response {
err
==
m
.
ErrDashboardWithSameUIDExists
||
err
==
m
.
ErrFolderNotFound
||
err
==
m
.
ErrDashboardFolderCannotHaveParent
||
err
==
m
.
ErrDashboardFolderNameExists
{
err
==
m
.
ErrDashboardFolderNameExists
||
err
==
m
.
ErrDashboardCannotSaveProvisionedDashboard
{
return
Error
(
400
,
err
.
Error
(),
nil
)
}
...
...
pkg/api/dashboard_test.go
View file @
c1204154
...
...
@@ -42,6 +42,11 @@ func TestDashboardApiEndpoint(t *testing.T) {
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
query
*
m
.
IsDashboardProvisionedQuery
)
error
{
query
.
Result
=
false
return
nil
})
viewerRole
:=
m
.
ROLE_VIEWER
editorRole
:=
m
.
ROLE_EDITOR
...
...
@@ -192,6 +197,11 @@ func TestDashboardApiEndpoint(t *testing.T) {
fakeDash
.
HasAcl
=
true
setting
.
ViewersCanEdit
=
false
bus
.
AddHandler
(
"test"
,
func
(
query
*
m
.
IsDashboardProvisionedQuery
)
error
{
query
.
Result
=
false
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
query
*
m
.
GetDashboardsBySlugQuery
)
error
{
dashboards
:=
[]
*
m
.
Dashboard
{
fakeDash
}
query
.
Result
=
dashboards
...
...
@@ -625,6 +635,11 @@ func TestDashboardApiEndpoint(t *testing.T) {
dashTwo
.
FolderId
=
3
dashTwo
.
HasAcl
=
false
bus
.
AddHandler
(
"test"
,
func
(
query
*
m
.
IsDashboardProvisionedQuery
)
error
{
query
.
Result
=
false
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
query
*
m
.
GetDashboardsBySlugQuery
)
error
{
dashboards
:=
[]
*
m
.
Dashboard
{
dashOne
,
dashTwo
}
query
.
Result
=
dashboards
...
...
@@ -720,6 +735,7 @@ func TestDashboardApiEndpoint(t *testing.T) {
{
SaveError
:
m
.
ErrDashboardUpdateAccessDenied
,
ExpectedStatusCode
:
403
},
{
SaveError
:
m
.
ErrDashboardInvalidUid
,
ExpectedStatusCode
:
400
},
{
SaveError
:
m
.
ErrDashboardUidToLong
,
ExpectedStatusCode
:
400
},
{
SaveError
:
m
.
ErrDashboardCannotSaveProvisionedDashboard
,
ExpectedStatusCode
:
400
},
{
SaveError
:
m
.
UpdatePluginDashboardError
{
PluginId
:
"plug"
},
ExpectedStatusCode
:
412
},
}
...
...
@@ -750,6 +766,11 @@ func TestDashboardApiEndpoint(t *testing.T) {
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
query
*
m
.
IsDashboardProvisionedQuery
)
error
{
query
.
Result
=
false
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
query
*
m
.
GetDashboardVersionQuery
)
error
{
query
.
Result
=
&
m
.
DashboardVersion
{
Data
:
simplejson
.
NewFromAny
(
map
[
string
]
interface
{}{
...
...
pkg/api/dtos/dashboard.go
View file @
c1204154
...
...
@@ -28,6 +28,7 @@ type DashboardMeta struct {
FolderId
int64
`json:"folderId"`
FolderTitle
string
`json:"folderTitle"`
FolderUrl
string
`json:"folderUrl"`
Provisioned
bool
`json:"provisioned"`
}
type
DashboardFullWithMeta
struct
{
...
...
pkg/models/dashboards.go
View file @
c1204154
...
...
@@ -13,26 +13,27 @@ import (
// Typed errors
var
(
ErrDashboardNotFound
=
errors
.
New
(
"Dashboard not found"
)
ErrDashboardFolderNotFound
=
errors
.
New
(
"Folder not found"
)
ErrDashboardSnapshotNotFound
=
errors
.
New
(
"Dashboard snapshot not found"
)
ErrDashboardWithSameUIDExists
=
errors
.
New
(
"A dashboard with the same uid already exists"
)
ErrDashboardWithSameNameInFolderExists
=
errors
.
New
(
"A dashboard with the same name in the folder already exists"
)
ErrDashboardVersionMismatch
=
errors
.
New
(
"The dashboard has been changed by someone else"
)
ErrDashboardTitleEmpty
=
errors
.
New
(
"Dashboard title cannot be empty"
)
ErrDashboardFolderCannotHaveParent
=
errors
.
New
(
"A Dashboard Folder cannot be added to another folder"
)
ErrDashboardContainsInvalidAlertData
=
errors
.
New
(
"Invalid alert data. Cannot save dashboard"
)
ErrDashboardFailedToUpdateAlertData
=
errors
.
New
(
"Failed to save alert data"
)
ErrDashboardsWithSameSlugExists
=
errors
.
New
(
"Multiple dashboards with the same slug exists"
)
ErrDashboardFailedGenerateUniqueUid
=
errors
.
New
(
"Failed to generate unique dashboard id"
)
ErrDashboardTypeMismatch
=
errors
.
New
(
"Dashboard cannot be changed to a folder"
)
ErrDashboardFolderWithSameNameAsDashboard
=
errors
.
New
(
"Folder name cannot be the same as one of its dashboards"
)
ErrDashboardWithSameNameAsFolder
=
errors
.
New
(
"Dashboard name cannot be the same as folder"
)
ErrDashboardFolderNameExists
=
errors
.
New
(
"A folder with that name already exists"
)
ErrDashboardUpdateAccessDenied
=
errors
.
New
(
"Access denied to save dashboard"
)
ErrDashboardInvalidUid
=
errors
.
New
(
"uid contains illegal characters"
)
ErrDashboardUidToLong
=
errors
.
New
(
"uid to long. max 40 characters"
)
RootFolderName
=
"General"
ErrDashboardNotFound
=
errors
.
New
(
"Dashboard not found"
)
ErrDashboardFolderNotFound
=
errors
.
New
(
"Folder not found"
)
ErrDashboardSnapshotNotFound
=
errors
.
New
(
"Dashboard snapshot not found"
)
ErrDashboardWithSameUIDExists
=
errors
.
New
(
"A dashboard with the same uid already exists"
)
ErrDashboardWithSameNameInFolderExists
=
errors
.
New
(
"A dashboard with the same name in the folder already exists"
)
ErrDashboardVersionMismatch
=
errors
.
New
(
"The dashboard has been changed by someone else"
)
ErrDashboardTitleEmpty
=
errors
.
New
(
"Dashboard title cannot be empty"
)
ErrDashboardFolderCannotHaveParent
=
errors
.
New
(
"A Dashboard Folder cannot be added to another folder"
)
ErrDashboardContainsInvalidAlertData
=
errors
.
New
(
"Invalid alert data. Cannot save dashboard"
)
ErrDashboardFailedToUpdateAlertData
=
errors
.
New
(
"Failed to save alert data"
)
ErrDashboardsWithSameSlugExists
=
errors
.
New
(
"Multiple dashboards with the same slug exists"
)
ErrDashboardFailedGenerateUniqueUid
=
errors
.
New
(
"Failed to generate unique dashboard id"
)
ErrDashboardTypeMismatch
=
errors
.
New
(
"Dashboard cannot be changed to a folder"
)
ErrDashboardFolderWithSameNameAsDashboard
=
errors
.
New
(
"Folder name cannot be the same as one of its dashboards"
)
ErrDashboardWithSameNameAsFolder
=
errors
.
New
(
"Dashboard name cannot be the same as folder"
)
ErrDashboardFolderNameExists
=
errors
.
New
(
"A folder with that name already exists"
)
ErrDashboardUpdateAccessDenied
=
errors
.
New
(
"Access denied to save dashboard"
)
ErrDashboardInvalidUid
=
errors
.
New
(
"uid contains illegal characters"
)
ErrDashboardUidToLong
=
errors
.
New
(
"uid to long. max 40 characters"
)
ErrDashboardCannotSaveProvisionedDashboard
=
errors
.
New
(
"Cannot save provisioned dashboard"
)
RootFolderName
=
"General"
)
type
UpdatePluginDashboardError
struct
{
...
...
@@ -322,6 +323,12 @@ type GetDashboardSlugByIdQuery struct {
Result
string
}
type
IsDashboardProvisionedQuery
struct
{
DashboardId
int64
Result
bool
}
type
GetProvisionedDashboardDataQuery
struct
{
Name
string
...
...
pkg/services/dashboards/dashboard_service.go
View file @
c1204154
...
...
@@ -57,7 +57,7 @@ func (dr *dashboardServiceImpl) GetProvisionedDashboardData(name string) ([]*mod
return
cmd
.
Result
,
nil
}
func
(
dr
*
dashboardServiceImpl
)
buildSaveDashboardCommand
(
dto
*
SaveDashboardDTO
,
validateAlerts
bool
)
(
*
models
.
SaveDashboardCommand
,
error
)
{
func
(
dr
*
dashboardServiceImpl
)
buildSaveDashboardCommand
(
dto
*
SaveDashboardDTO
,
validateAlerts
bool
,
validateProvisionedDashboard
bool
)
(
*
models
.
SaveDashboardCommand
,
error
)
{
dash
:=
dto
.
Dashboard
dash
.
Title
=
strings
.
TrimSpace
(
dash
.
Title
)
...
...
@@ -113,6 +113,19 @@ func (dr *dashboardServiceImpl) buildSaveDashboardCommand(dto *SaveDashboardDTO,
}
}
if
validateProvisionedDashboard
{
isDashboardProvisioned
:=
&
models
.
IsDashboardProvisionedQuery
{
DashboardId
:
dash
.
Id
}
err
:=
bus
.
Dispatch
(
isDashboardProvisioned
)
if
err
!=
nil
{
return
nil
,
err
}
if
isDashboardProvisioned
.
Result
{
return
nil
,
models
.
ErrDashboardCannotSaveProvisionedDashboard
}
}
guard
:=
guardian
.
New
(
dash
.
GetDashboardIdForSavePermissionCheck
(),
dto
.
OrgId
,
dto
.
User
)
if
canSave
,
err
:=
guard
.
CanSave
();
err
!=
nil
||
!
canSave
{
if
err
!=
nil
{
...
...
@@ -158,7 +171,7 @@ func (dr *dashboardServiceImpl) SaveProvisionedDashboard(dto *SaveDashboardDTO,
UserId
:
0
,
OrgRole
:
models
.
ROLE_ADMIN
,
}
cmd
,
err
:=
dr
.
buildSaveDashboardCommand
(
dto
,
true
)
cmd
,
err
:=
dr
.
buildSaveDashboardCommand
(
dto
,
true
,
false
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -188,7 +201,7 @@ func (dr *dashboardServiceImpl) SaveFolderForProvisionedDashboards(dto *SaveDash
UserId
:
0
,
OrgRole
:
models
.
ROLE_ADMIN
,
}
cmd
,
err
:=
dr
.
buildSaveDashboardCommand
(
dto
,
false
)
cmd
,
err
:=
dr
.
buildSaveDashboardCommand
(
dto
,
false
,
false
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -207,7 +220,7 @@ func (dr *dashboardServiceImpl) SaveFolderForProvisionedDashboards(dto *SaveDash
}
func
(
dr
*
dashboardServiceImpl
)
SaveDashboard
(
dto
*
SaveDashboardDTO
)
(
*
models
.
Dashboard
,
error
)
{
cmd
,
err
:=
dr
.
buildSaveDashboardCommand
(
dto
,
true
)
cmd
,
err
:=
dr
.
buildSaveDashboardCommand
(
dto
,
true
,
true
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -226,7 +239,7 @@ func (dr *dashboardServiceImpl) SaveDashboard(dto *SaveDashboardDTO) (*models.Da
}
func
(
dr
*
dashboardServiceImpl
)
ImportDashboard
(
dto
*
SaveDashboardDTO
)
(
*
models
.
Dashboard
,
error
)
{
cmd
,
err
:=
dr
.
buildSaveDashboardCommand
(
dto
,
false
)
cmd
,
err
:=
dr
.
buildSaveDashboardCommand
(
dto
,
false
,
true
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
pkg/services/dashboards/dashboard_service_test.go
View file @
c1204154
...
...
@@ -14,7 +14,9 @@ import (
func
TestDashboardService
(
t
*
testing
.
T
)
{
Convey
(
"Dashboard service tests"
,
t
,
func
()
{
service
:=
dashboardServiceImpl
{}
bus
.
ClearBusHandlers
()
service
:=
&
dashboardServiceImpl
{}
origNewDashboardGuardian
:=
guardian
.
New
guardian
.
MockDashboardGuardian
(
&
guardian
.
FakeDashboardGuardian
{
CanSaveValue
:
true
})
...
...
@@ -55,6 +57,11 @@ func TestDashboardService(t *testing.T) {
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
IsDashboardProvisionedQuery
)
error
{
cmd
.
Result
=
false
return
nil
})
testCases
:=
[]
struct
{
Uid
string
Error
error
...
...
@@ -73,12 +80,42 @@ func TestDashboardService(t *testing.T) {
dto
.
Dashboard
.
SetUid
(
tc
.
Uid
)
dto
.
User
=
&
models
.
SignedInUser
{}
_
,
err
:=
service
.
buildSaveDashboardCommand
(
dto
,
true
)
_
,
err
:=
service
.
buildSaveDashboardCommand
(
dto
,
true
,
false
)
So
(
err
,
ShouldEqual
,
tc
.
Error
)
}
})
Convey
(
"Should return validation error if dashboard is provisioned"
,
func
()
{
provisioningValidated
:=
false
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
IsDashboardProvisionedQuery
)
error
{
provisioningValidated
=
true
cmd
.
Result
=
true
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
ValidateDashboardAlertsCommand
)
error
{
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
ValidateDashboardBeforeSaveCommand
)
error
{
cmd
.
Result
=
&
models
.
ValidateDashboardBeforeSaveResult
{}
return
nil
})
dto
.
Dashboard
=
models
.
NewDashboard
(
"Dash"
)
dto
.
Dashboard
.
SetId
(
3
)
dto
.
User
=
&
models
.
SignedInUser
{
UserId
:
1
}
_
,
err
:=
service
.
SaveDashboard
(
dto
)
So
(
provisioningValidated
,
ShouldBeTrue
)
So
(
err
,
ShouldEqual
,
models
.
ErrDashboardCannotSaveProvisionedDashboard
)
})
Convey
(
"Should return validation error if alert data is invalid"
,
func
()
{
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
IsDashboardProvisionedQuery
)
error
{
cmd
.
Result
=
false
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
ValidateDashboardAlertsCommand
)
error
{
return
errors
.
New
(
"error"
)
})
...
...
@@ -89,6 +126,80 @@ func TestDashboardService(t *testing.T) {
})
})
Convey
(
"Save provisioned dashboard validation"
,
func
()
{
dto
:=
&
SaveDashboardDTO
{}
Convey
(
"Should not return validation error if dashboard is provisioned"
,
func
()
{
provisioningValidated
:=
false
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
IsDashboardProvisionedQuery
)
error
{
provisioningValidated
=
true
cmd
.
Result
=
true
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
ValidateDashboardAlertsCommand
)
error
{
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
ValidateDashboardBeforeSaveCommand
)
error
{
cmd
.
Result
=
&
models
.
ValidateDashboardBeforeSaveResult
{}
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
SaveProvisionedDashboardCommand
)
error
{
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
UpdateDashboardAlertsCommand
)
error
{
return
nil
})
dto
.
Dashboard
=
models
.
NewDashboard
(
"Dash"
)
dto
.
Dashboard
.
SetId
(
3
)
dto
.
User
=
&
models
.
SignedInUser
{
UserId
:
1
}
_
,
err
:=
service
.
SaveProvisionedDashboard
(
dto
,
nil
)
So
(
err
,
ShouldBeNil
)
So
(
provisioningValidated
,
ShouldBeFalse
)
})
})
Convey
(
"Import dashboard validation"
,
func
()
{
dto
:=
&
SaveDashboardDTO
{}
Convey
(
"Should return validation error if dashboard is provisioned"
,
func
()
{
provisioningValidated
:=
false
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
IsDashboardProvisionedQuery
)
error
{
provisioningValidated
=
true
cmd
.
Result
=
true
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
ValidateDashboardAlertsCommand
)
error
{
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
ValidateDashboardBeforeSaveCommand
)
error
{
cmd
.
Result
=
&
models
.
ValidateDashboardBeforeSaveResult
{}
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
SaveProvisionedDashboardCommand
)
error
{
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
UpdateDashboardAlertsCommand
)
error
{
return
nil
})
dto
.
Dashboard
=
models
.
NewDashboard
(
"Dash"
)
dto
.
Dashboard
.
SetId
(
3
)
dto
.
User
=
&
models
.
SignedInUser
{
UserId
:
1
}
_
,
err
:=
service
.
ImportDashboard
(
dto
)
So
(
provisioningValidated
,
ShouldBeTrue
)
So
(
err
,
ShouldEqual
,
models
.
ErrDashboardCannotSaveProvisionedDashboard
)
})
})
Reset
(
func
()
{
guardian
.
New
=
origNewDashboardGuardian
})
...
...
pkg/services/dashboards/folder_service.go
View file @
c1204154
...
...
@@ -104,7 +104,7 @@ func (dr *dashboardServiceImpl) CreateFolder(cmd *models.CreateFolderCommand) er
User
:
dr
.
user
,
}
saveDashboardCmd
,
err
:=
dr
.
buildSaveDashboardCommand
(
dto
,
false
)
saveDashboardCmd
,
err
:=
dr
.
buildSaveDashboardCommand
(
dto
,
false
,
false
)
if
err
!=
nil
{
return
toFolderError
(
err
)
}
...
...
@@ -141,7 +141,7 @@ func (dr *dashboardServiceImpl) UpdateFolder(existingUid string, cmd *models.Upd
Overwrite
:
cmd
.
Overwrite
,
}
saveDashboardCmd
,
err
:=
dr
.
buildSaveDashboardCommand
(
dto
,
false
)
saveDashboardCmd
,
err
:=
dr
.
buildSaveDashboardCommand
(
dto
,
false
,
false
)
if
err
!=
nil
{
return
toFolderError
(
err
)
}
...
...
pkg/services/dashboards/folder_service_test.go
View file @
c1204154
...
...
@@ -110,11 +110,19 @@ func TestFolderService(t *testing.T) {
return
nil
})
provisioningValidated
:=
false
bus
.
AddHandler
(
"test"
,
func
(
query
*
models
.
IsDashboardProvisionedQuery
)
error
{
provisioningValidated
=
true
return
nil
})
Convey
(
"When creating folder should not return access denied error"
,
func
()
{
err
:=
service
.
CreateFolder
(
&
models
.
CreateFolderCommand
{
Title
:
"Folder"
,
})
So
(
err
,
ShouldBeNil
)
So
(
provisioningValidated
,
ShouldBeFalse
)
})
Convey
(
"When updating folder should not return access denied error"
,
func
()
{
...
...
@@ -123,6 +131,7 @@ func TestFolderService(t *testing.T) {
Title
:
"Folder"
,
})
So
(
err
,
ShouldBeNil
)
So
(
provisioningValidated
,
ShouldBeFalse
)
})
Convey
(
"When deleting folder by uid should not return access denied error"
,
func
()
{
...
...
pkg/services/provisioning/dashboards/types.go
View file @
c1204154
...
...
@@ -55,9 +55,6 @@ func createDashboardJson(data *simplejson.Json, lastModified time.Time, cfg *Das
dash
.
OrgId
=
cfg
.
OrgId
dash
.
Dashboard
.
OrgId
=
cfg
.
OrgId
dash
.
Dashboard
.
FolderId
=
folderId
if
!
cfg
.
Editable
{
dash
.
Dashboard
.
Data
.
Set
(
"editable"
,
cfg
.
Editable
)
}
if
dash
.
Dashboard
.
Title
==
""
{
return
nil
,
models
.
ErrDashboardTitleEmpty
...
...
pkg/services/sqlstore/dashboard_provisioning.go
View file @
c1204154
...
...
@@ -8,6 +8,7 @@ import (
func
init
()
{
bus
.
AddHandler
(
"sql"
,
GetProvisionedDashboardDataQuery
)
bus
.
AddHandler
(
"sql"
,
SaveProvisionedDashboard
)
bus
.
AddHandler
(
"sql"
,
GetProvisionedDataByDashboardId
)
}
type
DashboardExtras
struct
{
...
...
@@ -17,6 +18,19 @@ type DashboardExtras struct {
Value
string
}
func
GetProvisionedDataByDashboardId
(
cmd
*
models
.
IsDashboardProvisionedQuery
)
error
{
result
:=
&
models
.
DashboardProvisioning
{}
exist
,
err
:=
x
.
Where
(
"dashboard_id = ?"
,
cmd
.
DashboardId
)
.
Get
(
result
)
if
err
!=
nil
{
return
err
}
cmd
.
Result
=
exist
return
nil
}
func
SaveProvisionedDashboard
(
cmd
*
models
.
SaveProvisionedDashboardCommand
)
error
{
return
inTransaction
(
func
(
sess
*
DBSession
)
error
{
err
:=
saveDashboard
(
sess
,
cmd
.
DashboardCmd
)
...
...
pkg/services/sqlstore/dashboard_provisioning_test.go
View file @
c1204154
...
...
@@ -50,6 +50,23 @@ func TestDashboardProvisioningTest(t *testing.T) {
So
(
query
.
Result
[
0
]
.
DashboardId
,
ShouldEqual
,
dashId
)
So
(
query
.
Result
[
0
]
.
Updated
,
ShouldEqual
,
now
.
Unix
())
})
Convey
(
"Can query for one provisioned dashboard"
,
func
()
{
query
:=
&
models
.
IsDashboardProvisionedQuery
{
DashboardId
:
cmd
.
Result
.
Id
}
err
:=
GetProvisionedDataByDashboardId
(
query
)
So
(
err
,
ShouldBeNil
)
So
(
query
.
Result
,
ShouldBeTrue
)
})
Convey
(
"Can query for none provisioned dashboard"
,
func
()
{
query
:=
&
models
.
IsDashboardProvisionedQuery
{
DashboardId
:
3000
}
err
:=
GetProvisionedDataByDashboardId
(
query
)
So
(
err
,
ShouldBeNil
)
So
(
query
.
Result
,
ShouldBeFalse
)
})
})
})
}
pkg/services/sqlstore/dashboard_service_integration_test.go
View file @
c1204154
...
...
@@ -19,7 +19,6 @@ func TestIntegratedDashboardService(t *testing.T) {
var
testOrgId
int64
=
1
Convey
(
"Given saved folders and dashboards in organization A"
,
func
()
{
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
ValidateDashboardAlertsCommand
)
error
{
return
nil
})
...
...
@@ -28,6 +27,11 @@ func TestIntegratedDashboardService(t *testing.T) {
return
nil
})
bus
.
AddHandler
(
"test"
,
func
(
cmd
*
models
.
IsDashboardProvisionedQuery
)
error
{
cmd
.
Result
=
false
return
nil
})
savedFolder
:=
saveTestFolder
(
"Saved folder"
,
testOrgId
)
savedDashInFolder
:=
saveTestDashboard
(
"Saved dash in folder"
,
testOrgId
,
savedFolder
.
Id
)
saveTestDashboard
(
"Other saved dash in folder"
,
testOrgId
,
savedFolder
.
Id
)
...
...
public/app/features/dashboard/all.ts
View file @
c1204154
...
...
@@ -6,6 +6,7 @@ import './dashnav/dashnav';
import
'./submenu/submenu'
;
import
'./save_as_modal'
;
import
'./save_modal'
;
import
'./save_provisioned_modal'
;
import
'./shareModalCtrl'
;
import
'./share_snapshot_ctrl'
;
import
'./dashboard_srv'
;
...
...
public/app/features/dashboard/dashboard_srv.ts
View file @
c1204154
...
...
@@ -105,6 +105,10 @@ export class DashboardSrv {
this
.
setCurrent
(
this
.
create
(
clone
,
this
.
dash
.
meta
));
}
if
(
this
.
dash
.
meta
.
provisioned
)
{
return
this
.
showDashboardProvisionedModal
();
}
if
(
!
this
.
dash
.
meta
.
canSave
&&
options
.
makeEditable
!==
true
)
{
return
Promise
.
resolve
();
}
...
...
@@ -120,6 +124,12 @@ export class DashboardSrv {
return
this
.
save
(
this
.
dash
.
getSaveModelClone
(),
options
);
}
showDashboardProvisionedModal
()
{
this
.
$rootScope
.
appEvent
(
'show-modal'
,
{
templateHtml
:
'<save-provisioned-dashboard-modal dismiss="dismiss()"></save-provisioned-dashboard-modal>'
,
});
}
showSaveAsModal
()
{
this
.
$rootScope
.
appEvent
(
'show-modal'
,
{
templateHtml
:
'<save-dashboard-as-modal dismiss="dismiss()"></save-dashboard-as-modal>'
,
...
...
public/app/features/dashboard/save_provisioned_modal.ts
0 → 100644
View file @
c1204154
import
angular
from
'angular'
;
import
{
saveAs
}
from
'file-saver'
;
import
coreModule
from
'app/core/core_module'
;
const
template
=
`
<div class="modal-body">
<div class="modal-header">
<h2 class="modal-header-title">
<i class="fa fa-save"></i><span class="p-l-1">Cannot save provisioned dashboard</span>
</h2>
<a class="modal-header-close" ng-click="ctrl.dismiss();">
<i class="fa fa-remove"></i>
</a>
</div>
<div class="modal-content">
<small>
This dashboard cannot be saved from Grafana's UI since it has been provisioned from another source.
Copy the JSON or save it to a file below. Then you can update your dashboard in corresponding provisioning source.<br/>
<i>See <a class="external-link" href="http://docs.grafana.org/administration/provisioning/#dashboards" target="_blank">
documentation</a> for more information about provisioning.</i>
</small>
<div class="p-t-2">
<div class="gf-form">
<code-editor content="ctrl.dashboardJson" data-mode="json" data-max-lines=15></code-editor>
</div>
<div class="gf-form-button-row">
<button class="btn btn-success" clipboard-button="ctrl.getJsonForClipboard()">
<i class="fa fa-clipboard"></i> Copy JSON to Clipboard
</button>
<button class="btn btn-secondary" clipboard-button="ctrl.save()">
<i class="fa fa-save"></i> Save JSON to file
</button>
<a class="btn btn-link" ng-click="ctrl.dismiss();">Cancel</a>
</div>
</div>
</div>
</div>
`
;
export
class
SaveProvisionedDashboardModalCtrl
{
dash
:
any
;
dashboardJson
:
string
;
dismiss
:
()
=>
void
;
/** @ngInject */
constructor
(
dashboardSrv
)
{
this
.
dash
=
dashboardSrv
.
getCurrent
().
getSaveModelClone
();
delete
this
.
dash
.
id
;
this
.
dashboardJson
=
JSON
.
stringify
(
this
.
dash
,
null
,
2
);
}
save
()
{
var
blob
=
new
Blob
([
angular
.
toJson
(
this
.
dash
,
true
)],
{
type
:
'application/json;charset=utf-8'
,
});
saveAs
(
blob
,
this
.
dash
.
title
+
'-'
+
new
Date
().
getTime
()
+
'.json'
);
}
getJsonForClipboard
()
{
return
this
.
dashboardJson
;
}
}
export
function
saveProvisionedDashboardModalDirective
()
{
return
{
restrict
:
'E'
,
template
:
template
,
controller
:
SaveProvisionedDashboardModalCtrl
,
bindToController
:
true
,
controllerAs
:
'ctrl'
,
scope
:
{
dismiss
:
'&'
},
};
}
coreModule
.
directive
(
'saveProvisionedDashboardModal'
,
saveProvisionedDashboardModalDirective
);
public/app/features/dashboard/specs/save_provisioned_modal.jest.ts
0 → 100644
View file @
c1204154
import
{
SaveProvisionedDashboardModalCtrl
}
from
'../save_provisioned_modal'
;
describe
(
'SaveProvisionedDashboardModalCtrl'
,
()
=>
{
var
json
=
{
title
:
'name'
,
id
:
5
,
};
var
mockDashboardSrv
=
{
getCurrent
:
function
()
{
return
{
id
:
5
,
meta
:
{},
getSaveModelClone
:
function
()
{
return
json
;
},
};
},
};
var
ctrl
=
new
SaveProvisionedDashboardModalCtrl
(
mockDashboardSrv
);
it
(
'should remove id from dashboard model'
,
()
=>
{
expect
(
ctrl
.
dash
.
id
).
toBeUndefined
();
});
it
(
'should remove id from dashboard model in clipboard json'
,
()
=>
{
expect
(
ctrl
.
getJsonForClipboard
()).
toBe
(
JSON
.
stringify
({
title
:
'name'
},
null
,
2
));
});
});
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