diff --git a/CHANGELOG.md b/CHANGELOG.md index 5470a86fb47..82b3ba2037e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * **InfluxDB**: Small fix for the "glow" when focus the field for LIMIT and SLIMIT [#7799](https://github.com/grafana/grafana/pull/7799) thx [@thuck](https://github.com/thuck) * **Panels**: Delay loading & Lazy load panels as they become visible (scrolled into view) [#5216](https://github.com/grafana/grafana/issues/5216) thx [@jifwin](https://github.com/jifwin) * **Graph**: Support auto grid min/max when using log scale [#3090](https://github.com/grafana/grafana/issues/3090), thx [@bigbenhur](https://github.com/bigbenhur) +* **Elasticsearch**: Support histogram aggregations [#3164](https://github.com/grafana/grafana/issues/3164) ## Minor Enchancements diff --git a/conf/defaults.ini b/conf/defaults.ini index 9f2c9ed6de3..5c12937f4f8 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -74,7 +74,6 @@ password = url = # Max conn setting default is 0 (mean not set) -max_conn = max_idle_conn = max_open_conn = @@ -206,6 +205,9 @@ default_theme = dark # Set to true to disable (hide) the login form, useful if you use OAuth disable_login_form = false +# Set to true to disable the signout link in the side menu. useful if you use auth.proxy +disable_signout_menu = false + #################################### Anonymous Auth ###################### [auth.anonymous] # enable anonymous access diff --git a/conf/sample.ini b/conf/sample.ini index 3b7415e4217..87505221790 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -83,7 +83,6 @@ ;path = grafana.db # Max conn setting default is 0 (mean not set) -;max_conn = ;max_idle_conn = ;max_open_conn = @@ -193,6 +192,9 @@ # Set to true to disable (hide) the login form, useful if you use OAuth, defaults to false ;disable_login_form = false +# Set to true to disable the signout link in the side menu. useful if you use auth.proxy, defaults to false +;disable_signout_menu = false + #################################### Anonymous Auth ########################## [auth.anonymous] # enable anonymous access diff --git a/docs/sources/guides/whats-new-in-v4.md b/docs/sources/guides/whats-new-in-v4.md index cfd454cdc23..68a40ed7a1e 100644 --- a/docs/sources/guides/whats-new-in-v4.md +++ b/docs/sources/guides/whats-new-in-v4.md @@ -27,7 +27,7 @@ notifications will be sent out when the rule conditions are met. This feature has been worked on for over a year with many iterations and rewrites just to make sure the foundations are really solid. We are really proud to finally release it! -Since the alerting execution is processed in the backend all data source plugins are not supported. +Since the alerting execution is processed in the backend not all data source plugins are supported. Right now Graphite, Prometheus, InfluxDB and OpenTSDB are supported. Elasticsearch is being worked on but will be not ready for v4 release. @@ -70,8 +70,8 @@ to add graph comments in the form of annotations directly from within Grafana in {{< imgbox max-width="30%" img="/img/docs/v4/alert_list_panel.png" caption="Alert List Panel" >}} -This new panel allows you to show alert rules or a history of alert rule state changes. You can filter based on states your -interested in. Very useful panel for overview style dashboards. +This new panel allows you to show alert rules or a history of alert rule state changes. You can filter based on states you are +interested in. This panel is very useful for overview style dashboards.
@@ -79,8 +79,8 @@ interested in. Very useful panel for overview style dashboards. {{< imgbox max-width="30%" img="/img/docs/v4/adhoc_filters.gif" caption="Ad-hoc filters variable" >}} -This is a new and very different type of template variable. It will allow you to create new key/value filters on the fly. -With autocomplete for both key and values. The filter condition will be automatically applied to all +This is a new and very different type of template variable. It will allow you to create new key/value filters on the fly +with autocomplete for both key and values. The filter condition will be automatically applied to all queries that use that data source. This feature opens up more exploratory dashboards. In the gif animation to the right you have a dashboard for Elasticsearch log data. It uses one query variable that allow you to quickly change how the data is grouped, and an interval variable for controlling the granularity of the time buckets. What was missing @@ -126,15 +126,15 @@ We always try to bring some UX/UI refinements & polish in every release. {{< imgbox max-width="50%" img="/img/docs/v4/add_panel.gif" caption="Add Panel flow" >}} -We spent a lot of time improving the dashboard building experience. Trying to make it both +We spent a lot of time improving the dashboard building experience to make it both more efficient and easier for beginners. After many good but not great experiments with a `build mode` we eventually decided to just improve the green row menu and continue work on a `build mode` for a future release. The new row menu automatically slides out when you mouse over the edge of the row. You no longer need -to hover over the small green icon and the click it to expand the row menu. +to hover over the small green icon and then click it to expand the row menu. -There is some minor improvements to drag and drop behaviour. Now when dragging a panel from one row +There are some minor improvements to drag and drop behaviour. Now when dragging a panel from one row to another you will insert the panel and Grafana will automatically make room for it. When you drag a panel within a row you will simply reorder the panels. @@ -150,7 +150,7 @@ We plan to further improve dashboard building in the future with a more rich gri {{< imgbox max-width="40%" img="/img/docs/v4/shortcuts.png" caption="Shortcuts" >}} Grafana v4 introduces a number of really powerful keyboard shortcuts. You can now focus a panel -by hovering over it with your mouse. With a panel focused you can simple hit `e` to toggle panel +by hovering over it with your mouse. With a panel focused you can simply hit `e` to toggle panel edit mode, or `v` to toggle fullscreen mode. `p r` removes the panel. `p s` opens share modal. @@ -164,10 +164,10 @@ Some nice navigation shortcuts are: ## Upgrade & Breaking changes -There are no breaking changes. Old dashboards and features should work the same. Grafana-server will automatically upgrade it's db +There are no breaking changes. Old dashboards and features should work the same. Grafana-server will automatically upgrade its db schema on restart. It's advisable to do a backup of Grafana's database before updating. -If your are using plugins make sure to update your plugins as some might not work perfectly v4. +If you are using plugins make sure to update your plugins as some might not work perfectly v4. You can update plugins using grafana-cli diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index 50d28560672..176f843e86b 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -267,6 +267,10 @@ options are `Admin` and `Editor` and `Read Only Editor`. e.g. : Set to true to disable (hide) the login form, useful if you use OAuth, defaults to false. +### disable_signout_menu + +Set to true to disable the signout link in the side menu. useful if you use auth.proxy, defaults to false. +
## [auth.anonymous] @@ -427,6 +431,11 @@ Set to `true` to enable LDAP integration (default: `false`) ### config_file Path to the LDAP specific configuration file (default: `/etc/grafana/ldap.toml`) +### allow_sign_up + +Allow sign up should almost always be true (default) to allow new Grafana users to be created (if ldap authentication is ok). If set to +false only pre-existing Grafana users will be able to login (if ldap authentication is ok). + > For details on LDAP Configuration, go to the [LDAP Integration]({{< relref "ldap.md" >}}) page.
diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index 328b8abbc5f..11e70dccc0d 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -133,16 +133,17 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro } jsonObj := map[string]interface{}{ - "defaultDatasource": defaultDatasource, - "datasources": datasources, - "panels": panels, - "appSubUrl": setting.AppSubUrl, - "allowOrgCreate": (setting.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin, - "authProxyEnabled": setting.AuthProxyEnabled, - "ldapEnabled": setting.LdapEnabled, - "alertingEnabled": setting.AlertingEnabled, - "googleAnalyticsId": setting.GoogleAnalyticsId, - "disableLoginForm": setting.DisableLoginForm, + "defaultDatasource": defaultDatasource, + "datasources": datasources, + "panels": panels, + "appSubUrl": setting.AppSubUrl, + "allowOrgCreate": (setting.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin, + "authProxyEnabled": setting.AuthProxyEnabled, + "ldapEnabled": setting.LdapEnabled, + "alertingEnabled": setting.AlertingEnabled, + "googleAnalyticsId": setting.GoogleAnalyticsId, + "disableLoginForm": setting.DisableLoginForm, + "disableSignoutMenu": setting.DisableSignoutMenu, "buildInfo": map[string]interface{}{ "version": setting.BuildVersion, "commit": setting.BuildCommit, diff --git a/pkg/services/alerting/notifiers/slack.go b/pkg/services/alerting/notifiers/slack.go index 0dc88a926c4..a0d08ae2ba7 100644 --- a/pkg/services/alerting/notifiers/slack.go +++ b/pkg/services/alerting/notifiers/slack.go @@ -116,6 +116,7 @@ func (this *SlackNotifier) Notify(evalContext *alerting.EvalContext) error { body := map[string]interface{}{ "attachments": []map[string]interface{}{ { + "fallback": evalContext.GetNotificationTitle(), "color": evalContext.GetStateModel().Color, "title": evalContext.GetNotificationTitle(), "title_link": ruleUrl, diff --git a/pkg/services/sqlstore/migrations/alert_mig.go b/pkg/services/sqlstore/migrations/alert_mig.go index b6956be41c7..7b6558656f1 100644 --- a/pkg/services/sqlstore/migrations/alert_mig.go +++ b/pkg/services/sqlstore/migrations/alert_mig.go @@ -50,7 +50,7 @@ func addAlertMigrations(mg *Migrator) { Columns: []*Column{ {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "org_id", Type: DB_BigInt, Nullable: false}, - {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "name", Type: DB_NVarchar, Length: 190, Nullable: false}, {Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "settings", Type: DB_Text, Nullable: false}, {Name: "created", Type: DB_DateTime, Nullable: false}, @@ -67,4 +67,19 @@ func addAlertMigrations(mg *Migrator) { })) mg.AddMigration("add index alert_notification org_id & name", NewAddIndexMigration(alert_notification, alert_notification.Indices[0])) + mg.AddMigration("Update alert table charset", NewTableCharsetMigration("alert", []*Column{ + {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "message", Type: DB_Text, Nullable: false}, + {Name: "state", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "settings", Type: DB_Text, Nullable: false}, + {Name: "severity", Type: DB_Text, Nullable: false}, + {Name: "execution_error", Type: DB_Text, Nullable: false}, + {Name: "eval_data", Type: DB_Text, Nullable: true}, + })) + + mg.AddMigration("Update alert_notification table charset", NewTableCharsetMigration("alert_notification", []*Column{ + {Name: "name", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "settings", Type: DB_Text, Nullable: false}, + })) } diff --git a/pkg/services/sqlstore/migrations/annotation_mig.go b/pkg/services/sqlstore/migrations/annotation_mig.go index a307100ad3c..4a7206f9d64 100644 --- a/pkg/services/sqlstore/migrations/annotation_mig.go +++ b/pkg/services/sqlstore/migrations/annotation_mig.go @@ -44,4 +44,14 @@ func addAnnotationMig(mg *Migrator) { mg.AddMigration("add index annotation 2 v3", NewAddIndexMigration(table, table.Indices[2])) mg.AddMigration("add index annotation 3 v3", NewAddIndexMigration(table, table.Indices[3])) mg.AddMigration("add index annotation 4 v3", NewAddIndexMigration(table, table.Indices[4])) + + mg.AddMigration("Update annotation table charset", NewTableCharsetMigration("annotation", []*Column{ + {Name: "type", Type: DB_NVarchar, Length: 25, Nullable: false}, + {Name: "title", Type: DB_Text, Nullable: false}, + {Name: "text", Type: DB_Text, Nullable: false}, + {Name: "metric", Type: DB_NVarchar, Length: 255, Nullable: true}, + {Name: "prev_state", Type: DB_NVarchar, Length: 25, Nullable: false}, + {Name: "new_state", Type: DB_NVarchar, Length: 25, Nullable: false}, + {Name: "data", Type: DB_Text, Nullable: false}, + })) } diff --git a/pkg/services/sqlstore/migrations/apikey_mig.go b/pkg/services/sqlstore/migrations/apikey_mig.go index a02e759f551..928f84c4fb0 100644 --- a/pkg/services/sqlstore/migrations/apikey_mig.go +++ b/pkg/services/sqlstore/migrations/apikey_mig.go @@ -8,7 +8,7 @@ func addApiKeyMigrations(mg *Migrator) { Columns: []*Column{ {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "account_id", Type: DB_BigInt, Nullable: false}, - {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "name", Type: DB_NVarchar, Length: 190, Nullable: false}, {Name: "key", Type: DB_Varchar, Length: 64, Nullable: false}, {Name: "role", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "created", Type: DB_DateTime, Nullable: false}, @@ -41,8 +41,8 @@ func addApiKeyMigrations(mg *Migrator) { Columns: []*Column{ {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "org_id", Type: DB_BigInt, Nullable: false}, - {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, - {Name: "key", Type: DB_Varchar, Length: 255, Nullable: false}, + {Name: "name", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "key", Type: DB_Varchar, Length: 190, Nullable: false}, {Name: "role", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "created", Type: DB_DateTime, Nullable: false}, {Name: "updated", Type: DB_DateTime, Nullable: false}, @@ -72,4 +72,10 @@ func addApiKeyMigrations(mg *Migrator) { })) mg.AddMigration("Drop old table api_key_v1", NewDropTableMigration("api_key_v1")) + + mg.AddMigration("Update api_key table charset", NewTableCharsetMigration("api_key", []*Column{ + {Name: "name", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "key", Type: DB_Varchar, Length: 190, Nullable: false}, + {Name: "role", Type: DB_NVarchar, Length: 255, Nullable: false}, + })) } diff --git a/pkg/services/sqlstore/migrations/dashboard_mig.go b/pkg/services/sqlstore/migrations/dashboard_mig.go index 283501d366f..0ef2f3be54f 100644 --- a/pkg/services/sqlstore/migrations/dashboard_mig.go +++ b/pkg/services/sqlstore/migrations/dashboard_mig.go @@ -8,7 +8,7 @@ func addDashboardMigration(mg *Migrator) { Columns: []*Column{ {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "version", Type: DB_Int, Nullable: false}, - {Name: "slug", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "slug", Type: DB_NVarchar, Length: 190, Nullable: false}, {Name: "title", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "data", Type: DB_Text, Nullable: false}, {Name: "account_id", Type: DB_BigInt, Nullable: false}, @@ -56,7 +56,7 @@ func addDashboardMigration(mg *Migrator) { Columns: []*Column{ {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "version", Type: DB_Int, Nullable: false}, - {Name: "slug", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "slug", Type: DB_NVarchar, Length: 190, Nullable: false}, {Name: "title", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "data", Type: DB_Text, Nullable: false}, {Name: "org_id", Type: DB_BigInt, Nullable: false}, @@ -125,4 +125,15 @@ func addDashboardMigration(mg *Migrator) { mg.AddMigration("Add index for dashboard_id in dashboard_tag", NewAddIndexMigration(dashboardTagV1, &Index{ Cols: []string{"dashboard_id"}, Type: IndexType, })) + + mg.AddMigration("Update dashboard table charset", NewTableCharsetMigration("dashboard", []*Column{ + {Name: "slug", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "title", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "plugin_id", Type: DB_NVarchar, Nullable: true, Length: 255}, + {Name: "data", Type: DB_MediumText, Nullable: false}, + })) + + mg.AddMigration("Update dashboard_tag table charset", NewTableCharsetMigration("dashboard_tag", []*Column{ + {Name: "term", Type: DB_NVarchar, Length: 50, Nullable: false}, + })) } diff --git a/pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go b/pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go index b08cc451e55..1a72bcba929 100644 --- a/pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go +++ b/pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go @@ -8,7 +8,7 @@ func addDashboardSnapshotMigrations(mg *Migrator) { Columns: []*Column{ {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, - {Name: "key", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "key", Type: DB_NVarchar, Length: 190, Nullable: false}, {Name: "dashboard", Type: DB_Text, Nullable: false}, {Name: "expires", Type: DB_DateTime, Nullable: false}, {Name: "created", Type: DB_DateTime, Nullable: false}, @@ -28,8 +28,8 @@ func addDashboardSnapshotMigrations(mg *Migrator) { Columns: []*Column{ {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, - {Name: "key", Type: DB_NVarchar, Length: 255, Nullable: false}, - {Name: "delete_key", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "key", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "delete_key", Type: DB_NVarchar, Length: 190, Nullable: false}, {Name: "org_id", Type: DB_BigInt, Nullable: false}, {Name: "user_id", Type: DB_BigInt, Nullable: false}, {Name: "external", Type: DB_Bool, Nullable: false}, @@ -54,4 +54,12 @@ func addDashboardSnapshotMigrations(mg *Migrator) { Sqlite("SELECT 0 WHERE 0;"). Postgres("SELECT 0;"). Mysql("ALTER TABLE dashboard_snapshot MODIFY dashboard MEDIUMTEXT;")) + + mg.AddMigration("Update dashboard_snapshot table charset", NewTableCharsetMigration("dashboard_snapshot", []*Column{ + {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "key", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "delete_key", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "external_url", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "dashboard", Type: DB_MediumText, Nullable: false}, + })) } diff --git a/pkg/services/sqlstore/migrations/datasource_mig.go b/pkg/services/sqlstore/migrations/datasource_mig.go index 396f80df99f..c694b5b7cfb 100644 --- a/pkg/services/sqlstore/migrations/datasource_mig.go +++ b/pkg/services/sqlstore/migrations/datasource_mig.go @@ -10,7 +10,7 @@ func addDataSourceMigration(mg *Migrator) { {Name: "account_id", Type: DB_BigInt, Nullable: false}, {Name: "version", Type: DB_Int, Nullable: false}, {Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false}, - {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "name", Type: DB_NVarchar, Length: 190, Nullable: false}, {Name: "access", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "url", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "password", Type: DB_NVarchar, Length: 255, Nullable: true}, @@ -49,7 +49,7 @@ func addDataSourceMigration(mg *Migrator) { {Name: "org_id", Type: DB_BigInt, Nullable: false}, {Name: "version", Type: DB_Int, Nullable: false}, {Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false}, - {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "name", Type: DB_NVarchar, Length: 190, Nullable: false}, {Name: "access", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "url", Type: DB_NVarchar, Length: 255, Nullable: false}, {Name: "password", Type: DB_NVarchar, Length: 255, Nullable: true}, @@ -106,4 +106,18 @@ func addDataSourceMigration(mg *Migrator) { mg.AddMigration("Add secure json data column", NewAddColumnMigration(tableV2, &Column{ Name: "secure_json_data", Type: DB_Text, Nullable: true, })) + + mg.AddMigration("Update data_source table charset", NewTableCharsetMigration(tableV2.Name, []*Column{ + {Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "name", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "access", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "url", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "password", Type: DB_NVarchar, Length: 255, Nullable: true}, + {Name: "user", Type: DB_NVarchar, Length: 255, Nullable: true}, + {Name: "database", Type: DB_NVarchar, Length: 255, Nullable: true}, + {Name: "basic_auth_user", Type: DB_NVarchar, Length: 255, Nullable: true}, + {Name: "basic_auth_password", Type: DB_NVarchar, Length: 255, Nullable: true}, + {Name: "json_data", Type: DB_Text, Nullable: true}, + {Name: "secure_json_data", Type: DB_Text, Nullable: true}, + })) } diff --git a/pkg/services/sqlstore/migrations/org_mig.go b/pkg/services/sqlstore/migrations/org_mig.go index 8e25da76b58..12e0a04256a 100644 --- a/pkg/services/sqlstore/migrations/org_mig.go +++ b/pkg/services/sqlstore/migrations/org_mig.go @@ -8,7 +8,7 @@ func addOrgMigrations(mg *Migrator) { Columns: []*Column{ {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "version", Type: DB_Int, Nullable: false}, - {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "name", Type: DB_NVarchar, Length: 190, Nullable: false}, {Name: "address1", Type: DB_NVarchar, Length: 255, Nullable: true}, {Name: "address2", Type: DB_NVarchar, Length: 255, Nullable: true}, {Name: "city", Type: DB_NVarchar, Length: 255, Nullable: true}, @@ -68,4 +68,19 @@ func addOrgMigrations(mg *Migrator) { mg.AddMigration("Drop old table account", NewDropTableMigration("account")) mg.AddMigration("Drop old table account_user", NewDropTableMigration("account_user")) + + mg.AddMigration("Update org table charset", NewTableCharsetMigration("org", []*Column{ + {Name: "name", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "address1", Type: DB_NVarchar, Length: 255, Nullable: true}, + {Name: "address2", Type: DB_NVarchar, Length: 255, Nullable: true}, + {Name: "city", Type: DB_NVarchar, Length: 255, Nullable: true}, + {Name: "state", Type: DB_NVarchar, Length: 255, Nullable: true}, + {Name: "zip_code", Type: DB_NVarchar, Length: 50, Nullable: true}, + {Name: "country", Type: DB_NVarchar, Length: 255, Nullable: true}, + {Name: "billing_email", Type: DB_NVarchar, Length: 255, Nullable: true}, + })) + + mg.AddMigration("Update org_user table charset", NewTableCharsetMigration("org_user", []*Column{ + {Name: "role", Type: DB_NVarchar, Length: 20}, + })) } diff --git a/pkg/services/sqlstore/migrations/playlist_mig.go b/pkg/services/sqlstore/migrations/playlist_mig.go index 636fc091006..44ae4b6cb0e 100644 --- a/pkg/services/sqlstore/migrations/playlist_mig.go +++ b/pkg/services/sqlstore/migrations/playlist_mig.go @@ -32,4 +32,15 @@ func addPlaylistMigrations(mg *Migrator) { } mg.AddMigration("create playlist item table v2", NewAddTableMigration(playlistItemV2)) + + mg.AddMigration("Update playlist table charset", NewTableCharsetMigration("playlist", []*Column{ + {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "interval", Type: DB_NVarchar, Length: 255, Nullable: false}, + })) + + mg.AddMigration("Update playlist_item table charset", NewTableCharsetMigration("playlist_item", []*Column{ + {Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "value", Type: DB_Text, Nullable: false}, + {Name: "title", Type: DB_Text, Nullable: false}, + })) } diff --git a/pkg/services/sqlstore/migrations/plugin_setting.go b/pkg/services/sqlstore/migrations/plugin_setting.go index 0700ab67d2f..66a984b56d4 100644 --- a/pkg/services/sqlstore/migrations/plugin_setting.go +++ b/pkg/services/sqlstore/migrations/plugin_setting.go @@ -9,7 +9,7 @@ func addAppSettingsMigration(mg *Migrator) { Columns: []*Column{ {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "org_id", Type: DB_BigInt, Nullable: true}, - {Name: "plugin_id", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "plugin_id", Type: DB_NVarchar, Length: 190, Nullable: false}, {Name: "enabled", Type: DB_Bool, Nullable: false}, {Name: "pinned", Type: DB_Bool, Nullable: false}, {Name: "json_data", Type: DB_Text, Nullable: true}, @@ -32,4 +32,10 @@ func addAppSettingsMigration(mg *Migrator) { Name: "plugin_version", Type: DB_NVarchar, Nullable: true, Length: 50, })) + mg.AddMigration("Update plugin_setting table charset", NewTableCharsetMigration("plugin_setting", []*Column{ + {Name: "plugin_id", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "json_data", Type: DB_Text, Nullable: true}, + {Name: "secure_json_data", Type: DB_Text, Nullable: true}, + {Name: "plugin_version", Type: DB_NVarchar, Nullable: true, Length: 50}, + })) } diff --git a/pkg/services/sqlstore/migrations/preferences_mig.go b/pkg/services/sqlstore/migrations/preferences_mig.go index 67a8169a7a8..b3822fe5239 100644 --- a/pkg/services/sqlstore/migrations/preferences_mig.go +++ b/pkg/services/sqlstore/migrations/preferences_mig.go @@ -29,4 +29,9 @@ func addPreferencesMigrations(mg *Migrator) { // create table mg.AddMigration("create preferences table v3", NewAddTableMigration(preferencesV2)) + + mg.AddMigration("Update preferences table charset", NewTableCharsetMigration("preferences", []*Column{ + {Name: "timezone", Type: DB_NVarchar, Length: 50, Nullable: false}, + {Name: "theme", Type: DB_NVarchar, Length: 20, Nullable: false}, + })) } diff --git a/pkg/services/sqlstore/migrations/quota_mig.go b/pkg/services/sqlstore/migrations/quota_mig.go index d877bb4c3c1..34f0da662a9 100644 --- a/pkg/services/sqlstore/migrations/quota_mig.go +++ b/pkg/services/sqlstore/migrations/quota_mig.go @@ -12,7 +12,7 @@ func addQuotaMigration(mg *Migrator) { {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "org_id", Type: DB_BigInt, Nullable: true}, {Name: "user_id", Type: DB_BigInt, Nullable: true}, - {Name: "target", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "target", Type: DB_NVarchar, Length: 190, Nullable: false}, {Name: "limit", Type: DB_BigInt, Nullable: false}, {Name: "created", Type: DB_DateTime, Nullable: false}, {Name: "updated", Type: DB_DateTime, Nullable: false}, @@ -25,4 +25,8 @@ func addQuotaMigration(mg *Migrator) { //------- indexes ------------------ addTableIndicesMigrations(mg, "v1", quotaV1) + + mg.AddMigration("Update quota table charset", NewTableCharsetMigration("quota", []*Column{ + {Name: "target", Type: DB_NVarchar, Length: 190, Nullable: false}, + })) } diff --git a/pkg/services/sqlstore/migrations/temp_user.go b/pkg/services/sqlstore/migrations/temp_user.go index 3cae5d82472..5592ab7e4ad 100644 --- a/pkg/services/sqlstore/migrations/temp_user.go +++ b/pkg/services/sqlstore/migrations/temp_user.go @@ -35,4 +35,13 @@ func addTempUserMigrations(mg *Migrator) { // create table mg.AddMigration("create temp user table v1-7", NewAddTableMigration(tempUserV1)) addTableIndicesMigrations(mg, "v1-7", tempUserV1) + + mg.AddMigration("Update temp_user table charset", NewTableCharsetMigration("temp_user", []*Column{ + {Name: "email", Type: DB_NVarchar, Length: 255}, + {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: true}, + {Name: "role", Type: DB_NVarchar, Length: 20, Nullable: true}, + {Name: "code", Type: DB_NVarchar, Length: 255}, + {Name: "status", Type: DB_Varchar, Length: 20}, + {Name: "remote_addr", Type: DB_Varchar, Length: 255, Nullable: true}, + })) } diff --git a/pkg/services/sqlstore/migrations/user_mig.go b/pkg/services/sqlstore/migrations/user_mig.go index 67446f64d1a..a12c4987792 100644 --- a/pkg/services/sqlstore/migrations/user_mig.go +++ b/pkg/services/sqlstore/migrations/user_mig.go @@ -8,8 +8,8 @@ func addUserMigrations(mg *Migrator) { Columns: []*Column{ {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "version", Type: DB_Int, Nullable: false}, - {Name: "login", Type: DB_NVarchar, Length: 255, Nullable: false}, - {Name: "email", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "login", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "email", Type: DB_NVarchar, Length: 190, Nullable: false}, {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: true}, {Name: "password", Type: DB_NVarchar, Length: 255, Nullable: true}, {Name: "salt", Type: DB_NVarchar, Length: 50, Nullable: true}, @@ -47,8 +47,8 @@ func addUserMigrations(mg *Migrator) { Columns: []*Column{ {Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, {Name: "version", Type: DB_Int, Nullable: false}, - {Name: "login", Type: DB_NVarchar, Length: 255, Nullable: false}, - {Name: "email", Type: DB_NVarchar, Length: 255, Nullable: false}, + {Name: "login", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "email", Type: DB_NVarchar, Length: 190, Nullable: false}, {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: true}, {Name: "password", Type: DB_NVarchar, Length: 255, Nullable: true}, {Name: "salt", Type: DB_NVarchar, Length: 50, Nullable: true}, @@ -92,4 +92,15 @@ func addUserMigrations(mg *Migrator) { mg.AddMigration("Add column help_flags1 to user table", NewAddColumnMigration(userV2, &Column{ Name: "help_flags1", Type: DB_BigInt, Nullable: false, Default: "0", })) + + mg.AddMigration("Update user table charset", NewTableCharsetMigration("user", []*Column{ + {Name: "login", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "email", Type: DB_NVarchar, Length: 190, Nullable: false}, + {Name: "name", Type: DB_NVarchar, Length: 255, Nullable: true}, + {Name: "password", Type: DB_NVarchar, Length: 255, Nullable: true}, + {Name: "salt", Type: DB_NVarchar, Length: 50, Nullable: true}, + {Name: "rands", Type: DB_NVarchar, Length: 50, Nullable: true}, + {Name: "company", Type: DB_NVarchar, Length: 255, Nullable: true}, + {Name: "theme", Type: DB_NVarchar, Length: 255, Nullable: true}, + })) } diff --git a/pkg/services/sqlstore/migrator/dialect.go b/pkg/services/sqlstore/migrator/dialect.go index 4473b560428..651405921d9 100644 --- a/pkg/services/sqlstore/migrator/dialect.go +++ b/pkg/services/sqlstore/migrator/dialect.go @@ -29,6 +29,7 @@ type Dialect interface { TableCheckSql(tableName string) (string, []interface{}) RenameTable(oldName string, newName string) string + UpdateTableSql(tableName string, columns []*Column) string } func NewDialect(name string) Dialect { @@ -102,7 +103,7 @@ func (b *BaseDialect) CreateTableSql(table *Table) string { sql = sql[:len(sql)-2] + ")" if b.dialect.SupportEngine() { - sql += " ENGINE=InnoDB DEFAULT CHARSET UTF8 " + sql += " ENGINE=InnoDB DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci" } sql += ";" @@ -160,3 +161,7 @@ func (db *BaseDialect) DropIndexSql(tableName string, index *Index) string { name = index.XName(tableName) return fmt.Sprintf("DROP INDEX %v ON %s", quote(name), quote(tableName)) } + +func (db *BaseDialect) UpdateTableSql(tableName string, columns []*Column) string { + return "-- NOT REQUIRED" +} diff --git a/pkg/services/sqlstore/migrator/migrations.go b/pkg/services/sqlstore/migrator/migrations.go index 7d97abb6bb9..2fec8825fa4 100644 --- a/pkg/services/sqlstore/migrator/migrations.go +++ b/pkg/services/sqlstore/migrator/migrations.go @@ -200,3 +200,17 @@ func (m *CopyTableDataMigration) IfTableExists(tableName string) *CopyTableDataM func (m *CopyTableDataMigration) Sql(d Dialect) string { return d.CopyTableData(m.sourceTable, m.targetTable, m.sourceCols, m.targetCols) } + +type TableCharsetMigration struct { + MigrationBase + tableName string + columns []*Column +} + +func NewTableCharsetMigration(tableName string, columns []*Column) *TableCharsetMigration { + return &TableCharsetMigration{tableName: tableName, columns: columns} +} + +func (m *TableCharsetMigration) Sql(d Dialect) string { + return d.UpdateTableSql(m.tableName, m.columns) +} diff --git a/pkg/services/sqlstore/migrator/mysql_dialect.go b/pkg/services/sqlstore/migrator/mysql_dialect.go index 48c2cd3ea55..1968558dbb8 100644 --- a/pkg/services/sqlstore/migrator/mysql_dialect.go +++ b/pkg/services/sqlstore/migrator/mysql_dialect.go @@ -1,6 +1,9 @@ package migrator -import "strconv" +import ( + "strconv" + "strings" +) type Mysql struct { BaseDialect @@ -76,6 +79,12 @@ func (db *Mysql) SqlType(c *Column) string { } else if hasLen1 { res += "(" + strconv.Itoa(c.Length) + ")" } + + switch c.Type { + case DB_Char, DB_Varchar, DB_NVarchar, DB_TinyText, DB_Text, DB_MediumText, DB_LongText: + res += " CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" + } + return res } @@ -84,3 +93,15 @@ func (db *Mysql) TableCheckSql(tableName string) (string, []interface{}) { sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?" return sql, args } + +func (db *Mysql) UpdateTableSql(tableName string, columns []*Column) string { + var statements = []string{} + + statements = append(statements, "DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci") + + for _, col := range columns { + statements = append(statements, "MODIFY "+col.StringNoPk(db)) + } + + return "ALTER TABLE " + db.Quote(tableName) + " " + strings.Join(statements, ", ") + ";" +} diff --git a/pkg/services/sqlstore/migrator/postgres_dialect.go b/pkg/services/sqlstore/migrator/postgres_dialect.go index 5500b9f1684..92109efdfab 100644 --- a/pkg/services/sqlstore/migrator/postgres_dialect.go +++ b/pkg/services/sqlstore/migrator/postgres_dialect.go @@ -3,6 +3,7 @@ package migrator import ( "fmt" "strconv" + "strings" ) type Postgres struct { @@ -112,3 +113,13 @@ func (db *Postgres) DropIndexSql(tableName string, index *Index) string { idxName := index.XName(tableName) return fmt.Sprintf("DROP INDEX %v", quote(idxName)) } + +func (db *Postgres) UpdateTableSql(tableName string, columns []*Column) string { + var statements = []string{} + + for _, col := range columns { + statements = append(statements, "ALTER "+db.QuoteStr()+col.Name+db.QuoteStr()+" TYPE "+db.SqlType(col)) + } + + return "ALTER TABLE " + db.Quote(tableName) + " " + strings.Join(statements, ", ") + ";" +} diff --git a/pkg/services/sqlstore/sqlstore.go b/pkg/services/sqlstore/sqlstore.go index ef22dd9b6c6..a2106ddbffd 100644 --- a/pkg/services/sqlstore/sqlstore.go +++ b/pkg/services/sqlstore/sqlstore.go @@ -29,7 +29,6 @@ type DatabaseConfig struct { ClientKeyPath string ClientCertPath string ServerCertName string - MaxConn int MaxOpenConn int MaxIdleConn int } @@ -115,7 +114,7 @@ func getEngine() (*xorm.Engine, error) { protocol = "unix" } - cnnstr = fmt.Sprintf("%s:%s@%s(%s)/%s?charset=utf8", + cnnstr = fmt.Sprintf("%s:%s@%s(%s)/%s?charset=utf8mb4", DbCfg.User, DbCfg.Pwd, protocol, DbCfg.Host, DbCfg.Name) if DbCfg.SslMode == "true" || DbCfg.SslMode == "skip-verify" { @@ -157,7 +156,6 @@ func getEngine() (*xorm.Engine, error) { if err != nil { return nil, err } else { - engine.SetMaxConns(DbCfg.MaxConn) engine.SetMaxOpenConns(DbCfg.MaxOpenConn) engine.SetMaxIdleConns(DbCfg.MaxIdleConn) // engine.SetLogger(NewXormLogger(log.LvlInfo, log.New("sqlstore.xorm"))) @@ -191,7 +189,6 @@ func LoadConfig() { DbCfg.Host = sec.Key("host").String() DbCfg.Name = sec.Key("name").String() DbCfg.User = sec.Key("user").String() - DbCfg.MaxConn = sec.Key("max_conn").MustInt(0) DbCfg.MaxOpenConn = sec.Key("max_open_conn").MustInt(0) DbCfg.MaxIdleConn = sec.Key("max_idle_conn").MustInt(0) if len(DbCfg.Pwd) == 0 { diff --git a/pkg/services/sqlstore/sqlutil/sqlutil.go b/pkg/services/sqlstore/sqlutil/sqlutil.go index 075b56c1c18..68ced55722c 100644 --- a/pkg/services/sqlstore/sqlutil/sqlutil.go +++ b/pkg/services/sqlstore/sqlutil/sqlutil.go @@ -12,7 +12,7 @@ type TestDB struct { } var TestDB_Sqlite3 = TestDB{DriverName: "sqlite3", ConnStr: ":memory:?_loc=Local"} -var TestDB_Mysql = TestDB{DriverName: "mysql", ConnStr: "grafana:password@tcp(localhost:3306)/grafana_tests?charset=utf8"} +var TestDB_Mysql = TestDB{DriverName: "mysql", ConnStr: "grafana:password@tcp(localhost:3306)/grafana_tests?charset=utf8mb4"} var TestDB_Postgres = TestDB{DriverName: "postgres", ConnStr: "user=grafanatest password=grafanatest host=localhost port=5432 dbname=grafanatest sslmode=disable"} func CleanDB(x *xorm.Engine) { diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index 99390ecc1c9..cacb4547162 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -96,6 +96,7 @@ var ( LoginHint string DefaultTheme string DisableLoginForm bool + DisableSignoutMenu bool // Http auth AdminUser string @@ -528,6 +529,7 @@ func NewConfigContext(args *CommandLineArgs) error { // auth auth := Cfg.Section("auth") DisableLoginForm = auth.Key("disable_login_form").MustBool(false) + DisableSignoutMenu = auth.Key("disable_signout_menu").MustBool(false) // anonymous access AnonymousEnabled = Cfg.Section("auth.anonymous").Key("enabled").MustBool(false) diff --git a/public/app/core/components/sidemenu/sidemenu.ts b/public/app/core/components/sidemenu/sidemenu.ts index 2e8e03eca7a..a6bc170fddd 100644 --- a/public/app/core/components/sidemenu/sidemenu.ts +++ b/public/app/core/components/sidemenu/sidemenu.ts @@ -23,7 +23,7 @@ export class SideMenuCtrl { this.isSignedIn = contextSrv.isSignedIn; this.user = contextSrv.user; this.appSubUrl = config.appSubUrl; - this.showSignout = this.contextSrv.isSignedIn && !config['authProxyEnabled']; + this.showSignout = this.contextSrv.isSignedIn && !config['disableSignoutMenu']; this.maxShownOrgs = 10; this.mainLinks = config.bootData.mainNavLinks; diff --git a/public/app/features/panel/panel_directive.ts b/public/app/features/panel/panel_directive.ts index 0482abc0437..5868bfcbf54 100644 --- a/public/app/features/panel/panel_directive.ts +++ b/public/app/features/panel/panel_directive.ts @@ -156,11 +156,21 @@ module.directive('grafanaPanel', function($rootScope, $document) { content: function() { return ctrl.getInfoContent({mode: 'tooltip'}); }, - position: 'top center', classes: ctrl.error ? 'drop-error' : 'drop-help', openOn: 'hover', hoverOpenDelay: 100, - constrainToScrollParent: false, + remove: true, + tetherOptions: { + attachment: 'bottom left', + targetAttachment: 'top left', + constraints: [ + { + to: 'window', + attachment: 'together', + pin: true + } + ], + } }); } } @@ -185,6 +195,10 @@ module.directive('grafanaPanel', function($rootScope, $document) { if (ctrl.skippedLastRefresh) { ctrl.refresh(); } + + if (infoDrop) { + infoDrop.position(); + } }; $document.on('scroll', refreshOnScroll); diff --git a/public/app/plugins/datasource/elasticsearch/bucket_agg.js b/public/app/plugins/datasource/elasticsearch/bucket_agg.js index 28f1df08251..d6d641c1655 100644 --- a/public/app/plugins/datasource/elasticsearch/bucket_agg.js +++ b/public/app/plugins/datasource/elasticsearch/bucket_agg.js @@ -50,6 +50,7 @@ function (angular, _, queryDef) { switch($scope.agg.type) { case 'date_histogram': + case 'histogram': case 'terms': { delete $scope.agg.query; $scope.agg.field = 'select field'; @@ -132,6 +133,16 @@ function (angular, _, queryDef) { } break; } + case 'histogram': { + settings.interval = settings.interval || 1000; + settings.min_doc_count = _.defaultTo(settings.min_doc_count, 1); + settingsLinkText = 'Interval: ' + settings.interval; + + if (settings.min_doc_count > 0) { + settingsLinkText += ', Min Doc Count: ' + settings.min_doc_count; + } + break; + } case 'geohash_grid': { // limit precision to 7 settings.precision = Math.max(Math.min(settings.precision, 7), 1); diff --git a/public/app/plugins/datasource/elasticsearch/partials/bucket_agg.html b/public/app/plugins/datasource/elasticsearch/partials/bucket_agg.html index 562f0b86e56..f1e650f6830 100644 --- a/public/app/plugins/datasource/elasticsearch/partials/bucket_agg.html +++ b/public/app/plugins/datasource/elasticsearch/partials/bucket_agg.html @@ -52,6 +52,17 @@ +
+
+ + +
+
+ + +
+
+
diff --git a/public/app/plugins/datasource/elasticsearch/query_builder.js b/public/app/plugins/datasource/elasticsearch/query_builder.js index 11e8b69ddaa..808fea3cc70 100644 --- a/public/app/plugins/datasource/elasticsearch/query_builder.js +++ b/public/app/plugins/datasource/elasticsearch/query_builder.js @@ -79,6 +79,19 @@ function (queryDef) { return esAgg; }; + ElasticQueryBuilder.prototype.getHistogramAgg = function(aggDef) { + var esAgg = {}; + var settings = aggDef.settings || {}; + esAgg.interval = settings.interval; + esAgg.field = aggDef.field; + esAgg.min_doc_count = settings.min_doc_count || 0; + + if (settings.missing) { + esAgg.missing = settings.missing; + } + return esAgg; + }; + ElasticQueryBuilder.prototype.getFiltersAgg = function(aggDef) { var filterObj = {}; for (var i = 0; i < aggDef.settings.filters.length; i++) { @@ -192,6 +205,10 @@ function (queryDef) { esAgg["date_histogram"] = this.getDateHistogramAgg(aggDef); break; } + case 'histogram': { + esAgg["histogram"] = this.getHistogramAgg(aggDef); + break; + } case 'filters': { esAgg["filters"] = {filters: this.getFiltersAgg(aggDef)}; break; diff --git a/public/app/plugins/datasource/elasticsearch/query_def.js b/public/app/plugins/datasource/elasticsearch/query_def.js index 5afc908edba..a55e2dfd9e5 100644 --- a/public/app/plugins/datasource/elasticsearch/query_def.js +++ b/public/app/plugins/datasource/elasticsearch/query_def.js @@ -24,6 +24,7 @@ function (_) { {text: "Filters", value: 'filters' }, {text: "Geo Hash Grid", value: 'geohash_grid', requiresField: true}, {text: "Date Histogram", value: 'date_histogram', requiresField: true}, + {text: "Histogram", value: 'histogram', requiresField: true}, ], orderByOptions: [ diff --git a/public/app/plugins/datasource/elasticsearch/specs/elastic_response_specs.ts b/public/app/plugins/datasource/elasticsearch/specs/elastic_response_specs.ts index 4b87cc52c04..589e0ccbfab 100644 --- a/public/app/plugins/datasource/elasticsearch/specs/elastic_response_specs.ts +++ b/public/app/plugins/datasource/elasticsearch/specs/elastic_response_specs.ts @@ -361,6 +361,39 @@ describe('ElasticResponse', function() { }); }); + describe('histogram response', function() { + var result; + + beforeEach(function() { + targets = [{ + refId: 'A', + metrics: [{type: 'count', id: '1'}], + bucketAggs: [{type: 'histogram', field: 'bytes', id: '3'}], + }]; + response = { + responses: [{ + aggregations: { + "3": { + buckets: [ + {doc_count: 1, key: 1000}, + {doc_count: 3, key: 2000}, + {doc_count: 2, key: 1000}, + ] + } + } + }] + }; + + result = new ElasticResponse(targets, response).getTimeSeries(); + }); + + it('should return docs with byte and count', function() { + expect(result.data[0].datapoints.length).to.be(3); + expect(result.data[0].datapoints[0].Count).to.be(1); + expect(result.data[0].datapoints[0].bytes).to.be(1000); + }); + }); + describe('with two filters agg', function() { var result; diff --git a/public/app/plugins/datasource/elasticsearch/specs/query_builder_specs.ts b/public/app/plugins/datasource/elasticsearch/specs/query_builder_specs.ts index e60cde7a163..18645ad498d 100644 --- a/public/app/plugins/datasource/elasticsearch/specs/query_builder_specs.ts +++ b/public/app/plugins/datasource/elasticsearch/specs/query_builder_specs.ts @@ -249,6 +249,23 @@ describe('ElasticQueryBuilder', function() { expect(firstLevel.aggs["2"].derivative.buckets_path).to.be("3"); }); + it('with histogram', function() { + var query = builder.build({ + metrics: [ + {id: '1', type: 'count' }, + ], + bucketAggs: [ + {type: 'histogram', field: 'bytes', id: '3', settings: {interval: 10, min_doc_count: 2, missing: 5}} + ], + }); + + var firstLevel = query.aggs["3"]; + expect(firstLevel.histogram.field).to.be('bytes'); + expect(firstLevel.histogram.interval).to.be(10); + expect(firstLevel.histogram.min_doc_count).to.be(2); + expect(firstLevel.histogram.missing).to.be(5); + }); + it('with adhoc filters', function() { var query = builder.build({ metrics: [{type: 'Count', id: '0'}],