add isPublic to dashboard (#48012)
adds toggle to make a dashboard public * config struct for public dashboard config * api endpoints for public dashboard configuration * ui for toggling public dashboard on and off * load public dashboard config on share modal Co-authored-by: Owen Smallwood <owen.smallwood@grafana.com> Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
This commit is contained in:
co-authored by
Owen Smallwood
Torkel Ödegaard
parent
156e14e296
commit
c7f8c2cc73
@@ -6,9 +6,18 @@ import (
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
// Generating mocks is handled by vektra/mockery
|
||||
// 1. install go mockery https://github.com/vektra/mockery#go-install
|
||||
// 2. add your method to the relevant services
|
||||
// 3. from the same directory as this file run `go generate` and it will update the mock
|
||||
// If you don't see any output, this most likely means your OS can't find the mockery binary
|
||||
// `which mockery` to confirm and follow one of the installation methods
|
||||
|
||||
// DashboardService is a service for operating on dashboards.
|
||||
type DashboardService interface {
|
||||
SaveDashboard(ctx context.Context, dto *SaveDashboardDTO, allowUiUpdate bool) (*models.Dashboard, error)
|
||||
GetPublicDashboardConfig(ctx context.Context, orgId int64, dashboardUid string) (*models.PublicDashboardConfig, error)
|
||||
SavePublicDashboardConfig(ctx context.Context, dto *SavePublicDashboardConfigDTO) (*models.PublicDashboardConfig, error)
|
||||
ImportDashboard(ctx context.Context, dto *SaveDashboardDTO) (*models.Dashboard, error)
|
||||
DeleteDashboard(ctx context.Context, dashboardId int64, orgId int64) error
|
||||
MakeUserAdmin(ctx context.Context, orgID int64, userID, dashboardID int64, setViewAndEditPermissions bool) error
|
||||
@@ -45,6 +54,8 @@ type Store interface {
|
||||
GetProvisionedDashboardData(name string) ([]*models.DashboardProvisioning, error)
|
||||
SaveProvisionedDashboard(cmd models.SaveDashboardCommand, provisioning *models.DashboardProvisioning) (*models.Dashboard, error)
|
||||
SaveDashboard(cmd models.SaveDashboardCommand) (*models.Dashboard, error)
|
||||
SavePublicDashboardConfig(cmd models.SavePublicDashboardConfigCommand) (*models.PublicDashboardConfig, error)
|
||||
GetPublicDashboardConfig(orgId int64, dashboardUid string) (*models.PublicDashboardConfig, error)
|
||||
UpdateDashboardACL(ctx context.Context, uid int64, items []*models.DashboardAcl) error
|
||||
DeleteOrphanedProvisionedDashboards(ctx context.Context, cmd *models.DeleteOrphanedProvisionedDashboardsCommand) error
|
||||
// SaveAlerts saves dashboard alerts.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.10.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.12.1. DO NOT EDIT.
|
||||
|
||||
package dashboards
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
|
||||
models "github.com/grafana/grafana/pkg/models"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
testing "testing"
|
||||
)
|
||||
|
||||
// FakeDashboardProvisioning is an autogenerated mock type for the DashboardProvisioningService type
|
||||
@@ -170,3 +172,13 @@ func (_m *FakeDashboardProvisioning) UnprovisionDashboard(ctx context.Context, d
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// NewFakeDashboardProvisioning creates a new instance of FakeDashboardProvisioning. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewFakeDashboardProvisioning(t testing.TB) *FakeDashboardProvisioning {
|
||||
mock := &FakeDashboardProvisioning{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
|
||||
@@ -10,11 +10,13 @@ type FakeDashboardService struct {
|
||||
DashboardService
|
||||
|
||||
SaveDashboardResult *models.Dashboard
|
||||
SaveDashboardError error
|
||||
SavedDashboards []*SaveDashboardDTO
|
||||
ProvisionedDashData *models.DashboardProvisioning
|
||||
|
||||
GetDashboardFn func(ctx context.Context, cmd *models.GetDashboardQuery) error
|
||||
PublicDashboardConfigResult *models.PublicDashboardConfig
|
||||
PublicDashboardConfigError error
|
||||
SaveDashboardError error
|
||||
GetDashboardFn func(ctx context.Context, cmd *models.GetDashboardQuery) error
|
||||
}
|
||||
|
||||
func (s *FakeDashboardService) SaveDashboard(ctx context.Context, dto *SaveDashboardDTO, allowUiUpdate bool) (*models.Dashboard, error) {
|
||||
@@ -27,6 +29,14 @@ func (s *FakeDashboardService) SaveDashboard(ctx context.Context, dto *SaveDashb
|
||||
return s.SaveDashboardResult, s.SaveDashboardError
|
||||
}
|
||||
|
||||
func (s *FakeDashboardService) GetPublicDashboardConfig(ctx context.Context, orgId int64, dashboardUid string) (*models.PublicDashboardConfig, error) {
|
||||
return s.PublicDashboardConfigResult, s.PublicDashboardConfigError
|
||||
}
|
||||
|
||||
func (s *FakeDashboardService) SavePublicDashboardConfig(ctx context.Context, dto *SavePublicDashboardConfigDTO) (*models.PublicDashboardConfig, error) {
|
||||
return s.PublicDashboardConfigResult, s.PublicDashboardConfigError
|
||||
}
|
||||
|
||||
func (s *FakeDashboardService) ImportDashboard(ctx context.Context, dto *SaveDashboardDTO) (*models.Dashboard, error) {
|
||||
return s.SaveDashboard(ctx, dto, true)
|
||||
}
|
||||
|
||||
@@ -187,6 +187,47 @@ func (d *DashboardStore) SaveDashboard(cmd models.SaveDashboardCommand) (*models
|
||||
return cmd.Result, err
|
||||
}
|
||||
|
||||
// retrieves public dashboard configuration
|
||||
func (d *DashboardStore) GetPublicDashboardConfig(orgId int64, dashboardUid string) (*models.PublicDashboardConfig, error) {
|
||||
var result []*models.Dashboard
|
||||
|
||||
err := d.sqlStore.WithTransactionalDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||
return sess.Where("org_id = ? AND uid= ?", orgId, dashboardUid).Find(&result)
|
||||
})
|
||||
|
||||
if len(result) == 0 {
|
||||
return nil, models.ErrDashboardNotFound
|
||||
}
|
||||
|
||||
pdc := &models.PublicDashboardConfig{
|
||||
IsPublic: result[0].IsPublic,
|
||||
}
|
||||
|
||||
return pdc, err
|
||||
}
|
||||
|
||||
// stores public dashboard configuration
|
||||
func (d *DashboardStore) SavePublicDashboardConfig(cmd models.SavePublicDashboardConfigCommand) (*models.PublicDashboardConfig, error) {
|
||||
err := d.sqlStore.WithTransactionalDbSession(context.Background(), func(sess *sqlstore.DBSession) error {
|
||||
affectedRowCount, err := sess.Table("dashboard").Where("org_id = ? AND uid = ?", cmd.OrgId, cmd.Uid).Update(map[string]interface{}{"is_public": cmd.PublicDashboardConfig.IsPublic})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if affectedRowCount == 0 {
|
||||
return models.ErrDashboardNotFound
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &cmd.PublicDashboardConfig, nil
|
||||
}
|
||||
|
||||
func (d *DashboardStore) UpdateDashboardACL(ctx context.Context, dashboardID int64, items []*models.DashboardAcl) error {
|
||||
return d.sqlStore.WithTransactionalDbSession(ctx, func(sess *sqlstore.DBSession) error {
|
||||
// delete existing items
|
||||
|
||||
@@ -210,6 +210,29 @@ func (_m *FakeDashboardStore) GetProvisionedDataByDashboardUID(orgID int64, dash
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetPublicDashboardConfig provides a mock function with given fields: dashboardUid
|
||||
func (_m *FakeDashboardStore) GetPublicDashboardConfig(orgId int64, dashboardUid string) (*models.PublicDashboardConfig, error) {
|
||||
ret := _m.Called(dashboardUid)
|
||||
|
||||
var r0 *models.PublicDashboardConfig
|
||||
if rf, ok := ret.Get(0).(func(string) *models.PublicDashboardConfig); ok {
|
||||
r0 = rf(dashboardUid)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*models.PublicDashboardConfig)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||
r1 = rf(dashboardUid)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// SaveAlerts provides a mock function with given fields: ctx, dashID, alerts
|
||||
func (_m *FakeDashboardStore) SaveAlerts(ctx context.Context, dashID int64, alerts []*models.Alert) error {
|
||||
ret := _m.Called(ctx, dashID, alerts)
|
||||
@@ -270,6 +293,29 @@ func (_m *FakeDashboardStore) SaveProvisionedDashboard(cmd models.SaveDashboardC
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// SavePublicDashboardConfig provides a mock function with given fields: cmd
|
||||
func (_m *FakeDashboardStore) SavePublicDashboardConfig(cmd models.SavePublicDashboardConfigCommand) (*models.PublicDashboardConfig, error) {
|
||||
ret := _m.Called(cmd)
|
||||
|
||||
var r0 *models.PublicDashboardConfig
|
||||
if rf, ok := ret.Get(0).(func(models.SavePublicDashboardConfigCommand) *models.PublicDashboardConfig); ok {
|
||||
r0 = rf(cmd)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*models.PublicDashboardConfig)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(models.SavePublicDashboardConfigCommand) error); ok {
|
||||
r1 = rf(cmd)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// UnprovisionDashboard provides a mock function with given fields: ctx, id
|
||||
func (_m *FakeDashboardStore) UnprovisionDashboard(ctx context.Context, id int64) error {
|
||||
ret := _m.Called(ctx, id)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.10.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.12.1. DO NOT EDIT.
|
||||
|
||||
package dashboards
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
|
||||
models "github.com/grafana/grafana/pkg/models"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
testing "testing"
|
||||
)
|
||||
|
||||
// FakeFolderService is an autogenerated mock type for the FolderService type
|
||||
@@ -179,3 +181,13 @@ func (_m *FakeFolderService) UpdateFolder(ctx context.Context, user *models.Sign
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// NewFakeFolderService creates a new instance of FakeFolderService. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewFakeFolderService(t testing.TB) *FakeFolderService {
|
||||
mock := &FakeFolderService{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.10.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.12.1. DO NOT EDIT.
|
||||
|
||||
package dashboards
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
|
||||
models "github.com/grafana/grafana/pkg/models"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
|
||||
testing "testing"
|
||||
)
|
||||
|
||||
// FakeFolderStore is an autogenerated mock type for the FolderStore type
|
||||
@@ -82,3 +84,13 @@ func (_m *FakeFolderStore) GetFolderByUID(ctx context.Context, orgID int64, uid
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// NewFakeFolderStore creates a new instance of FakeFolderStore. It also registers the testing.TB interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
func NewFakeFolderStore(t testing.TB) *FakeFolderStore {
|
||||
mock := &FakeFolderStore{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
|
||||
@@ -14,3 +14,9 @@ type SaveDashboardDTO struct {
|
||||
Overwrite bool
|
||||
Dashboard *models.Dashboard
|
||||
}
|
||||
|
||||
type SavePublicDashboardConfigDTO struct {
|
||||
Uid string
|
||||
OrgId int64
|
||||
PublicDashboardConfig models.PublicDashboardConfig
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
||||
@@ -342,6 +341,33 @@ func (dr *DashboardServiceImpl) SaveDashboard(ctx context.Context, dto *m.SaveDa
|
||||
return dash, nil
|
||||
}
|
||||
|
||||
// GetPublicDashboardConfig is a helper method to retrieve the public dashboard configuration for a given dashboard from the database
|
||||
func (dr *DashboardServiceImpl) GetPublicDashboardConfig(ctx context.Context, orgId int64, dashboardUid string) (*models.PublicDashboardConfig, error) {
|
||||
pdc, err := dr.dashboardStore.GetPublicDashboardConfig(orgId, dashboardUid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pdc, nil
|
||||
}
|
||||
|
||||
// SavePublicDashboardConfig is a helper method to persist the sharing config
|
||||
// to the database. It handles validations for sharing config and persistence
|
||||
func (dr *DashboardServiceImpl) SavePublicDashboardConfig(ctx context.Context, dto *m.SavePublicDashboardConfigDTO) (*models.PublicDashboardConfig, error) {
|
||||
cmd := models.SavePublicDashboardConfigCommand{
|
||||
Uid: dto.Uid,
|
||||
OrgId: dto.OrgId,
|
||||
PublicDashboardConfig: dto.PublicDashboardConfig,
|
||||
}
|
||||
|
||||
pdc, err := dr.dashboardStore.SavePublicDashboardConfig(cmd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pdc, nil
|
||||
}
|
||||
|
||||
// DeleteDashboard removes dashboard from the DB. Errors out if the dashboard was provisioned. Should be used for
|
||||
// operations by the user where we want to make sure user does not delete provisioned dashboard.
|
||||
func (dr *DashboardServiceImpl) DeleteDashboard(ctx context.Context, dashboardId int64, orgId int64) error {
|
||||
|
||||
Reference in New Issue
Block a user