Public Dashboards: Add Public Tag to Dashboard Title (#52351)

Adds Public tag to dashboard title when it has an enabled public dashboard
This commit is contained in:
owensmallwood 2022-07-19 17:44:41 -06:00 committed by GitHub
parent acd85314b3
commit 3bc13e2335
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 143 additions and 6 deletions

View File

@ -77,6 +77,18 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) response.Response {
if rsp != nil {
return rsp
}
var (
hasPublicDashboard bool
err error
)
if hs.Features.IsEnabled(featuremgmt.FlagPublicDashboards) {
hasPublicDashboard, err = hs.PublicDashboardsApi.PublicDashboardService.PublicDashboardEnabled(c.Req.Context(), dash.Uid)
if err != nil {
return response.Error(500, "Error while retrieving public dashboards", err)
}
}
// When dash contains only keys id, uid that means dashboard data is not valid and json decode failed.
if dash.Data != nil {
isEmptyData := true
@ -139,6 +151,7 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) response.Response {
Url: dash.GetUrl(),
FolderTitle: "General",
AnnotationsPermissions: annotationPermissions,
PublicDashboardEnabled: hasPublicDashboard,
}
// lookup folder title

View File

@ -261,6 +261,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
AccessControl: accesscontrolmock.New(),
DashboardService: dashboardService,
dashboardVersionService: fakeDashboardVersionService,
Features: featuremgmt.WithFeatures(),
}
hs.CoremodelStaticRegistry, hs.CoremodelRegistry = setupDashboardCoremodel(t)
@ -901,6 +902,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
SQLStore: mockSQLStore,
AccessControl: accesscontrolmock.New(),
DashboardService: dashboardService,
Features: featuremgmt.WithFeatures(),
}
hs.CoremodelStaticRegistry, hs.CoremodelRegistry = setupDashboardCoremodel(t)
hs.callGetDashboard(sc)
@ -955,6 +957,7 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
folderPermissions, dashboardPermissions, ac,
),
DashboardService: dashboardService,
Features: featuremgmt.WithFeatures(),
}
hs.CoremodelStaticRegistry, hs.CoremodelRegistry = setupDashboardCoremodel(t)
@ -1053,6 +1056,7 @@ func postDiffScenario(t *testing.T, desc string, url string, routePattern string
LibraryElementService: &mockLibraryElementService{},
SQLStore: sqlmock,
dashboardVersionService: fakeDashboardVersionService,
Features: featuremgmt.WithFeatures(),
}
hs.CoremodelStaticRegistry, hs.CoremodelRegistry = setupDashboardCoremodel(t)

View File

@ -34,6 +34,7 @@ type DashboardMeta struct {
ProvisionedExternalId string `json:"provisionedExternalId"`
AnnotationsPermissions *AnnotationPermission `json:"annotationsPermissions"`
PublicDashboardAccessToken string `json:"publicDashboardAccessToken"`
PublicDashboardEnabled bool `json:"publicDashboardEnabled"`
}
type AnnotationPermission struct {
Dashboard AnnotationActions `json:"dashboard"`

View File

@ -1,4 +1,4 @@
// Code generated by mockery v2.12.2. DO NOT EDIT.
// Code generated by mockery v2.12.1. DO NOT EDIT.
package dashboards

View File

@ -1,4 +1,4 @@
// Code generated by mockery v2.12.2. DO NOT EDIT.
// Code generated by mockery v2.12.1. DO NOT EDIT.
package dashboards

View File

@ -171,3 +171,21 @@ func (d *PublicDashboardStoreImpl) UpdatePublicDashboardConfig(ctx context.Conte
return err
}
func (d *PublicDashboardStoreImpl) PublicDashboardEnabled(ctx context.Context, dashboardUid string) (bool, error) {
hasPublicDashboard := false
err := d.sqlStore.WithDbSession(ctx, func(dbSession *sqlstore.DBSession) error {
sql := "SELECT COUNT(*) FROM dashboard_public WHERE dashboard_uid=? AND is_enabled=true"
result, err := dbSession.SQL(sql, dashboardUid).Count()
if err != nil {
return err
}
hasPublicDashboard = result > 0
return err
})
return hasPublicDashboard, err
}

View File

@ -10,7 +10,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
dashboards "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards"
dashboardsDB "github.com/grafana/grafana/pkg/services/dashboards/database"
"github.com/grafana/grafana/pkg/services/featuremgmt"
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
@ -38,6 +38,54 @@ func TestIntegrationGetPublicDashboard(t *testing.T) {
savedDashboard = insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true)
}
t.Run("PublicDashboardEnabled Will return true when dashboard has at least one enabled public dashboard", func(t *testing.T) {
setup()
_, err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
DashboardUid: savedDashboard.Uid,
OrgId: savedDashboard.OrgId,
PublicDashboard: PublicDashboard{
IsEnabled: true,
Uid: "abc123",
DashboardUid: savedDashboard.Uid,
OrgId: savedDashboard.OrgId,
CreatedAt: time.Now(),
CreatedBy: 7,
AccessToken: "NOTAREALUUID",
},
})
require.NoError(t, err)
res, err := publicdashboardStore.PublicDashboardEnabled(context.Background(), savedDashboard.Uid)
require.NoError(t, err)
require.True(t, res)
})
t.Run("PublicDashboardEnabled will return false when dashboard has public dashboards but they are not enabled", func(t *testing.T) {
setup()
_, err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
DashboardUid: savedDashboard.Uid,
OrgId: savedDashboard.OrgId,
PublicDashboard: PublicDashboard{
IsEnabled: false,
Uid: "abc123",
DashboardUid: savedDashboard.Uid,
OrgId: savedDashboard.OrgId,
CreatedAt: time.Now(),
CreatedBy: 7,
AccessToken: "NOTAREALUUID",
},
})
require.NoError(t, err)
res, err := publicdashboardStore.PublicDashboardEnabled(context.Background(), savedDashboard.Uid)
require.NoError(t, err)
require.False(t, res)
})
t.Run("returns PublicDashboard and Dashboard", func(t *testing.T) {
setup()
pubdash, err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{

View File

@ -1,4 +1,4 @@
// Code generated by mockery v2.12.2. DO NOT EDIT.
// Code generated by mockery v2.12.1. DO NOT EDIT.
package publicdashboards
@ -110,6 +110,27 @@ func (_m *FakePublicDashboardService) GetPublicDashboardConfig(ctx context.Conte
return r0, r1
}
// PublicDashboardEnabled provides a mock function with given fields: ctx, dashboardUid
func (_m *FakePublicDashboardService) PublicDashboardEnabled(ctx context.Context, dashboardUid string) (bool, error) {
ret := _m.Called(ctx, dashboardUid)
var r0 bool
if rf, ok := ret.Get(0).(func(context.Context, string) bool); ok {
r0 = rf(ctx, dashboardUid)
} else {
r0 = ret.Get(0).(bool)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, dashboardUid)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// SavePublicDashboardConfig provides a mock function with given fields: ctx, dto
func (_m *FakePublicDashboardService) SavePublicDashboardConfig(ctx context.Context, dto *publicdashboardsmodels.SavePublicDashboardConfigDTO) (*publicdashboardsmodels.PublicDashboard, error) {
ret := _m.Called(ctx, dto)

View File

@ -1,4 +1,4 @@
// Code generated by mockery v2.12.2. DO NOT EDIT.
// Code generated by mockery v2.12.1. DO NOT EDIT.
package publicdashboards
@ -94,6 +94,27 @@ func (_m *FakePublicDashboardStore) GetPublicDashboardConfig(ctx context.Context
return r0, r1
}
// PublicDashboardEnabled provides a mock function with given fields: ctx, dashboardUid
func (_m *FakePublicDashboardStore) PublicDashboardEnabled(ctx context.Context, dashboardUid string) (bool, error) {
ret := _m.Called(ctx, dashboardUid)
var r0 bool
if rf, ok := ret.Get(0).(func(context.Context, string) bool); ok {
r0 = rf(ctx, dashboardUid)
} else {
r0 = ret.Get(0).(bool)
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, dashboardUid)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// SavePublicDashboardConfig provides a mock function with given fields: ctx, cmd
func (_m *FakePublicDashboardStore) SavePublicDashboardConfig(ctx context.Context, cmd models.SavePublicDashboardConfigCommand) (*models.PublicDashboard, error) {
ret := _m.Called(ctx, cmd)

View File

@ -17,6 +17,7 @@ type Service interface {
GetPublicDashboardConfig(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
SavePublicDashboardConfig(ctx context.Context, dto *SavePublicDashboardConfigDTO) (*PublicDashboard, error)
BuildPublicDashboardMetricRequest(ctx context.Context, dashboard *models.Dashboard, publicDashboard *PublicDashboard, panelId int64) (dtos.MetricRequest, error)
PublicDashboardEnabled(ctx context.Context, dashboardUid string) (bool, error)
}
//go:generate mockery --name Store --structname FakePublicDashboardStore --inpackage --filename public_dashboard_store_mock.go
@ -26,4 +27,5 @@ type Store interface {
GenerateNewPublicDashboardUid(ctx context.Context) (string, error)
SavePublicDashboardConfig(ctx context.Context, cmd SavePublicDashboardConfigCommand) (*PublicDashboard, error)
UpdatePublicDashboardConfig(ctx context.Context, cmd SavePublicDashboardConfigCommand) error
PublicDashboardEnabled(ctx context.Context, dashboardUid string) (bool, error)
}

View File

@ -189,6 +189,10 @@ func (pd *PublicDashboardServiceImpl) BuildAnonymousUser(ctx context.Context, da
return anonymousUser, nil
}
func (pd *PublicDashboardServiceImpl) PublicDashboardEnabled(ctx context.Context, dashboardUid string) (bool, error) {
return pd.store.PublicDashboardEnabled(ctx, dashboardUid)
}
// generates a uuid formatted without dashes to use as access token
func GenerateAccessToken() (string, error) {
token, err := uuid.NewRandom()

View File

@ -4,7 +4,7 @@ import { useLocation } from 'react-router-dom';
import { locationUtil, textUtil } from '@grafana/data';
import { locationService } from '@grafana/runtime';
import { ButtonGroup, ModalsController, ToolbarButton, PageToolbar, useForceUpdate } from '@grafana/ui';
import { ButtonGroup, ModalsController, ToolbarButton, PageToolbar, useForceUpdate, Tag } from '@grafana/ui';
import { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
import { NavToolbarSeparator } from 'app/core/components/AppChrome/NavToolbarSeparator';
import config from 'app/core/config';
@ -154,6 +154,10 @@ export const DashNav = React.memo<Props>((props) => {
);
}
if (dashboard.meta.publicDashboardEnabled) {
buttons.push(<Tag name="Public" colorIndex={5}></Tag>);
}
if (dashboard.uid && config.featureToggles.dashboardComments) {
buttons.push(
<ModalsController key="button-dashboard-comments">

View File

@ -42,6 +42,7 @@ export interface DashboardMeta {
hasUnsavedFolderChange?: boolean;
annotationsPermissions?: AnnotationsPermissions;
publicDashboardAccessToken?: string;
publicDashboardEnabled?: boolean;
}
export interface AnnotationActions {