* Extend interpolate endpoint to support community dashboard json interpolation Added unit tests * Implement Frontend Side - Show tabs - Fetch Community dashboads - basic cards for community - Search bar for community * Improve card community and show thumbnails * quick poc with template dashboards * better cards ui * entry point conditional added. dashboard card improved * dev dashboard for testing * details removed in template dashboard modal * improvement when loading the templates * dashboard from template entry points * interactions added * tracking event improvements. card improvement * unused import removed * 90% Complete MVP community dashboards integraton - Use DashboardCard component - Search grafana dashboard in the community tab - Make Tabs and pagination sticky - Adjust titles to be scoped by datasource name/type - Add skeleton loading for community tabs and pagination - Add dashboard details tooltip * Use DataSourcePicker for extra configuration page * Fix suggested dashboard, don't use filter but slug and also add gcomURLink * Implement badge, for now reuse Badge component * translations added * Refactor code, extract to utils function and clean up code * refactor provisioned dashboards images * add missing file * Extract API functions * standarize event handlers * Auto select tab when provisioned or community are not present, also add empty state for provisioned tab * use SecondaryAction iconButton for Details, and also use Tooltip * For suggested dashboards change Grid for Stack to fix issue with less than 3 dashboards, also add the details next to the main action * Fix styling issue with description miss-aligment * Change "use template" to use dashboard * update i18n * fix broken unit test * FF added * uid changed to make it work for both scenarios * Apply PR feedback - add eventLocation - Fix description placeholder - Fix issue with suggested dashboards card aligment, change to Grid * use datasource type instead of name, extract i18n and fix linting * Improve View on Grafana.com link * remove console.log * Fix issue with cards styling * improvements * Apply suggestion from @juanicabanas Co-authored-by: Juan Cabanas <juan.cabanas@grafana.com> * Use query params for modal state and reorder dashboard empty to keep suggestions in the middle * extract common interpolate logic in new function * fix linting * rename loadTemplateDashboard function to loadSuggestedDashboard * Improve automapping layout, add dashboard name to title and pipe the mappings * Apply style guide for callback functions, and refactor constant inputs initialization wiht reduce * Fix styling issues with focus border and pagination * fix issue with card aligment * use attach skeleton instead of custom css * Adjust all i18n to use dashboard-library key * Refactor mapping form to use one array to handle unmapped ds * Update public/app/features/dashboard/dashgrid/DashboardLibrary/CommunityDashboardSection.tsx Co-authored-by: Juan Cabanas <juan.cabanas@grafana.com> * Refactor pagination, use api pagination data * Remove unnecesary trim * Fix issue with Stack height and justifyContent in modal * Update public/app/features/dashboard/dashgrid/DashboardLibrary/SuggestedDashboards.tsx Co-authored-by: Juan Cabanas <juan.cabanas@grafana.com> * Add missing dependency * Fix issue with mapping config form, make buttons to be aligned at the bottom * Fix unit tests * Add and refactor tracking interactions to support experiment KPIS * rename unmappedInputs to unmappedDsInputs for clarity * Update public/app/features/dashboard/dashgrid/DashboardLibrary/CommunityDashboardSection.tsx Co-authored-by: Juan Cabanas <juan.cabanas@grafana.com> * rename modal and move modal to section * Simplify search params, extrack user selected dashboards to helper function, update pagination styles and use url based pagination * Move modal logic to the suggested dashboards component * Fix tracking duplication on first load and revert change on pagination url persistence * Extrac on preview community dashboard into utils * Bring old datasource-provisioned box back and rely on new feature toggle for community dashboards * change logic for showing suggested dashboards, we only need to enable that feature toggle * update i18n * Fix unit test for basic provisioned dashboard * fix css * Apply feedback * Add suggested dashboards to endpoint * Add missing feature toggle check in the backend to expose the interpolate api * Add extra test case * update swagger * Update public/app/features/dashboard/dashgrid/DashboardEmpty/DashboardEmpty.tsx Co-authored-by: Juan Cabanas <juan.cabanas@grafana.com> * update swagger * changes applied to retrieve templates dashboards from raintank * translations * Remove duplicated tracking and add gnet id to the save tracking action * interactions * improvements applied * last improvements * tracking events modified with merge. translations fixed * tests fixed * uid property removed from dto. new way of tracking the ds types added * ds types from gnet dashboard removed * fixes * tracking changed * tracking modified --------- Co-authored-by: alexandra vargas <alexa1866@gmail.com> Co-authored-by: Alexa Vargas <239999+axelavargas@users.noreply.github.com> Co-authored-by: nmarrs <nathanielmarrs@gmail.com>
162 lines
5.4 KiB
Go
162 lines
5.4 KiB
Go
package api
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
|
|
"github.com/grafana/grafana/pkg/api/apierrors"
|
|
"github.com/grafana/grafana/pkg/api/response"
|
|
"github.com/grafana/grafana/pkg/api/routing"
|
|
"github.com/grafana/grafana/pkg/middleware"
|
|
"github.com/grafana/grafana/pkg/services/accesscontrol"
|
|
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
|
|
"github.com/grafana/grafana/pkg/services/dashboardimport"
|
|
"github.com/grafana/grafana/pkg/services/dashboardimport/utils"
|
|
"github.com/grafana/grafana/pkg/services/dashboards"
|
|
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
|
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
|
|
"github.com/grafana/grafana/pkg/services/quota"
|
|
"github.com/grafana/grafana/pkg/web"
|
|
)
|
|
|
|
type ImportDashboardAPI struct {
|
|
dashboardImportService dashboardimport.Service
|
|
quotaService QuotaService
|
|
pluginStore pluginstore.Store
|
|
ac accesscontrol.AccessControl
|
|
features featuremgmt.FeatureToggles
|
|
}
|
|
|
|
func New(dashboardImportService dashboardimport.Service, quotaService QuotaService,
|
|
pluginStore pluginstore.Store, ac accesscontrol.AccessControl, features featuremgmt.FeatureToggles) *ImportDashboardAPI {
|
|
return &ImportDashboardAPI{
|
|
dashboardImportService: dashboardImportService,
|
|
quotaService: quotaService,
|
|
pluginStore: pluginStore,
|
|
ac: ac,
|
|
features: features,
|
|
}
|
|
}
|
|
|
|
func (api *ImportDashboardAPI) RegisterAPIEndpoints(routeRegister routing.RouteRegister) {
|
|
authorize := accesscontrol.Middleware(api.ac)
|
|
routeRegister.Group("/api/dashboards", func(route routing.RouteRegister) {
|
|
route.Post(
|
|
"/import",
|
|
authorize(accesscontrol.EvalPermission(dashboards.ActionDashboardsCreate)),
|
|
routing.Wrap(api.ImportDashboard),
|
|
)
|
|
//nolint:staticcheck // not yet migrated to OpenFeature
|
|
if api.features.IsEnabledGlobally(featuremgmt.FlagDashboardLibrary) || api.features.IsEnabledGlobally(featuremgmt.FlagSuggestedDashboards) || api.features.IsEnabledGlobally(featuremgmt.FlagDashboardTemplates) {
|
|
route.Post(
|
|
"/interpolate",
|
|
authorize(accesscontrol.EvalPermission(dashboards.ActionDashboardsCreate)),
|
|
routing.Wrap(api.InterpolateDashboard),
|
|
)
|
|
}
|
|
}, middleware.ReqSignedIn)
|
|
}
|
|
|
|
// swagger:route POST /dashboards/interpolate dashboards interpolateDashboard
|
|
//
|
|
// Interpolate dashboard. This is an experimental endpoint under dashboardLibrary or suggestedDashboards feature flags and is subject to change.
|
|
//
|
|
// Responses:
|
|
// 200: interpolateDashboardResponse
|
|
// 400: badRequestError
|
|
// 401: unauthorisedError
|
|
// 422: unprocessableEntityError
|
|
// 500: internalServerError
|
|
func (api *ImportDashboardAPI) InterpolateDashboard(c *contextmodel.ReqContext) response.Response {
|
|
req := dashboardimport.ImportDashboardRequest{}
|
|
if err := web.Bind(c.Req, &req); err != nil {
|
|
return response.Error(http.StatusBadRequest, "bad request data", err)
|
|
}
|
|
|
|
if req.PluginId == "" && req.Dashboard == nil {
|
|
return response.Error(http.StatusUnprocessableEntity, "pluginId or dashboard must be set", nil)
|
|
}
|
|
|
|
resp, err := api.dashboardImportService.InterpolateDashboard(c.Req.Context(), &req)
|
|
if err != nil {
|
|
return response.Error(http.StatusInternalServerError, "failed to interpolate dashboard", err)
|
|
}
|
|
|
|
resp.Del("__elements")
|
|
resp.Del("__inputs")
|
|
resp.Del("__requires")
|
|
|
|
return response.JSON(http.StatusOK, resp)
|
|
}
|
|
|
|
// swagger:route POST /dashboards/import dashboards importDashboard
|
|
//
|
|
// Import dashboard.
|
|
//
|
|
// Responses:
|
|
// 200: importDashboardResponse
|
|
// 400: badRequestError
|
|
// 401: unauthorisedError
|
|
// 412: preconditionFailedError
|
|
// 422: unprocessableEntityError
|
|
// 500: internalServerError
|
|
func (api *ImportDashboardAPI) ImportDashboard(c *contextmodel.ReqContext) response.Response {
|
|
req := dashboardimport.ImportDashboardRequest{}
|
|
if err := web.Bind(c.Req, &req); err != nil {
|
|
return response.Error(http.StatusBadRequest, "bad request data", err)
|
|
}
|
|
|
|
if req.PluginId == "" && req.Dashboard == nil {
|
|
return response.Error(http.StatusUnprocessableEntity, "Dashboard must be set", nil)
|
|
}
|
|
|
|
limitReached, err := api.quotaService.QuotaReached(c, dashboards.QuotaTargetSrv)
|
|
if err != nil {
|
|
return response.Err(err)
|
|
}
|
|
|
|
if limitReached {
|
|
return response.Error(http.StatusForbidden, "Quota reached", nil)
|
|
}
|
|
|
|
req.User = c.SignedInUser
|
|
resp, err := api.dashboardImportService.ImportDashboard(c.Req.Context(), &req)
|
|
if err != nil {
|
|
if errors.Is(err, utils.ErrDashboardInputMissing) {
|
|
return response.Error(http.StatusBadRequest, err.Error(), err)
|
|
}
|
|
return apierrors.ToDashboardErrorResponse(c.Req.Context(), api.pluginStore, err)
|
|
}
|
|
|
|
return response.JSON(http.StatusOK, resp)
|
|
}
|
|
|
|
type QuotaService interface {
|
|
QuotaReached(c *contextmodel.ReqContext, target quota.TargetSrv) (bool, error)
|
|
}
|
|
|
|
type quotaServiceFunc func(c *contextmodel.ReqContext, target quota.TargetSrv) (bool, error)
|
|
|
|
func (fn quotaServiceFunc) QuotaReached(c *contextmodel.ReqContext, target quota.TargetSrv) (bool, error) {
|
|
return fn(c, target)
|
|
}
|
|
|
|
// swagger:parameters importDashboard
|
|
type ImportDashboardParams struct {
|
|
// in:body
|
|
// required:true
|
|
Body dashboardimport.ImportDashboardRequest
|
|
}
|
|
|
|
// swagger:response importDashboardResponse
|
|
type ImportDashboardResponse struct {
|
|
// in: body
|
|
Body dashboardimport.ImportDashboardResponse `json:"body"`
|
|
}
|
|
|
|
// swagger:response interpolateDashboardResponse
|
|
type InterpolateDashboardResponse struct {
|
|
// in: body
|
|
Body interface{} `json:"body"`
|
|
}
|