mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
parent
acd85314b3
commit
3bc13e2335
@ -77,6 +77,18 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) response.Response {
|
|||||||
if rsp != nil {
|
if rsp != nil {
|
||||||
return rsp
|
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.
|
// When dash contains only keys id, uid that means dashboard data is not valid and json decode failed.
|
||||||
if dash.Data != nil {
|
if dash.Data != nil {
|
||||||
isEmptyData := true
|
isEmptyData := true
|
||||||
@ -139,6 +151,7 @@ func (hs *HTTPServer) GetDashboard(c *models.ReqContext) response.Response {
|
|||||||
Url: dash.GetUrl(),
|
Url: dash.GetUrl(),
|
||||||
FolderTitle: "General",
|
FolderTitle: "General",
|
||||||
AnnotationsPermissions: annotationPermissions,
|
AnnotationsPermissions: annotationPermissions,
|
||||||
|
PublicDashboardEnabled: hasPublicDashboard,
|
||||||
}
|
}
|
||||||
|
|
||||||
// lookup folder title
|
// lookup folder title
|
||||||
|
@ -261,6 +261,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
|||||||
AccessControl: accesscontrolmock.New(),
|
AccessControl: accesscontrolmock.New(),
|
||||||
DashboardService: dashboardService,
|
DashboardService: dashboardService,
|
||||||
dashboardVersionService: fakeDashboardVersionService,
|
dashboardVersionService: fakeDashboardVersionService,
|
||||||
|
Features: featuremgmt.WithFeatures(),
|
||||||
}
|
}
|
||||||
hs.CoremodelStaticRegistry, hs.CoremodelRegistry = setupDashboardCoremodel(t)
|
hs.CoremodelStaticRegistry, hs.CoremodelRegistry = setupDashboardCoremodel(t)
|
||||||
|
|
||||||
@ -901,6 +902,7 @@ func TestDashboardAPIEndpoint(t *testing.T) {
|
|||||||
SQLStore: mockSQLStore,
|
SQLStore: mockSQLStore,
|
||||||
AccessControl: accesscontrolmock.New(),
|
AccessControl: accesscontrolmock.New(),
|
||||||
DashboardService: dashboardService,
|
DashboardService: dashboardService,
|
||||||
|
Features: featuremgmt.WithFeatures(),
|
||||||
}
|
}
|
||||||
hs.CoremodelStaticRegistry, hs.CoremodelRegistry = setupDashboardCoremodel(t)
|
hs.CoremodelStaticRegistry, hs.CoremodelRegistry = setupDashboardCoremodel(t)
|
||||||
hs.callGetDashboard(sc)
|
hs.callGetDashboard(sc)
|
||||||
@ -955,6 +957,7 @@ func getDashboardShouldReturn200WithConfig(t *testing.T, sc *scenarioContext, pr
|
|||||||
folderPermissions, dashboardPermissions, ac,
|
folderPermissions, dashboardPermissions, ac,
|
||||||
),
|
),
|
||||||
DashboardService: dashboardService,
|
DashboardService: dashboardService,
|
||||||
|
Features: featuremgmt.WithFeatures(),
|
||||||
}
|
}
|
||||||
hs.CoremodelStaticRegistry, hs.CoremodelRegistry = setupDashboardCoremodel(t)
|
hs.CoremodelStaticRegistry, hs.CoremodelRegistry = setupDashboardCoremodel(t)
|
||||||
|
|
||||||
@ -1053,6 +1056,7 @@ func postDiffScenario(t *testing.T, desc string, url string, routePattern string
|
|||||||
LibraryElementService: &mockLibraryElementService{},
|
LibraryElementService: &mockLibraryElementService{},
|
||||||
SQLStore: sqlmock,
|
SQLStore: sqlmock,
|
||||||
dashboardVersionService: fakeDashboardVersionService,
|
dashboardVersionService: fakeDashboardVersionService,
|
||||||
|
Features: featuremgmt.WithFeatures(),
|
||||||
}
|
}
|
||||||
hs.CoremodelStaticRegistry, hs.CoremodelRegistry = setupDashboardCoremodel(t)
|
hs.CoremodelStaticRegistry, hs.CoremodelRegistry = setupDashboardCoremodel(t)
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ type DashboardMeta struct {
|
|||||||
ProvisionedExternalId string `json:"provisionedExternalId"`
|
ProvisionedExternalId string `json:"provisionedExternalId"`
|
||||||
AnnotationsPermissions *AnnotationPermission `json:"annotationsPermissions"`
|
AnnotationsPermissions *AnnotationPermission `json:"annotationsPermissions"`
|
||||||
PublicDashboardAccessToken string `json:"publicDashboardAccessToken"`
|
PublicDashboardAccessToken string `json:"publicDashboardAccessToken"`
|
||||||
|
PublicDashboardEnabled bool `json:"publicDashboardEnabled"`
|
||||||
}
|
}
|
||||||
type AnnotationPermission struct {
|
type AnnotationPermission struct {
|
||||||
Dashboard AnnotationActions `json:"dashboard"`
|
Dashboard AnnotationActions `json:"dashboard"`
|
||||||
|
@ -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
|
package dashboards
|
||||||
|
|
||||||
|
@ -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
|
package dashboards
|
||||||
|
|
||||||
|
@ -171,3 +171,21 @@ func (d *PublicDashboardStoreImpl) UpdatePublicDashboardConfig(ctx context.Conte
|
|||||||
|
|
||||||
return err
|
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
|
||||||
|
}
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/grafana/grafana/pkg/components/simplejson"
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
||||||
"github.com/grafana/grafana/pkg/models"
|
"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"
|
dashboardsDB "github.com/grafana/grafana/pkg/services/dashboards/database"
|
||||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||||
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
|
. "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)
|
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) {
|
t.Run("returns PublicDashboard and Dashboard", func(t *testing.T) {
|
||||||
setup()
|
setup()
|
||||||
pubdash, err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
|
pubdash, err := publicdashboardStore.SavePublicDashboardConfig(context.Background(), SavePublicDashboardConfigCommand{
|
||||||
|
@ -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
|
package publicdashboards
|
||||||
|
|
||||||
@ -110,6 +110,27 @@ func (_m *FakePublicDashboardService) GetPublicDashboardConfig(ctx context.Conte
|
|||||||
return r0, r1
|
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
|
// SavePublicDashboardConfig provides a mock function with given fields: ctx, dto
|
||||||
func (_m *FakePublicDashboardService) SavePublicDashboardConfig(ctx context.Context, dto *publicdashboardsmodels.SavePublicDashboardConfigDTO) (*publicdashboardsmodels.PublicDashboard, error) {
|
func (_m *FakePublicDashboardService) SavePublicDashboardConfig(ctx context.Context, dto *publicdashboardsmodels.SavePublicDashboardConfigDTO) (*publicdashboardsmodels.PublicDashboard, error) {
|
||||||
ret := _m.Called(ctx, dto)
|
ret := _m.Called(ctx, dto)
|
||||||
|
@ -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
|
package publicdashboards
|
||||||
|
|
||||||
@ -94,6 +94,27 @@ func (_m *FakePublicDashboardStore) GetPublicDashboardConfig(ctx context.Context
|
|||||||
return r0, r1
|
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
|
// SavePublicDashboardConfig provides a mock function with given fields: ctx, cmd
|
||||||
func (_m *FakePublicDashboardStore) SavePublicDashboardConfig(ctx context.Context, cmd models.SavePublicDashboardConfigCommand) (*models.PublicDashboard, error) {
|
func (_m *FakePublicDashboardStore) SavePublicDashboardConfig(ctx context.Context, cmd models.SavePublicDashboardConfigCommand) (*models.PublicDashboard, error) {
|
||||||
ret := _m.Called(ctx, cmd)
|
ret := _m.Called(ctx, cmd)
|
||||||
|
@ -17,6 +17,7 @@ type Service interface {
|
|||||||
GetPublicDashboardConfig(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
|
GetPublicDashboardConfig(ctx context.Context, orgId int64, dashboardUid string) (*PublicDashboard, error)
|
||||||
SavePublicDashboardConfig(ctx context.Context, dto *SavePublicDashboardConfigDTO) (*PublicDashboard, error)
|
SavePublicDashboardConfig(ctx context.Context, dto *SavePublicDashboardConfigDTO) (*PublicDashboard, error)
|
||||||
BuildPublicDashboardMetricRequest(ctx context.Context, dashboard *models.Dashboard, publicDashboard *PublicDashboard, panelId int64) (dtos.MetricRequest, 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
|
//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)
|
GenerateNewPublicDashboardUid(ctx context.Context) (string, error)
|
||||||
SavePublicDashboardConfig(ctx context.Context, cmd SavePublicDashboardConfigCommand) (*PublicDashboard, error)
|
SavePublicDashboardConfig(ctx context.Context, cmd SavePublicDashboardConfigCommand) (*PublicDashboard, error)
|
||||||
UpdatePublicDashboardConfig(ctx context.Context, cmd SavePublicDashboardConfigCommand) error
|
UpdatePublicDashboardConfig(ctx context.Context, cmd SavePublicDashboardConfigCommand) error
|
||||||
|
PublicDashboardEnabled(ctx context.Context, dashboardUid string) (bool, error)
|
||||||
}
|
}
|
||||||
|
@ -189,6 +189,10 @@ func (pd *PublicDashboardServiceImpl) BuildAnonymousUser(ctx context.Context, da
|
|||||||
return anonymousUser, nil
|
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
|
// generates a uuid formatted without dashes to use as access token
|
||||||
func GenerateAccessToken() (string, error) {
|
func GenerateAccessToken() (string, error) {
|
||||||
token, err := uuid.NewRandom()
|
token, err := uuid.NewRandom()
|
||||||
|
@ -4,7 +4,7 @@ import { useLocation } from 'react-router-dom';
|
|||||||
|
|
||||||
import { locationUtil, textUtil } from '@grafana/data';
|
import { locationUtil, textUtil } from '@grafana/data';
|
||||||
import { locationService } from '@grafana/runtime';
|
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 { AppChromeUpdate } from 'app/core/components/AppChrome/AppChromeUpdate';
|
||||||
import { NavToolbarSeparator } from 'app/core/components/AppChrome/NavToolbarSeparator';
|
import { NavToolbarSeparator } from 'app/core/components/AppChrome/NavToolbarSeparator';
|
||||||
import config from 'app/core/config';
|
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) {
|
if (dashboard.uid && config.featureToggles.dashboardComments) {
|
||||||
buttons.push(
|
buttons.push(
|
||||||
<ModalsController key="button-dashboard-comments">
|
<ModalsController key="button-dashboard-comments">
|
||||||
|
@ -42,6 +42,7 @@ export interface DashboardMeta {
|
|||||||
hasUnsavedFolderChange?: boolean;
|
hasUnsavedFolderChange?: boolean;
|
||||||
annotationsPermissions?: AnnotationsPermissions;
|
annotationsPermissions?: AnnotationsPermissions;
|
||||||
publicDashboardAccessToken?: string;
|
publicDashboardAccessToken?: string;
|
||||||
|
publicDashboardEnabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AnnotationActions {
|
export interface AnnotationActions {
|
||||||
|
Loading…
Reference in New Issue
Block a user