diff --git a/.gitignore b/.gitignore
index 1c8a89215da..fd04dcd1523 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,6 +31,7 @@ public/css/*.min.css
conf/custom.ini
fig.yml
+docker-compose.yml
profile.cov
/grafana
.notouch
diff --git a/CHANGELOG.md b/CHANGELOG.md
index acefeaec860..c7763166f20 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
* **Snapshots UI**: Dashboard snapshots list can be managed through UI, closes[#1984](https://github.com/grafana/grafana/issues/1984)
* **Prometheus**: Prometheus annotation support, closes[#2883](https://github.com/grafana/grafana/pull/2883)
* **Cli**: New cli tool for downloading and updating plugins
+* **Annotations**: Annotations can now contain links that can be clicked (you can navigate on to annotation popovers), closes [#1588](https://github.com/grafana/grafana/issues/1588)
### Breaking changes
* **Plugin API**: Both datasource and panel plugin api (and plugin.json schema) have been updated, requiring an update to plugins. See [plugin api](https://github.com/grafana/grafana/blob/master/public/app/plugins/plugin_api.md) for more info.
diff --git a/docker/build_fig.sh b/docker/create_docker_compose.sh
similarity index 97%
rename from docker/build_fig.sh
rename to docker/create_docker_compose.sh
index aca4f68413f..8588c1c474a 100755
--- a/docker/build_fig.sh
+++ b/docker/create_docker_compose.sh
@@ -7,7 +7,7 @@ template_dir=templates
grafana_config_file=conf.tmp
grafana_config=config
-fig_file=fig.yml
+fig_file=docker-compose.yml
fig_config=fig
if [ "$#" == 0 ]; then
diff --git a/docs/sources/installation/debian.md b/docs/sources/installation/debian.md
index ec6e30b35f1..b5c72f3182c 100644
--- a/docs/sources/installation/debian.md
+++ b/docs/sources/installation/debian.md
@@ -122,8 +122,8 @@ To configure Grafana add a configuration file named `custom.ini` to the
`conf` folder and override any of the settings defined in
`conf/defaults.ini`.
-Start Grafana by executing `./grafana-server web`. The `grafana-server` binary needs
-the working directory to be the root install directory (where the binary
-and the `public` folder is located).
+Start Grafana by executing `./bin/grafana-server web`. The `grafana-server`
+binary needs the working directory to be the root install directory (where the
+binary and the `public` folder is located).
diff --git a/pkg/api/api.go b/pkg/api/api.go
index c21deae5a59..90d613e46e0 100644
--- a/pkg/api/api.go
+++ b/pkg/api/api.go
@@ -126,9 +126,9 @@ func Register(r *macaron.Macaron) {
r.Patch("/invites/:code/revoke", wrap(RevokeInvite))
// apps
- r.Get("/apps", wrap(GetOrgAppsList))
- r.Get("/apps/:appId/settings", wrap(GetAppSettingsById))
- r.Post("/apps/:appId/settings", bind(m.UpdateAppSettingsCmd{}), wrap(UpdateAppSettings))
+ r.Get("/plugins", wrap(GetPluginList))
+ r.Get("/plugins/:pluginId/settings", wrap(GetPluginSettingById))
+ r.Post("/plugins/:pluginId/settings", bind(m.UpdatePluginSettingCmd{}), wrap(UpdatePluginSetting))
}, reqOrgAdmin)
// create new org
diff --git a/pkg/api/app_settings.go b/pkg/api/app_settings.go
deleted file mode 100644
index fd0f1a1eab1..00000000000
--- a/pkg/api/app_settings.go
+++ /dev/null
@@ -1,59 +0,0 @@
-package api
-
-import (
- "github.com/grafana/grafana/pkg/api/dtos"
- "github.com/grafana/grafana/pkg/bus"
- "github.com/grafana/grafana/pkg/middleware"
- m "github.com/grafana/grafana/pkg/models"
- "github.com/grafana/grafana/pkg/plugins"
-)
-
-func GetOrgAppsList(c *middleware.Context) Response {
- orgApps, err := plugins.GetOrgAppSettings(c.OrgId)
-
- if err != nil {
- return ApiError(500, "Failed to list of apps", err)
- }
-
- result := make([]*dtos.AppSettings, 0)
- for _, app := range plugins.Apps {
- orgApp := orgApps[app.Id]
- result = append(result, dtos.NewAppSettingsDto(app, orgApp))
- }
-
- return Json(200, result)
-}
-
-func GetAppSettingsById(c *middleware.Context) Response {
- appId := c.Params(":appId")
-
- if pluginDef, exists := plugins.Apps[appId]; !exists {
- return ApiError(404, "PluginId not found, no installed plugin with that id", nil)
- } else {
- orgApps, err := plugins.GetOrgAppSettings(c.OrgId)
- if err != nil {
- return ApiError(500, "Failed to get org app settings ", nil)
- }
- orgApp := orgApps[appId]
-
- return Json(200, dtos.NewAppSettingsDto(pluginDef, orgApp))
- }
-}
-
-func UpdateAppSettings(c *middleware.Context, cmd m.UpdateAppSettingsCmd) Response {
- appId := c.Params(":appId")
-
- cmd.OrgId = c.OrgId
- cmd.AppId = appId
-
- if _, ok := plugins.Apps[cmd.AppId]; !ok {
- return ApiError(404, "App type not installed.", nil)
- }
-
- err := bus.Dispatch(&cmd)
- if err != nil {
- return ApiError(500, "Failed to update App Plugin", err)
- }
-
- return ApiSuccess("App updated")
-}
diff --git a/pkg/api/cloudwatch/cloudwatch.go b/pkg/api/cloudwatch/cloudwatch.go
index babcf9fddb0..88d22800d65 100644
--- a/pkg/api/cloudwatch/cloudwatch.go
+++ b/pkg/api/cloudwatch/cloudwatch.go
@@ -33,6 +33,7 @@ func init() {
actionHandlers = map[string]actionHandler{
"GetMetricStatistics": handleGetMetricStatistics,
"ListMetrics": handleListMetrics,
+ "DescribeAlarms": handleDescribeAlarms,
"DescribeAlarmsForMetric": handleDescribeAlarmsForMetric,
"DescribeAlarmHistory": handleDescribeAlarmHistory,
"DescribeInstances": handleDescribeInstances,
@@ -142,6 +143,49 @@ func handleListMetrics(req *cwRequest, c *middleware.Context) {
c.JSON(200, resp)
}
+func handleDescribeAlarms(req *cwRequest, c *middleware.Context) {
+ cfg := &aws.Config{
+ Region: aws.String(req.Region),
+ Credentials: getCredentials(req.DataSource.Database),
+ }
+
+ svc := cloudwatch.New(session.New(cfg), cfg)
+
+ reqParam := &struct {
+ Parameters struct {
+ ActionPrefix string `json:"actionPrefix"`
+ AlarmNamePrefix string `json:"alarmNamePrefix"`
+ AlarmNames []*string `json:"alarmNames"`
+ StateValue string `json:"stateValue"`
+ } `json:"parameters"`
+ }{}
+ json.Unmarshal(req.Body, reqParam)
+
+ params := &cloudwatch.DescribeAlarmsInput{
+ MaxRecords: aws.Int64(100),
+ }
+ if reqParam.Parameters.ActionPrefix != "" {
+ params.ActionPrefix = aws.String(reqParam.Parameters.ActionPrefix)
+ }
+ if reqParam.Parameters.AlarmNamePrefix != "" {
+ params.AlarmNamePrefix = aws.String(reqParam.Parameters.AlarmNamePrefix)
+ }
+ if len(reqParam.Parameters.AlarmNames) != 0 {
+ params.AlarmNames = reqParam.Parameters.AlarmNames
+ }
+ if reqParam.Parameters.StateValue != "" {
+ params.StateValue = aws.String(reqParam.Parameters.StateValue)
+ }
+
+ resp, err := svc.DescribeAlarms(params)
+ if err != nil {
+ c.JsonApiErr(500, "Unable to call AWS API", err)
+ return
+ }
+
+ c.JSON(200, resp)
+}
+
func handleDescribeAlarmsForMetric(req *cwRequest, c *middleware.Context) {
cfg := &aws.Config{
Region: aws.String(req.Region),
diff --git a/pkg/api/dataproxy.go b/pkg/api/dataproxy.go
index 4d4556c40cb..6e6b4394e2d 100644
--- a/pkg/api/dataproxy.go
+++ b/pkg/api/dataproxy.go
@@ -64,20 +64,12 @@ func NewReverseProxy(ds *m.DataSource, proxyPath string, targetUrl *url.URL) *ht
return &httputil.ReverseProxy{Director: director}
}
-var dsMap map[int64]*m.DataSource = make(map[int64]*m.DataSource)
-
func getDatasource(id int64, orgId int64) (*m.DataSource, error) {
- // ds, exists := dsMap[id]
- // if exists && ds.OrgId == orgId {
- // return ds, nil
- // }
-
query := m.GetDataSourceByIdQuery{Id: id, OrgId: orgId}
if err := bus.Dispatch(&query); err != nil {
return nil, err
}
- dsMap[id] = &query.Result
return &query.Result, nil
}
diff --git a/pkg/api/dtos/apps.go b/pkg/api/dtos/apps.go
deleted file mode 100644
index ba26e3eb617..00000000000
--- a/pkg/api/dtos/apps.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package dtos
-
-import (
- "github.com/grafana/grafana/pkg/models"
- "github.com/grafana/grafana/pkg/plugins"
-)
-
-type AppSettings struct {
- Name string `json:"name"`
- AppId string `json:"appId"`
- Enabled bool `json:"enabled"`
- Pinned bool `json:"pinned"`
- Module string `json:"module"`
- BaseUrl string `json:"baseUrl"`
- Info *plugins.PluginInfo `json:"info"`
- Pages []*plugins.AppPluginPage `json:"pages"`
- Includes []*plugins.AppIncludeInfo `json:"includes"`
- JsonData map[string]interface{} `json:"jsonData"`
-}
-
-func NewAppSettingsDto(def *plugins.AppPlugin, data *models.AppSettings) *AppSettings {
- dto := &AppSettings{
- AppId: def.Id,
- Name: def.Name,
- Info: &def.Info,
- Module: def.Module,
- BaseUrl: def.BaseUrl,
- Pages: def.Pages,
- Includes: def.Includes,
- }
-
- if data != nil {
- dto.Enabled = data.Enabled
- dto.Pinned = data.Pinned
- dto.Info = &def.Info
- dto.JsonData = data.JsonData
- }
-
- return dto
-}
diff --git a/pkg/api/dtos/index.go b/pkg/api/dtos/index.go
index 7c28d734be4..21201d30adf 100644
--- a/pkg/api/dtos/index.go
+++ b/pkg/api/dtos/index.go
@@ -16,9 +16,10 @@ type PluginCss struct {
}
type NavLink struct {
- Text string `json:"text"`
- Icon string `json:"icon"`
- Img string `json:"img"`
- Url string `json:"url"`
- Children []*NavLink `json:"children"`
+ Text string `json:"text,omitempty"`
+ Icon string `json:"icon,omitempty"`
+ Img string `json:"img,omitempty"`
+ Url string `json:"url,omitempty"`
+ Divider bool `json:"divider,omitempty"`
+ Children []*NavLink `json:"children,omitempty"`
}
diff --git a/pkg/api/dtos/plugins.go b/pkg/api/dtos/plugins.go
new file mode 100644
index 00000000000..af96202222f
--- /dev/null
+++ b/pkg/api/dtos/plugins.go
@@ -0,0 +1,26 @@
+package dtos
+
+import "github.com/grafana/grafana/pkg/plugins"
+
+type PluginSetting struct {
+ Name string `json:"name"`
+ Type string `json:"type"`
+ PluginId string `json:"pluginId"`
+ Enabled bool `json:"enabled"`
+ Pinned bool `json:"pinned"`
+ Module string `json:"module"`
+ BaseUrl string `json:"baseUrl"`
+ Info *plugins.PluginInfo `json:"info"`
+ Pages []*plugins.AppPluginPage `json:"pages"`
+ Includes []*plugins.AppIncludeInfo `json:"includes"`
+ JsonData map[string]interface{} `json:"jsonData"`
+}
+
+type PluginListItem struct {
+ Name string `json:"name"`
+ Type string `json:"type"`
+ PluginId string `json:"pluginId"`
+ Enabled bool `json:"enabled"`
+ Pinned bool `json:"pinned"`
+ Info *plugins.PluginInfo `json:"info"`
+}
diff --git a/pkg/api/index.go b/pkg/api/index.go
index 72277fe301b..df752109530 100644
--- a/pkg/api/index.go
+++ b/pkg/api/index.go
@@ -53,15 +53,15 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
Icon: "icon-gf icon-gf-dashboard",
Url: setting.AppSubUrl + "/",
Children: []*dtos.NavLink{
- {Text: "Home dashboard", Icon: "fa fa-fw fa-list", Url: setting.AppSubUrl + "/"},
- {Text: "Playlists", Icon: "fa fa-fw fa-list", Url: setting.AppSubUrl + "/playlists"},
- {Text: "Snapshots", Icon: "fa-fw icon-gf icon-gf-snapshot", Url: setting.AppSubUrl + "/dashboard/snapshots"},
+ {Text: "Home", Url: setting.AppSubUrl + "/"},
+ {Text: "Playlists", Url: setting.AppSubUrl + "/playlists"},
+ {Text: "Snapshots", Url: setting.AppSubUrl + "/dashboard/snapshots"},
+ {Divider: true},
+ {Text: "New", Url: setting.AppSubUrl + "/dashboard/new"},
+ {Text: "Import", Url: setting.AppSubUrl + "/import/dashboard"},
},
})
- // data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{Text: "Playlists", Icon: "fa fa-fw fa-list", Url: setting.AppSubUrl + "/playlists"})
- // data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{Text: "Snapshots", Icon: "fa-fw icon-gf icon-gf-snapshot", Url: setting.AppSubUrl + "/dashboard/snapshots"})
-
if c.OrgRole == m.ROLE_ADMIN {
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
Text: "Data Sources",
@@ -72,7 +72,7 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
Text: "Plugins",
Icon: "icon-gf icon-gf-apps",
- Url: setting.AppSubUrl + "/apps",
+ Url: setting.AppSubUrl + "/plugins",
})
}
diff --git a/pkg/api/plugin_setting.go b/pkg/api/plugin_setting.go
new file mode 100644
index 00000000000..08fc5296434
--- /dev/null
+++ b/pkg/api/plugin_setting.go
@@ -0,0 +1,88 @@
+package api
+
+import (
+ "github.com/grafana/grafana/pkg/api/dtos"
+ "github.com/grafana/grafana/pkg/bus"
+ "github.com/grafana/grafana/pkg/middleware"
+ m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/plugins"
+)
+
+func GetPluginList(c *middleware.Context) Response {
+ pluginSettingsMap, err := plugins.GetPluginSettings(c.OrgId)
+
+ if err != nil {
+ return ApiError(500, "Failed to get list of plugins", err)
+ }
+
+ result := make([]*dtos.PluginListItem, 0)
+ for _, pluginDef := range plugins.Plugins {
+ listItem := &dtos.PluginListItem{
+ PluginId: pluginDef.Id,
+ Name: pluginDef.Name,
+ Type: pluginDef.Type,
+ Info: &pluginDef.Info,
+ }
+
+ if pluginSetting, exists := pluginSettingsMap[pluginDef.Id]; exists {
+ listItem.Enabled = pluginSetting.Enabled
+ listItem.Pinned = pluginSetting.Pinned
+ }
+
+ result = append(result, listItem)
+ }
+
+ return Json(200, result)
+}
+
+func GetPluginSettingById(c *middleware.Context) Response {
+ pluginId := c.Params(":pluginId")
+
+ if def, exists := plugins.Plugins[pluginId]; !exists {
+ return ApiError(404, "Plugin not found, no installed plugin with that id", nil)
+ } else {
+ dto := &dtos.PluginSetting{
+ Type: def.Type,
+ PluginId: def.Id,
+ Name: def.Name,
+ Info: &def.Info,
+ }
+
+ if app, exists := plugins.Apps[pluginId]; exists {
+ dto.Pages = app.Pages
+ dto.Includes = app.Includes
+ dto.BaseUrl = app.BaseUrl
+ dto.Module = app.Module
+ }
+
+ query := m.GetPluginSettingByIdQuery{PluginId: pluginId, OrgId: c.OrgId}
+ if err := bus.Dispatch(&query); err != nil {
+ if err != m.ErrPluginSettingNotFound {
+ return ApiError(500, "Failed to get login settings", nil)
+ }
+ } else {
+ dto.Enabled = query.Result.Enabled
+ dto.Pinned = query.Result.Pinned
+ dto.JsonData = query.Result.JsonData
+ }
+
+ return Json(200, dto)
+ }
+}
+
+func UpdatePluginSetting(c *middleware.Context, cmd m.UpdatePluginSettingCmd) Response {
+ pluginId := c.Params(":pluginId")
+
+ cmd.OrgId = c.OrgId
+ cmd.PluginId = pluginId
+
+ if _, ok := plugins.Apps[cmd.PluginId]; !ok {
+ return ApiError(404, "Plugin not installed.", nil)
+ }
+
+ if err := bus.Dispatch(&cmd); err != nil {
+ return ApiError(500, "Failed to update plugin setting", err)
+ }
+
+ return ApiSuccess("Plugin settings updated")
+}
diff --git a/pkg/api/pluginproxy/pluginproxy.go b/pkg/api/pluginproxy/pluginproxy.go
index 55aa0c013ce..92d07988b64 100644
--- a/pkg/api/pluginproxy/pluginproxy.go
+++ b/pkg/api/pluginproxy/pluginproxy.go
@@ -26,7 +26,7 @@ type templateData struct {
func getHeaders(route *plugins.AppPluginRoute, orgId int64, appId string) (http.Header, error) {
result := http.Header{}
- query := m.GetAppSettingByAppIdQuery{OrgId: orgId, AppId: appId}
+ query := m.GetPluginSettingByIdQuery{OrgId: orgId, PluginId: appId}
if err := bus.Dispatch(&query); err != nil {
return nil, err
diff --git a/pkg/api/pluginproxy/pluginproxy_test.go b/pkg/api/pluginproxy/pluginproxy_test.go
index 0b6e9523ffd..f14ca6975e6 100644
--- a/pkg/api/pluginproxy/pluginproxy_test.go
+++ b/pkg/api/pluginproxy/pluginproxy_test.go
@@ -22,8 +22,8 @@ func TestPluginProxy(t *testing.T) {
setting.SecretKey = "password"
- bus.AddHandler("test", func(query *m.GetAppSettingByAppIdQuery) error {
- query.Result = &m.AppSettings{
+ bus.AddHandler("test", func(query *m.GetPluginSettingByIdQuery) error {
+ query.Result = &m.PluginSetting{
SecureJsonData: map[string][]byte{
"key": util.Encrypt([]byte("123"), "password"),
},
diff --git a/pkg/models/app_settings.go b/pkg/models/plugin_setting.go
similarity index 71%
rename from pkg/models/app_settings.go
rename to pkg/models/plugin_setting.go
index 6a7bbde694d..777f4599241 100644
--- a/pkg/models/app_settings.go
+++ b/pkg/models/plugin_setting.go
@@ -9,12 +9,12 @@ import (
)
var (
- ErrAppSettingNotFound = errors.New("AppSetting not found")
+ ErrPluginSettingNotFound = errors.New("Plugin setting not found")
)
-type AppSettings struct {
+type PluginSetting struct {
Id int64
- AppId string
+ PluginId string
OrgId int64
Enabled bool
Pinned bool
@@ -39,17 +39,17 @@ func (s SecureJsonData) Decrypt() map[string]string {
// COMMANDS
// Also acts as api DTO
-type UpdateAppSettingsCmd struct {
+type UpdatePluginSettingCmd struct {
Enabled bool `json:"enabled"`
Pinned bool `json:"pinned"`
JsonData map[string]interface{} `json:"jsonData"`
SecureJsonData map[string]string `json:"secureJsonData"`
- AppId string `json:"-"`
- OrgId int64 `json:"-"`
+ PluginId string `json:"-"`
+ OrgId int64 `json:"-"`
}
-func (cmd *UpdateAppSettingsCmd) GetEncryptedJsonData() SecureJsonData {
+func (cmd *UpdatePluginSettingCmd) GetEncryptedJsonData() SecureJsonData {
encrypted := make(SecureJsonData)
for key, data := range cmd.SecureJsonData {
encrypted[key] = util.Encrypt([]byte(data), setting.SecretKey)
@@ -59,13 +59,13 @@ func (cmd *UpdateAppSettingsCmd) GetEncryptedJsonData() SecureJsonData {
// ---------------------
// QUERIES
-type GetAppSettingsQuery struct {
+type GetPluginSettingsQuery struct {
OrgId int64
- Result []*AppSettings
+ Result []*PluginSetting
}
-type GetAppSettingByAppIdQuery struct {
- AppId string
- OrgId int64
- Result *AppSettings
+type GetPluginSettingByIdQuery struct {
+ PluginId string
+ OrgId int64
+ Result *PluginSetting
}
diff --git a/pkg/plugins/frontend_plugin.go b/pkg/plugins/frontend_plugin.go
index a1bcd0c68b5..5acb9966495 100644
--- a/pkg/plugins/frontend_plugin.go
+++ b/pkg/plugins/frontend_plugin.go
@@ -56,6 +56,10 @@ func (fp *FrontendPluginBase) handleModuleDefaults() {
}
func evalRelativePluginUrlPath(pathStr string, pluginId string) string {
+ if pathStr == "" {
+ return ""
+ }
+
u, _ := url.Parse(pathStr)
if u.IsAbs() {
return pathStr
diff --git a/pkg/plugins/queries.go b/pkg/plugins/queries.go
index 8e628c5024e..b3cc92bf7d1 100644
--- a/pkg/plugins/queries.go
+++ b/pkg/plugins/queries.go
@@ -5,44 +5,40 @@ import (
m "github.com/grafana/grafana/pkg/models"
)
-func GetOrgAppSettings(orgId int64) (map[string]*m.AppSettings, error) {
- query := m.GetAppSettingsQuery{OrgId: orgId}
+func GetPluginSettings(orgId int64) (map[string]*m.PluginSetting, error) {
+ query := m.GetPluginSettingsQuery{OrgId: orgId}
if err := bus.Dispatch(&query); err != nil {
return nil, err
}
- orgAppsMap := make(map[string]*m.AppSettings)
- for _, orgApp := range query.Result {
- orgAppsMap[orgApp.AppId] = orgApp
+ pluginMap := make(map[string]*m.PluginSetting)
+ for _, plug := range query.Result {
+ pluginMap[plug.PluginId] = plug
}
- return orgAppsMap, nil
+ return pluginMap, nil
}
func GetEnabledPlugins(orgId int64) (*EnabledPlugins, error) {
enabledPlugins := NewEnabledPlugins()
- orgApps, err := GetOrgAppSettings(orgId)
+ orgPlugins, err := GetPluginSettings(orgId)
if err != nil {
return nil, err
}
enabledApps := make(map[string]bool)
- for appId, installedApp := range Apps {
- var app AppPlugin
- app = *installedApp
+ for pluginId, app := range Apps {
- // check if the app is stored in the DB for this org and if so, use the
- // state stored there.
- if b, ok := orgApps[appId]; ok {
+ if b, ok := orgPlugins[pluginId]; ok {
app.Enabled = b.Enabled
app.Pinned = b.Pinned
}
if app.Enabled {
- enabledApps[app.Id] = true
- enabledPlugins.Apps = append(enabledPlugins.Apps, &app)
+ enabledApps[pluginId] = true
+ enabledPlugins.Apps = append(enabledPlugins.Apps, app)
}
}
diff --git a/pkg/services/sqlstore/app_settings.go b/pkg/services/sqlstore/app_settings.go
deleted file mode 100644
index e7d8a90a495..00000000000
--- a/pkg/services/sqlstore/app_settings.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package sqlstore
-
-import (
- "time"
-
- "github.com/grafana/grafana/pkg/bus"
- m "github.com/grafana/grafana/pkg/models"
- "github.com/grafana/grafana/pkg/setting"
- "github.com/grafana/grafana/pkg/util"
-)
-
-func init() {
- bus.AddHandler("sql", GetAppSettings)
- bus.AddHandler("sql", GetAppSettingByAppId)
- bus.AddHandler("sql", UpdateAppSettings)
-}
-
-func GetAppSettings(query *m.GetAppSettingsQuery) error {
- sess := x.Where("org_id=?", query.OrgId)
-
- query.Result = make([]*m.AppSettings, 0)
- return sess.Find(&query.Result)
-}
-
-func GetAppSettingByAppId(query *m.GetAppSettingByAppIdQuery) error {
- appSetting := m.AppSettings{OrgId: query.OrgId, AppId: query.AppId}
- has, err := x.Get(&appSetting)
- if err != nil {
- return err
- } else if has == false {
- return m.ErrAppSettingNotFound
- }
- query.Result = &appSetting
- return nil
-}
-
-func UpdateAppSettings(cmd *m.UpdateAppSettingsCmd) error {
- return inTransaction2(func(sess *session) error {
- var app m.AppSettings
-
- exists, err := sess.Where("org_id=? and app_id=?", cmd.OrgId, cmd.AppId).Get(&app)
- sess.UseBool("enabled")
- sess.UseBool("pinned")
- if !exists {
- app = m.AppSettings{
- AppId: cmd.AppId,
- OrgId: cmd.OrgId,
- Enabled: cmd.Enabled,
- Pinned: cmd.Pinned,
- JsonData: cmd.JsonData,
- SecureJsonData: cmd.GetEncryptedJsonData(),
- Created: time.Now(),
- Updated: time.Now(),
- }
- _, err = sess.Insert(&app)
- return err
- } else {
- for key, data := range cmd.SecureJsonData {
- app.SecureJsonData[key] = util.Encrypt([]byte(data), setting.SecretKey)
- }
- app.SecureJsonData = cmd.GetEncryptedJsonData()
- app.Updated = time.Now()
- app.Enabled = cmd.Enabled
- app.JsonData = cmd.JsonData
- app.Pinned = cmd.Pinned
- _, err = sess.Id(app.Id).Update(&app)
- return err
- }
- })
-}
diff --git a/pkg/services/sqlstore/migrations/app_settings.go b/pkg/services/sqlstore/migrations/plugin_setting.go
similarity index 63%
rename from pkg/services/sqlstore/migrations/app_settings.go
rename to pkg/services/sqlstore/migrations/plugin_setting.go
index 885dbbf9f05..4a8729691d3 100644
--- a/pkg/services/sqlstore/migrations/app_settings.go
+++ b/pkg/services/sqlstore/migrations/plugin_setting.go
@@ -4,12 +4,12 @@ import . "github.com/grafana/grafana/pkg/services/sqlstore/migrator"
func addAppSettingsMigration(mg *Migrator) {
- appSettingsV2 := Table{
- Name: "app_settings",
+ pluginSettingTable := Table{
+ Name: "plugin_setting",
Columns: []*Column{
{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
{Name: "org_id", Type: DB_BigInt, Nullable: true},
- {Name: "app_id", Type: DB_NVarchar, Length: 255, Nullable: false},
+ {Name: "plugin_id", Type: DB_NVarchar, Length: 255, Nullable: false},
{Name: "enabled", Type: DB_Bool, Nullable: false},
{Name: "pinned", Type: DB_Bool, Nullable: false},
{Name: "json_data", Type: DB_Text, Nullable: true},
@@ -18,14 +18,12 @@ func addAppSettingsMigration(mg *Migrator) {
{Name: "updated", Type: DB_DateTime, Nullable: false},
},
Indices: []*Index{
- {Cols: []string{"org_id", "app_id"}, Type: UniqueIndex},
+ {Cols: []string{"org_id", "plugin_id"}, Type: UniqueIndex},
},
}
- mg.AddMigration("Drop old table app_settings v1", NewDropTableMigration("app_settings"))
-
- mg.AddMigration("create app_settings table v2", NewAddTableMigration(appSettingsV2))
+ mg.AddMigration("create plugin_setting table", NewAddTableMigration(pluginSettingTable))
//------- indexes ------------------
- addTableIndicesMigrations(mg, "v3", appSettingsV2)
+ addTableIndicesMigrations(mg, "v1", pluginSettingTable)
}
diff --git a/pkg/services/sqlstore/plugin_setting.go b/pkg/services/sqlstore/plugin_setting.go
new file mode 100644
index 00000000000..53f4857d9b6
--- /dev/null
+++ b/pkg/services/sqlstore/plugin_setting.go
@@ -0,0 +1,70 @@
+package sqlstore
+
+import (
+ "time"
+
+ "github.com/grafana/grafana/pkg/bus"
+ m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/setting"
+ "github.com/grafana/grafana/pkg/util"
+)
+
+func init() {
+ bus.AddHandler("sql", GetPluginSettings)
+ bus.AddHandler("sql", GetPluginSettingById)
+ bus.AddHandler("sql", UpdatePluginSetting)
+}
+
+func GetPluginSettings(query *m.GetPluginSettingsQuery) error {
+ sess := x.Where("org_id=?", query.OrgId)
+
+ query.Result = make([]*m.PluginSetting, 0)
+ return sess.Find(&query.Result)
+}
+
+func GetPluginSettingById(query *m.GetPluginSettingByIdQuery) error {
+ pluginSetting := m.PluginSetting{OrgId: query.OrgId, PluginId: query.PluginId}
+ has, err := x.Get(&pluginSetting)
+ if err != nil {
+ return err
+ } else if has == false {
+ return m.ErrPluginSettingNotFound
+ }
+ query.Result = &pluginSetting
+ return nil
+}
+
+func UpdatePluginSetting(cmd *m.UpdatePluginSettingCmd) error {
+ return inTransaction2(func(sess *session) error {
+ var pluginSetting m.PluginSetting
+
+ exists, err := sess.Where("org_id=? and plugin_id=?", cmd.OrgId, cmd.PluginId).Get(&pluginSetting)
+ sess.UseBool("enabled")
+ sess.UseBool("pinned")
+ if !exists {
+ pluginSetting = m.PluginSetting{
+ PluginId: cmd.PluginId,
+ OrgId: cmd.OrgId,
+ Enabled: cmd.Enabled,
+ Pinned: cmd.Pinned,
+ JsonData: cmd.JsonData,
+ SecureJsonData: cmd.GetEncryptedJsonData(),
+ Created: time.Now(),
+ Updated: time.Now(),
+ }
+ _, err = sess.Insert(&pluginSetting)
+ return err
+ } else {
+ for key, data := range cmd.SecureJsonData {
+ pluginSetting.SecureJsonData[key] = util.Encrypt([]byte(data), setting.SecretKey)
+ }
+ pluginSetting.SecureJsonData = cmd.GetEncryptedJsonData()
+ pluginSetting.Updated = time.Now()
+ pluginSetting.Enabled = cmd.Enabled
+ pluginSetting.JsonData = cmd.JsonData
+ pluginSetting.Pinned = cmd.Pinned
+ _, err = sess.Id(pluginSetting.Id).Update(&pluginSetting)
+ return err
+ }
+ })
+}
diff --git a/public/app/core/components/colorpicker/colorpicker.ts b/public/app/core/components/colorpicker/colorpicker.ts
new file mode 100644
index 00000000000..9c879b867ff
--- /dev/null
+++ b/public/app/core/components/colorpicker/colorpicker.ts
@@ -0,0 +1,81 @@
+///