mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Annotations: Adds tags endpoint (#36199)
* Annotations: Adds tags endpoint * Chore: fixes sql statement * Refactor: adds count to the api * Chore: changes after PR comments * Refactor: changes after PR comments
This commit is contained in:
parent
1490c255f1
commit
63f9231de1
@ -288,3 +288,19 @@ func canSave(c *models.ReqContext, repo annotations.Repository, annotationID int
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetAnnotationTags(c *models.ReqContext) response.Response {
|
||||||
|
query := &annotations.TagsQuery{
|
||||||
|
OrgID: c.OrgId,
|
||||||
|
Tag: c.Query("tag"),
|
||||||
|
Limit: c.QueryInt64("limit"),
|
||||||
|
}
|
||||||
|
|
||||||
|
repo := annotations.GetRepository()
|
||||||
|
result, err := repo.FindTags(query)
|
||||||
|
if err != nil {
|
||||||
|
return response.Error(500, "Failed to find annotation tags", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.JSON(200, util.DynMap{"result": result})
|
||||||
|
}
|
||||||
|
@ -259,6 +259,12 @@ func (repo *fakeAnnotationsRepo) Find(query *annotations.ItemQuery) ([]*annotati
|
|||||||
annotations := []*annotations.ItemDTO{{Id: 1}}
|
annotations := []*annotations.ItemDTO{{Id: 1}}
|
||||||
return annotations, nil
|
return annotations, nil
|
||||||
}
|
}
|
||||||
|
func (repo *fakeAnnotationsRepo) FindTags(query *annotations.TagsQuery) (annotations.FindTagsResult, error) {
|
||||||
|
result := annotations.FindTagsResult{
|
||||||
|
Tags: []*annotations.TagsDTO{},
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
var fakeAnnoRepo *fakeAnnotationsRepo
|
var fakeAnnoRepo *fakeAnnotationsRepo
|
||||||
|
|
||||||
|
@ -410,6 +410,7 @@ func (hs *HTTPServer) registerRoutes() {
|
|||||||
annotationsRoute.Put("/:annotationId", bind(dtos.UpdateAnnotationsCmd{}), routing.Wrap(UpdateAnnotation))
|
annotationsRoute.Put("/:annotationId", bind(dtos.UpdateAnnotationsCmd{}), routing.Wrap(UpdateAnnotation))
|
||||||
annotationsRoute.Patch("/:annotationId", bind(dtos.PatchAnnotationsCmd{}), routing.Wrap(PatchAnnotation))
|
annotationsRoute.Patch("/:annotationId", bind(dtos.PatchAnnotationsCmd{}), routing.Wrap(PatchAnnotation))
|
||||||
annotationsRoute.Post("/graphite", reqEditorRole, bind(dtos.PostGraphiteAnnotationsCmd{}), routing.Wrap(PostGraphiteAnnotation))
|
annotationsRoute.Post("/graphite", reqEditorRole, bind(dtos.PostGraphiteAnnotationsCmd{}), routing.Wrap(PostGraphiteAnnotation))
|
||||||
|
annotationsRoute.Get("/tags", routing.Wrap(GetAnnotationTags))
|
||||||
})
|
})
|
||||||
|
|
||||||
apiRoute.Post("/frontend-metrics", bind(metrics.PostFrontendMetricsCommand{}), routing.Wrap(hs.PostFrontendMetrics))
|
apiRoute.Post("/frontend-metrics", bind(metrics.PostFrontendMetricsCommand{}), routing.Wrap(hs.PostFrontendMetrics))
|
||||||
|
@ -17,6 +17,7 @@ type Repository interface {
|
|||||||
Update(item *Item) error
|
Update(item *Item) error
|
||||||
Find(query *ItemQuery) ([]*ItemDTO, error)
|
Find(query *ItemQuery) ([]*ItemDTO, error)
|
||||||
Delete(params *DeleteParams) error
|
Delete(params *DeleteParams) error
|
||||||
|
FindTags(query *TagsQuery) (FindTagsResult, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnnotationCleaner is responsible for cleaning up old annotations
|
// AnnotationCleaner is responsible for cleaning up old annotations
|
||||||
@ -40,6 +41,28 @@ type ItemQuery struct {
|
|||||||
Limit int64 `json:"limit"`
|
Limit int64 `json:"limit"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TagsQuery struct {
|
||||||
|
OrgID int64 `json:"orgId"`
|
||||||
|
Tag string `json:"tag"`
|
||||||
|
|
||||||
|
Limit int64 `json:"limit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tags struct {
|
||||||
|
Key string
|
||||||
|
Value string
|
||||||
|
Count int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type TagsDTO struct {
|
||||||
|
Tag string `json:"tag"`
|
||||||
|
Count int64 `json:"count"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FindTagsResult struct {
|
||||||
|
Tags []*TagsDTO `json:"tags"`
|
||||||
|
}
|
||||||
|
|
||||||
type DeleteParams struct {
|
type DeleteParams struct {
|
||||||
OrgId int64
|
OrgId int64
|
||||||
Id int64
|
Id int64
|
||||||
|
@ -268,3 +268,52 @@ func (r *SQLAnnotationRepo) Delete(params *annotations.DeleteParams) error {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *SQLAnnotationRepo) FindTags(query *annotations.TagsQuery) (annotations.FindTagsResult, error) {
|
||||||
|
if query.Limit == 0 {
|
||||||
|
query.Limit = 100
|
||||||
|
}
|
||||||
|
|
||||||
|
var sql bytes.Buffer
|
||||||
|
params := make([]interface{}, 0)
|
||||||
|
tagKey := `tag.` + dialect.Quote("key")
|
||||||
|
tagValue := `tag.` + dialect.Quote("value")
|
||||||
|
|
||||||
|
sql.WriteString(`
|
||||||
|
SELECT
|
||||||
|
` + tagKey + `,
|
||||||
|
` + tagValue + `,
|
||||||
|
count(*) as count
|
||||||
|
FROM tag
|
||||||
|
INNER JOIN annotation_tag ON tag.id = annotation_tag.tag_id
|
||||||
|
`)
|
||||||
|
|
||||||
|
sql.WriteString(`WHERE EXISTS(SELECT 1 FROM annotation WHERE annotation.id = annotation_tag.annotation_id AND annotation.org_id = ?)`)
|
||||||
|
params = append(params, query.OrgID)
|
||||||
|
|
||||||
|
sql.WriteString(` AND (` + tagKey + ` ` + dialect.LikeStr() + ` ? OR ` + tagValue + ` ` + dialect.LikeStr() + ` ?)`)
|
||||||
|
params = append(params, `%`+query.Tag+`%`, `%`+query.Tag+`%`)
|
||||||
|
|
||||||
|
sql.WriteString(` GROUP BY ` + tagKey + `,` + tagValue)
|
||||||
|
sql.WriteString(` ORDER BY ` + tagKey + `,` + tagValue)
|
||||||
|
sql.WriteString(` ` + dialect.Limit(query.Limit))
|
||||||
|
|
||||||
|
var items []*annotations.Tags
|
||||||
|
if err := x.SQL(sql.String(), params...).Find(&items); err != nil {
|
||||||
|
return annotations.FindTagsResult{Tags: []*annotations.TagsDTO{}}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tags := make([]*annotations.TagsDTO, 0)
|
||||||
|
for _, item := range items {
|
||||||
|
tag := item.Key
|
||||||
|
if len(item.Value) > 0 {
|
||||||
|
tag = item.Key + ":" + item.Value
|
||||||
|
}
|
||||||
|
tags = append(tags, &annotations.TagsDTO{
|
||||||
|
Tag: tag,
|
||||||
|
Count: item.Count,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return annotations.FindTagsResult{Tags: tags}, nil
|
||||||
|
}
|
||||||
|
@ -251,5 +251,47 @@ func TestAnnotations(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Empty(t, items)
|
assert.Empty(t, items)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Should find tags by key", func(t *testing.T) {
|
||||||
|
result, err := repo.FindTags(&annotations.TagsQuery{
|
||||||
|
OrgID: 1,
|
||||||
|
Tag: "server",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, result.Tags, 1)
|
||||||
|
require.Equal(t, "server:server-1", result.Tags[0].Tag)
|
||||||
|
require.Equal(t, int64(1), result.Tags[0].Count)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should find tags by value", func(t *testing.T) {
|
||||||
|
result, err := repo.FindTags(&annotations.TagsQuery{
|
||||||
|
OrgID: 1,
|
||||||
|
Tag: "outage",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, result.Tags, 2)
|
||||||
|
require.Equal(t, "outage", result.Tags[0].Tag)
|
||||||
|
require.Equal(t, "type:outage", result.Tags[1].Tag)
|
||||||
|
require.Equal(t, int64(1), result.Tags[0].Count)
|
||||||
|
require.Equal(t, int64(1), result.Tags[1].Count)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should not find tags in other org", func(t *testing.T) {
|
||||||
|
result, err := repo.FindTags(&annotations.TagsQuery{
|
||||||
|
OrgID: 0,
|
||||||
|
Tag: "server-1",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, result.Tags, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Should not find tags that do not exist", func(t *testing.T) {
|
||||||
|
result, err := repo.FindTags(&annotations.TagsQuery{
|
||||||
|
OrgID: 0,
|
||||||
|
Tag: "unknown:tag",
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, result.Tags, 0)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user