mirror of
https://github.com/grafana/grafana.git
synced 2025-01-23 15:03:41 -06:00
72628c8ea0
This feature would provide a way for administrators to limit the minimum dashboard refresh interval globally. Filters out the refresh intervals available in the time picker that are lower than the set minimum refresh interval in the configuration .ini file Adds the minimum refresh interval as available in the time picker. If the user tries to enter a refresh interval that is lower than the minimum in the URL, defaults to the minimum interval. When trying to update the JSON via the API, rejects the update if the dashboard's refresh interval is lower than the minimum. When trying to update a dashboard via provisioning having a lower refresh interval than the minimum, defaults to the minimum interval and logs a warning. Fixes #3356 Co-authored-by: Marcus Efraimsson <marcus.efraimsson@gmail.com>
364 lines
9.3 KiB
Go
364 lines
9.3 KiB
Go
package models
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gosimple/slug"
|
|
"github.com/grafana/grafana/pkg/components/simplejson"
|
|
"github.com/grafana/grafana/pkg/setting"
|
|
)
|
|
|
|
// Typed errors
|
|
var (
|
|
ErrDashboardNotFound = errors.New("Dashboard not found")
|
|
ErrDashboardFolderNotFound = errors.New("Folder not found")
|
|
ErrDashboardSnapshotNotFound = errors.New("Dashboard snapshot not found")
|
|
ErrDashboardWithSameUIDExists = errors.New("A dashboard with the same uid already exists")
|
|
ErrDashboardWithSameNameInFolderExists = errors.New("A dashboard with the same name in the folder already exists")
|
|
ErrDashboardVersionMismatch = errors.New("The dashboard has been changed by someone else")
|
|
ErrDashboardTitleEmpty = errors.New("Dashboard title cannot be empty")
|
|
ErrDashboardFolderCannotHaveParent = errors.New("A Dashboard Folder cannot be added to another folder")
|
|
ErrDashboardsWithSameSlugExists = errors.New("Multiple dashboards with the same slug exists")
|
|
ErrDashboardFailedGenerateUniqueUid = errors.New("Failed to generate unique dashboard id")
|
|
ErrDashboardTypeMismatch = errors.New("Dashboard cannot be changed to a folder")
|
|
ErrDashboardFolderWithSameNameAsDashboard = errors.New("Folder name cannot be the same as one of its dashboards")
|
|
ErrDashboardWithSameNameAsFolder = errors.New("Dashboard name cannot be the same as folder")
|
|
ErrDashboardFolderNameExists = errors.New("A folder with that name already exists")
|
|
ErrDashboardUpdateAccessDenied = errors.New("Access denied to save dashboard")
|
|
ErrDashboardInvalidUid = errors.New("uid contains illegal characters")
|
|
ErrDashboardUidToLong = errors.New("uid to long. max 40 characters")
|
|
ErrDashboardCannotSaveProvisionedDashboard = errors.New("Cannot save provisioned dashboard")
|
|
ErrDashboardRefreshIntervalTooShort = errors.New("Dashboard refresh interval is too low")
|
|
ErrDashboardCannotDeleteProvisionedDashboard = errors.New("provisioned dashboard cannot be deleted")
|
|
ErrDashboardIdentifierNotSet = errors.New("Unique identfier needed to be able to get a dashboard")
|
|
RootFolderName = "General"
|
|
)
|
|
|
|
type UpdatePluginDashboardError struct {
|
|
PluginId string
|
|
}
|
|
|
|
func (d UpdatePluginDashboardError) Error() string {
|
|
return "Dashboard belong to plugin"
|
|
}
|
|
|
|
var (
|
|
DashTypeJson = "file"
|
|
DashTypeDB = "db"
|
|
DashTypeScript = "script"
|
|
DashTypeSnapshot = "snapshot"
|
|
)
|
|
|
|
// Dashboard model
|
|
type Dashboard struct {
|
|
Id int64
|
|
Uid string
|
|
Slug string
|
|
OrgId int64
|
|
GnetId int64
|
|
Version int
|
|
PluginId string
|
|
|
|
Created time.Time
|
|
Updated time.Time
|
|
|
|
UpdatedBy int64
|
|
CreatedBy int64
|
|
FolderId int64
|
|
IsFolder bool
|
|
HasAcl bool
|
|
|
|
Title string
|
|
Data *simplejson.Json
|
|
}
|
|
|
|
func (d *Dashboard) SetId(id int64) {
|
|
d.Id = id
|
|
d.Data.Set("id", id)
|
|
}
|
|
|
|
func (d *Dashboard) SetUid(uid string) {
|
|
d.Uid = uid
|
|
d.Data.Set("uid", uid)
|
|
}
|
|
|
|
func (d *Dashboard) SetVersion(version int) {
|
|
d.Version = version
|
|
d.Data.Set("version", version)
|
|
}
|
|
|
|
// GetDashboardIdForSavePermissionCheck return the dashboard id to be used for checking permission of dashboard
|
|
func (d *Dashboard) GetDashboardIdForSavePermissionCheck() int64 {
|
|
if d.Id == 0 {
|
|
return d.FolderId
|
|
}
|
|
|
|
return d.Id
|
|
}
|
|
|
|
// NewDashboard creates a new dashboard
|
|
func NewDashboard(title string) *Dashboard {
|
|
dash := &Dashboard{}
|
|
dash.Data = simplejson.New()
|
|
dash.Data.Set("title", title)
|
|
dash.Title = title
|
|
dash.Created = time.Now()
|
|
dash.Updated = time.Now()
|
|
dash.UpdateSlug()
|
|
return dash
|
|
}
|
|
|
|
// NewDashboardFolder creates a new dashboard folder
|
|
func NewDashboardFolder(title string) *Dashboard {
|
|
folder := NewDashboard(title)
|
|
folder.IsFolder = true
|
|
folder.Data.Set("schemaVersion", 17)
|
|
folder.Data.Set("version", 0)
|
|
folder.IsFolder = true
|
|
return folder
|
|
}
|
|
|
|
// GetTags turns the tags in data json into go string array
|
|
func (dash *Dashboard) GetTags() []string {
|
|
return dash.Data.Get("tags").MustStringArray()
|
|
}
|
|
|
|
func NewDashboardFromJson(data *simplejson.Json) *Dashboard {
|
|
dash := &Dashboard{}
|
|
dash.Data = data
|
|
dash.Title = dash.Data.Get("title").MustString()
|
|
dash.UpdateSlug()
|
|
update := false
|
|
|
|
if id, err := dash.Data.Get("id").Float64(); err == nil {
|
|
dash.Id = int64(id)
|
|
update = true
|
|
}
|
|
|
|
if uid, err := dash.Data.Get("uid").String(); err == nil {
|
|
dash.Uid = uid
|
|
update = true
|
|
}
|
|
|
|
if version, err := dash.Data.Get("version").Float64(); err == nil && update {
|
|
dash.Version = int(version)
|
|
dash.Updated = time.Now()
|
|
} else {
|
|
dash.Data.Set("version", 0)
|
|
dash.Created = time.Now()
|
|
dash.Updated = time.Now()
|
|
}
|
|
|
|
if gnetId, err := dash.Data.Get("gnetId").Float64(); err == nil {
|
|
dash.GnetId = int64(gnetId)
|
|
}
|
|
|
|
return dash
|
|
}
|
|
|
|
// GetDashboardModel turns the command into the saveable model
|
|
func (cmd *SaveDashboardCommand) GetDashboardModel() *Dashboard {
|
|
dash := NewDashboardFromJson(cmd.Dashboard)
|
|
userId := cmd.UserId
|
|
|
|
if userId == 0 {
|
|
userId = -1
|
|
}
|
|
|
|
dash.UpdatedBy = userId
|
|
dash.OrgId = cmd.OrgId
|
|
dash.PluginId = cmd.PluginId
|
|
dash.IsFolder = cmd.IsFolder
|
|
dash.FolderId = cmd.FolderId
|
|
dash.UpdateSlug()
|
|
return dash
|
|
}
|
|
|
|
// GetString a
|
|
func (dash *Dashboard) GetString(prop string, defaultValue string) string {
|
|
return dash.Data.Get(prop).MustString(defaultValue)
|
|
}
|
|
|
|
// UpdateSlug updates the slug
|
|
func (dash *Dashboard) UpdateSlug() {
|
|
title := dash.Data.Get("title").MustString()
|
|
dash.Slug = SlugifyTitle(title)
|
|
}
|
|
|
|
func SlugifyTitle(title string) string {
|
|
return slug.Make(strings.ToLower(title))
|
|
}
|
|
|
|
// GetUrl return the html url for a folder if it's folder, otherwise for a dashboard
|
|
func (dash *Dashboard) GetUrl() string {
|
|
return GetDashboardFolderUrl(dash.IsFolder, dash.Uid, dash.Slug)
|
|
}
|
|
|
|
// Return the html url for a dashboard
|
|
func (dash *Dashboard) GenerateUrl() string {
|
|
return GetDashboardUrl(dash.Uid, dash.Slug)
|
|
}
|
|
|
|
// GetDashboardFolderUrl return the html url for a folder if it's folder, otherwise for a dashboard
|
|
func GetDashboardFolderUrl(isFolder bool, uid string, slug string) string {
|
|
if isFolder {
|
|
return GetFolderUrl(uid, slug)
|
|
}
|
|
|
|
return GetDashboardUrl(uid, slug)
|
|
}
|
|
|
|
// GetDashboardUrl return the html url for a dashboard
|
|
func GetDashboardUrl(uid string, slug string) string {
|
|
return fmt.Sprintf("%s/d/%s/%s", setting.AppSubUrl, uid, slug)
|
|
}
|
|
|
|
// GetFullDashboardUrl return the full url for a dashboard
|
|
func GetFullDashboardUrl(uid string, slug string) string {
|
|
return fmt.Sprintf("%sd/%s/%s", setting.AppUrl, uid, slug)
|
|
}
|
|
|
|
// GetFolderUrl return the html url for a folder
|
|
func GetFolderUrl(folderUid string, slug string) string {
|
|
return fmt.Sprintf("%s/dashboards/f/%s/%s", setting.AppSubUrl, folderUid, slug)
|
|
}
|
|
|
|
type ValidateDashboardBeforeSaveResult struct {
|
|
IsParentFolderChanged bool
|
|
}
|
|
|
|
//
|
|
// COMMANDS
|
|
//
|
|
|
|
type SaveDashboardCommand struct {
|
|
Dashboard *simplejson.Json `json:"dashboard" binding:"Required"`
|
|
UserId int64 `json:"userId"`
|
|
Overwrite bool `json:"overwrite"`
|
|
Message string `json:"message"`
|
|
OrgId int64 `json:"-"`
|
|
RestoredFrom int `json:"-"`
|
|
PluginId string `json:"-"`
|
|
FolderId int64 `json:"folderId"`
|
|
IsFolder bool `json:"isFolder"`
|
|
|
|
UpdatedAt time.Time
|
|
|
|
Result *Dashboard
|
|
}
|
|
|
|
type DashboardProvisioning struct {
|
|
Id int64
|
|
DashboardId int64
|
|
Name string
|
|
ExternalId string
|
|
CheckSum string
|
|
Updated int64
|
|
}
|
|
|
|
type SaveProvisionedDashboardCommand struct {
|
|
DashboardCmd *SaveDashboardCommand
|
|
DashboardProvisioning *DashboardProvisioning
|
|
|
|
Result *Dashboard
|
|
}
|
|
|
|
type DeleteDashboardCommand struct {
|
|
Id int64
|
|
OrgId int64
|
|
}
|
|
|
|
type ValidateDashboardBeforeSaveCommand struct {
|
|
OrgId int64
|
|
Dashboard *Dashboard
|
|
Overwrite bool
|
|
Result *ValidateDashboardBeforeSaveResult
|
|
}
|
|
|
|
//
|
|
// QUERIES
|
|
//
|
|
|
|
type GetDashboardQuery struct {
|
|
Slug string // required if no Id or Uid is specified
|
|
Id int64 // optional if slug is set
|
|
Uid string // optional if slug is set
|
|
OrgId int64
|
|
|
|
Result *Dashboard
|
|
}
|
|
|
|
type DashboardTagCloudItem struct {
|
|
Term string `json:"term"`
|
|
Count int `json:"count"`
|
|
}
|
|
|
|
type GetDashboardTagsQuery struct {
|
|
OrgId int64
|
|
Result []*DashboardTagCloudItem
|
|
}
|
|
|
|
type GetDashboardsQuery struct {
|
|
DashboardIds []int64
|
|
Result []*Dashboard
|
|
}
|
|
|
|
type GetDashboardPermissionsForUserQuery struct {
|
|
DashboardIds []int64
|
|
OrgId int64
|
|
UserId int64
|
|
OrgRole RoleType
|
|
Result []*DashboardPermissionForUser
|
|
}
|
|
|
|
type GetDashboardsByPluginIdQuery struct {
|
|
OrgId int64
|
|
PluginId string
|
|
Result []*Dashboard
|
|
}
|
|
|
|
type GetDashboardSlugByIdQuery struct {
|
|
Id int64
|
|
Result string
|
|
}
|
|
|
|
type GetProvisionedDashboardDataByIdQuery struct {
|
|
DashboardId int64
|
|
Result *DashboardProvisioning
|
|
}
|
|
|
|
type GetProvisionedDashboardDataQuery struct {
|
|
Name string
|
|
Result []*DashboardProvisioning
|
|
}
|
|
|
|
type GetDashboardsBySlugQuery struct {
|
|
OrgId int64
|
|
Slug string
|
|
|
|
Result []*Dashboard
|
|
}
|
|
|
|
type DashboardPermissionForUser struct {
|
|
DashboardId int64 `json:"dashboardId"`
|
|
Permission PermissionType `json:"permission"`
|
|
PermissionName string `json:"permissionName"`
|
|
}
|
|
|
|
type DashboardRef struct {
|
|
Uid string
|
|
Slug string
|
|
}
|
|
|
|
type GetDashboardRefByIdQuery struct {
|
|
Id int64
|
|
Result *DashboardRef
|
|
}
|
|
|
|
type UnprovisionDashboardCommand struct {
|
|
Id int64
|
|
}
|