Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PublicDashboards: Add annotations support #56413

Merged
merged 49 commits into from
Oct 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
a526987
Adds backend pubdash support for annotations
owensmallwood Oct 4, 2022
8889988
Adds frontend support for pubdash annotations
owensmallwood Oct 4, 2022
baf4e58
dont get rules when its a public dashboard
owensmallwood Oct 4, 2022
ded15f6
Merge branch 'main' into owensmallwood/pubdash-add-annotations-support
owensmallwood Oct 4, 2022
1db5187
Only send out request for grafana annotations. Don't support query an…
owensmallwood Oct 5, 2022
e420e4e
Adds permissions for getting annotations. Anonymous user needs to be …
owensmallwood Oct 5, 2022
5091e31
regenerates mocks for pubdash service
owensmallwood Oct 5, 2022
fcb47a1
Adds validation for getting pubdash annotations
owensmallwood Oct 5, 2022
9ee81c1
Fixes failing tests. Needed to provide annotations service.
owensmallwood Oct 5, 2022
e23cf1d
Adds tests for pubdash annotations api
owensmallwood Oct 5, 2022
5f75198
formatting
owensmallwood Oct 5, 2022
a2eb4ba
Generates mock for annotations service
owensmallwood Oct 5, 2022
1747f98
Adds pubdash service tests for getting annotations
owensmallwood Oct 5, 2022
302535f
change annotations repo on http_server back to private
owensmallwood Oct 6, 2022
0651445
JsonEditorSettings: Fix invisible json editor
kaydelaney Oct 6, 2022
0b773a0
Merge branch 'main' into owensmallwood/pubdash-add-annotations-support
owensmallwood Oct 6, 2022
9639d9a
Merge remote-tracking branch 'origin/fix-json-editor-settings' into o…
owensmallwood Oct 6, 2022
8bb014f
Gets pubdash annotations from the backend in one request. WIP
owensmallwood Oct 6, 2022
0afb9f4
Gathers all pubdash annotations on the backend. Uses default annotati…
owensmallwood Oct 7, 2022
234287e
Merge branch 'main' into owensmallwood/pubdash-add-annotations-support
owensmallwood Oct 7, 2022
6b8a9c8
Updates pubdash annotations tests
owensmallwood Oct 7, 2022
c28a48e
Excludes annotation queries when looping over dashboard annotations. …
owensmallwood Oct 7, 2022
a3ff68b
Updates test to make sure disabled dashboard annotations are excluded.
owensmallwood Oct 7, 2022
c200233
removes stuff from bad merge
owensmallwood Oct 7, 2022
430f6df
removes more from bad merge
owensmallwood Oct 7, 2022
0e5b6f9
Uses generated type for dashboard annotations. Adds cue schema for an…
owensmallwood Oct 11, 2022
64b3406
regenerates pubdash service mock
owensmallwood Oct 11, 2022
d79798d
renames test helper function
owensmallwood Oct 11, 2022
50a1e46
removes unused struct
owensmallwood Oct 11, 2022
4000e10
adds comment
owensmallwood Oct 12, 2022
23974b1
Adds tests to pubdash frontend ds
owensmallwood Oct 12, 2022
9cfdcbc
adds support for tag annotation queries
owensmallwood Oct 12, 2022
c25e6d0
makes sure duplicate events are not returned. Events from tag queries…
owensmallwood Oct 12, 2022
cec0371
fixes failing frontend and backend tests for pubdash
owensmallwood Oct 13, 2022
ee705c8
Merge branch 'main' into owensmallwood/pubdash-add-annotations-support
owensmallwood Oct 13, 2022
feaa835
Makes a new schema for Annotation Target. Accidentally used the Panel…
owensmallwood Oct 14, 2022
71feb57
some small refactors and cleanup
owensmallwood Oct 14, 2022
346191e
Merge branch 'main' into owensmallwood/pubdash-add-annotations-support
owensmallwood Oct 14, 2022
e41cfc3
renames repo
owensmallwood Oct 14, 2022
53c1cea
adds helpful comment
owensmallwood Oct 14, 2022
c59e3da
refactors scopes to use constants
owensmallwood Oct 14, 2022
ec55cd3
had to move internal package test helper to its own file in models pa…
owensmallwood Oct 14, 2022
8dccc5d
formats imports. Removes helper function because linter says its a se…
owensmallwood Oct 14, 2022
acaf30f
Merge branch 'main' into owensmallwood/pubdash-add-annotations-support
owensmallwood Oct 14, 2022
45550c1
If it's a tags annotation, don't scope query by dashboard id since ta…
owensmallwood Oct 17, 2022
4e0437d
linter fix - ineffectual assignment to error
owensmallwood Oct 17, 2022
27e5d6c
resolves PR comments. Moves some test helper functions into the tests…
owensmallwood Oct 18, 2022
3f02f95
Merged master. Resolved conflicts.
owensmallwood Oct 18, 2022
884ca8f
Merge branch 'main' into owensmallwood/pubdash-add-annotations-support
owensmallwood Oct 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -40,7 +40,12 @@ export interface AnnotationQuery {
*/
rawQuery?: string;
showIn: number;
target?: Record<string, unknown>;
target?: {
limit: number;
matchAny: boolean;
tags: Array<string>;
type: string;
};
type: string;
}

Expand Down
9 changes: 8 additions & 1 deletion pkg/coremodel/dashboard/coremodel.cue
Expand Up @@ -84,6 +84,13 @@ seqs: [
///////////////////////////////////////
// Definitions (referenced above) are declared below

#AnnotationTarget: {
limit: int64
matchAny: bool
tags: [...string]
type: string
}

// TODO docs
// FROM: AnnotationQuery in grafana-data/src/types/annotations.ts
#AnnotationQuery: {
Expand All @@ -106,7 +113,7 @@ seqs: [
// Query for annotation data.
rawQuery?: string @grafanamaturity(NeedsExpertReview)
showIn: uint8 | *0 @grafanamaturity(NeedsExpertReview)
target?: #Target @grafanamaturity(NeedsExpertReview) // TODO currently a generic in AnnotationQuery
target?: #AnnotationTarget @grafanamaturity(NeedsExpertReview)
} @cuetsy(kind="interface")

// FROM: packages/grafana-data/src/types/templateVars.ts
Expand Down
27 changes: 15 additions & 12 deletions pkg/coremodel/dashboard/dashboard_gen.go
Expand Up @@ -343,18 +343,21 @@ type AnnotationQuery struct {
Name *string `json:"name,omitempty"`

// Query for annotation data.
RawQuery *string `json:"rawQuery,omitempty"`
ShowIn int `json:"showIn"`

// Schema for panel targets is specified by datasource
// plugins. We use a placeholder definition, which the Go
// schema loader either left open/as-is with the Base
// variant of the Model and Panel families, or filled
// with types derived from plugins in the Instance variant.
// When working directly from CUE, importers can extend this
// type directly to achieve the same effect.
Target *Target `json:"target,omitempty"`
Type string `json:"type"`
RawQuery *string `json:"rawQuery,omitempty"`
ShowIn int `json:"showIn"`
Target *AnnotationTarget `json:"target,omitempty"`
Type string `json:"type"`
}

// AnnotationTarget is the Go representation of a dashboard.AnnotationTarget.
//
// THIS TYPE IS INTENDED FOR INTERNAL USE BY THE GRAFANA BACKEND, AND IS SUBJECT TO BREAKING CHANGES.
// Equivalent Go types at stable import paths are provided in https://github.com/grafana/grok.
type AnnotationTarget struct {
Limit int64 `json:"limit"`
MatchAny bool `json:"matchAny"`
Tags []string `json:"tags"`
Type string `json:"type"`
}

// 0 for no shared crosshair or tooltip (default).
Expand Down
1 change: 1 addition & 0 deletions pkg/services/annotations/annotations.go
Expand Up @@ -13,6 +13,7 @@ var (
ErrBaseTagLimitExceeded = errutil.NewBase(errutil.StatusBadRequest, "annotations.tag-limit-exceeded", errutil.WithPublicMessage("Tags length exceeds the maximum allowed."))
)

//go:generate mockery --name Repository --structname FakeAnnotationsRepo --inpackage --filename annotations_repository_mock.go
jalevin marked this conversation as resolved.
Show resolved Hide resolved
type Repository interface {
Save(ctx context.Context, item *Item) error
Update(ctx context.Context, item *Item) error
Expand Down
111 changes: 111 additions & 0 deletions pkg/services/annotations/annotations_repository_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 16 additions & 0 deletions pkg/services/publicdashboards/api/api.go
Expand Up @@ -63,6 +63,7 @@ func (api *Api) RegisterAPIEndpoints() {
// public endpoints
api.RouteRegister.Get("/api/public/dashboards/:accessToken", routing.Wrap(api.GetPublicDashboard))
api.RouteRegister.Post("/api/public/dashboards/:accessToken/panels/:panelId/query", routing.Wrap(api.QueryPublicDashboard))
api.RouteRegister.Get("/api/public/dashboards/:accessToken/annotations", routing.Wrap(api.GetAnnotations))

// List Public Dashboards
api.RouteRegister.Get("/api/dashboards/public", middleware.ReqSignedIn, routing.Wrap(api.ListPublicDashboards))
Expand Down Expand Up @@ -187,6 +188,21 @@ func (api *Api) QueryPublicDashboard(c *models.ReqContext) response.Response {
return toJsonStreamingResponse(api.Features, resp)
}

func (api *Api) GetAnnotations(c *models.ReqContext) response.Response {
reqDTO := AnnotationsQueryDTO{
From: c.QueryInt64("from"),
To: c.QueryInt64("to"),
}

annotations, err := api.PublicDashboardService.GetAnnotations(c.Req.Context(), reqDTO, web.Params(c.Req)[":accessToken"])

if err != nil {
return api.handleError(c.Req.Context(), http.StatusInternalServerError, "error getting public dashboard annotations", err)
}

return response.JSON(http.StatusOK, annotations)
}

// util to help us unpack dashboard and publicdashboard errors or use default http code and message
// we should look to do some future refactoring of these errors as publicdashboard err is the same as a dashboarderr, just defined in a
// different package.
Expand Down
55 changes: 54 additions & 1 deletion pkg/services/publicdashboards/api/api_test.go
Expand Up @@ -22,6 +22,7 @@ import (
"github.com/grafana/grafana/pkg/infra/localcache"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/annotations/annotationstest"
"github.com/grafana/grafana/pkg/services/dashboards"
dashboardStore "github.com/grafana/grafana/pkg/services/dashboards/database"
"github.com/grafana/grafana/pkg/services/datasources"
Expand Down Expand Up @@ -49,6 +50,56 @@ type JsonErrResponse struct {
Error string `json:"error"`
}

func TestAPIGetAnnotations(t *testing.T) {
testCases := []struct {
Name string
ExpectedHttpResponse int
Annotations []AnnotationEvent
ServiceError error
From string
To string
}{
{
Name: "will return success when there is no error and to and from are provided",
ExpectedHttpResponse: http.StatusOK,
Annotations: []AnnotationEvent{{Id: 1}},
ServiceError: nil,
From: "123",
To: "123",
},
{
Name: "will return 500 when service returns an error",
ExpectedHttpResponse: http.StatusInternalServerError,
Annotations: nil,
ServiceError: errors.New("an error happened"),
From: "123",
To: "123",
},
}
for _, test := range testCases {
t.Run(test.Name, func(t *testing.T) {
cfg := setting.NewCfg()
cfg.RBACEnabled = false
service := publicdashboards.NewFakePublicDashboardService(t)
service.On("GetAnnotations", mock.Anything, mock.Anything, mock.AnythingOfType("string")).
Return(test.Annotations, test.ServiceError).Once()
testServer := setupTestServer(t, cfg, featuremgmt.WithFeatures(featuremgmt.FlagPublicDashboards), service, nil, anonymousUser)

path := fmt.Sprintf("/api/public/dashboards/abc123/annotations?from=%s&to=%s", test.From, test.To)
response := callAPI(testServer, http.MethodGet, path, nil, t)

assert.Equal(t, test.ExpectedHttpResponse, response.Code)

if test.ExpectedHttpResponse == http.StatusOK {
var items []AnnotationEvent
err := json.Unmarshal(response.Body.Bytes(), &items)
assert.NoError(t, err)
assert.Equal(t, items, test.Annotations)
}
jalevin marked this conversation as resolved.
Show resolved Hide resolved
})
}
}

func TestAPIFeatureFlag(t *testing.T) {
testCases := []struct {
Name string
Expand Down Expand Up @@ -630,11 +681,13 @@ func TestIntegrationUnauthenticatedUserCanGetPubdashPanelQueryData(t *testing.T)
},
}

annotationsService := annotationstest.NewFakeAnnotationsRepo()

// create public dashboard
store := publicdashboardsStore.ProvideStore(db)
cfg := setting.NewCfg()
cfg.RBACEnabled = false
service := publicdashboardsService.ProvideService(cfg, store, qds)
service := publicdashboardsService.ProvideService(cfg, store, qds, annotationsService)
pubdash, err := service.SavePublicDashboardConfig(context.Background(), &user.SignedInUser{}, savePubDashboardCmd)
require.NoError(t, err)

Expand Down
28 changes: 28 additions & 0 deletions pkg/services/publicdashboards/models/models.go
Expand Up @@ -5,6 +5,7 @@ import (
"strconv"
"time"

"github.com/grafana/grafana/pkg/coremodel/dashboard"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/tsdb/legacydata"
)
Expand Down Expand Up @@ -77,6 +78,28 @@ type PublicDashboard struct {
UpdatedAt time.Time `json:"updatedAt" xorm:"updated_at"`
}

// Alias the generated type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this is needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its not totally necessary. I'm using the generated dashboard types, but I still want to be explicit about what models/types we want to be used within pubdash. I think its helpful to the next reader to keep all the models we want to use in one place. It def would have helped me. I had no idea the generated types existed before this, and ended up creating my own AnnotationQuery type.

type DashAnnotation = dashboard.AnnotationQuery

type AnnotationsDto struct {
Annotations struct {
List []DashAnnotation `json:"list"`
}
}

type AnnotationEvent struct {
Id int64 `json:"id"`
DashboardId int64 `json:"dashboardId"`
PanelId int64 `json:"panelId"`
Tags []string `json:"tags"`
IsRegion bool `json:"isRegion"`
Text string `json:"text"`
Color string `json:"color"`
Time int64 `json:"time"`
TimeEnd int64 `json:"timeEnd"`
Source dashboard.AnnotationQuery `json:"source"`
}

func (pd PublicDashboard) TableName() string {
return "dashboard_public"
}
Expand Down Expand Up @@ -135,6 +158,11 @@ type PublicDashboardQueryDTO struct {
MaxDataPoints int64
}

type AnnotationsQueryDTO struct {
From int64
To int64
}

//
// COMMANDS
//
Expand Down
23 changes: 23 additions & 0 deletions pkg/services/publicdashboards/public_dashboard_service_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions pkg/services/publicdashboards/publicdashboard.go
Expand Up @@ -16,6 +16,7 @@ import (
type Service interface {
AccessTokenExists(ctx context.Context, accessToken string) (bool, error)
BuildAnonymousUser(ctx context.Context, dashboard *models.Dashboard) *user.SignedInUser
GetAnnotations(ctx context.Context, reqDTO AnnotationsQueryDTO, accessToken string) ([]AnnotationEvent, error)
GetDashboard(ctx context.Context, dashboardUid string) (*models.Dashboard, error)
GetMetricRequest(ctx context.Context, dashboard *models.Dashboard, publicDashboard *PublicDashboard, panelId int64, reqDTO PublicDashboardQueryDTO) (dtos.MetricRequest, error)
GetPublicDashboard(ctx context.Context, accessToken string) (*PublicDashboard, *models.Dashboard, error)
Expand Down