mirror of
https://github.com/grafana/grafana.git
synced 2025-08-01 11:02:13 +08:00
LibraryPanels: Fixes error when importing plugin dashboard (#34557)
This commit is contained in:
@ -1348,10 +1348,6 @@ func (m *mockLibraryPanelService) ConnectLibraryPanelsForDashboard(c *models.Req
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockLibraryPanelService) ImportDashboard(c *models.ReqContext, dashboard *simplejson.Json, importedID int64) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type mockLibraryElementService struct {
|
type mockLibraryElementService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,13 +220,13 @@ func (hs *HTTPServer) ImportDashboard(c *models.ReqContext, apiCmd dtos.ImportDa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dashInfo, err := hs.PluginManager.ImportDashboard(apiCmd.PluginId, apiCmd.Path, c.OrgId, apiCmd.FolderId,
|
dashInfo, dash, err := hs.PluginManager.ImportDashboard(apiCmd.PluginId, apiCmd.Path, c.OrgId, apiCmd.FolderId,
|
||||||
apiCmd.Dashboard, apiCmd.Overwrite, apiCmd.Inputs, c.SignedInUser, hs.DataService)
|
apiCmd.Dashboard, apiCmd.Overwrite, apiCmd.Inputs, c.SignedInUser, hs.DataService)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hs.dashboardSaveErrorToApiResponse(err)
|
return hs.dashboardSaveErrorToApiResponse(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = hs.LibraryPanelService.ImportDashboard(c, apiCmd.Dashboard, dashInfo.DashboardId)
|
err = hs.LibraryPanelService.ConnectLibraryPanelsForDashboard(c, dash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return response.Error(500, "Error while connecting library panels", err)
|
return response.Error(500, "Error while connecting library panels", err)
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ type Manager interface {
|
|||||||
// ImportDashboard imports a dashboard.
|
// ImportDashboard imports a dashboard.
|
||||||
ImportDashboard(pluginID, path string, orgID, folderID int64, dashboardModel *simplejson.Json,
|
ImportDashboard(pluginID, path string, orgID, folderID int64, dashboardModel *simplejson.Json,
|
||||||
overwrite bool, inputs []ImportDashboardInput, user *models.SignedInUser,
|
overwrite bool, inputs []ImportDashboardInput, user *models.SignedInUser,
|
||||||
requestHandler DataRequestHandler) (PluginDashboardInfoDTO, error)
|
requestHandler DataRequestHandler) (PluginDashboardInfoDTO, *models.Dashboard, error)
|
||||||
// ScanningErrors returns plugin scanning errors encountered.
|
// ScanningErrors returns plugin scanning errors encountered.
|
||||||
ScanningErrors() []PluginError
|
ScanningErrors() []PluginError
|
||||||
// LoadPluginDashboard loads a plugin dashboard.
|
// LoadPluginDashboard loads a plugin dashboard.
|
||||||
|
@ -23,12 +23,12 @@ func (e DashboardInputMissingError) Error() string {
|
|||||||
|
|
||||||
func (pm *PluginManager) ImportDashboard(pluginID, path string, orgID, folderID int64, dashboardModel *simplejson.Json,
|
func (pm *PluginManager) ImportDashboard(pluginID, path string, orgID, folderID int64, dashboardModel *simplejson.Json,
|
||||||
overwrite bool, inputs []plugins.ImportDashboardInput, user *models.SignedInUser,
|
overwrite bool, inputs []plugins.ImportDashboardInput, user *models.SignedInUser,
|
||||||
requestHandler plugins.DataRequestHandler) (plugins.PluginDashboardInfoDTO, error) {
|
requestHandler plugins.DataRequestHandler) (plugins.PluginDashboardInfoDTO, *models.Dashboard, error) {
|
||||||
var dashboard *models.Dashboard
|
var dashboard *models.Dashboard
|
||||||
if pluginID != "" {
|
if pluginID != "" {
|
||||||
var err error
|
var err error
|
||||||
if dashboard, err = pm.LoadPluginDashboard(pluginID, path); err != nil {
|
if dashboard, err = pm.LoadPluginDashboard(pluginID, path); err != nil {
|
||||||
return plugins.PluginDashboardInfoDTO{}, err
|
return plugins.PluginDashboardInfoDTO{}, &models.Dashboard{}, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dashboard = models.NewDashboardFromJson(dashboardModel)
|
dashboard = models.NewDashboardFromJson(dashboardModel)
|
||||||
@ -41,7 +41,7 @@ func (pm *PluginManager) ImportDashboard(pluginID, path string, orgID, folderID
|
|||||||
|
|
||||||
generatedDash, err := evaluator.Eval()
|
generatedDash, err := evaluator.Eval()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return plugins.PluginDashboardInfoDTO{}, err
|
return plugins.PluginDashboardInfoDTO{}, &models.Dashboard{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
saveCmd := models.SaveDashboardCommand{
|
saveCmd := models.SaveDashboardCommand{
|
||||||
@ -62,7 +62,7 @@ func (pm *PluginManager) ImportDashboard(pluginID, path string, orgID, folderID
|
|||||||
|
|
||||||
savedDash, err := dashboards.NewService(pm.SQLStore).ImportDashboard(dto)
|
savedDash, err := dashboards.NewService(pm.SQLStore).ImportDashboard(dto)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return plugins.PluginDashboardInfoDTO{}, err
|
return plugins.PluginDashboardInfoDTO{}, &models.Dashboard{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return plugins.PluginDashboardInfoDTO{
|
return plugins.PluginDashboardInfoDTO{
|
||||||
@ -77,7 +77,7 @@ func (pm *PluginManager) ImportDashboard(pluginID, path string, orgID, folderID
|
|||||||
Imported: true,
|
Imported: true,
|
||||||
DashboardId: savedDash.Id,
|
DashboardId: savedDash.Id,
|
||||||
Slug: savedDash.Slug,
|
Slug: savedDash.Slug,
|
||||||
}, nil
|
}, savedDash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type DashTemplateEvaluator struct {
|
type DashTemplateEvaluator struct {
|
||||||
|
@ -21,12 +21,13 @@ func TestDashboardImport(t *testing.T) {
|
|||||||
mock := &dashboards.FakeDashboardService{}
|
mock := &dashboards.FakeDashboardService{}
|
||||||
dashboards.MockDashboardService(mock)
|
dashboards.MockDashboardService(mock)
|
||||||
|
|
||||||
info, err := pm.ImportDashboard("test-app", "dashboards/connections.json", 1, 0, nil, false,
|
info, dash, err := pm.ImportDashboard("test-app", "dashboards/connections.json", 1, 0, nil, false,
|
||||||
[]plugins.ImportDashboardInput{
|
[]plugins.ImportDashboardInput{
|
||||||
{Name: "*", Type: "datasource", Value: "graphite"},
|
{Name: "*", Type: "datasource", Value: "graphite"},
|
||||||
}, &models.SignedInUser{UserId: 1, OrgRole: models.ROLE_ADMIN}, nil)
|
}, &models.SignedInUser{UserId: 1, OrgRole: models.ROLE_ADMIN}, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, info)
|
require.NotNil(t, info)
|
||||||
|
require.NotNil(t, dash)
|
||||||
|
|
||||||
resultStr, err := mock.SavedDashboards[0].Dashboard.Data.EncodePretty()
|
resultStr, err := mock.SavedDashboards[0].Dashboard.Data.EncodePretty()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -145,7 +145,7 @@ func (s *Service) autoUpdateAppDashboard(pluginDashInfo *plugins.PluginDashboard
|
|||||||
s.logger.Info("Auto updating App dashboard", "dashboard", dash.Title, "newRev",
|
s.logger.Info("Auto updating App dashboard", "dashboard", dash.Title, "newRev",
|
||||||
pluginDashInfo.Revision, "oldRev", pluginDashInfo.ImportedRevision)
|
pluginDashInfo.Revision, "oldRev", pluginDashInfo.ImportedRevision)
|
||||||
user := &models.SignedInUser{UserId: 0, OrgRole: models.ROLE_ADMIN}
|
user := &models.SignedInUser{UserId: 0, OrgRole: models.ROLE_ADMIN}
|
||||||
_, err = s.PluginManager.ImportDashboard(pluginDashInfo.PluginId, pluginDashInfo.Path, orgID, 0, dash.Data, true,
|
_, _, err = s.PluginManager.ImportDashboard(pluginDashInfo.PluginId, pluginDashInfo.Path, orgID, 0, dash.Data, true,
|
||||||
nil, user, s.DataService)
|
nil, user, s.DataService)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@ type Service interface {
|
|||||||
LoadLibraryPanelsForDashboard(c *models.ReqContext, dash *models.Dashboard) error
|
LoadLibraryPanelsForDashboard(c *models.ReqContext, dash *models.Dashboard) error
|
||||||
CleanLibraryPanelsForDashboard(dash *models.Dashboard) error
|
CleanLibraryPanelsForDashboard(dash *models.Dashboard) error
|
||||||
ConnectLibraryPanelsForDashboard(c *models.ReqContext, dash *models.Dashboard) error
|
ConnectLibraryPanelsForDashboard(c *models.ReqContext, dash *models.Dashboard) error
|
||||||
ImportDashboard(c *models.ReqContext, dashboard *simplejson.Json, importedID int64) error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LibraryPanelService is the service for the Panel Library feature.
|
// LibraryPanelService is the service for the Panel Library feature.
|
||||||
@ -193,11 +192,3 @@ func (lps *LibraryPanelService) ConnectLibraryPanelsForDashboard(c *models.ReqCo
|
|||||||
|
|
||||||
return lps.LibraryElementService.ConnectElementsToDashboard(c, elementUIDs, dash.Id)
|
return lps.LibraryElementService.ConnectElementsToDashboard(c, elementUIDs, dash.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportDashboard loops through all panels in dashboard JSON and connects any library panels to the dashboard.
|
|
||||||
func (lps *LibraryPanelService) ImportDashboard(c *models.ReqContext, dashboard *simplejson.Json, importedID int64) error {
|
|
||||||
dash := models.NewDashboardFromJson(dashboard)
|
|
||||||
dash.Id = importedID
|
|
||||||
|
|
||||||
return lps.ConnectLibraryPanelsForDashboard(c, dash)
|
|
||||||
}
|
|
||||||
|
@ -572,106 +572,6 @@ func TestConnectLibraryPanelsForDashboard(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestImportDashboard(t *testing.T) {
|
|
||||||
scenarioWithLibraryPanel(t, "When an admin tries to import a dashboard with a library panel, it should connect the two",
|
|
||||||
func(t *testing.T, sc scenarioContext) {
|
|
||||||
importedJSON := map[string]interface{}{
|
|
||||||
"panels": []interface{}{},
|
|
||||||
}
|
|
||||||
importedDashboard := models.Dashboard{
|
|
||||||
Title: "Dummy dash that simulates an imported dash",
|
|
||||||
Data: simplejson.NewFromAny(importedJSON),
|
|
||||||
}
|
|
||||||
importedDashInDB := createDashboard(t, sc.sqlStore, sc.user, &importedDashboard, sc.folder.Id)
|
|
||||||
elements, err := sc.elementService.GetElementsForDashboard(sc.reqContext, importedDashInDB.Id)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, elements, 0)
|
|
||||||
|
|
||||||
dashJSON := map[string]interface{}{
|
|
||||||
"title": "Testing ImportDashboard",
|
|
||||||
"panels": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"id": int64(1),
|
|
||||||
"gridPos": map[string]interface{}{
|
|
||||||
"h": 6,
|
|
||||||
"w": 6,
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
map[string]interface{}{
|
|
||||||
"id": int64(2),
|
|
||||||
"gridPos": map[string]interface{}{
|
|
||||||
"h": 6,
|
|
||||||
"w": 6,
|
|
||||||
"x": 6,
|
|
||||||
"y": 0,
|
|
||||||
},
|
|
||||||
"datasource": "${DS_GDEV-TESTDATA}",
|
|
||||||
"libraryPanel": map[string]interface{}{
|
|
||||||
"uid": sc.initialResult.Result.UID,
|
|
||||||
"name": sc.initialResult.Result.Name,
|
|
||||||
},
|
|
||||||
"title": "Text - Library Panel",
|
|
||||||
"type": "text",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
dash := simplejson.NewFromAny(dashJSON)
|
|
||||||
err = sc.service.ImportDashboard(sc.reqContext, dash, importedDashInDB.Id)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
elements, err = sc.elementService.GetElementsForDashboard(sc.reqContext, importedDashInDB.Id)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Len(t, elements, 1)
|
|
||||||
require.Equal(t, sc.initialResult.Result.UID, elements[sc.initialResult.Result.UID].UID)
|
|
||||||
})
|
|
||||||
|
|
||||||
scenarioWithLibraryPanel(t, "When an admin tries to import a dashboard with a library panel without uid, it should fail",
|
|
||||||
func(t *testing.T, sc scenarioContext) {
|
|
||||||
importedJSON := map[string]interface{}{
|
|
||||||
"panels": []interface{}{},
|
|
||||||
}
|
|
||||||
importedDashboard := models.Dashboard{
|
|
||||||
Title: "Dummy dash that simulates an imported dash",
|
|
||||||
Data: simplejson.NewFromAny(importedJSON),
|
|
||||||
}
|
|
||||||
importedDashInDB := createDashboard(t, sc.sqlStore, sc.user, &importedDashboard, sc.folder.Id)
|
|
||||||
|
|
||||||
dashJSON := map[string]interface{}{
|
|
||||||
"panels": []interface{}{
|
|
||||||
map[string]interface{}{
|
|
||||||
"id": int64(1),
|
|
||||||
"gridPos": map[string]interface{}{
|
|
||||||
"h": 6,
|
|
||||||
"w": 6,
|
|
||||||
"x": 0,
|
|
||||||
"y": 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
map[string]interface{}{
|
|
||||||
"id": int64(2),
|
|
||||||
"gridPos": map[string]interface{}{
|
|
||||||
"h": 6,
|
|
||||||
"w": 6,
|
|
||||||
"x": 6,
|
|
||||||
"y": 0,
|
|
||||||
},
|
|
||||||
"datasource": "${DS_GDEV-TESTDATA}",
|
|
||||||
"libraryPanel": map[string]interface{}{
|
|
||||||
"name": sc.initialResult.Result.Name,
|
|
||||||
},
|
|
||||||
"title": "Text - Library Panel",
|
|
||||||
"type": "text",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
dash := simplejson.NewFromAny(dashJSON)
|
|
||||||
err := sc.service.ImportDashboard(sc.reqContext, dash, importedDashInDB.Id)
|
|
||||||
require.EqualError(t, err, errLibraryPanelHeaderUIDMissing.Error())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type libraryPanel struct {
|
type libraryPanel struct {
|
||||||
ID int64
|
ID int64
|
||||||
OrgID int64
|
OrgID int64
|
||||||
|
Reference in New Issue
Block a user