diff --git a/pkg/api/dashboard_test.go b/pkg/api/dashboard_test.go index fd500c617af..45389f4ee92 100644 --- a/pkg/api/dashboard_test.go +++ b/pkg/api/dashboard_test.go @@ -1348,6 +1348,10 @@ func (m *mockLibraryPanelService) ConnectLibraryPanelsForDashboard(c *models.Req return nil } +func (m *mockLibraryPanelService) ImportDashboard(c *models.ReqContext, dashboard *simplejson.Json, importedID int64) error { + return nil +} + type mockLibraryElementService struct { } diff --git a/pkg/api/plugins.go b/pkg/api/plugins.go index 31f1cbd2c11..761163c2d9d 100644 --- a/pkg/api/plugins.go +++ b/pkg/api/plugins.go @@ -226,6 +226,11 @@ func (hs *HTTPServer) ImportDashboard(c *models.ReqContext, apiCmd dtos.ImportDa return hs.dashboardSaveErrorToApiResponse(err) } + err = hs.LibraryPanelService.ImportDashboard(c, apiCmd.Dashboard, dashInfo.DashboardId) + if err != nil { + return response.Error(500, "Error while connecting library panels", err) + } + return response.JSON(200, dashInfo) } diff --git a/pkg/services/librarypanels/librarypanels.go b/pkg/services/librarypanels/librarypanels.go index 8d1cedf8a4a..10a8dd9378f 100644 --- a/pkg/services/librarypanels/librarypanels.go +++ b/pkg/services/librarypanels/librarypanels.go @@ -18,6 +18,7 @@ type Service interface { LoadLibraryPanelsForDashboard(c *models.ReqContext, dash *models.Dashboard) error CleanLibraryPanelsForDashboard(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. @@ -166,7 +167,7 @@ func (lps *LibraryPanelService) CleanLibraryPanelsForDashboard(dash *models.Dash // ConnectLibraryPanelsForDashboard loops through all panels in dashboard JSON and connects any library panels to the dashboard. func (lps *LibraryPanelService) ConnectLibraryPanelsForDashboard(c *models.ReqContext, dash *models.Dashboard) error { panels := dash.Data.Get("panels").MustArray() - var libraryPanels []string + libraryPanels := make(map[string]string) for _, panel := range panels { panelAsJSON := simplejson.NewFromAny(panel) libraryPanel := panelAsJSON.Get("libraryPanel") @@ -179,8 +180,24 @@ func (lps *LibraryPanelService) ConnectLibraryPanelsForDashboard(c *models.ReqCo if len(uid) == 0 { return errLibraryPanelHeaderUIDMissing } - libraryPanels = append(libraryPanels, uid) + _, exists := libraryPanels[uid] + if !exists { + libraryPanels[uid] = uid + } } - return lps.LibraryElementService.ConnectElementsToDashboard(c, libraryPanels, dash.Id) + elementUIDs := make([]string, 0, len(libraryPanels)) + for libraryPanel := range libraryPanels { + elementUIDs = append(elementUIDs, libraryPanel) + } + + 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) } diff --git a/pkg/services/librarypanels/librarypanels_test.go b/pkg/services/librarypanels/librarypanels_test.go index 1e57b813a0e..7ee014d4a34 100644 --- a/pkg/services/librarypanels/librarypanels_test.go +++ b/pkg/services/librarypanels/librarypanels_test.go @@ -572,6 +572,106 @@ 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 { ID int64 OrgID int64