From 099f5cbf97c1ca3dffbc6bdc2ba2bda57610d589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Wed, 24 Mar 2021 14:57:02 +0100 Subject: [PATCH] LibraryPanels: Adds Type and Description to DB (#32258) (#32288) * Refactor: adds description to getCreateCommand * Refactor: Adds type and description fields * Chore: Updates FrontEnd * Update pkg/services/librarypanels/database.go Co-authored-by: Arve Knudsen * Update pkg/services/librarypanels/database.go Co-authored-by: Arve Knudsen * Chore: fixes backend linting error Co-authored-by: Arve Knudsen (cherry picked from commit 7f5487a461472f3af1226af1dddb7f9ad9bea666) --- pkg/services/librarypanels/database.go | 150 ++++++++++-------- pkg/services/librarypanels/librarypanels.go | 10 +- .../librarypanels_create_test.go | 42 ++--- .../librarypanels_get_all_test.go | 126 ++++++++------- .../librarypanels/librarypanels_get_test.go | 21 +-- .../librarypanels/librarypanels_patch_test.go | 106 ++++++++++--- .../librarypanels/librarypanels_test.go | 32 ++-- pkg/services/librarypanels/models.go | 50 +++--- .../LibraryPanelsView/reducer.test.ts | 4 + public/app/features/library-panels/types.ts | 2 + 10 files changed, 335 insertions(+), 208 deletions(-) diff --git a/pkg/services/librarypanels/database.go b/pkg/services/librarypanels/database.go index 9b9c2a3a4d4..8faf686d43c 100644 --- a/pkg/services/librarypanels/database.go +++ b/pkg/services/librarypanels/database.go @@ -9,14 +9,13 @@ import ( "github.com/grafana/grafana/pkg/api/dtos" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/sqlstore" - "github.com/grafana/grafana/pkg/services/sqlstore/migrator" "github.com/grafana/grafana/pkg/util" ) var ( sqlStatmentLibrayPanelDTOWithMeta = ` SELECT DISTINCT - lp.id, lp.org_id, lp.folder_id, lp.uid, lp.name, lp.model, lp.created, lp.created_by, lp.updated, lp.updated_by, lp.version + lp.id, lp.org_id, lp.folder_id, lp.uid, lp.name, lp.type, lp.description, lp.model, lp.created, lp.created_by, lp.updated, lp.updated_by, lp.version , 0 AS can_edit , u1.login AS created_by_name , u1.email AS created_by_email @@ -29,13 +28,23 @@ FROM library_panel AS lp ` ) -func syncTitleWithName(libraryPanel *LibraryPanel) error { +func syncFieldsWithModel(libraryPanel *LibraryPanel) error { var model map[string]interface{} if err := json.Unmarshal(libraryPanel.Model, &model); err != nil { return err } model["title"] = libraryPanel.Name + if model["type"] != nil { + libraryPanel.Type = model["type"].(string) + } else { + model["type"] = libraryPanel.Type + } + if model["description"] != nil { + libraryPanel.Description = model["description"].(string) + } else { + model["description"] = libraryPanel.Description + } syncedModel, err := json.Marshal(&model) if err != nil { return err @@ -63,7 +72,7 @@ func (lps *LibraryPanelService) createLibraryPanel(c *models.ReqContext, cmd cre UpdatedBy: c.SignedInUser.UserId, } - if err := syncTitleWithName(&libraryPanel); err != nil { + if err := syncFieldsWithModel(&libraryPanel); err != nil { return LibraryPanelDTO{}, err } @@ -81,13 +90,15 @@ func (lps *LibraryPanelService) createLibraryPanel(c *models.ReqContext, cmd cre }) dto := LibraryPanelDTO{ - ID: libraryPanel.ID, - OrgID: libraryPanel.OrgID, - FolderID: libraryPanel.FolderID, - UID: libraryPanel.UID, - Name: libraryPanel.Name, - Model: libraryPanel.Model, - Version: libraryPanel.Version, + ID: libraryPanel.ID, + OrgID: libraryPanel.OrgID, + FolderID: libraryPanel.FolderID, + UID: libraryPanel.UID, + Name: libraryPanel.Name, + Type: libraryPanel.Type, + Description: libraryPanel.Description, + Model: libraryPanel.Model, + Version: libraryPanel.Version, Meta: LibraryPanelDTOMeta{ CanEdit: true, ConnectedDashboards: 0, @@ -109,7 +120,17 @@ func (lps *LibraryPanelService) createLibraryPanel(c *models.ReqContext, cmd cre return dto, err } -func connectDashboard(session *sqlstore.DBSession, dialect migrator.Dialect, user *models.SignedInUser, uid string, dashboardID int64) error { +// connectDashboard adds a connection between a Library Panel and a Dashboard. +func (lps *LibraryPanelService) connectDashboard(c *models.ReqContext, uid string, dashboardID int64) error { + err := lps.SQLStore.WithTransactionalDbSession(c.Context.Req.Context(), func(session *sqlstore.DBSession) error { + return lps.internalConnectDashboard(session, c.SignedInUser, uid, dashboardID) + }) + + return err +} + +func (lps *LibraryPanelService) internalConnectDashboard(session *sqlstore.DBSession, user *models.SignedInUser, + uid string, dashboardID int64) error { panel, err := getLibraryPanel(session, uid, user.OrgId) if err != nil { return err @@ -118,8 +139,6 @@ func connectDashboard(session *sqlstore.DBSession, dialect migrator.Dialect, use return err } - // TODO add check that dashboard exists - libraryPanelDashboard := libraryPanelDashboard{ DashboardID: dashboardID, LibraryPanelID: panel.ID, @@ -127,7 +146,7 @@ func connectDashboard(session *sqlstore.DBSession, dialect migrator.Dialect, use CreatedBy: user.UserId, } if _, err := session.Insert(&libraryPanelDashboard); err != nil { - if dialect.IsUniqueConstraintViolation(err) { + if lps.SQLStore.Dialect.IsUniqueConstraintViolation(err) { return nil } return err @@ -135,15 +154,6 @@ func connectDashboard(session *sqlstore.DBSession, dialect migrator.Dialect, use return nil } -// connectDashboard adds a connection between a Library Panel and a Dashboard. -func (lps *LibraryPanelService) connectDashboard(c *models.ReqContext, uid string, dashboardID int64) error { - err := lps.SQLStore.WithTransactionalDbSession(c.Context.Req.Context(), func(session *sqlstore.DBSession) error { - return connectDashboard(session, lps.SQLStore.Dialect, c.SignedInUser, uid, dashboardID) - }) - - return err -} - // connectLibraryPanelsForDashboard adds connections for all Library Panels in a Dashboard. func (lps *LibraryPanelService) connectLibraryPanelsForDashboard(c *models.ReqContext, uids []string, dashboardID int64) error { err := lps.SQLStore.WithTransactionalDbSession(c.Context.Req.Context(), func(session *sqlstore.DBSession) error { @@ -152,7 +162,7 @@ func (lps *LibraryPanelService) connectLibraryPanelsForDashboard(c *models.ReqCo return err } for _, uid := range uids { - err := connectDashboard(session, lps.SQLStore.Dialect, c.SignedInUser, uid, dashboardID) + err := lps.internalConnectDashboard(session, c.SignedInUser, uid, dashboardID) if err != nil { return err } @@ -343,13 +353,15 @@ func (lps *LibraryPanelService) getLibraryPanel(c *models.ReqContext, uid string }) dto := LibraryPanelDTO{ - ID: libraryPanel.ID, - OrgID: libraryPanel.OrgID, - FolderID: libraryPanel.FolderID, - UID: libraryPanel.UID, - Name: libraryPanel.Name, - Model: libraryPanel.Model, - Version: libraryPanel.Version, + ID: libraryPanel.ID, + OrgID: libraryPanel.OrgID, + FolderID: libraryPanel.FolderID, + UID: libraryPanel.UID, + Name: libraryPanel.Name, + Type: libraryPanel.Type, + Description: libraryPanel.Description, + Model: libraryPanel.Model, + Version: libraryPanel.Version, Meta: LibraryPanelDTOMeta{ CanEdit: true, ConnectedDashboards: libraryPanel.ConnectedDashboards, @@ -416,13 +428,15 @@ func (lps *LibraryPanelService) getAllLibraryPanels(c *models.ReqContext, perPag retDTOs := make([]LibraryPanelDTO, 0) for _, panel := range libraryPanels { retDTOs = append(retDTOs, LibraryPanelDTO{ - ID: panel.ID, - OrgID: panel.OrgID, - FolderID: panel.FolderID, - UID: panel.UID, - Name: panel.Name, - Model: panel.Model, - Version: panel.Version, + ID: panel.ID, + OrgID: panel.OrgID, + FolderID: panel.FolderID, + UID: panel.UID, + Name: panel.Name, + Type: panel.Type, + Description: panel.Description, + Model: panel.Model, + Version: panel.Version, Meta: LibraryPanelDTOMeta{ CanEdit: true, ConnectedDashboards: panel.ConnectedDashboards, @@ -512,13 +526,15 @@ func (lps *LibraryPanelService) getLibraryPanelsForDashboardID(c *models.ReqCont for _, panel := range libraryPanels { libraryPanelMap[panel.UID] = LibraryPanelDTO{ - ID: panel.ID, - OrgID: panel.OrgID, - FolderID: panel.FolderID, - UID: panel.UID, - Name: panel.Name, - Model: panel.Model, - Version: panel.Version, + ID: panel.ID, + OrgID: panel.OrgID, + FolderID: panel.FolderID, + UID: panel.UID, + Name: panel.Name, + Type: panel.Type, + Description: panel.Description, + Model: panel.Model, + Version: panel.Version, Meta: LibraryPanelDTOMeta{ CanEdit: panel.CanEdit, ConnectedDashboards: panel.ConnectedDashboards, @@ -580,17 +596,19 @@ func (lps *LibraryPanelService) patchLibraryPanel(c *models.ReqContext, cmd patc } var libraryPanel = LibraryPanel{ - ID: panelInDB.ID, - OrgID: c.SignedInUser.OrgId, - FolderID: cmd.FolderID, - UID: uid, - Name: cmd.Name, - Model: cmd.Model, - Version: panelInDB.Version + 1, - Created: panelInDB.Created, - CreatedBy: panelInDB.CreatedBy, - Updated: time.Now(), - UpdatedBy: c.SignedInUser.UserId, + ID: panelInDB.ID, + OrgID: c.SignedInUser.OrgId, + FolderID: cmd.FolderID, + UID: uid, + Name: cmd.Name, + Type: panelInDB.Type, + Description: panelInDB.Description, + Model: cmd.Model, + Version: panelInDB.Version + 1, + Created: panelInDB.Created, + CreatedBy: panelInDB.CreatedBy, + Updated: time.Now(), + UpdatedBy: c.SignedInUser.UserId, } if cmd.Name == "" { @@ -602,7 +620,7 @@ func (lps *LibraryPanelService) patchLibraryPanel(c *models.ReqContext, cmd patc if err := handleFolderIDPatches(&libraryPanel, panelInDB.FolderID, cmd.FolderID, c.SignedInUser); err != nil { return err } - if err := syncTitleWithName(&libraryPanel); err != nil { + if err := syncFieldsWithModel(&libraryPanel); err != nil { return err } if rowsAffected, err := session.ID(panelInDB.ID).Update(&libraryPanel); err != nil { @@ -615,13 +633,15 @@ func (lps *LibraryPanelService) patchLibraryPanel(c *models.ReqContext, cmd patc } dto = LibraryPanelDTO{ - ID: libraryPanel.ID, - OrgID: libraryPanel.OrgID, - FolderID: libraryPanel.FolderID, - UID: libraryPanel.UID, - Name: libraryPanel.Name, - Model: libraryPanel.Model, - Version: libraryPanel.Version, + ID: libraryPanel.ID, + OrgID: libraryPanel.OrgID, + FolderID: libraryPanel.FolderID, + UID: libraryPanel.UID, + Name: libraryPanel.Name, + Type: libraryPanel.Type, + Description: libraryPanel.Description, + Model: libraryPanel.Model, + Version: libraryPanel.Version, Meta: LibraryPanelDTOMeta{ CanEdit: true, ConnectedDashboards: panelInDB.ConnectedDashboards, diff --git a/pkg/services/librarypanels/librarypanels.go b/pkg/services/librarypanels/librarypanels.go index db05fa42a9a..0ad83428b6c 100644 --- a/pkg/services/librarypanels/librarypanels.go +++ b/pkg/services/librarypanels/librarypanels.go @@ -102,9 +102,11 @@ func (lps *LibraryPanelService) LoadLibraryPanelsForDashboard(c *models.ReqConte elem.Set("gridPos", panelAsJSON.Get("gridPos").MustMap()) elem.Set("id", panelAsJSON.Get("id").MustInt64()) elem.Set("libraryPanel", map[string]interface{}{ - "uid": libraryPanelInDB.UID, - "name": libraryPanelInDB.Name, - "version": libraryPanelInDB.Version, + "uid": libraryPanelInDB.UID, + "name": libraryPanelInDB.Name, + "type": libraryPanelInDB.Type, + "description": libraryPanelInDB.Description, + "version": libraryPanelInDB.Version, "meta": map[string]interface{}{ "canEdit": libraryPanelInDB.Meta.CanEdit, "connectedDashboards": libraryPanelInDB.Meta.ConnectedDashboards, @@ -242,6 +244,8 @@ func (lps *LibraryPanelService) AddMigration(mg *migrator.Migrator) { {Name: "folder_id", Type: migrator.DB_BigInt, Nullable: false}, {Name: "uid", Type: migrator.DB_NVarchar, Length: 40, Nullable: false}, {Name: "name", Type: migrator.DB_NVarchar, Length: 255, Nullable: false}, + {Name: "type", Type: migrator.DB_NVarchar, Length: 40, Nullable: false}, + {Name: "description", Type: migrator.DB_NVarchar, Length: 255, Nullable: false}, {Name: "model", Type: migrator.DB_Text, Nullable: false}, {Name: "created", Type: migrator.DB_DateTime, Nullable: false}, {Name: "created_by", Type: migrator.DB_BigInt, Nullable: false}, diff --git a/pkg/services/librarypanels/librarypanels_create_test.go b/pkg/services/librarypanels/librarypanels_create_test.go index 852e77a8c0d..240c633f078 100644 --- a/pkg/services/librarypanels/librarypanels_create_test.go +++ b/pkg/services/librarypanels/librarypanels_create_test.go @@ -19,16 +19,19 @@ func TestCreateLibraryPanel(t *testing.T) { func(t *testing.T, sc scenarioContext) { var expected = libraryPanelResult{ Result: libraryPanel{ - ID: 1, - OrgID: 1, - FolderID: 1, - UID: sc.initialResult.Result.UID, - Name: "Text - Library Panel", + ID: 1, + OrgID: 1, + FolderID: 1, + UID: sc.initialResult.Result.UID, + Name: "Text - Library Panel", + Type: "text", + Description: "A description", Model: map[string]interface{}{ - "datasource": "${DS_GDEV-TESTDATA}", - "id": float64(1), - "title": "Text - Library Panel", - "type": "text", + "datasource": "${DS_GDEV-TESTDATA}", + "description": "A description", + "id": float64(1), + "title": "Text - Library Panel", + "type": "text", }, Version: 1, Meta: LibraryPanelDTOMeta{ @@ -61,16 +64,19 @@ func TestCreateLibraryPanel(t *testing.T) { var result = validateAndUnMarshalResponse(t, resp) var expected = libraryPanelResult{ Result: libraryPanel{ - ID: 1, - OrgID: 1, - FolderID: 1, - UID: result.Result.UID, - Name: "Library Panel Name", + ID: 1, + OrgID: 1, + FolderID: 1, + UID: result.Result.UID, + Name: "Library Panel Name", + Type: "text", + Description: "A description", Model: map[string]interface{}{ - "datasource": "${DS_GDEV-TESTDATA}", - "id": float64(1), - "title": "Library Panel Name", - "type": "text", + "datasource": "${DS_GDEV-TESTDATA}", + "description": "A description", + "id": float64(1), + "title": "Library Panel Name", + "type": "text", }, Version: 1, Meta: LibraryPanelDTOMeta{ diff --git a/pkg/services/librarypanels/librarypanels_get_all_test.go b/pkg/services/librarypanels/librarypanels_get_all_test.go index d70e85d5f06..a34c36c8bbc 100644 --- a/pkg/services/librarypanels/librarypanels_get_all_test.go +++ b/pkg/services/librarypanels/librarypanels_get_all_test.go @@ -51,16 +51,19 @@ func TestGetAllLibraryPanels(t *testing.T) { PerPage: 100, LibraryPanels: []libraryPanel{ { - ID: 1, - OrgID: 1, - FolderID: 1, - UID: result.Result.LibraryPanels[0].UID, - Name: "Text - Library Panel", + ID: 1, + OrgID: 1, + FolderID: 1, + UID: result.Result.LibraryPanels[0].UID, + Name: "Text - Library Panel", + Type: "text", + Description: "A description", Model: map[string]interface{}{ - "datasource": "${DS_GDEV-TESTDATA}", - "id": float64(1), - "title": "Text - Library Panel", - "type": "text", + "datasource": "${DS_GDEV-TESTDATA}", + "description": "A description", + "id": float64(1), + "title": "Text - Library Panel", + "type": "text", }, Version: 1, Meta: LibraryPanelDTOMeta{ @@ -81,16 +84,19 @@ func TestGetAllLibraryPanels(t *testing.T) { }, }, { - ID: 2, - OrgID: 1, - FolderID: 1, - UID: result.Result.LibraryPanels[1].UID, - Name: "Text - Library Panel2", + ID: 2, + OrgID: 1, + FolderID: 1, + UID: result.Result.LibraryPanels[1].UID, + Name: "Text - Library Panel2", + Type: "text", + Description: "A description", Model: map[string]interface{}{ - "datasource": "${DS_GDEV-TESTDATA}", - "id": float64(1), - "title": "Text - Library Panel2", - "type": "text", + "datasource": "${DS_GDEV-TESTDATA}", + "description": "A description", + "id": float64(1), + "title": "Text - Library Panel2", + "type": "text", }, Version: 1, Meta: LibraryPanelDTOMeta{ @@ -140,16 +146,19 @@ func TestGetAllLibraryPanels(t *testing.T) { PerPage: 100, LibraryPanels: []libraryPanel{ { - ID: 2, - OrgID: 1, - FolderID: 1, - UID: result.Result.LibraryPanels[0].UID, - Name: "Text - Library Panel2", + ID: 2, + OrgID: 1, + FolderID: 1, + UID: result.Result.LibraryPanels[0].UID, + Name: "Text - Library Panel2", + Type: "text", + Description: "A description", Model: map[string]interface{}{ - "datasource": "${DS_GDEV-TESTDATA}", - "id": float64(1), - "title": "Text - Library Panel2", - "type": "text", + "datasource": "${DS_GDEV-TESTDATA}", + "description": "A description", + "id": float64(1), + "title": "Text - Library Panel2", + "type": "text", }, Version: 1, Meta: LibraryPanelDTOMeta{ @@ -199,16 +208,19 @@ func TestGetAllLibraryPanels(t *testing.T) { PerPage: 1, LibraryPanels: []libraryPanel{ { - ID: 1, - OrgID: 1, - FolderID: 1, - UID: result.Result.LibraryPanels[0].UID, - Name: "Text - Library Panel", + ID: 1, + OrgID: 1, + FolderID: 1, + UID: result.Result.LibraryPanels[0].UID, + Name: "Text - Library Panel", + Type: "text", + Description: "A description", Model: map[string]interface{}{ - "datasource": "${DS_GDEV-TESTDATA}", - "id": float64(1), - "title": "Text - Library Panel", - "type": "text", + "datasource": "${DS_GDEV-TESTDATA}", + "description": "A description", + "id": float64(1), + "title": "Text - Library Panel", + "type": "text", }, Version: 1, Meta: LibraryPanelDTOMeta{ @@ -259,16 +271,19 @@ func TestGetAllLibraryPanels(t *testing.T) { PerPage: 1, LibraryPanels: []libraryPanel{ { - ID: 2, - OrgID: 1, - FolderID: 1, - UID: result.Result.LibraryPanels[0].UID, - Name: "Text - Library Panel2", + ID: 2, + OrgID: 1, + FolderID: 1, + UID: result.Result.LibraryPanels[0].UID, + Name: "Text - Library Panel2", + Type: "text", + Description: "A description", Model: map[string]interface{}{ - "datasource": "${DS_GDEV-TESTDATA}", - "id": float64(1), - "title": "Text - Library Panel2", - "type": "text", + "datasource": "${DS_GDEV-TESTDATA}", + "description": "A description", + "id": float64(1), + "title": "Text - Library Panel2", + "type": "text", }, Version: 1, Meta: LibraryPanelDTOMeta{ @@ -320,16 +335,19 @@ func TestGetAllLibraryPanels(t *testing.T) { PerPage: 1, LibraryPanels: []libraryPanel{ { - ID: 2, - OrgID: 1, - FolderID: 1, - UID: result.Result.LibraryPanels[0].UID, - Name: "Text - Library Panel2", + ID: 2, + OrgID: 1, + FolderID: 1, + UID: result.Result.LibraryPanels[0].UID, + Name: "Text - Library Panel2", + Type: "text", + Description: "A description", Model: map[string]interface{}{ - "datasource": "${DS_GDEV-TESTDATA}", - "id": float64(1), - "title": "Text - Library Panel2", - "type": "text", + "datasource": "${DS_GDEV-TESTDATA}", + "description": "A description", + "id": float64(1), + "title": "Text - Library Panel2", + "type": "text", }, Version: 1, Meta: LibraryPanelDTOMeta{ diff --git a/pkg/services/librarypanels/librarypanels_get_test.go b/pkg/services/librarypanels/librarypanels_get_test.go index f6ba8057724..df5a37801ca 100644 --- a/pkg/services/librarypanels/librarypanels_get_test.go +++ b/pkg/services/librarypanels/librarypanels_get_test.go @@ -24,16 +24,19 @@ func TestGetLibraryPanel(t *testing.T) { var result = validateAndUnMarshalResponse(t, resp) var expected = libraryPanelResult{ Result: libraryPanel{ - ID: 1, - OrgID: 1, - FolderID: 1, - UID: result.Result.UID, - Name: "Text - Library Panel", + ID: 1, + OrgID: 1, + FolderID: 1, + UID: result.Result.UID, + Name: "Text - Library Panel", + Type: "text", + Description: "A description", Model: map[string]interface{}{ - "datasource": "${DS_GDEV-TESTDATA}", - "id": float64(1), - "title": "Text - Library Panel", - "type": "text", + "datasource": "${DS_GDEV-TESTDATA}", + "description": "A description", + "id": float64(1), + "title": "Text - Library Panel", + "type": "text", }, Version: 1, Meta: LibraryPanelDTOMeta{ diff --git a/pkg/services/librarypanels/librarypanels_patch_test.go b/pkg/services/librarypanels/librarypanels_patch_test.go index cd0627708ef..364eb06b0ea 100644 --- a/pkg/services/librarypanels/librarypanels_patch_test.go +++ b/pkg/services/librarypanels/librarypanels_patch_test.go @@ -32,9 +32,10 @@ func TestPatchLibraryPanel(t *testing.T) { Model: []byte(` { "datasource": "${DS_GDEV-TESTDATA}", + "description": "An updated description", "id": 1, "title": "Model - New name", - "type": "text" + "type": "graph" } `), Version: 1, @@ -45,16 +46,19 @@ func TestPatchLibraryPanel(t *testing.T) { var result = validateAndUnMarshalResponse(t, resp) var expected = libraryPanelResult{ Result: libraryPanel{ - ID: 1, - OrgID: 1, - FolderID: newFolder.Id, - UID: sc.initialResult.Result.UID, - Name: "Panel - New name", + ID: 1, + OrgID: 1, + FolderID: newFolder.Id, + UID: sc.initialResult.Result.UID, + Name: "Panel - New name", + Type: "graph", + Description: "An updated description", Model: map[string]interface{}{ - "datasource": "${DS_GDEV-TESTDATA}", - "id": float64(1), - "title": "Panel - New name", - "type": "text", + "datasource": "${DS_GDEV-TESTDATA}", + "description": "An updated description", + "id": float64(1), + "title": "Panel - New name", + "type": "graph", }, Version: 2, Meta: LibraryPanelDTOMeta{ @@ -64,8 +68,8 @@ func TestPatchLibraryPanel(t *testing.T) { Updated: result.Result.Meta.Updated, CreatedBy: LibraryPanelDTOMetaUser{ ID: 1, - Name: "user_in_db", - AvatarUrl: "/avatar/402d08de060496d6b6874495fe20f5ad", + Name: UserInDbName, + AvatarUrl: UserInDbAvatar, }, UpdatedBy: LibraryPanelDTOMetaUser{ ID: 1, @@ -92,8 +96,8 @@ func TestPatchLibraryPanel(t *testing.T) { require.Equal(t, 200, resp.Status()) var result = validateAndUnMarshalResponse(t, resp) sc.initialResult.Result.FolderID = newFolder.Id - sc.initialResult.Result.Meta.CreatedBy.Name = "user_in_db" - sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = "/avatar/402d08de060496d6b6874495fe20f5ad" + sc.initialResult.Result.Meta.CreatedBy.Name = UserInDbName + sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = UserInDbAvatar sc.initialResult.Result.Version = 2 if diff := cmp.Diff(sc.initialResult.Result, result.Result, getCompareOptions()...); diff != "" { t.Fatalf("Result mismatch (-want +got):\n%s", diff) @@ -111,8 +115,8 @@ func TestPatchLibraryPanel(t *testing.T) { resp := sc.service.patchHandler(sc.reqContext, cmd) var result = validateAndUnMarshalResponse(t, resp) sc.initialResult.Result.Name = "New Name" - sc.initialResult.Result.Meta.CreatedBy.Name = "user_in_db" - sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = "/avatar/402d08de060496d6b6874495fe20f5ad" + sc.initialResult.Result.Meta.CreatedBy.Name = UserInDbName + sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = UserInDbAvatar sc.initialResult.Result.Model["title"] = "New Name" sc.initialResult.Result.Version = 2 if diff := cmp.Diff(sc.initialResult.Result, result.Result, getCompareOptions()...); diff != "" { @@ -120,22 +124,76 @@ func TestPatchLibraryPanel(t *testing.T) { } }) - scenarioWithLibraryPanel(t, "When an admin tries to patch a library panel with model only, it should change model successfully and return correct result", + scenarioWithLibraryPanel(t, "When an admin tries to patch a library panel with model only, it should change model successfully, sync name, type and description fields and return correct result", func(t *testing.T, sc scenarioContext) { cmd := patchLibraryPanelCommand{ FolderID: -1, - Model: []byte(`{ "title": "New Model Title", "name": "New Model Name" }`), + Model: []byte(`{ "title": "New Model Title", "name": "New Model Name", "type":"graph", "description": "New description" }`), Version: 1, } sc.reqContext.ReplaceAllParams(map[string]string{":uid": sc.initialResult.Result.UID}) resp := sc.service.patchHandler(sc.reqContext, cmd) var result = validateAndUnMarshalResponse(t, resp) + sc.initialResult.Result.Type = "graph" + sc.initialResult.Result.Description = "New description" sc.initialResult.Result.Model = map[string]interface{}{ - "title": "Text - Library Panel", - "name": "New Model Name", + "title": "Text - Library Panel", + "name": "New Model Name", + "type": "graph", + "description": "New description", } - sc.initialResult.Result.Meta.CreatedBy.Name = "user_in_db" - sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = "/avatar/402d08de060496d6b6874495fe20f5ad" + sc.initialResult.Result.Meta.CreatedBy.Name = UserInDbName + sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = UserInDbAvatar + sc.initialResult.Result.Version = 2 + if diff := cmp.Diff(sc.initialResult.Result, result.Result, getCompareOptions()...); diff != "" { + t.Fatalf("Result mismatch (-want +got):\n%s", diff) + } + }) + + scenarioWithLibraryPanel(t, "When an admin tries to patch a library panel with model.description only, it should change model successfully, sync name, type and description fields and return correct result", + func(t *testing.T, sc scenarioContext) { + cmd := patchLibraryPanelCommand{ + FolderID: -1, + Model: []byte(`{ "description": "New description" }`), + Version: 1, + } + sc.reqContext.ReplaceAllParams(map[string]string{":uid": sc.initialResult.Result.UID}) + resp := sc.service.patchHandler(sc.reqContext, cmd) + var result = validateAndUnMarshalResponse(t, resp) + sc.initialResult.Result.Type = "text" + sc.initialResult.Result.Description = "New description" + sc.initialResult.Result.Model = map[string]interface{}{ + "title": "Text - Library Panel", + "type": "text", + "description": "New description", + } + sc.initialResult.Result.Meta.CreatedBy.Name = UserInDbName + sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = UserInDbAvatar + sc.initialResult.Result.Version = 2 + if diff := cmp.Diff(sc.initialResult.Result, result.Result, getCompareOptions()...); diff != "" { + t.Fatalf("Result mismatch (-want +got):\n%s", diff) + } + }) + + scenarioWithLibraryPanel(t, "When an admin tries to patch a library panel with model.type only, it should change model successfully, sync name, type and description fields and return correct result", + func(t *testing.T, sc scenarioContext) { + cmd := patchLibraryPanelCommand{ + FolderID: -1, + Model: []byte(`{ "type": "graph" }`), + Version: 1, + } + sc.reqContext.ReplaceAllParams(map[string]string{":uid": sc.initialResult.Result.UID}) + resp := sc.service.patchHandler(sc.reqContext, cmd) + var result = validateAndUnMarshalResponse(t, resp) + sc.initialResult.Result.Type = "graph" + sc.initialResult.Result.Description = "A description" + sc.initialResult.Result.Model = map[string]interface{}{ + "title": "Text - Library Panel", + "type": "graph", + "description": "A description", + } + sc.initialResult.Result.Meta.CreatedBy.Name = UserInDbName + sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = UserInDbAvatar sc.initialResult.Result.Version = 2 if diff := cmp.Diff(sc.initialResult.Result, result.Result, getCompareOptions()...); diff != "" { t.Fatalf("Result mismatch (-want +got):\n%s", diff) @@ -150,8 +208,8 @@ func TestPatchLibraryPanel(t *testing.T) { resp := sc.service.patchHandler(sc.reqContext, cmd) var result = validateAndUnMarshalResponse(t, resp) sc.initialResult.Result.Meta.UpdatedBy.ID = int64(2) - sc.initialResult.Result.Meta.CreatedBy.Name = "user_in_db" - sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = "/avatar/402d08de060496d6b6874495fe20f5ad" + sc.initialResult.Result.Meta.CreatedBy.Name = UserInDbName + sc.initialResult.Result.Meta.CreatedBy.AvatarUrl = UserInDbAvatar sc.initialResult.Result.Version = 2 if diff := cmp.Diff(sc.initialResult.Result, result.Result, getCompareOptions()...); diff != "" { t.Fatalf("Result mismatch (-want +got):\n%s", diff) diff --git a/pkg/services/librarypanels/librarypanels_test.go b/pkg/services/librarypanels/librarypanels_test.go index 849a3084aa7..848fd7c8c22 100644 --- a/pkg/services/librarypanels/librarypanels_test.go +++ b/pkg/services/librarypanels/librarypanels_test.go @@ -84,11 +84,14 @@ func TestLoadLibraryPanelsForDashboard(t *testing.T) { "x": 6, "y": 0, }, - "datasource": "${DS_GDEV-TESTDATA}", + "datasource": "${DS_GDEV-TESTDATA}", + "description": "A description", "libraryPanel": map[string]interface{}{ - "uid": sc.initialResult.Result.UID, - "name": sc.initialResult.Result.Name, - "version": sc.initialResult.Result.Version, + "uid": sc.initialResult.Result.UID, + "name": sc.initialResult.Result.Name, + "type": sc.initialResult.Result.Type, + "description": sc.initialResult.Result.Description, + "version": sc.initialResult.Result.Version, "meta": map[string]interface{}{ "canEdit": false, "connectedDashboards": int64(1), @@ -664,14 +667,16 @@ func TestDeleteLibraryPanelsInFolder(t *testing.T) { } type libraryPanel struct { - ID int64 `json:"id"` - OrgID int64 `json:"orgId"` - FolderID int64 `json:"folderId"` - UID string `json:"uid"` - Name string `json:"name"` - Model map[string]interface{} `json:"model"` - Version int64 `json:"version"` - Meta LibraryPanelDTOMeta `json:"meta"` + ID int64 `json:"id"` + OrgID int64 `json:"orgId"` + FolderID int64 `json:"folderId"` + UID string `json:"uid"` + Name string `json:"name"` + Type string + Description string + Model map[string]interface{} `json:"model"` + Version int64 `json:"version"` + Meta LibraryPanelDTOMeta `json:"meta"` } type libraryPanelResult struct { @@ -723,7 +728,8 @@ func getCreateCommand(folderID int64, name string) createLibraryPanelCommand { "datasource": "${DS_GDEV-TESTDATA}", "id": 1, "title": "Text - Library Panel", - "type": "text" + "type": "text", + "description": "A description" } `), } diff --git a/pkg/services/librarypanels/models.go b/pkg/services/librarypanels/models.go index 87b9ef00bf4..c499cee5706 100644 --- a/pkg/services/librarypanels/models.go +++ b/pkg/services/librarypanels/models.go @@ -8,13 +8,15 @@ import ( // LibraryPanel is the model for library panel definitions. type LibraryPanel struct { - ID int64 `xorm:"pk autoincr 'id'"` - OrgID int64 `xorm:"org_id"` - FolderID int64 `xorm:"folder_id"` - UID string `xorm:"uid"` - Name string - Model json.RawMessage - Version int64 + ID int64 `xorm:"pk autoincr 'id'"` + OrgID int64 `xorm:"org_id"` + FolderID int64 `xorm:"folder_id"` + UID string `xorm:"uid"` + Name string + Type string + Description string + Model json.RawMessage + Version int64 Created time.Time Updated time.Time @@ -25,13 +27,15 @@ type LibraryPanel struct { // LibraryPanelWithMeta is the model used to retrieve library panels with additional meta information. type LibraryPanelWithMeta struct { - ID int64 `xorm:"pk autoincr 'id'"` - OrgID int64 `xorm:"org_id"` - FolderID int64 `xorm:"folder_id"` - UID string `xorm:"uid"` - Name string - Model json.RawMessage - Version int64 + ID int64 `xorm:"pk autoincr 'id'"` + OrgID int64 `xorm:"org_id"` + FolderID int64 `xorm:"folder_id"` + UID string `xorm:"uid"` + Name string + Type string + Description string + Model json.RawMessage + Version int64 Created time.Time Updated time.Time @@ -48,14 +52,16 @@ type LibraryPanelWithMeta struct { // LibraryPanelDTO is the frontend DTO for library panels. type LibraryPanelDTO struct { - ID int64 `json:"id"` - OrgID int64 `json:"orgId"` - FolderID int64 `json:"folderId"` - UID string `json:"uid"` - Name string `json:"name"` - Model json.RawMessage `json:"model"` - Version int64 `json:"version"` - Meta LibraryPanelDTOMeta `json:"meta"` + ID int64 `json:"id"` + OrgID int64 `json:"orgId"` + FolderID int64 `json:"folderId"` + UID string `json:"uid"` + Name string `json:"name"` + Type string `json:"type"` + Description string `json:"description"` + Model json.RawMessage `json:"model"` + Version int64 `json:"version"` + Meta LibraryPanelDTOMeta `json:"meta"` } // LibraryPanelSearchResult is the search result for library panels. diff --git a/public/app/features/library-panels/components/LibraryPanelsView/reducer.test.ts b/public/app/features/library-panels/components/LibraryPanelsView/reducer.test.ts index 1ab6841ec82..12b0990eb8a 100644 --- a/public/app/features/library-panels/components/LibraryPanelsView/reducer.test.ts +++ b/public/app/features/library-panels/components/LibraryPanelsView/reducer.test.ts @@ -130,6 +130,8 @@ function mockLibraryPanel({ updatedBy: { id: 2, name: 'User Y', avatarUrl: '/avatar/xyz' }, }, version = 1, + description = 'a description', + type = 'text', }: Partial = {}): LibraryPanelDTO { return { uid, @@ -140,5 +142,7 @@ function mockLibraryPanel({ model, version, meta, + description, + type, }; } diff --git a/public/app/features/library-panels/types.ts b/public/app/features/library-panels/types.ts index 36f509e66b4..c9ffab6187c 100644 --- a/public/app/features/library-panels/types.ts +++ b/public/app/features/library-panels/types.ts @@ -15,6 +15,8 @@ export interface LibraryPanelDTO { folderId: number; uid: string; name: string; + type: string; + description: string; model: any; version: number; meta: LibraryPanelDTOMeta;