mirror of
https://github.com/grafana/grafana.git
synced 2024-12-26 17:01:09 -06:00
LibraryElements: Creates usage stats for panels and variables (#34476)
* LibraryPanels: Adds usage collection * Refactor: renames Panel and Variable consts * Chore: initialize stats * Refactor: moves library element migrations to migration namespace
This commit is contained in:
parent
abe5c06d69
commit
7204a64717
@ -185,6 +185,12 @@ var (
|
||||
grafanaBuildVersion *prometheus.GaugeVec
|
||||
|
||||
grafanaPluginBuildInfoDesc *prometheus.GaugeVec
|
||||
|
||||
// StatsTotalLibraryPanels is a metric of total number of library panels stored in Grafana.
|
||||
StatsTotalLibraryPanels prometheus.Gauge
|
||||
|
||||
// StatsTotalLibraryVariables is a metric of total number of library variables stored in Grafana.
|
||||
StatsTotalLibraryVariables prometheus.Gauge
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -547,6 +553,18 @@ func init() {
|
||||
Help: "number of evaluation calls",
|
||||
Namespace: ExporterName,
|
||||
})
|
||||
|
||||
StatsTotalLibraryPanels = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "stat_totals_library_panels",
|
||||
Help: "total amount of library panels in the database",
|
||||
Namespace: ExporterName,
|
||||
})
|
||||
|
||||
StatsTotalLibraryVariables = prometheus.NewGauge(prometheus.GaugeOpts{
|
||||
Name: "stat_totals_library_variables",
|
||||
Help: "total amount of library variables in the database",
|
||||
Namespace: ExporterName,
|
||||
})
|
||||
}
|
||||
|
||||
// SetBuildInformation sets the build information for this binary
|
||||
@ -640,6 +658,8 @@ func initMetricVars() {
|
||||
StatsTotalDashboardVersions,
|
||||
StatsTotalAnnotations,
|
||||
MAccessEvaluationCount,
|
||||
StatsTotalLibraryPanels,
|
||||
StatsTotalLibraryVariables,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,8 @@ func (uss *UsageStatsService) GetUsageReport(ctx context.Context) (UsageReport,
|
||||
metrics["stats.dashboard_versions.count"] = statsQuery.Result.DashboardVersions
|
||||
metrics["stats.annotations.count"] = statsQuery.Result.Annotations
|
||||
metrics["stats.alert_rules.count"] = statsQuery.Result.AlertRules
|
||||
metrics["stats.library_panels.count"] = statsQuery.Result.LibraryPanels
|
||||
metrics["stats.library_variables.count"] = statsQuery.Result.LibraryVariables
|
||||
validLicCount := 0
|
||||
if uss.License.HasValidLicense() {
|
||||
validLicCount = 1
|
||||
@ -317,6 +319,8 @@ func (uss *UsageStatsService) updateTotalStats() {
|
||||
metrics.StatsTotalDashboardVersions.Set(float64(statsQuery.Result.DashboardVersions))
|
||||
metrics.StatsTotalAnnotations.Set(float64(statsQuery.Result.Annotations))
|
||||
metrics.StatsTotalAlertRules.Set(float64(statsQuery.Result.AlertRules))
|
||||
metrics.StatsTotalLibraryPanels.Set(float64(statsQuery.Result.LibraryPanels))
|
||||
metrics.StatsTotalLibraryVariables.Set(float64(statsQuery.Result.LibraryVariables))
|
||||
|
||||
dsStats := models.GetDataSourceStatsQuery{}
|
||||
if err := uss.Bus.Dispatch(&dsStats); err != nil {
|
||||
|
@ -63,6 +63,8 @@ func TestMetrics(t *testing.T) {
|
||||
DashboardVersions: 16,
|
||||
Annotations: 17,
|
||||
AlertRules: 18,
|
||||
LibraryPanels: 19,
|
||||
LibraryVariables: 20,
|
||||
}
|
||||
getSystemStatsQuery = query
|
||||
return nil
|
||||
@ -313,6 +315,8 @@ func TestMetrics(t *testing.T) {
|
||||
assert.Equal(t, 16, metrics.Get("stats.dashboard_versions.count").MustInt())
|
||||
assert.Equal(t, 17, metrics.Get("stats.annotations.count").MustInt())
|
||||
assert.Equal(t, 18, metrics.Get("stats.alert_rules.count").MustInt())
|
||||
assert.Equal(t, 19, metrics.Get("stats.library_panels.count").MustInt())
|
||||
assert.Equal(t, 20, metrics.Get("stats.library_variables.count").MustInt())
|
||||
|
||||
assert.Equal(t, 9, metrics.Get("stats.ds."+models.DS_ES+".count").MustInt())
|
||||
assert.Equal(t, 10, metrics.Get("stats.ds."+models.DS_PROMETHEUS+".count").MustInt())
|
||||
|
13
pkg/models/libraryelements.go
Normal file
13
pkg/models/libraryelements.go
Normal file
@ -0,0 +1,13 @@
|
||||
package models
|
||||
|
||||
// LibraryElementKind is used for the kind of library element
|
||||
type LibraryElementKind int
|
||||
|
||||
const (
|
||||
// PanelElement is used for library elements that are of the Panel kind
|
||||
PanelElement LibraryElementKind = iota + 1
|
||||
// VariableElement is used for library elements that are of the Variable kind
|
||||
VariableElement
|
||||
)
|
||||
|
||||
const LibraryElementConnectionTableName = "library_element_connection"
|
@ -19,6 +19,8 @@ type SystemStats struct {
|
||||
DashboardVersions int64
|
||||
Annotations int64
|
||||
AlertRules int64
|
||||
LibraryPanels int64
|
||||
LibraryVariables int64
|
||||
|
||||
Admins int
|
||||
Editors int
|
||||
|
@ -22,7 +22,7 @@ SELECT DISTINCT
|
||||
, u1.email AS created_by_email
|
||||
, u2.login AS updated_by_name
|
||||
, u2.email AS updated_by_email
|
||||
, (SELECT COUNT(connection_id) FROM ` + connectionTableName + ` WHERE element_id = le.id AND kind=1) AS connected_dashboards`
|
||||
, (SELECT COUNT(connection_id) FROM ` + models.LibraryElementConnectionTableName + ` WHERE element_id = le.id AND kind=1) AS connected_dashboards`
|
||||
)
|
||||
|
||||
func getFromLibraryElementDTOWithMeta(dialect migrator.Dialect) string {
|
||||
@ -41,9 +41,9 @@ func syncFieldsWithModel(libraryElement *LibraryElement) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if LibraryElementKind(libraryElement.Kind) == Panel {
|
||||
if models.LibraryElementKind(libraryElement.Kind) == models.PanelElement {
|
||||
model["title"] = libraryElement.Name
|
||||
} else if LibraryElementKind(libraryElement.Kind) == Variable {
|
||||
} else if models.LibraryElementKind(libraryElement.Kind) == models.VariableElement {
|
||||
model["name"] = libraryElement.Name
|
||||
}
|
||||
if model["type"] != nil {
|
||||
@ -520,7 +520,7 @@ func (l *LibraryElementService) getConnections(c *models.ReqContext, uid string)
|
||||
var libraryElementConnections []libraryElementConnectionWithMeta
|
||||
builder := sqlstore.SQLBuilder{}
|
||||
builder.Write("SELECT lec.*, u1.login AS created_by_name, u1.email AS created_by_email")
|
||||
builder.Write(" FROM " + connectionTableName + " AS lec")
|
||||
builder.Write(" FROM " + models.LibraryElementConnectionTableName + " AS lec")
|
||||
builder.Write(" LEFT JOIN " + l.SQLStore.Dialect.Quote("user") + " AS u1 ON lec.created_by = u1.id")
|
||||
builder.Write(" INNER JOIN dashboard AS dashboard on lec.connection_id = dashboard.id")
|
||||
builder.Write(` WHERE lec.element_id=?`, element.ID)
|
||||
@ -562,7 +562,7 @@ func (l *LibraryElementService) getElementsForDashboardID(c *models.ReqContext,
|
||||
", coalesce(dashboard.uid, '') AS folder_uid" +
|
||||
getFromLibraryElementDTOWithMeta(l.SQLStore.Dialect) +
|
||||
" LEFT JOIN dashboard AS dashboard ON dashboard.id = le.folder_id" +
|
||||
" INNER JOIN " + connectionTableName + " AS lce ON lce.element_id = le.id AND lce.kind=1 AND lce.connection_id=?"
|
||||
" INNER JOIN " + models.LibraryElementConnectionTableName + " AS lce ON lce.element_id = le.id AND lce.kind=1 AND lce.connection_id=?"
|
||||
sess := session.SQL(sql, dashboardID)
|
||||
err := sess.Find(&libraryElements)
|
||||
if err != nil {
|
||||
@ -610,7 +610,7 @@ func (l *LibraryElementService) getElementsForDashboardID(c *models.ReqContext,
|
||||
// connectElementsToDashboardID adds connections for all elements Library Elements in a Dashboard.
|
||||
func (l *LibraryElementService) connectElementsToDashboardID(c *models.ReqContext, elementUIDs []string, dashboardID int64) error {
|
||||
err := l.SQLStore.WithTransactionalDbSession(c.Context.Req.Context(), func(session *sqlstore.DBSession) error {
|
||||
_, err := session.Exec("DELETE FROM "+connectionTableName+" WHERE kind=1 AND connection_id=?", dashboardID)
|
||||
_, err := session.Exec("DELETE FROM "+models.LibraryElementConnectionTableName+" WHERE kind=1 AND connection_id=?", dashboardID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -646,7 +646,7 @@ func (l *LibraryElementService) connectElementsToDashboardID(c *models.ReqContex
|
||||
// disconnectElementsFromDashboardID deletes connections for all Library Elements in a Dashboard.
|
||||
func (l *LibraryElementService) disconnectElementsFromDashboardID(c *models.ReqContext, dashboardID int64) error {
|
||||
return l.SQLStore.WithTransactionalDbSession(c.Context.Req.Context(), func(session *sqlstore.DBSession) error {
|
||||
_, err := session.Exec("DELETE FROM "+connectionTableName+" WHERE kind=1 AND connection_id=?", dashboardID)
|
||||
_, err := session.Exec("DELETE FROM "+models.LibraryElementConnectionTableName+" WHERE kind=1 AND connection_id=?", dashboardID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -676,7 +676,7 @@ func (l *LibraryElementService) deleteLibraryElementsInFolderUID(c *models.ReqCo
|
||||
ConnectionID int64 `xorm:"connection_id"`
|
||||
}
|
||||
sql := "SELECT lec.connection_id FROM library_element AS le"
|
||||
sql += " INNER JOIN " + connectionTableName + " AS lec on le.id = lec.element_id"
|
||||
sql += " INNER JOIN " + models.LibraryElementConnectionTableName + " AS lec on le.id = lec.element_id"
|
||||
sql += " WHERE le.folder_id=? AND le.org_id=?"
|
||||
err = session.SQL(sql, folderID, c.SignedInUser.OrgId).Find(&connectionIDs)
|
||||
if err != nil {
|
||||
@ -694,7 +694,7 @@ func (l *LibraryElementService) deleteLibraryElementsInFolderUID(c *models.ReqCo
|
||||
return err
|
||||
}
|
||||
for _, elementID := range elementIDs {
|
||||
_, err := session.Exec("DELETE FROM "+connectionTableName+" WHERE element_id=?", elementID.ID)
|
||||
_, err := session.Exec("DELETE FROM "+models.LibraryElementConnectionTableName+" WHERE element_id=?", elementID.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -11,11 +11,11 @@ func isGeneralFolder(folderID int64) bool {
|
||||
}
|
||||
|
||||
func (l *LibraryElementService) requireSupportedElementKind(kindAsInt int64) error {
|
||||
kind := LibraryElementKind(kindAsInt)
|
||||
kind := models.LibraryElementKind(kindAsInt)
|
||||
switch kind {
|
||||
case Panel:
|
||||
case models.PanelElement:
|
||||
return nil
|
||||
case Variable:
|
||||
case models.VariableElement:
|
||||
return nil
|
||||
default:
|
||||
return errLibraryElementUnSupportedElementKind
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/registry"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
@ -27,8 +26,6 @@ type LibraryElementService struct {
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
const connectionTableName = "library_element_connection"
|
||||
|
||||
func init() {
|
||||
registry.RegisterService(&LibraryElementService{})
|
||||
}
|
||||
@ -66,51 +63,3 @@ func (l *LibraryElementService) DisconnectElementsFromDashboard(c *models.ReqCon
|
||||
func (l *LibraryElementService) DeleteLibraryElementsInFolder(c *models.ReqContext, folderUID string) error {
|
||||
return l.deleteLibraryElementsInFolderUID(c, folderUID)
|
||||
}
|
||||
|
||||
// AddMigration defines database migrations.
|
||||
// If Panel Library is not enabled does nothing.
|
||||
func (l *LibraryElementService) AddMigration(mg *migrator.Migrator) {
|
||||
libraryElementsV1 := migrator.Table{
|
||||
Name: "library_element",
|
||||
Columns: []*migrator.Column{
|
||||
{Name: "id", Type: migrator.DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
|
||||
{Name: "org_id", Type: migrator.DB_BigInt, Nullable: false},
|
||||
{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: 150, Nullable: false},
|
||||
{Name: "kind", Type: migrator.DB_BigInt, 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},
|
||||
{Name: "updated", Type: migrator.DB_DateTime, Nullable: false},
|
||||
{Name: "updated_by", Type: migrator.DB_BigInt, Nullable: false},
|
||||
{Name: "version", Type: migrator.DB_BigInt, Nullable: false},
|
||||
},
|
||||
Indices: []*migrator.Index{
|
||||
{Cols: []string{"org_id", "folder_id", "name", "kind"}, Type: migrator.UniqueIndex},
|
||||
},
|
||||
}
|
||||
|
||||
mg.AddMigration("create library_element table v1", migrator.NewAddTableMigration(libraryElementsV1))
|
||||
mg.AddMigration("add index library_element org_id-folder_id-name-kind", migrator.NewAddIndexMigration(libraryElementsV1, libraryElementsV1.Indices[0]))
|
||||
|
||||
libraryElementConnectionV1 := migrator.Table{
|
||||
Name: connectionTableName,
|
||||
Columns: []*migrator.Column{
|
||||
{Name: "id", Type: migrator.DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
|
||||
{Name: "element_id", Type: migrator.DB_BigInt, Nullable: false},
|
||||
{Name: "kind", Type: migrator.DB_BigInt, Nullable: false},
|
||||
{Name: "connection_id", Type: migrator.DB_BigInt, Nullable: false},
|
||||
{Name: "created", Type: migrator.DB_DateTime, Nullable: false},
|
||||
{Name: "created_by", Type: migrator.DB_BigInt, Nullable: false},
|
||||
},
|
||||
Indices: []*migrator.Index{
|
||||
{Cols: []string{"element_id", "kind", "connection_id"}, Type: migrator.UniqueIndex},
|
||||
},
|
||||
}
|
||||
|
||||
mg.AddMigration("create "+connectionTableName+" table v1", migrator.NewAddTableMigration(libraryElementConnectionV1))
|
||||
mg.AddMigration("add index "+connectionTableName+" element_id-kind-connection_id", migrator.NewAddIndexMigration(libraryElementConnectionV1, libraryElementConnectionV1.Indices[0]))
|
||||
}
|
||||
|
@ -5,6 +5,8 @@ import (
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
func TestCreateLibraryElement(t *testing.T) {
|
||||
@ -24,7 +26,7 @@ func TestCreateLibraryElement(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: sc.initialResult.Result.UID,
|
||||
Name: "Text - Library Panel",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
@ -69,7 +71,7 @@ func TestCreateLibraryElement(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.UID,
|
||||
Name: "Library Panel Name",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
|
@ -42,7 +42,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
|
||||
err := sc.reqContext.Req.ParseForm()
|
||||
require.NoError(t, err)
|
||||
sc.reqContext.Req.Form.Add("kind", strconv.FormatInt(int64(Panel), 10))
|
||||
sc.reqContext.Req.Form.Add("kind", strconv.FormatInt(int64(models.PanelElement), 10))
|
||||
|
||||
resp = sc.service.getAllHandler(sc.reqContext)
|
||||
require.Equal(t, 200, resp.Status())
|
||||
@ -62,7 +62,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[0].UID,
|
||||
Name: "Text - Library Panel",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
@ -107,7 +107,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
|
||||
err := sc.reqContext.Req.ParseForm()
|
||||
require.NoError(t, err)
|
||||
sc.reqContext.Req.Form.Add("kind", strconv.FormatInt(int64(Variable), 10))
|
||||
sc.reqContext.Req.Form.Add("kind", strconv.FormatInt(int64(models.VariableElement), 10))
|
||||
|
||||
resp = sc.service.getAllHandler(sc.reqContext)
|
||||
require.Equal(t, 200, resp.Status())
|
||||
@ -127,7 +127,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[0].UID,
|
||||
Name: "query0",
|
||||
Kind: int64(Variable),
|
||||
Kind: int64(models.VariableElement),
|
||||
Type: "query",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
@ -187,7 +187,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[0].UID,
|
||||
Name: "Text - Library Panel",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
@ -222,7 +222,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[1].UID,
|
||||
Name: "Text - Library Panel2",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
@ -286,7 +286,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[0].UID,
|
||||
Name: "Text - Library Panel2",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
@ -321,7 +321,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[1].UID,
|
||||
Name: "Text - Library Panel",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
@ -360,7 +360,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
|
||||
scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and typeFilter is set to existing types, it should succeed and the result should be correct",
|
||||
func(t *testing.T, sc scenarioContext) {
|
||||
command := getCreateCommandWithModel(sc.folder.Id, "Gauge - Library Panel", Panel, []byte(`
|
||||
command := getCreateCommandWithModel(sc.folder.Id, "Gauge - Library Panel", models.PanelElement, []byte(`
|
||||
{
|
||||
"datasource": "${DS_GDEV-TESTDATA}",
|
||||
"id": 1,
|
||||
@ -372,7 +372,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
resp := sc.service.createHandler(sc.reqContext, command)
|
||||
require.Equal(t, 200, resp.Status())
|
||||
|
||||
command = getCreateCommandWithModel(sc.folder.Id, "BarGauge - Library Panel", Panel, []byte(`
|
||||
command = getCreateCommandWithModel(sc.folder.Id, "BarGauge - Library Panel", models.PanelElement, []byte(`
|
||||
{
|
||||
"datasource": "${DS_GDEV-TESTDATA}",
|
||||
"id": 1,
|
||||
@ -405,7 +405,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[0].UID,
|
||||
Name: "BarGauge - Library Panel",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "bargauge",
|
||||
Description: "BarGauge description",
|
||||
Model: map[string]interface{}{
|
||||
@ -440,7 +440,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[1].UID,
|
||||
Name: "Gauge - Library Panel",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "gauge",
|
||||
Description: "Gauge description",
|
||||
Model: map[string]interface{}{
|
||||
@ -479,7 +479,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
|
||||
scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and typeFilter is set to a nonexistent type, it should succeed and the result should be correct",
|
||||
func(t *testing.T, sc scenarioContext) {
|
||||
command := getCreateCommandWithModel(sc.folder.Id, "Gauge - Library Panel", Panel, []byte(`
|
||||
command := getCreateCommandWithModel(sc.folder.Id, "Gauge - Library Panel", models.PanelElement, []byte(`
|
||||
{
|
||||
"datasource": "${DS_GDEV-TESTDATA}",
|
||||
"id": 1,
|
||||
@ -542,7 +542,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: newFolder.Id,
|
||||
UID: result.Result.Elements[0].UID,
|
||||
Name: "Text - Library Panel2",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
@ -637,7 +637,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[0].UID,
|
||||
Name: "Text - Library Panel",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
@ -672,7 +672,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[1].UID,
|
||||
Name: "Text - Library Panel2",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
@ -736,7 +736,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[0].UID,
|
||||
Name: "Text - Library Panel2",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
@ -800,7 +800,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[0].UID,
|
||||
Name: "Text - Library Panel",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
@ -865,7 +865,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[0].UID,
|
||||
Name: "Text - Library Panel2",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
@ -904,7 +904,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
|
||||
scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and searchString exists in the description, it should succeed and the result should be correct",
|
||||
func(t *testing.T, sc scenarioContext) {
|
||||
command := getCreateCommandWithModel(sc.folder.Id, "Text - Library Panel2", Panel, []byte(`
|
||||
command := getCreateCommandWithModel(sc.folder.Id, "Text - Library Panel2", models.PanelElement, []byte(`
|
||||
{
|
||||
"datasource": "${DS_GDEV-TESTDATA}",
|
||||
"id": 1,
|
||||
@ -939,7 +939,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[0].UID,
|
||||
Name: "Text - Library Panel",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
@ -978,7 +978,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
|
||||
scenarioWithPanel(t, "When an admin tries to get all library panels and two exist and searchString exists in both name and description, it should succeed and the result should be correct",
|
||||
func(t *testing.T, sc scenarioContext) {
|
||||
command := getCreateCommandWithModel(sc.folder.Id, "Some Other", Panel, []byte(`
|
||||
command := getCreateCommandWithModel(sc.folder.Id, "Some Other", models.PanelElement, []byte(`
|
||||
{
|
||||
"datasource": "${DS_GDEV-TESTDATA}",
|
||||
"id": 1,
|
||||
@ -1011,7 +1011,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[0].UID,
|
||||
Name: "Some Other",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A Library Panel",
|
||||
Model: map[string]interface{}{
|
||||
@ -1046,7 +1046,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[1].UID,
|
||||
Name: "Text - Library Panel",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
@ -1112,7 +1112,7 @@ func TestGetAllLibraryElements(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: result.Result.Elements[0].UID,
|
||||
Name: "Text - Library Panel2",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
|
@ -35,7 +35,7 @@ func TestGetLibraryElement(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: res.Result.UID,
|
||||
Name: "Text - Library Panel",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
@ -130,7 +130,7 @@ func TestGetLibraryElement(t *testing.T) {
|
||||
FolderID: 1,
|
||||
UID: res.Result.UID,
|
||||
Name: "Text - Library Panel",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "text",
|
||||
Description: "A description",
|
||||
Model: map[string]interface{}{
|
||||
|
@ -5,12 +5,14 @@ import (
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
)
|
||||
|
||||
func TestPatchLibraryElement(t *testing.T) {
|
||||
scenarioWithPanel(t, "When an admin tries to patch a library panel that does not exist, it should fail",
|
||||
func(t *testing.T, sc scenarioContext) {
|
||||
cmd := patchLibraryElementCommand{Kind: int64(Panel)}
|
||||
cmd := patchLibraryElementCommand{Kind: int64(models.PanelElement)}
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": "unknown"})
|
||||
resp := sc.service.patchHandler(sc.reqContext, cmd)
|
||||
require.Equal(t, 404, resp.Status())
|
||||
@ -31,7 +33,7 @@ func TestPatchLibraryElement(t *testing.T) {
|
||||
"type": "graph"
|
||||
}
|
||||
`),
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Version: 1,
|
||||
}
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": sc.initialResult.Result.UID})
|
||||
@ -45,7 +47,7 @@ func TestPatchLibraryElement(t *testing.T) {
|
||||
FolderID: newFolder.Id,
|
||||
UID: sc.initialResult.Result.UID,
|
||||
Name: "Panel - New name",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Type: "graph",
|
||||
Description: "An updated description",
|
||||
Model: map[string]interface{}{
|
||||
@ -83,7 +85,7 @@ func TestPatchLibraryElement(t *testing.T) {
|
||||
newFolder := createFolderWithACL(t, sc.sqlStore, "NewFolder", sc.user, []folderACLItem{})
|
||||
cmd := patchLibraryElementCommand{
|
||||
FolderID: newFolder.Id,
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Version: 1,
|
||||
}
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": sc.initialResult.Result.UID})
|
||||
@ -104,7 +106,7 @@ func TestPatchLibraryElement(t *testing.T) {
|
||||
cmd := patchLibraryElementCommand{
|
||||
FolderID: -1,
|
||||
Name: "New Name",
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Version: 1,
|
||||
}
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": sc.initialResult.Result.UID})
|
||||
@ -125,7 +127,7 @@ func TestPatchLibraryElement(t *testing.T) {
|
||||
cmd := patchLibraryElementCommand{
|
||||
FolderID: -1,
|
||||
Model: []byte(`{ "title": "New Model Title", "name": "New Model Name", "type":"graph", "description": "New description" }`),
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Version: 1,
|
||||
}
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": sc.initialResult.Result.UID})
|
||||
@ -152,7 +154,7 @@ func TestPatchLibraryElement(t *testing.T) {
|
||||
cmd := patchLibraryElementCommand{
|
||||
FolderID: -1,
|
||||
Model: []byte(`{ "description": "New description" }`),
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Version: 1,
|
||||
}
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": sc.initialResult.Result.UID})
|
||||
@ -178,7 +180,7 @@ func TestPatchLibraryElement(t *testing.T) {
|
||||
cmd := patchLibraryElementCommand{
|
||||
FolderID: -1,
|
||||
Model: []byte(`{ "type": "graph" }`),
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
Version: 1,
|
||||
}
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": sc.initialResult.Result.UID})
|
||||
@ -201,7 +203,7 @@ func TestPatchLibraryElement(t *testing.T) {
|
||||
|
||||
scenarioWithPanel(t, "When another admin tries to patch a library panel, it should change UpdatedBy successfully and return correct result",
|
||||
func(t *testing.T, sc scenarioContext) {
|
||||
cmd := patchLibraryElementCommand{FolderID: -1, Version: 1, Kind: int64(Panel)}
|
||||
cmd := patchLibraryElementCommand{FolderID: -1, Version: 1, Kind: int64(models.PanelElement)}
|
||||
sc.reqContext.UserId = 2
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": sc.initialResult.Result.UID})
|
||||
resp := sc.service.patchHandler(sc.reqContext, cmd)
|
||||
@ -223,7 +225,7 @@ func TestPatchLibraryElement(t *testing.T) {
|
||||
cmd := patchLibraryElementCommand{
|
||||
Name: "Text - Library Panel",
|
||||
Version: 1,
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
}
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": result.Result.UID})
|
||||
resp = sc.service.patchHandler(sc.reqContext, cmd)
|
||||
@ -239,7 +241,7 @@ func TestPatchLibraryElement(t *testing.T) {
|
||||
cmd := patchLibraryElementCommand{
|
||||
FolderID: 1,
|
||||
Version: 1,
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
}
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": result.Result.UID})
|
||||
resp = sc.service.patchHandler(sc.reqContext, cmd)
|
||||
@ -251,7 +253,7 @@ func TestPatchLibraryElement(t *testing.T) {
|
||||
cmd := patchLibraryElementCommand{
|
||||
FolderID: sc.folder.Id,
|
||||
Version: 1,
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
}
|
||||
sc.reqContext.OrgId = 2
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": sc.initialResult.Result.UID})
|
||||
@ -264,7 +266,7 @@ func TestPatchLibraryElement(t *testing.T) {
|
||||
cmd := patchLibraryElementCommand{
|
||||
FolderID: sc.folder.Id,
|
||||
Version: 1,
|
||||
Kind: int64(Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
}
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": sc.initialResult.Result.UID})
|
||||
resp := sc.service.patchHandler(sc.reqContext, cmd)
|
||||
@ -278,14 +280,14 @@ func TestPatchLibraryElement(t *testing.T) {
|
||||
cmd := patchLibraryElementCommand{
|
||||
FolderID: sc.folder.Id,
|
||||
Version: 1,
|
||||
Kind: int64(Variable),
|
||||
Kind: int64(models.VariableElement),
|
||||
}
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": sc.initialResult.Result.UID})
|
||||
resp := sc.service.patchHandler(sc.reqContext, cmd)
|
||||
require.Equal(t, 200, resp.Status())
|
||||
var result = validateAndUnMarshalResponse(t, resp)
|
||||
sc.initialResult.Result.Type = "text"
|
||||
sc.initialResult.Result.Kind = int64(Panel)
|
||||
sc.initialResult.Result.Kind = int64(models.PanelElement)
|
||||
sc.initialResult.Result.Description = "A description"
|
||||
sc.initialResult.Result.Model = map[string]interface{}{
|
||||
"datasource": "${DS_GDEV-TESTDATA}",
|
||||
|
@ -84,7 +84,7 @@ func TestLibraryElementPermissions(t *testing.T) {
|
||||
toFolder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, testCase.items)
|
||||
sc.reqContext.SignedInUser.OrgRole = testCase.role
|
||||
|
||||
cmd := patchLibraryElementCommand{FolderID: toFolder.Id, Version: 1, Kind: int64(Panel)}
|
||||
cmd := patchLibraryElementCommand{FolderID: toFolder.Id, Version: 1, Kind: int64(models.PanelElement)}
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": result.Result.UID})
|
||||
resp = sc.service.patchHandler(sc.reqContext, cmd)
|
||||
require.Equal(t, testCase.status, resp.Status())
|
||||
@ -99,7 +99,7 @@ func TestLibraryElementPermissions(t *testing.T) {
|
||||
toFolder := createFolderWithACL(t, sc.sqlStore, "Folder", sc.user, everyonePermissions)
|
||||
sc.reqContext.SignedInUser.OrgRole = testCase.role
|
||||
|
||||
cmd := patchLibraryElementCommand{FolderID: toFolder.Id, Version: 1, Kind: int64(Panel)}
|
||||
cmd := patchLibraryElementCommand{FolderID: toFolder.Id, Version: 1, Kind: int64(models.PanelElement)}
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": result.Result.UID})
|
||||
resp = sc.service.patchHandler(sc.reqContext, cmd)
|
||||
require.Equal(t, testCase.status, resp.Status())
|
||||
@ -146,7 +146,7 @@ func TestLibraryElementPermissions(t *testing.T) {
|
||||
result := validateAndUnMarshalResponse(t, resp)
|
||||
sc.reqContext.SignedInUser.OrgRole = testCase.role
|
||||
|
||||
cmd := patchLibraryElementCommand{FolderID: 0, Version: 1, Kind: int64(Panel)}
|
||||
cmd := patchLibraryElementCommand{FolderID: 0, Version: 1, Kind: int64(models.PanelElement)}
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": result.Result.UID})
|
||||
resp = sc.service.patchHandler(sc.reqContext, cmd)
|
||||
require.Equal(t, testCase.status, resp.Status())
|
||||
@ -160,7 +160,7 @@ func TestLibraryElementPermissions(t *testing.T) {
|
||||
result := validateAndUnMarshalResponse(t, resp)
|
||||
sc.reqContext.SignedInUser.OrgRole = testCase.role
|
||||
|
||||
cmd := patchLibraryElementCommand{FolderID: folder.Id, Version: 1, Kind: int64(Panel)}
|
||||
cmd := patchLibraryElementCommand{FolderID: folder.Id, Version: 1, Kind: int64(models.PanelElement)}
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": result.Result.UID})
|
||||
resp = sc.service.patchHandler(sc.reqContext, cmd)
|
||||
require.Equal(t, testCase.status, resp.Status())
|
||||
@ -205,7 +205,7 @@ func TestLibraryElementPermissions(t *testing.T) {
|
||||
result := validateAndUnMarshalResponse(t, resp)
|
||||
sc.reqContext.SignedInUser.OrgRole = testCase.role
|
||||
|
||||
cmd := patchLibraryElementCommand{FolderID: -100, Version: 1, Kind: int64(Panel)}
|
||||
cmd := patchLibraryElementCommand{FolderID: -100, Version: 1, Kind: int64(models.PanelElement)}
|
||||
sc.reqContext.ReplaceAllParams(map[string]string{":uid": result.Result.UID})
|
||||
resp = sc.service.patchHandler(sc.reqContext, cmd)
|
||||
require.Equal(t, 404, resp.Status())
|
||||
|
@ -126,7 +126,7 @@ type libraryElementsSearchResult struct {
|
||||
}
|
||||
|
||||
func getCreatePanelCommand(folderID int64, name string) CreateLibraryElementCommand {
|
||||
command := getCreateCommandWithModel(folderID, name, Panel, []byte(`
|
||||
command := getCreateCommandWithModel(folderID, name, models.PanelElement, []byte(`
|
||||
{
|
||||
"datasource": "${DS_GDEV-TESTDATA}",
|
||||
"id": 1,
|
||||
@ -140,7 +140,7 @@ func getCreatePanelCommand(folderID int64, name string) CreateLibraryElementComm
|
||||
}
|
||||
|
||||
func getCreateVariableCommand(folderID int64, name string) CreateLibraryElementCommand {
|
||||
command := getCreateCommandWithModel(folderID, name, Variable, []byte(`
|
||||
command := getCreateCommandWithModel(folderID, name, models.VariableElement, []byte(`
|
||||
{
|
||||
"datasource": "${DS_GDEV-TESTDATA}",
|
||||
"name": "query0",
|
||||
@ -152,7 +152,7 @@ func getCreateVariableCommand(folderID int64, name string) CreateLibraryElementC
|
||||
return command
|
||||
}
|
||||
|
||||
func getCreateCommandWithModel(folderID int64, name string, kind LibraryElementKind, model []byte) CreateLibraryElementCommand {
|
||||
func getCreateCommandWithModel(folderID int64, name string, kind models.LibraryElementKind, model []byte) CreateLibraryElementCommand {
|
||||
command := CreateLibraryElementCommand{
|
||||
FolderID: folderID,
|
||||
Name: name,
|
||||
|
@ -6,13 +6,6 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type LibraryElementKind int
|
||||
|
||||
const (
|
||||
Panel LibraryElementKind = iota + 1
|
||||
Variable
|
||||
)
|
||||
|
||||
type LibraryConnectionKind int
|
||||
|
||||
const (
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
)
|
||||
|
||||
@ -38,7 +39,7 @@ func writePerPageSQL(query searchLibraryElementsQuery, sqlStore *sqlstore.SQLSto
|
||||
}
|
||||
|
||||
func writeKindSQL(query searchLibraryElementsQuery, builder *sqlstore.SQLBuilder) {
|
||||
if LibraryElementKind(query.kind) == Panel || LibraryElementKind(query.kind) == Variable {
|
||||
if models.LibraryElementKind(query.kind) == models.PanelElement || models.LibraryElementKind(query.kind) == models.VariableElement {
|
||||
builder.Write(" AND le.kind = ?", query.kind)
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ func (lps *LibraryPanelService) LoadLibraryPanelsForDashboard(c *models.ReqConte
|
||||
continue
|
||||
}
|
||||
|
||||
if libraryelements.LibraryElementKind(elementInDB.Kind) != libraryelements.Panel {
|
||||
if models.LibraryElementKind(elementInDB.Kind) != models.PanelElement {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -493,7 +493,7 @@ func TestConnectLibraryPanelsForDashboard(t *testing.T) {
|
||||
"description": "Unused description"
|
||||
}
|
||||
`),
|
||||
Kind: int64(libraryelements.Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
dashJSON := map[string]interface{}{
|
||||
@ -783,7 +783,7 @@ func scenarioWithLibraryPanel(t *testing.T, desc string, fn func(t *testing.T, s
|
||||
"description": "A description"
|
||||
}
|
||||
`),
|
||||
Kind: int64(libraryelements.Panel),
|
||||
Kind: int64(models.PanelElement),
|
||||
}
|
||||
resp, err := sc.elementService.CreateElement(sc.reqContext, command)
|
||||
require.NoError(t, err)
|
||||
|
53
pkg/services/sqlstore/migrations/libraryelements.go
Normal file
53
pkg/services/sqlstore/migrations/libraryelements.go
Normal file
@ -0,0 +1,53 @@
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
)
|
||||
|
||||
// addLibraryElementsMigrations defines database migrations for library elements.
|
||||
func addLibraryElementsMigrations(mg *migrator.Migrator) {
|
||||
libraryElementsV1 := migrator.Table{
|
||||
Name: "library_element",
|
||||
Columns: []*migrator.Column{
|
||||
{Name: "id", Type: migrator.DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
|
||||
{Name: "org_id", Type: migrator.DB_BigInt, Nullable: false},
|
||||
{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: 150, Nullable: false},
|
||||
{Name: "kind", Type: migrator.DB_BigInt, 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},
|
||||
{Name: "updated", Type: migrator.DB_DateTime, Nullable: false},
|
||||
{Name: "updated_by", Type: migrator.DB_BigInt, Nullable: false},
|
||||
{Name: "version", Type: migrator.DB_BigInt, Nullable: false},
|
||||
},
|
||||
Indices: []*migrator.Index{
|
||||
{Cols: []string{"org_id", "folder_id", "name", "kind"}, Type: migrator.UniqueIndex},
|
||||
},
|
||||
}
|
||||
|
||||
mg.AddMigration("create library_element table v1", migrator.NewAddTableMigration(libraryElementsV1))
|
||||
mg.AddMigration("add index library_element org_id-folder_id-name-kind", migrator.NewAddIndexMigration(libraryElementsV1, libraryElementsV1.Indices[0]))
|
||||
|
||||
libraryElementConnectionV1 := migrator.Table{
|
||||
Name: models.LibraryElementConnectionTableName,
|
||||
Columns: []*migrator.Column{
|
||||
{Name: "id", Type: migrator.DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
|
||||
{Name: "element_id", Type: migrator.DB_BigInt, Nullable: false},
|
||||
{Name: "kind", Type: migrator.DB_BigInt, Nullable: false},
|
||||
{Name: "connection_id", Type: migrator.DB_BigInt, Nullable: false},
|
||||
{Name: "created", Type: migrator.DB_DateTime, Nullable: false},
|
||||
{Name: "created_by", Type: migrator.DB_BigInt, Nullable: false},
|
||||
},
|
||||
Indices: []*migrator.Index{
|
||||
{Cols: []string{"element_id", "kind", "connection_id"}, Type: migrator.UniqueIndex},
|
||||
},
|
||||
}
|
||||
|
||||
mg.AddMigration("create "+models.LibraryElementConnectionTableName+" table v1", migrator.NewAddTableMigration(libraryElementConnectionV1))
|
||||
mg.AddMigration("add index "+models.LibraryElementConnectionTableName+" element_id-kind-connection_id", migrator.NewAddIndexMigration(libraryElementConnectionV1, libraryElementConnectionV1.Indices[0]))
|
||||
}
|
@ -40,6 +40,7 @@ func AddMigrations(mg *Migrator) {
|
||||
addShortURLMigrations(mg)
|
||||
ualert.AddTablesMigrations(mg)
|
||||
ualert.AddDashAlertMigration(mg)
|
||||
addLibraryElementsMigrations(mg)
|
||||
}
|
||||
|
||||
func addMigrationLogMigrations(mg *Migrator) {
|
||||
|
@ -80,6 +80,8 @@ func GetSystemStats(query *models.GetSystemStatsQuery) error {
|
||||
sb.Write(`(SELECT COUNT(id) FROM ` + dialect.Quote("team") + `) AS teams,`)
|
||||
sb.Write(`(SELECT COUNT(id) FROM ` + dialect.Quote("user_auth_token") + `) AS auth_tokens,`)
|
||||
sb.Write(`(SELECT COUNT(id) FROM ` + dialect.Quote("alert_rule") + `) AS alert_rules,`)
|
||||
sb.Write(`(SELECT COUNT(id) FROM `+dialect.Quote("library_element")+` WHERE kind = ?) AS library_panels,`, models.PanelElement)
|
||||
sb.Write(`(SELECT COUNT(id) FROM `+dialect.Quote("library_element")+` WHERE kind = ?) AS library_variables,`, models.VariableElement)
|
||||
|
||||
sb.Write(roleCounterSQL())
|
||||
|
||||
|
@ -24,6 +24,8 @@ func TestStatsDataAccess(t *testing.T) {
|
||||
assert.Equal(t, 0, query.Result.Editors)
|
||||
assert.Equal(t, 0, query.Result.Viewers)
|
||||
assert.Equal(t, 3, query.Result.Admins)
|
||||
assert.Equal(t, int64(0), query.Result.LibraryPanels)
|
||||
assert.Equal(t, int64(0), query.Result.LibraryVariables)
|
||||
})
|
||||
|
||||
t.Run("Get system user count stats should not results in error", func(t *testing.T) {
|
||||
|
Loading…
Reference in New Issue
Block a user