From c5eea16cfe48fc3df1222f795adede27c5d6b8d0 Mon Sep 17 00:00:00 2001 From: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com> Date: Mon, 9 Aug 2021 09:19:46 -0400 Subject: [PATCH 01/31] Logs panel: Set default scrolling for ascending order to bottom (#37634) * LogsPanel: When ascending order, scroll to bottom * Add tests * Refactor style * Update scroll position when logs change --- .../app/plugins/panel/logs/LogsPanel.test.tsx | 18 +++++++- public/app/plugins/panel/logs/LogsPanel.tsx | 41 +++++++++++++------ 2 files changed, 45 insertions(+), 14 deletions(-) diff --git a/public/app/plugins/panel/logs/LogsPanel.test.tsx b/public/app/plugins/panel/logs/LogsPanel.test.tsx index 9274d668cda..029b2392dfe 100644 --- a/public/app/plugins/panel/logs/LogsPanel.test.tsx +++ b/public/app/plugins/panel/logs/LogsPanel.test.tsx @@ -1,6 +1,6 @@ import React, { ComponentProps } from 'react'; import { render, screen } from '@testing-library/react'; -import { LoadingState, MutableDataFrame, FieldType } from '@grafana/data'; +import { LoadingState, MutableDataFrame, FieldType, LogsSortOrder } from '@grafana/data'; import { LogsPanel } from './LogsPanel'; type LogsPanelProps = ComponentProps; @@ -38,6 +38,22 @@ describe('LogsPanel', () => { expect(screen.getByText(/common_app/i)).toBeInTheDocument(); expect(screen.getByText(/common_job/i)).toBeInTheDocument(); }); + it('shows common labels on top when descending sort order', () => { + const { container } = setup({ + data: { series: seriesWithCommonLabels }, + options: { showCommonLabels: true, sortOrder: LogsSortOrder.Descending }, + }); + + expect(container.firstChild?.childNodes[0].textContent).toMatch(/^Common labels:common_appcommon_job/); + }); + it('shows common labels on bottom when ascending sort order', () => { + const { container } = setup({ + data: { series: seriesWithCommonLabels }, + options: { showCommonLabels: true, sortOrder: LogsSortOrder.Ascending }, + }); + + expect(container.firstChild?.childNodes[0].textContent).toMatch(/Common labels:common_appcommon_job$/); + }); it('does not show common labels when showCommonLabels is set to false', () => { setup({ data: { series: seriesWithCommonLabels }, options: { showCommonLabels: false } }); diff --git a/public/app/plugins/panel/logs/LogsPanel.tsx b/public/app/plugins/panel/logs/LogsPanel.tsx index 1cfb4db2fda..7446ff246f2 100644 --- a/public/app/plugins/panel/logs/LogsPanel.tsx +++ b/public/app/plugins/panel/logs/LogsPanel.tsx @@ -1,7 +1,7 @@ -import React, { useCallback, useMemo } from 'react'; +import React, { useCallback, useMemo, useRef, useLayoutEffect, useState } from 'react'; import { css } from '@emotion/css'; import { LogRows, CustomScrollbar, LogLabels, useStyles2 } from '@grafana/ui'; -import { PanelProps, Field, Labels, GrafanaTheme2 } from '@grafana/data'; +import { PanelProps, Field, Labels, GrafanaTheme2, LogsSortOrder } from '@grafana/data'; import { Options } from './types'; import { dataFrameToLogsModel, dedupLogRows } from 'app/core/logs_model'; import { getFieldLinksForExplore } from 'app/features/explore/utils/links'; @@ -24,7 +24,10 @@ export const LogsPanel: React.FunctionComponent = ({ }, title, }) => { - const style = useStyles2(getStyles(title)); + const isAscending = sortOrder === LogsSortOrder.Ascending; + const style = useStyles2(getStyles(title, isAscending)); + const [scrollTop, setScrollTop] = useState(0); + const logsContainerRef = useRef(null); // Important to memoize stuff here, as panel rerenders a lot for example when resizing. const [logRows, deduplicatedRows, commonLabels] = useMemo(() => { @@ -35,6 +38,14 @@ export const LogsPanel: React.FunctionComponent = ({ return [logRows, deduplicatedRows, commonLabels]; }, [data, dedupStrategy]); + useLayoutEffect(() => { + if (isAscending && logsContainerRef.current) { + setScrollTop(logsContainerRef.current.offsetHeight); + } else { + setScrollTop(0); + } + }, [isAscending, logRows]); + const getFieldLinks = useCallback( (field: Field, rowIndex: number) => { return getFieldLinksForExplore({ field, rowIndex, range: data.timeRange }); @@ -50,15 +61,17 @@ export const LogsPanel: React.FunctionComponent = ({ ); } + const renderCommonLabels = () => ( +
+ Common labels: + +
+ ); + return ( - -
- {showCommonLabels && ( -
- Common labels: - -
- )} + +
+ {showCommonLabels && !isAscending && renderCommonLabels()} = ({ getFieldLinks={getFieldLinks} logsSortOrder={sortOrder} enableLogDetails={enableLogDetails} + previewLimit={isAscending ? logRows.length : undefined} /> + {showCommonLabels && isAscending && renderCommonLabels()}
); }; -const getStyles = (title: string) => (theme: GrafanaTheme2) => ({ +const getStyles = (title: string, isAscending: boolean) => (theme: GrafanaTheme2) => ({ container: css` margin-bottom: ${theme.spacing(1.5)}; //We can remove this hot-fix when we fix panel menu with no title overflowing top of all panels margin-top: ${theme.spacing(!title ? 2.5 : 0)}; `, labelContainer: css` - margin: ${theme.spacing(0, 0, 0.5, 0.5)}; + margin: ${isAscending ? theme.spacing(0.5, 0, 0.5, 0) : theme.spacing(0, 0, 0.5, 0.5)}; display: flex; align-items: center; `, From fe500315f049f973004eba6c2343be67f31f337b Mon Sep 17 00:00:00 2001 From: Jeremy Price Date: Mon, 9 Aug 2021 15:26:27 +0200 Subject: [PATCH 02/31] Accesscontrol update api examples (#37654) * Fix status, add global flags * Check examples are working, correct where they aren't --- docs/sources/http_api/access_control.md | 52 ++++++++++++++----------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/docs/sources/http_api/access_control.md b/docs/sources/http_api/access_control.md index cbb021dde4b..3937fb72294 100644 --- a/docs/sources/http_api/access_control.md +++ b/docs/sources/http_api/access_control.md @@ -26,10 +26,11 @@ Returns an indicator to check if fine-grained access control is enabled or not. | -------------------- | ---------------------- | | status:accesscontrol | services:accesscontrol | + #### Example request ```http -GET /api/access-control/check +GET /api/access-control/status Accept: application/json Content-Type: application/json ``` @@ -61,6 +62,7 @@ Content-Type: application/json; charset=UTF-8 `GET /api/access-control/roles` Gets all existing roles. The response contains all global and organization local roles, for the organization which user is signed in. + Refer to the [Role scopes]({{< relref "../enterprise/access-control/roles.md#built-in-role-assignments" >}}) for more information. #### Required permissions @@ -254,6 +256,7 @@ Content-Type: application/json; charset=UTF-8 #### Status codes + | Code | Description | | ---- | ---------------------------------------------------------------------------------- | | 200 | Role is updated. | @@ -276,6 +279,7 @@ For example, if a user does not have required permissions for creating users, th | ----------- | -------------------- | | roles:write | permissions:delegate | + #### Example request ```http @@ -284,16 +288,17 @@ Accept: application/json Content-Type: application/json { - "version": 2, - "name": "custom:delete:create:roles", - "description": "My custom role which gives users permissions to delete and create roles", + "version": 3, + "name": "custom:delete:write:roles", + "description": "My custom role which gives users permissions to delete and write roles", + "global": true, "permissions": [ { "action": "roles:delete", "scope": "permissions:delegate" }, - { - "action": "roles:create", + { + "action": "roles:write", "scope": "permissions:delegate" } ] @@ -323,25 +328,27 @@ HTTP/1.1 200 OK Content-Type: application/json; charset=UTF-8 { - "version": 3, - "name": "custom:delete:create:roles", - "description": "My custom role which gives users permissions to delete and create roles", - "permissions": [ + "version":3, + "uid":"jZrmlLCGka", + "name":"custom:delete:write:roles", + "description":"My custom role which gives users permissions to delete and write roles", + "permissions":[ { - "action": "roles:delete", - "scope": "permissions:delegate", - "updated": "2021-05-13T23:19:46.546146+02:00", - "created": "2021-05-13T23:19:46.546146+02:00" + "action":"roles:delete", + "scope":"permissions:delegate", + "updated":"2021-08-06T18:27:40+02:00", + "created":"2021-08-06T18:27:40+02:00" }, - { - "action": "roles:create", - "scope": "permissions:delegate", - "updated": "2021-05-13T23:19:46.546146+02:00", - "created": "2021-05-13T23:19:46.546146+02:00" + { + "action":"roles:write", + "scope":"permissions:delegate", + "updated":"2021-08-06T18:27:41+02:00", + "created":"2021-08-06T18:27:41+02:00" } ], - "updated": "2021-05-13T23:19:46.540987+02:00", - "created": "2021-05-13T23:19:46.540986+02:00" + "updated":"2021-08-06T18:27:41+02:00", + "created":"2021-08-06T18:27:40+02:00", + "global":true } ``` @@ -370,10 +377,11 @@ For example, if a user does not have required permissions for creating users, th | ------------ | -------------------- | | roles:delete | permissions:delegate | + #### Example request ```http -DELETE /api/access-control/roles/jZrmlLCGka?force=true +DELETE /api/access-control/roles/jZrmlLCGka?force=true&global=true Accept: application/json ``` From e0315dabe8da1cf99aecc05f975ffbcffeae8c41 Mon Sep 17 00:00:00 2001 From: Will Browne Date: Mon, 9 Aug 2021 16:07:54 +0200 Subject: [PATCH 03/31] Plugins: Use file extension allowlist when serving plugin assets instead of checking for UNIX executable (#37688) * explicitly check for plugin binary * remove check completely * resolve conflicts * allow module + logos * add tests * simplify * rework to allowlist * add case * remove old stuff * simplify * add case insensitive test --- pkg/api/plugins.go | 27 ++++++++----- pkg/api/plugins_test.go | 89 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 9 deletions(-) create mode 100644 pkg/api/plugins_test.go diff --git a/pkg/api/plugins.go b/pkg/api/plugins.go index 5f44bf939e3..b7bc2e2b47f 100644 --- a/pkg/api/plugins.go +++ b/pkg/api/plugins.go @@ -21,6 +21,14 @@ import ( "github.com/grafana/grafana/pkg/setting" ) +var permittedFileExts = []string{ + ".html", ".xhtml", ".css", ".js", ".json", ".jsonld", ".map", ".mjs", + ".jpeg", ".jpg", ".png", ".gif", ".svg", ".webp", ".ico", + ".woff", ".woff2", ".eot", ".ttf", ".otf", + ".wav", ".mp3", + ".md", ".pdf", ".txt", +} + func (hs *HTTPServer) GetPluginList(c *models.ReqContext) response.Response { typeFilter := c.Query("type") enabledFilter := c.Query("enabled") @@ -292,9 +300,9 @@ func (hs *HTTPServer) GetPluginAssets(c *models.ReqContext) { return } - if shouldExclude(fi) { + if accessForbidden(fi.Name()) { c.JsonApiErr(403, "Plugin file access forbidden", - fmt.Errorf("access is forbidden to executable plugin file %s", pluginFilePath)) + fmt.Errorf("access is forbidden to plugin file %s", pluginFilePath)) return } @@ -441,12 +449,13 @@ func translatePluginRequestErrorToAPIError(err error) response.Response { return response.Error(500, "Plugin request failed", err) } -func shouldExclude(fi os.FileInfo) bool { - normalizedFilename := strings.ToLower(fi.Name()) +func accessForbidden(pluginFilename string) bool { + ext := filepath.Ext(pluginFilename) - isUnixExecutable := fi.Mode()&0111 == 0111 - isWindowsExecutable := strings.HasSuffix(normalizedFilename, ".exe") - isScript := strings.HasSuffix(normalizedFilename, ".sh") - - return isUnixExecutable || isWindowsExecutable || isScript + for _, permittedExt := range permittedFileExts { + if strings.EqualFold(permittedExt, ext) { + return false + } + } + return true } diff --git a/pkg/api/plugins_test.go b/pkg/api/plugins_test.go new file mode 100644 index 00000000000..47ea607cda6 --- /dev/null +++ b/pkg/api/plugins_test.go @@ -0,0 +1,89 @@ +package api + +import ( + "testing" +) + +func Test_accessForbidden(t *testing.T) { + type testCase struct { + filename string + } + tests := []struct { + name string + t testCase + accessForbidden bool + }{ + { + name: ".exe files are forbidden", + t: testCase{ + filename: "test.exe", + }, + accessForbidden: true, + }, + { + name: ".sh files are forbidden", + t: testCase{ + filename: "test.sh", + }, + accessForbidden: true, + }, + { + name: "js is not forbidden", + t: testCase{ + + filename: "module.js", + }, + accessForbidden: false, + }, + { + name: "logos are not forbidden", + t: testCase{ + + filename: "logo.svg", + }, + accessForbidden: false, + }, + { + name: "JPGs are not forbidden", + t: testCase{ + filename: "img/test.jpg", + }, + accessForbidden: false, + }, + { + name: "JPEGs are not forbidden", + t: testCase{ + filename: "img/test.jpeg", + }, + accessForbidden: false, + }, + { + name: "ext case is ignored", + t: testCase{ + filename: "scripts/runThis.SH", + }, + accessForbidden: true, + }, + { + name: "no file ext is forbidden", + t: testCase{ + filename: "scripts/runThis", + }, + accessForbidden: true, + }, + { + name: "empty file ext is forbidden", + t: testCase{ + filename: "scripts/runThis.", + }, + accessForbidden: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := accessForbidden(tt.t.filename); got != tt.accessForbidden { + t.Errorf("accessForbidden() = %v, accessForbidden %v", got, tt.accessForbidden) + } + }) + } +} From acc77d5cefd26a23a5b84d90b88bedd1a061695b Mon Sep 17 00:00:00 2001 From: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Date: Mon, 9 Aug 2021 11:18:30 -0400 Subject: [PATCH 04/31] Fix typo. (#37697) --- docs/sources/datasources/cloudwatch.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/datasources/cloudwatch.md b/docs/sources/datasources/cloudwatch.md index 28dcb244913..5283220d342 100644 --- a/docs/sources/datasources/cloudwatch.md +++ b/docs/sources/datasources/cloudwatch.md @@ -41,7 +41,7 @@ There are three different authentication methods available. `AWS SDK Default` pe ### IAM roles -Currently all access to CloudWatch is done server side by the Grafana backend using the official AWS SDK. Providing you have chosen the _AWS SDK Default_ authentication method, and your Grafana server is running on AWS, you can use IAM Roles to handle authentication automically. +Currently all access to CloudWatch is done server side by the Grafana backend using the official AWS SDK. Providing you have chosen the _AWS SDK Default_ authentication method, and your Grafana server is running on AWS, you can use IAM Roles to handle authentication automatically. See the AWS documentation on [IAM Roles](http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/iam-roles-for-amazon-ec2.html) From 88487806e3078efceb3788e9f93255135dc0cfb0 Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Mon, 9 Aug 2021 17:22:40 +0100 Subject: [PATCH 05/31] Docs: Clarify how to enable "Forward OAuth Identity" for data sources (#37696) * Docs: Clarify how to enable "Forward OAuth Identity" for data sources * Update docs/sources/developers/plugins/add-authentication-for-data-source-plugins.md Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> * Update add-authentication-for-data-source-plugins.md Co-authored-by: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> --- .../plugins/add-authentication-for-data-source-plugins.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/developers/plugins/add-authentication-for-data-source-plugins.md b/docs/sources/developers/plugins/add-authentication-for-data-source-plugins.md index d0c5c2c4a70..bb0b333e998 100644 --- a/docs/sources/developers/plugins/add-authentication-for-data-source-plugins.md +++ b/docs/sources/developers/plugins/add-authentication-for-data-source-plugins.md @@ -285,9 +285,9 @@ func (ds *dataSource) QueryData(ctx context.Context, req *backend.QueryDataReque If your data source uses the same OAuth provider as Grafana itself, for example using [Generic OAuth Authentication]({{< relref "../../auth/generic-oauth.md" >}}), your data source plugin can reuse the access token for the logged-in Grafana user. -To allow Grafana to pass the access token to the plugin, the user needs to enable **Forward OAuth Identity** on the data source configuration page. This tells Grafana to pass the token to the plugin in a Authorization header. Note that your plugin needs to use the [DataSourceHttpSettings](https://developers.grafana.com/ui/latest/index.html?path=/story/data-source-datasourcehttpsettings--basic) component in the configuration editor to expose the setting for your data source plugin. +To allow Grafana to pass the access token to the plugin, update the data source configuration and set the` jsonData.oauthPassThru` property to `true`. The [DataSourceHttpSettings](https://developers.grafana.com/ui/latest/index.html?path=/story/data-source-datasourcehttpsettings--basic) provides a toggle, the **Forward OAuth Identity** option, for this. You can also build an appropriate toggle to set `jsonData.oauthPassThru` in your data source configuration page UI. -The Authorization header is available on the `DataQuery` object on the query data request in your backend data source. +When configured, Grafana will pass the user's token to the plugin in an Authorization header, available on the `QueryDataRequest` object on the `QueryData` request in your backend data source. ```go func (ds *dataSource) QueryData(ctx context.Context, req *backend.QueryDataRequest) (*backend.QueryDataResponse, error) { From e1637f70bd620dde5a9aec9bd42649bfd680a712 Mon Sep 17 00:00:00 2001 From: sam boyer Date: Mon, 9 Aug 2021 12:42:41 -0400 Subject: [PATCH 06/31] Strip nulls from all latest devenv dashboards (#37602) Everything schemaVersion >= 30 --- .../elasticsearch_compare.json | 1247 ++--------------- .../datasource-opentsdb/opentsdb_v2.3.json | 29 +- .../new_features_in_v8.json | 87 +- devenv/dev-dashboards/home.json | 24 +- .../panel-barchart/barchart-autosizing.json | 30 +- .../graph-ng-by-value-color-schemes.json | 24 +- .../panel-graph/graph-ng-nulls.json | 53 +- .../panel-histogram/histogram_tests.json | 26 +- .../panel-timeline/timeline-demo.json | 20 +- .../panel-timeline/timeline-modes.json | 17 +- .../transforms/config-from-query.json | 27 +- .../transforms/rows-to-fields.json | 35 +- 12 files changed, 191 insertions(+), 1428 deletions(-) diff --git a/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_compare.json b/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_compare.json index 82df5a1b18c..1b0698addfc 100644 --- a/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_compare.json +++ b/devenv/dev-dashboards/datasource-elasticsearch/elasticsearch_compare.json @@ -15,7 +15,6 @@ ] }, "editable": true, - "gnetId": null, "graphTooltip": 0, "iteration": 1620904436360, "links": [ @@ -34,7 +33,6 @@ "panels": [ { "collapsed": true, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -112,9 +110,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Basic (version one) - interval auto", "tooltip": { "shared": true, @@ -123,33 +119,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -221,9 +208,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Basic (version two) - interval auto", "tooltip": { "shared": true, @@ -232,33 +217,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -311,8 +287,7 @@ "id": "2", "settings": { "interval": "1m", - "min_doc_count": 50, - "trimEdges": null + "min_doc_count": 50 }, "type": "date_histogram" } @@ -330,9 +305,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Basic (version one) - interval 1m + min doc count 50", "tooltip": { "shared": true, @@ -341,33 +314,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -420,8 +384,7 @@ "id": "2", "settings": { "interval": "1m", - "min_doc_count": 50, - "trimEdges": null + "min_doc_count": 50 }, "type": "date_histogram" } @@ -439,9 +402,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Basic (version two) - interval 1m + min doc count 50", "tooltip": { "shared": true, @@ -450,33 +411,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -548,9 +500,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Basic (version one) - interval 5m + trim edges=10", "tooltip": { "shared": true, @@ -559,33 +509,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -657,9 +598,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Basic (version two) - interval 5m + trim edges=10", "tooltip": { "shared": true, @@ -668,33 +607,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], @@ -703,7 +633,6 @@ }, { "collapsed": true, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -762,8 +691,7 @@ "id": "2", "settings": { "interval": "auto", - "min_doc_count": 0, - "trimEdges": null + "min_doc_count": 0 }, "type": "date_histogram" } @@ -774,7 +702,6 @@ "id": "1", "meta": {}, "settings": { - "missing": null }, "type": "avg" } @@ -785,9 +712,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "avg (version one) - interval auto", "tooltip": { "shared": true, @@ -796,33 +721,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -875,8 +791,7 @@ "id": "2", "settings": { "interval": "auto", - "min_doc_count": 0, - "trimEdges": null + "min_doc_count": 0 }, "type": "date_histogram" } @@ -887,7 +802,6 @@ "id": "1", "meta": {}, "settings": { - "missing": null }, "type": "avg" } @@ -898,9 +812,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "avg (version two) - interval auto", "tooltip": { "shared": true, @@ -909,33 +821,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -988,8 +891,7 @@ "id": "2", "settings": { "interval": "auto", - "min_doc_count": 0, - "trimEdges": null + "min_doc_count": 0 }, "type": "date_histogram" } @@ -1000,7 +902,6 @@ "id": "1", "meta": {}, "settings": { - "missing": null }, "type": "sum" } @@ -1011,9 +912,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "sum (version one) - interval auto", "tooltip": { "shared": true, @@ -1022,33 +921,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -1101,8 +991,7 @@ "id": "2", "settings": { "interval": "auto", - "min_doc_count": 0, - "trimEdges": null + "min_doc_count": 0 }, "type": "date_histogram" } @@ -1113,7 +1002,6 @@ "id": "1", "meta": {}, "settings": { - "missing": null }, "type": "sum" } @@ -1124,9 +1012,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "sum (version two) - interval auto", "tooltip": { "shared": true, @@ -1135,33 +1021,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -1216,8 +1093,7 @@ "id": "2", "settings": { "interval": "auto", - "min_doc_count": 0, - "trimEdges": null + "min_doc_count": 0 }, "type": "date_histogram" } @@ -1237,9 +1113,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "max (version one) - interval auto", "tooltip": { "shared": true, @@ -1248,33 +1122,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -1329,8 +1194,7 @@ "id": "2", "settings": { "interval": "auto", - "min_doc_count": 0, - "trimEdges": null + "min_doc_count": 0 }, "type": "date_histogram" } @@ -1350,9 +1214,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "max (version two) - interval auto", "tooltip": { "shared": true, @@ -1361,33 +1223,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -1442,8 +1295,7 @@ "id": "2", "settings": { "interval": "auto", - "min_doc_count": 0, - "trimEdges": null + "min_doc_count": 0 }, "type": "date_histogram" } @@ -1463,9 +1315,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "min (version one) - interval auto", "tooltip": { "shared": true, @@ -1474,33 +1324,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -1555,8 +1396,7 @@ "id": "2", "settings": { "interval": "auto", - "min_doc_count": 0, - "trimEdges": null + "min_doc_count": 0 }, "type": "date_histogram" } @@ -1576,9 +1416,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "min (version two) - interval auto", "tooltip": { "shared": true, @@ -1587,33 +1425,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -1671,8 +1500,7 @@ "id": "2", "settings": { "interval": "auto", - "min_doc_count": 0, - "trimEdges": null + "min_doc_count": 0 }, "type": "date_histogram" } @@ -1701,9 +1529,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "extended stats (version one) - interval auto", "tooltip": { "shared": true, @@ -1712,33 +1538,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -1796,8 +1613,7 @@ "id": "2", "settings": { "interval": "auto", - "min_doc_count": 0, - "trimEdges": null + "min_doc_count": 0 }, "type": "date_histogram" } @@ -1826,9 +1642,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "extended stats (version two) - interval auto", "tooltip": { "shared": true, @@ -1837,33 +1651,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -1919,8 +1724,7 @@ "id": "2", "settings": { "interval": "auto", - "min_doc_count": 0, - "trimEdges": null + "min_doc_count": 0 }, "type": "date_histogram" } @@ -1948,9 +1752,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "percentiles (version one) - interval auto", "tooltip": { "shared": true, @@ -1959,33 +1761,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -2041,8 +1834,7 @@ "id": "2", "settings": { "interval": "auto", - "min_doc_count": 0, - "trimEdges": null + "min_doc_count": 0 }, "type": "date_histogram" } @@ -2053,7 +1845,6 @@ "id": "1", "meta": {}, "settings": { - "missing": null, "percents": [ 25, 50, @@ -2071,9 +1862,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "percentiles (version two) - interval auto", "tooltip": { "shared": true, @@ -2082,33 +1871,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -2164,8 +1944,7 @@ "id": "2", "settings": { "interval": "auto", - "min_doc_count": 0, - "trimEdges": null + "min_doc_count": 0 }, "type": "date_histogram" } @@ -2185,9 +1964,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "unique count (version one) - interval auto", "tooltip": { "shared": true, @@ -2196,33 +1973,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -2278,8 +2046,7 @@ "id": "2", "settings": { "interval": "auto", - "min_doc_count": 0, - "trimEdges": null + "min_doc_count": 0 }, "type": "date_histogram" } @@ -2299,9 +2066,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "unique count (version two) - interval auto", "tooltip": { "shared": true, @@ -2310,33 +2075,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], @@ -2345,7 +2101,6 @@ }, { "collapsed": true, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -2445,9 +2200,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "count (version one) - interval 5m", "tooltip": { "shared": true, @@ -2456,33 +2209,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -2576,9 +2320,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "count (version two) - interval 5m", "tooltip": { "shared": true, @@ -2587,33 +2329,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -2707,9 +2440,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "avg (version one) - interval 5m", "tooltip": { "shared": true, @@ -2718,33 +2449,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -2838,9 +2560,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "avg (version two) - interval 5m", "tooltip": { "shared": true, @@ -2849,33 +2569,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -2969,9 +2680,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "sum (version one) - interval 5m", "tooltip": { "shared": true, @@ -2980,33 +2689,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -3100,9 +2800,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "sum (version two) - interval 5m", "tooltip": { "shared": true, @@ -3111,33 +2809,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -3231,9 +2920,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "max (version one) - interval 5m", "tooltip": { "shared": true, @@ -3242,33 +2929,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -3362,9 +3040,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "max (version two) - interval 5m", "tooltip": { "shared": true, @@ -3373,33 +3049,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -3493,9 +3160,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "min (version one) - interval auto", "tooltip": { "shared": true, @@ -3504,33 +3169,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -3624,9 +3280,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "min (version two) - interval auto", "tooltip": { "shared": true, @@ -3635,33 +3289,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -3755,9 +3400,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "unique count (version one) - interval 5m", "tooltip": { "shared": true, @@ -3766,33 +3409,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -3886,9 +3520,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "unique count (version two) - interval 5m", "tooltip": { "shared": true, @@ -3897,33 +3529,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], @@ -3932,7 +3555,6 @@ }, { "collapsed": true, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -4027,9 +3649,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "count (version one) - interval auto", "tooltip": { "shared": true, @@ -4038,33 +3658,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -4153,9 +3764,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "count (version two) - interval auto", "tooltip": { "shared": true, @@ -4164,33 +3773,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -4279,9 +3879,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "avg (version one) - interval auto", "tooltip": { "shared": true, @@ -4290,33 +3888,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -4405,9 +3994,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "avg (version two) - interval auto", "tooltip": { "shared": true, @@ -4416,33 +4003,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -4531,9 +4109,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "sum (version one) - interval auto", "tooltip": { "shared": true, @@ -4542,33 +4118,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -4657,9 +4224,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "sum (version two) - interval auto", "tooltip": { "shared": true, @@ -4668,33 +4233,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -4783,9 +4339,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "max (version one) - interval 5m", "tooltip": { "shared": true, @@ -4794,33 +4348,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -4909,9 +4454,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "max (version two) - interval 5m", "tooltip": { "shared": true, @@ -4920,33 +4463,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -5035,9 +4569,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "min (version one) - interval auto", "tooltip": { "shared": true, @@ -5046,33 +4578,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -5161,9 +4684,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "min (version two) - interval auto", "tooltip": { "shared": true, @@ -5172,33 +4693,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -5287,9 +4799,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "unique count (version one) - interval 5m", "tooltip": { "shared": true, @@ -5298,33 +4808,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -5413,9 +4914,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "unique count (version two) - interval 5m", "tooltip": { "shared": true, @@ -5424,33 +4923,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], @@ -5459,7 +4949,6 @@ }, { "collapsed": true, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -5558,9 +5047,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "count (version one) - interval 5m", "tooltip": { "shared": true, @@ -5569,33 +5056,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -5688,9 +5166,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "count (version two) - interval 5m", "tooltip": { "shared": true, @@ -5699,33 +5175,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -5818,9 +5285,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "avg (version one) - interval 5m", "tooltip": { "shared": true, @@ -5829,33 +5294,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -5948,9 +5404,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "avg (version two) - interval 5m", "tooltip": { "shared": true, @@ -5959,33 +5413,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -6078,9 +5523,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "sum (version one) - interval 5m", "tooltip": { "shared": true, @@ -6089,33 +5532,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -6208,9 +5642,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "sum (version two) - interval 5m", "tooltip": { "shared": true, @@ -6219,33 +5651,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -6338,9 +5761,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "max (version one) - interval 5m", "tooltip": { "shared": true, @@ -6349,33 +5770,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -6468,9 +5880,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "max (version two) - interval 5m", "tooltip": { "shared": true, @@ -6479,33 +5889,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -6598,9 +5999,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "min (version one) - interval auto", "tooltip": { "shared": true, @@ -6609,33 +6008,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -6728,9 +6118,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "min (version two) - interval auto", "tooltip": { "shared": true, @@ -6739,33 +6127,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -6858,9 +6237,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "unique count (version one) - interval 5m", "tooltip": { "shared": true, @@ -6869,33 +6246,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -6988,9 +6356,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "unique count (version two) - interval 5m", "tooltip": { "shared": true, @@ -6999,33 +6365,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], @@ -7034,7 +6391,6 @@ }, { "collapsed": true, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -7133,9 +6489,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "count * 1000 (version one) - interval auto", "tooltip": { "shared": true, @@ -7144,33 +6498,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -7263,9 +6608,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "count * 1000 (version two) - interval auto", "tooltip": { "shared": true, @@ -7274,33 +6617,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -7405,9 +6739,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "count * avg (version one) - interval auto", "tooltip": { "shared": true, @@ -7416,33 +6748,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -7547,9 +6870,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "count * avg (version two) - interval auto", "tooltip": { "shared": true, @@ -7558,33 +6879,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], @@ -7593,7 +6905,6 @@ }, { "collapsed": true, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -7726,9 +7037,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "count/average with triple terms agg (version one) - interval auto", "tooltip": { "shared": true, @@ -7737,33 +7046,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -7890,9 +7190,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "count/average with triple terms agg (version two) - interval auto", "tooltip": { "shared": true, @@ -7901,33 +7199,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], @@ -7936,7 +7225,6 @@ }, { "collapsed": true, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -8027,9 +7315,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by Doc Count", "tooltip": { "shared": true, @@ -8038,33 +7324,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -8149,9 +7426,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by Doc Count", "tooltip": { "shared": true, @@ -8160,33 +7435,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -8271,9 +7537,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by Term value", "tooltip": { "shared": true, @@ -8282,33 +7546,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -8393,9 +7648,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by Term value", "tooltip": { "shared": true, @@ -8404,33 +7657,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -8516,9 +7760,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by avg", "tooltip": { "shared": true, @@ -8527,33 +7769,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -8639,9 +7872,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by avg", "tooltip": { "shared": true, @@ -8650,33 +7881,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -8762,9 +7984,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by unique count", "tooltip": { "shared": true, @@ -8773,33 +7993,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -8885,9 +8096,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by unique count", "tooltip": { "shared": true, @@ -8896,33 +8105,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], @@ -8931,7 +8131,6 @@ }, { "collapsed": true, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -9027,9 +8226,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by extended stats (avg)", "tooltip": { "shared": true, @@ -9038,33 +8235,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -9154,9 +8342,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by extended stats (avg)", "tooltip": { "shared": true, @@ -9165,33 +8351,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -9281,9 +8458,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by extended stats (min)", "tooltip": { "shared": true, @@ -9292,33 +8467,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -9408,9 +8574,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by extended stats (min)", "tooltip": { "shared": true, @@ -9419,33 +8583,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -9535,9 +8690,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by extended stats (max)", "tooltip": { "shared": true, @@ -9546,33 +8699,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -9662,9 +8806,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by extended stats (max)", "tooltip": { "shared": true, @@ -9673,33 +8815,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -9789,9 +8922,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by extended stats (sum)", "tooltip": { "shared": true, @@ -9800,33 +8931,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -9916,9 +9038,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by extended stats (sum)", "tooltip": { "shared": true, @@ -9927,33 +9047,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -10043,9 +9154,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by extended stats (count)", "tooltip": { "shared": true, @@ -10054,33 +9163,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -10170,9 +9270,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by extended stats (count)", "tooltip": { "shared": true, @@ -10181,33 +9279,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -10297,9 +9386,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by extended stats (std dev)", "tooltip": { "shared": true, @@ -10308,33 +9395,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -10424,9 +9502,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by extended stats (std dev)", "tooltip": { "shared": true, @@ -10435,33 +9511,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -10551,9 +9618,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by extended stats (std dev upper)", "tooltip": { "shared": true, @@ -10562,33 +9627,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -10678,9 +9734,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by extended stats (std dev upper)", "tooltip": { "shared": true, @@ -10689,33 +9743,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -10805,9 +9850,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by extended stats (std dev lower)", "tooltip": { "shared": true, @@ -10816,33 +9859,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -10932,9 +9966,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by extended stats (std dev lower)", "tooltip": { "shared": true, @@ -10943,33 +9975,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], @@ -10978,7 +10001,6 @@ }, { "collapsed": true, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -11069,9 +10091,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by percentile (25)", "tooltip": { "shared": true, @@ -11080,33 +10100,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -11191,9 +10202,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by percentile (25)", "tooltip": { "shared": true, @@ -11202,33 +10211,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -11313,9 +10313,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by percentile (99)", "tooltip": { "shared": true, @@ -11324,33 +10322,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -11435,9 +10424,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Terms order by percentile (99)", "tooltip": { "shared": true, @@ -11446,33 +10433,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], @@ -11481,7 +10459,6 @@ }, { "collapsed": true, - "datasource": null, "gridPos": { "h": 1, "w": 24, @@ -11533,8 +10510,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -11662,8 +10638,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -11768,8 +10743,6 @@ "text": "gdev-elasticsearch-v5-metrics", "value": "gdev-elasticsearch-v5-metrics" }, - "description": null, - "error": null, "hide": 0, "includeAll": false, "label": "Version One", @@ -11789,8 +10762,6 @@ "text": "gdev-elasticsearch-v56-metrics", "value": "gdev-elasticsearch-v56-metrics" }, - "description": null, - "error": null, "hide": 0, "includeAll": false, "label": "Version Two", @@ -11839,4 +10810,4 @@ "title": "Datasource tests - Elasticsearch comparison", "uid": "fuFWehBmk", "version": 4 -} \ No newline at end of file +} diff --git a/devenv/dev-dashboards/datasource-opentsdb/opentsdb_v2.3.json b/devenv/dev-dashboards/datasource-opentsdb/opentsdb_v2.3.json index b2b4a969ce7..287d5b434f1 100644 --- a/devenv/dev-dashboards/datasource-opentsdb/opentsdb_v2.3.json +++ b/devenv/dev-dashboards/datasource-opentsdb/opentsdb_v2.3.json @@ -13,7 +13,6 @@ ] }, "editable": true, - "gnetId": null, "graphTooltip": 0, "id": 3151, "links": [], @@ -90,9 +89,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "CPU per host", "tooltip": { "shared": true, @@ -101,33 +98,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } }, { @@ -199,9 +187,7 @@ } ], "thresholds": [], - "timeFrom": null, "timeRegions": [], - "timeShift": null, "title": "Login Count per host", "tooltip": { "shared": true, @@ -210,33 +196,24 @@ }, "type": "graph", "xaxis": { - "buckets": null, "mode": "time", - "name": null, "show": true, "values": [] }, "yaxes": [ { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true }, { "format": "short", - "label": null, "logBase": 1, - "max": null, - "min": null, "show": true } ], "yaxis": { - "align": false, - "alignLevel": null + "align": false } } ], @@ -255,4 +232,4 @@ "title": "Datasource tests - OpenTSDB v2.3", "uid": "rZRUGik7k", "version": 3 -} \ No newline at end of file +} diff --git a/devenv/dev-dashboards/datasource-testdata/new_features_in_v8.json b/devenv/dev-dashboards/datasource-testdata/new_features_in_v8.json index e0170fe82c0..2c476f956ca 100644 --- a/devenv/dev-dashboards/datasource-testdata/new_features_in_v8.json +++ b/devenv/dev-dashboards/datasource-testdata/new_features_in_v8.json @@ -13,13 +13,11 @@ ] }, "editable": true, - "gnetId": null, "graphTooltip": 0, "id": 625, "links": [], "panels": [ { - "datasource": null, "gridPos": { "h": 4, "w": 24, @@ -38,13 +36,10 @@ "target": "" } ], - "timeFrom": null, - "timeShift": null, "transparent": true, "type": "text" }, { - "cacheTimeout": null, "datasource": "gdev-testdata", "gridPos": { "h": 8, @@ -107,8 +102,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -166,7 +160,6 @@ "type": "state-timeline" }, { - "cacheTimeout": null, "datasource": "gdev-testdata", "gridPos": { "h": 15, @@ -207,8 +200,7 @@ "mode": "absolute", "steps": [ { - "color": "blue", - "value": null + "color": "blue" }, { "color": "green", @@ -293,8 +285,7 @@ "mode": "absolute", "steps": [ { - "color": "blue", - "value": null + "color": "blue" }, { "color": "green", @@ -343,7 +334,6 @@ "type": "timeseries" }, { - "cacheTimeout": null, "datasource": "gdev-testdata", "gridPos": { "h": 13, @@ -386,8 +376,7 @@ "mode": "absolute", "steps": [ { - "color": "blue", - "value": null + "color": "blue" }, { "color": "#EAB839", @@ -473,8 +462,7 @@ "mode": "absolute", "steps": [ { - "color": "blue", - "value": null + "color": "blue" }, { "color": "#EAB839", @@ -522,7 +510,6 @@ "type": "status-history" }, { - "cacheTimeout": null, "datasource": "gdev-testdata", "gridPos": { "h": 3, @@ -573,8 +560,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -713,8 +699,7 @@ "mode": "absolute", "steps": [ { - "color": "blue", - "value": null + "color": "blue" } ] }, @@ -757,7 +742,6 @@ "type": "barchart" }, { - "cacheTimeout": null, "datasource": "gdev-testdata", "gridPos": { "h": 3, @@ -783,7 +767,6 @@ "type": "text" }, { - "cacheTimeout": null, "datasource": "gdev-testdata", "gridPos": { "h": 6, @@ -848,8 +831,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -924,8 +906,6 @@ "stringInput": "" } ], - "timeFrom": null, - "timeShift": null, "title": "Interpolation mode: smooth", "type": "timeseries" }, @@ -969,8 +949,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -1045,8 +1024,6 @@ "stringInput": "1,20,90,30,5,0" } ], - "timeFrom": null, - "timeShift": null, "title": "Interpolation mode: Step before", "type": "timeseries" }, @@ -1090,8 +1067,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -1166,13 +1142,10 @@ "stringInput": "1,20,90,30,5,0" } ], - "timeFrom": null, - "timeShift": null, "title": "Interpolation mode: Step after", "type": "timeseries" }, { - "cacheTimeout": null, "datasource": "gdev-testdata", "gridPos": { "h": 8, @@ -1240,8 +1213,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -1300,8 +1272,6 @@ "stringInput": "10,11,12,11,10,11,12,12,11,10,9,10,11,12,10,10,11,12,13,11,10,9,10,11,12,13,14,10,10" } ], - "timeFrom": null, - "timeShift": null, "title": "Auto min max", "type": "timeseries" }, @@ -1351,8 +1321,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -1411,8 +1380,6 @@ "stringInput": "10,11,12,11,10,11,12,12,11,10,9,10,11,12,200,10,11,12,13,11,10,9,10,11,12,13,14,10,10" } ], - "timeFrom": null, - "timeShift": null, "title": "Hard min 0, max 30", "type": "timeseries" }, @@ -1462,8 +1429,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -1522,13 +1488,10 @@ "stringInput": "10,11,12,11,10,11,12,12,11,10,9,10,11,12,200,10,11,12,13,11,10,9,10,11,12,13,14,10,10" } ], - "timeFrom": null, - "timeShift": null, "title": "Soft min 0, soft max 30", "type": "timeseries" }, { - "cacheTimeout": null, "datasource": "gdev-testdata", "gridPos": { "h": 5, @@ -1595,8 +1558,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -1769,7 +1731,6 @@ "type": "timeseries" }, { - "cacheTimeout": null, "datasource": "gdev-testdata", "gridPos": { "h": 5, @@ -1844,8 +1805,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -2170,8 +2130,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -2493,8 +2452,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -2573,7 +2531,6 @@ "type": "timeseries" }, { - "cacheTimeout": null, "datasource": "gdev-testdata", "gridPos": { "h": 3, @@ -2620,8 +2577,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -2655,7 +2611,6 @@ "y": 83 }, "id": 49, - "maxDataPoints": null, "options": { "bucketOffset": 0, "bucketSize": 10, @@ -2719,8 +2674,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -2754,7 +2708,6 @@ "y": 83 }, "id": 77, - "maxDataPoints": null, "options": { "showHeader": true }, @@ -2838,4 +2791,4 @@ "title": "New Features in v8.0", "uid": "8mux8PqGz", "version": 17 - } \ No newline at end of file + } diff --git a/devenv/dev-dashboards/home.json b/devenv/dev-dashboards/home.json index a65bd3eeecd..3fd98704fff 100644 --- a/devenv/dev-dashboards/home.json +++ b/devenv/dev-dashboards/home.json @@ -19,12 +19,10 @@ ] }, "editable": true, - "gnetId": null, "graphTooltip": 0, "links": [], "panels": [ { - "datasource": null, "gridPos": { "h": 26, "w": 6, @@ -34,7 +32,6 @@ "id": 7, "links": [], "options": { - "folderId": null, "maxItems": 100, "query": "", "showHeadings": true, @@ -45,13 +42,10 @@ }, "pluginVersion": "8.1.0-pre", "tags": [], - "timeFrom": null, - "timeShift": null, "title": "Starred", "type": "dashlist" }, { - "datasource": null, "gridPos": { "h": 13, "w": 6, @@ -75,13 +69,10 @@ "tags": [ "panel-tests" ], - "timeFrom": null, - "timeShift": null, "title": "tag: panel-tests", "type": "dashlist" }, { - "datasource": null, "gridPos": { "h": 13, "w": 6, @@ -91,7 +82,6 @@ "id": 3, "links": [], "options": { - "folderId": null, "maxItems": 1000, "query": "", "showHeadings": false, @@ -108,13 +98,10 @@ "gdev", "demo" ], - "timeFrom": null, - "timeShift": null, "title": "tag: dashboard-demo", "type": "dashlist" }, { - "datasource": null, "gridPos": { "h": 26, "w": 6, @@ -124,7 +111,6 @@ "id": 5, "links": [], "options": { - "folderId": null, "maxItems": 1000, "query": "", "showHeadings": false, @@ -141,13 +127,10 @@ "gdev", "datasource-test" ], - "timeFrom": null, - "timeShift": null, "title": "Data source tests", "type": "dashlist" }, { - "datasource": null, "gridPos": { "h": 13, "w": 6, @@ -173,13 +156,10 @@ "templating", "gdev" ], - "timeFrom": null, - "timeShift": null, "title": "tag: templating ", "type": "dashlist" }, { - "datasource": null, "gridPos": { "h": 13, "w": 6, @@ -205,8 +185,6 @@ "gdev", "demo" ], - "timeFrom": null, - "timeShift": null, "title": "tag: transforms", "type": "dashlist" } @@ -250,4 +228,4 @@ "title": "Grafana Dev Overview & Home", "uid": "j6T00KRZz", "version": 2 -} \ No newline at end of file +} diff --git a/devenv/dev-dashboards/panel-barchart/barchart-autosizing.json b/devenv/dev-dashboards/panel-barchart/barchart-autosizing.json index 14440800c6a..064fbb20979 100644 --- a/devenv/dev-dashboards/panel-barchart/barchart-autosizing.json +++ b/devenv/dev-dashboards/panel-barchart/barchart-autosizing.json @@ -19,12 +19,10 @@ ] }, "editable": true, - "gnetId": null, "graphTooltip": 0, "links": [], "panels": [ { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -49,8 +47,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -96,7 +93,6 @@ "type": "barchart" }, { - "datasource": null, "description": "Should be smaller given the longer value", "fieldConfig": { "defaults": { @@ -123,8 +119,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -170,7 +165,6 @@ "type": "barchart" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -195,8 +189,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -242,7 +235,6 @@ "type": "barchart" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -267,8 +259,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -339,8 +330,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -386,7 +376,6 @@ "type": "barchart" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -412,8 +401,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -459,7 +447,6 @@ "type": "barchart" }, { - "datasource": null, "description": "", "fieldConfig": { "defaults": { @@ -485,8 +472,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -552,4 +538,4 @@ "title": "BarChart - Panel Tests - Value sizing", "uid": "WFlOM-jM1", "version": 9 -} \ No newline at end of file +} diff --git a/devenv/dev-dashboards/panel-graph/graph-ng-by-value-color-schemes.json b/devenv/dev-dashboards/panel-graph/graph-ng-by-value-color-schemes.json index 8e071d22fab..29e6d92cc0c 100644 --- a/devenv/dev-dashboards/panel-graph/graph-ng-by-value-color-schemes.json +++ b/devenv/dev-dashboards/panel-graph/graph-ng-by-value-color-schemes.json @@ -13,7 +13,6 @@ ] }, "editable": true, - "gnetId": null, "graphTooltip": 0, "links": [], "panels": [ @@ -59,8 +58,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "orange", @@ -104,7 +102,6 @@ "type": "timeseries" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -145,8 +142,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "orange", @@ -192,7 +188,6 @@ "startValue": 1 } ], - "timeFrom": null, "title": "Color bars by discrete thresholds", "type": "timeseries" }, @@ -238,8 +233,7 @@ "mode": "absolute", "steps": [ { - "color": "blue", - "value": null + "color": "blue" }, { "color": "green", @@ -328,8 +322,7 @@ "mode": "absolute", "steps": [ { - "color": "blue", - "value": null + "color": "blue" }, { "color": "green", @@ -418,8 +411,7 @@ "mode": "absolute", "steps": [ { - "color": "blue", - "value": null + "color": "blue" }, { "color": "green", @@ -467,7 +459,6 @@ "type": "timeseries" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -508,8 +499,7 @@ "mode": "absolute", "steps": [ { - "color": "blue", - "value": null + "color": "blue" }, { "color": "green", @@ -590,4 +580,4 @@ "title": "Panel Tests - Graph NG - By value color schemes", "uid": "aBXrJ0R7z", "version": 20 - } \ No newline at end of file + } diff --git a/devenv/dev-dashboards/panel-graph/graph-ng-nulls.json b/devenv/dev-dashboards/panel-graph/graph-ng-nulls.json index 2c86c73b870..1914a99e80d 100644 --- a/devenv/dev-dashboards/panel-graph/graph-ng-nulls.json +++ b/devenv/dev-dashboards/panel-graph/graph-ng-nulls.json @@ -13,7 +13,6 @@ ] }, "editable": true, - "gnetId": null, "graphTooltip": 0, "links": [ { @@ -69,8 +68,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -132,8 +130,6 @@ "target": "" } ], - "timeFrom": null, - "timeShift": null, "title": "Show gaps", "type": "timeseries" }, @@ -180,8 +176,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -251,8 +246,6 @@ "target": "" } ], - "timeFrom": null, - "timeShift": null, "title": "Gaps & null between every point for series B", "type": "timeseries" }, @@ -299,8 +292,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -390,8 +382,6 @@ "target": "" } ], - "timeFrom": null, - "timeShift": null, "title": "No nulls but unaligned series", "type": "timeseries" }, @@ -436,8 +426,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -499,8 +488,6 @@ "target": "" } ], - "timeFrom": null, - "timeShift": null, "title": "Connected", "type": "timeseries" }, @@ -547,8 +534,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -618,8 +604,6 @@ "target": "" } ], - "timeFrom": null, - "timeShift": null, "title": "Same as above but connected", "type": "timeseries" }, @@ -666,8 +650,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -757,8 +740,6 @@ "target": "" } ], - "timeFrom": null, - "timeShift": null, "title": "Same as above but connected", "type": "timeseries" }, @@ -803,8 +784,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -903,8 +883,6 @@ "stringInput": "1,20,90,30,5,0" } ], - "timeFrom": null, - "timeShift": null, "title": "Null values in first series & show gaps ", "transformations": [], "type": "timeseries" @@ -950,8 +928,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -1050,14 +1027,11 @@ "stringInput": "10,25,null,null,50,10" } ], - "timeFrom": null, - "timeShift": null, "title": "Null values in second series show gaps (bugged)", "transformations": [], "type": "timeseries" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -1097,8 +1071,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -1157,13 +1130,10 @@ "stringInput": "1,20,90,null,30,5,0" } ], - "timeFrom": null, - "timeShift": null, "title": "Span nulls below 1hr", "type": "timeseries" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -1205,8 +1175,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -1264,4 +1233,4 @@ "title": "Panel Tests - Graph NG - Gaps and Connected", "uid": "8mmCAF1Mz", "version": 12 -} \ No newline at end of file +} diff --git a/devenv/dev-dashboards/panel-histogram/histogram_tests.json b/devenv/dev-dashboards/panel-histogram/histogram_tests.json index 4b7588efd55..370432cce46 100644 --- a/devenv/dev-dashboards/panel-histogram/histogram_tests.json +++ b/devenv/dev-dashboards/panel-histogram/histogram_tests.json @@ -13,13 +13,11 @@ ] }, "editable": true, - "gnetId": null, "graphTooltip": 0, "id": 632, "links": [], "panels": [ { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -40,8 +38,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -100,8 +97,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -139,7 +135,6 @@ "type": "histogram" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -160,8 +155,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -212,7 +206,6 @@ "type": "histogram" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -233,8 +226,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -285,7 +277,6 @@ "type": "histogram" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -300,8 +291,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -353,7 +343,6 @@ "type": "table" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -368,8 +357,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -439,4 +427,4 @@ "title": "Panel Tests - Histogram", "uid": "UTv--wqMk", "version": 4 - } \ No newline at end of file + } diff --git a/devenv/dev-dashboards/panel-timeline/timeline-demo.json b/devenv/dev-dashboards/panel-timeline/timeline-demo.json index e2aec6e61db..0d6523350ad 100644 --- a/devenv/dev-dashboards/panel-timeline/timeline-demo.json +++ b/devenv/dev-dashboards/panel-timeline/timeline-demo.json @@ -13,12 +13,10 @@ ] }, "editable": true, - "gnetId": null, "graphTooltip": 0, "links": [], "panels": [ { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -55,8 +53,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -113,7 +110,6 @@ "type": "state-timeline" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -151,8 +147,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -207,7 +202,6 @@ "type": "state-timeline" }, { - "datasource": null, "description": "Should show gaps", "fieldConfig": { "defaults": { @@ -246,8 +240,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -301,7 +294,6 @@ "type": "state-timeline" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -319,8 +311,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -339,7 +330,6 @@ "y": 19 }, "id": 4, - "interval": null, "maxDataPoints": 20, "options": { "alignValue": "center", @@ -411,4 +401,4 @@ "title": "Timeline Demo", "uid": "mIJjFy8Kz", "version": 13 -} \ No newline at end of file +} diff --git a/devenv/dev-dashboards/panel-timeline/timeline-modes.json b/devenv/dev-dashboards/panel-timeline/timeline-modes.json index 8600d3274e8..cd613c34ccd 100644 --- a/devenv/dev-dashboards/panel-timeline/timeline-modes.json +++ b/devenv/dev-dashboards/panel-timeline/timeline-modes.json @@ -13,13 +13,11 @@ ] }, "editable": true, - "gnetId": null, "graphTooltip": 0, "id": 329, "links": [], "panels": [ { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -34,8 +32,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -165,7 +162,6 @@ 1616557148000 ], [ - null, 1616558756000 ], [ @@ -173,7 +169,6 @@ 1616561658000 ], [ - null, 1616562446000 ], [ @@ -181,7 +176,6 @@ 1616564104000 ], [ - null, 1616564548000 ], [ @@ -197,7 +191,6 @@ "type": "state-timeline" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -212,8 +205,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -267,7 +259,6 @@ "type": "state-timeline" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -282,8 +273,7 @@ "mode": "percentage", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "#EAB839", @@ -306,7 +296,6 @@ "y": 21 }, "id": 4, - "interval": null, "maxDataPoints": 20, "options": { "colWidth": 0.9, diff --git a/devenv/dev-dashboards/transforms/config-from-query.json b/devenv/dev-dashboards/transforms/config-from-query.json index ce834663b66..2139b024fb6 100644 --- a/devenv/dev-dashboards/transforms/config-from-query.json +++ b/devenv/dev-dashboards/transforms/config-from-query.json @@ -20,12 +20,10 @@ }, "description": "", "editable": true, - "gnetId": null, "graphTooltip": 0, "links": [], "panels": [ { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -64,8 +62,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -122,7 +119,6 @@ "type": "timeseries" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -137,8 +133,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -209,7 +204,6 @@ "type": "table" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -224,8 +218,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -291,7 +284,6 @@ "type": "table" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -306,8 +298,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -377,7 +368,6 @@ "type": "table" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -392,8 +382,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -446,7 +435,6 @@ "type": "table" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -470,8 +458,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -565,4 +552,4 @@ "title": "Transforms - Config from query", "uid": "Juj4_7ink", "version": 1 - } \ No newline at end of file + } diff --git a/devenv/dev-dashboards/transforms/rows-to-fields.json b/devenv/dev-dashboards/transforms/rows-to-fields.json index 4e27d9b94ec..fd3665a8be5 100644 --- a/devenv/dev-dashboards/transforms/rows-to-fields.json +++ b/devenv/dev-dashboards/transforms/rows-to-fields.json @@ -19,7 +19,6 @@ ] }, "editable": true, - "gnetId": null, "graphTooltip": 0, "links": [], "panels": [ @@ -39,8 +38,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -87,8 +85,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -146,7 +143,6 @@ "type": "table" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -157,8 +153,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -209,7 +204,6 @@ "type": "stat" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -221,8 +215,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -286,8 +279,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -334,8 +326,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -393,7 +384,6 @@ "type": "table" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -404,8 +394,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -454,7 +443,6 @@ "type": "bargauge" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -466,8 +454,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" } ] } @@ -530,7 +517,6 @@ "type": "gauge" }, { - "datasource": null, "fieldConfig": { "defaults": { "color": { @@ -541,8 +527,7 @@ "mode": "absolute", "steps": [ { - "color": "green", - "value": null + "color": "green" }, { "color": "red", @@ -612,4 +597,4 @@ "title": "Transforms - Rows to fields", "uid": "PMtIInink", "version": 1 - } \ No newline at end of file + } From 6ae5db5608e92409da9e80ff99bdbfcceef8c38c Mon Sep 17 00:00:00 2001 From: sam boyer Date: Mon, 9 Aug 2021 12:49:58 -0400 Subject: [PATCH 07/31] Adapt dashboard schema to validate on some devenv dashboards (#37594) * Remove null values from JSON * Specify the color field * Add note about openness of custom field's struct * Update schemaVersion * Specify thresholds * Add panel id * Add maxDataPoints and interval * Add mappings, albeit very under-specified * Allow empty string for timezone field This is probably not a good idea - same as allowing nulls. * Allow false for refresh - otherwise, string * Make threshold value optional * Make interval optional * Fix broken and changed decls in ui models * Add models.cue for timeseries panel * Fixups for home dashboard * Add timeShift, timeFrom * Abstract out #Target, rejigger comments --- cue/data/gen.cue | 126 +++++++++++++++--- cue/ui/gen.cue | 6 +- .../src/components/uPlot/models.cue | 5 +- .../app/plugins/panel/timeseries/models.cue | 42 ++++++ 4 files changed, 156 insertions(+), 23 deletions(-) create mode 100644 public/app/plugins/panel/timeseries/models.cue diff --git a/cue/data/gen.cue b/cue/data/gen.cue index d831033e321..c70dc314874 100644 --- a/cue/data/gen.cue +++ b/cue/data/gen.cue @@ -22,7 +22,7 @@ Family: scuemata.#Family & { // Theme of dashboard. style: *"light" | "dark" // Timezone of dashboard, - timezone?: *"browser" | "utc" + timezone?: *"browser" | "utc" | "" // Whether a dashboard is editable or not. editable: bool | *true // 0 for no shared crosshair or tooltip (default). @@ -66,14 +66,62 @@ Family: scuemata.#Family & { showIn: number | *0 }] // Auto-refresh interval. - refresh?: string + refresh?: string | false // Version of the JSON schema, incremented each time a Grafana update brings // changes to said schema. - schemaVersion: number | *25 + // FIXME this is the old schema numbering system, and will be replaced by scuemata + schemaVersion: number | *30 // Version of the dashboard, incremented each time the dashboard is updated. version?: number panels?: [...#Panel] + // TODO docs + #FieldColorModeId: "thresholds" | "palette-classic" | "palette-saturated" | "continuous-GrYlRd" | "fixed" @cuetsy(targetType="enum") + + // TODO docs + #FieldColorSeriesByMode: "min" | "max" | "last" @cuetsy(targetType="type") + + // TODO docs + #FieldColor: { + // The main color scheme mode + mode: #FieldColorModeId | string + // Stores the fixed color value if mode is fixed + fixedColor?: string + // Some visualizations need to know how to assign a series color from by value color schemes + seriesBy?: #FieldColorSeriesByMode + } @cuetsy(targetType="interface") + + // TODO docs + #Threshold: { + // TODO docs + // FIXME the corresponding typescript field is required/non-optional, but nulls currently appear here when serializing -Infinity to JSON + value?: number + // TODO docs + color: string + // TODO docs + // TODO are the values here enumerable into a disjunction? + // Some seem to be listed in typescript comment + state?: string + } @cuetsy(targetType="interface") + + #ThresholdsMode: "absolute" | "percentage" @cuetsy(targetType="enum") + + #ThresholdsConfig: { + mode: #ThresholdsMode + + // Must be sorted by 'value', first value is always -Infinity + steps: [...#Threshold] + } @cuetsy(targetType="interface") + + // Schema for panel targets is specified by datasource + // plugins. We use a placeholder definition, which the Go + // schema loader either left open/as-is with the Base + // variant of the Dashboard and Panel families, or filled + // with types derived from plugins in the Instance variant. + // When working directly from CUE, importers can extend this + // type directly to achieve the same effect. + #Target: {...} + // Dashboard panels. Panels are canonically defined inline // because they share a version timeline with the dashboard // schema; they do not vary independently. We create a separate, @@ -83,6 +131,15 @@ Family: scuemata.#Family & { // The panel plugin type id. type: !="" + // TODO docs + id?: number + + // FIXME this almost certainly has to be changed in favor of scuemata versions + pluginVersion?: string + + // TODO docs + tags?: [...string] + // Internal - the exact major and minor versions of the panel plugin // schema. Hidden and therefore not a part of the data model, but // expected to be filled with panel plugin schema versions so that it's @@ -93,6 +150,9 @@ Family: scuemata.#Family & { // TODO 2-tuple list instead of struct? panelSchema?: { maj: number, min: number } + // TODO docs + targets?: [...#Target] + // Panel title. title?: string // Description. @@ -115,20 +175,33 @@ Family: scuemata.#Family & { static?: bool } // Panel links. - // links?: [..._panelLink] + // FIXME this is temporarily specified as a closed list so + // that validation will pass when no links are present, but + // to force a failure as soon as it's checked against there + // being anything in the list so it can be fixed in + // accordance with that object + links?: [] + // Name of template variable to repeat for. repeat?: string // Direction to repeat in if 'repeat' is set. // "h" for horizontal, "v" for vertical. repeatDirection: *"h" | "v" - // Schema for panel targets is specified by datasource - // plugins. We use a placeholder definition, which the Go - // schema loader either left open/as-is with the Base - // variant of the Dashboard and Panel families, or filled - // with types derived from plugins in the Instance variant. - // When working directly from CUE, importers can extend this - // type directly to achieve the same effect. - targets?: [...{...}] + + // TODO docs + maxDataPoints?: number + + // TODO docs + // TODO tighter constraint + interval?: string + + // TODO docs + // TODO tighter constraint + timeFrom?: string + + // TODO docs + // TODO tighter constraint + timeShift?: string // The values depend on panel type options: {...} @@ -166,17 +239,25 @@ Family: scuemata.#Family & { min?: number max?: number - // // Convert input values into a display string - // mappings?: ValueMapping[]; + // Convert input values into a display string + // + // TODO this one corresponds to a complex type with + // generics on the typescript side. Ouch. Will + // either need special care, or we'll just need to + // accept a very loosely specified schema. It's very + // unlikely we'll be able to translate cue to + // typescript generics in the general case, though + // this particular one *may* be able to work. + mappings?: [...{...}] - // // Map numeric values to states - // thresholds?: ThresholdsConfig; + // Map numeric values to states + thresholds?: #ThresholdsConfig // // Map values to a display color - // color?: FieldColor; + color?: #FieldColor // // Used when reducing field values - // nullValueMode?: NullValueMode; + // nullValueMode?: NullValueMode // // The behavior when clicking on a result links?: [...] @@ -184,10 +265,17 @@ Family: scuemata.#Family & { // Alternative to empty string noValue?: string + // TODO conundrum: marking this struct as open would + // - i think - preclude closed validation of + // plugin-defined config bits. But, marking it + // closed makes it impossible to use just this + // schema (the "base" variant) to validate the base + // components of a dashboard. + // // Can always exist. Valid fields within this are // defined by the panel plugin - that's the // PanelFieldConfig that comes from the plugin. - custom?: {} + custom?: {...} } overrides: [...{ matcher: { diff --git a/cue/ui/gen.cue b/cue/ui/gen.cue index bd790839694..c52a1535b66 100644 --- a/cue/ui/gen.cue +++ b/cue/ui/gen.cue @@ -33,7 +33,7 @@ ScaleDistribution: "linear" | "log" @c GraphGradientMode: "none" | "opacity" | "hue" | "scheme" @cuetsy(targetType="enum") LineStyle: { fill?: "solid" | "dash" | "dot" | "square" - dash?: [number] + dash?: [...number] } @cuetsy(targetType="interface") LineConfig: { lineColor?: string @@ -68,7 +68,7 @@ AxisConfig: { HideSeriesConfig: { tooltip: bool legend: bool - graph: bool + viz: bool } @cuetsy(targetType="interface") LegendPlacement: "bottom" | "right" @cuetsy(targetType="type") LegendDisplayMode: "list" | "table" | "hidden" @cuetsy(targetType="enum") @@ -86,7 +86,7 @@ GraphFieldConfig: LineConfig & FillConfig & PointsConfig & AxisConfig & { VizLegendOptions: { displayMode: LegendDisplayMode placement: LegendPlacement - calcs: [string] + calcs: [...string] } @cuetsy(targetType="interface") VizTooltipOptions: { mode: TooltipDisplayMode diff --git a/packages/grafana-ui/src/components/uPlot/models.cue b/packages/grafana-ui/src/components/uPlot/models.cue index a7394e56206..71c80392870 100644 --- a/packages/grafana-ui/src/components/uPlot/models.cue +++ b/packages/grafana-ui/src/components/uPlot/models.cue @@ -50,9 +50,12 @@ AxisConfig: { HideSeriesConfig: { tooltip: bool legend: bool - graph: bool + viz: bool } @cuetsy(targetType="interface") +// TODO This is the same composition as what's used in the timeseries panel's +// PanelFieldConfig. If that's the only place it's used, it probably shouldn't +// be assembled here, too GraphFieldConfig: LineConfig & FillConfig & PointsConfig & AxisConfig & { drawStyle?: DrawStyle gradientMode?: GraphGradientMode diff --git a/public/app/plugins/panel/timeseries/models.cue b/public/app/plugins/panel/timeseries/models.cue new file mode 100644 index 00000000000..6fe9d4b43a3 --- /dev/null +++ b/public/app/plugins/panel/timeseries/models.cue @@ -0,0 +1,42 @@ +// Copyright 2021 Grafana Labs +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package grafanaschema + +import ( + ui "github.com/grafana/grafana/cue/ui:grafanaschema" +) + +Family: { + lineages: [ + [ + { + PanelOptions: { + legend: ui.VizLegendOptions + tooltip: ui.VizTooltipOptions + } + PanelFieldConfig: { + ui.LineConfig + ui.FillConfig + ui.PointsConfig + ui.AxisConfig + drawStyle?: ui.DrawStyle + gradientMode?: ui.GraphGradientMode + hideFrom?: ui.HideSeriesConfig + } + } + ] + ] + migrations: [] +} From 2bc2315e99c0e6cb6738153f4f43b8c8d6a7564a Mon Sep 17 00:00:00 2001 From: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Date: Mon, 9 Aug 2021 13:37:11 -0400 Subject: [PATCH 08/31] Updated note by adding the word "longer". (#37707) --- docs/sources/sharing/share-panel.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/sharing/share-panel.md b/docs/sources/sharing/share-panel.md index 8d016f2b1f1..00e224b0f5f 100644 --- a/docs/sources/sharing/share-panel.md +++ b/docs/sources/sharing/share-panel.md @@ -62,7 +62,7 @@ If you created a snapshot by mistake, click **delete snapshot** to remove the sn You can embed a panel using an iframe on another web site. A viewer must be signed into Grafana to view the graph. -**> Note:** As of Grafana 8.0, anonymous access permission is no available for Grafana Cloud. +**> Note:** As of Grafana 8.0, anonymous access permission is no longer available for Grafana Cloud. ![Panel share embed](/static/img/docs/sharing/share-panel-embedded-link-8-0.png) From 72b1b0e90ec9a39239c2d5a5ba0569e005554f62 Mon Sep 17 00:00:00 2001 From: "Grot (@grafanabot)" <43478413+grafanabot@users.noreply.github.com> Date: Mon, 9 Aug 2021 19:53:44 +0200 Subject: [PATCH 09/31] ReleaseNotes: Updated changelog and release notes for 8.1.1 (#37692) * ReleaseNotes: Updated changelog and release notes for 8.1.1 * Update _index.md * Update CHANGELOG.md Co-authored-by: Leonard Gram --- CHANGELOG.md | 11 +++++++++++ docs/sources/release-notes/_index.md | 1 + docs/sources/release-notes/release-notes-8-1-1.md | 14 ++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 docs/sources/release-notes/release-notes-8-1-1.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d3e0fb182a..9533c8acc16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,14 @@ + + + +# 8.1.1 (2021-08-09) + +### Bug fixes + +* **CloudWatch Logs:** Fix crash when no region is selected. [#37639](https://github.com/grafana/grafana/pull/37639), [@aocenas](https://github.com/aocenas) +* **Reporting:** Fix timezone parsing for scheduler (enterprise) + + # 8.1.0 (2021-08-05) diff --git a/docs/sources/release-notes/_index.md b/docs/sources/release-notes/_index.md index 43035fed2ad..8f713d5d1b0 100644 --- a/docs/sources/release-notes/_index.md +++ b/docs/sources/release-notes/_index.md @@ -8,6 +8,7 @@ weight = 10000 Here you can find detailed release notes that list everything that is included in every release as well as notices about deprecations, breaking changes as well as changes that relate to plugin development. +- [Release notes for 8.1.1]({{< relref "release-notes-8-1-1" >}}) - [Release notes for 8.1.0]({{< relref "release-notes-8-1-0" >}}) - [Release notes for 8.1.0-beta3]({{< relref "release-notes-8-1-0-beta3" >}}) - [Release notes for 8.1.0-beta2]({{< relref "release-notes-8-1-0-beta2" >}}) diff --git a/docs/sources/release-notes/release-notes-8-1-1.md b/docs/sources/release-notes/release-notes-8-1-1.md new file mode 100644 index 00000000000..b5e51b3cd23 --- /dev/null +++ b/docs/sources/release-notes/release-notes-8-1-1.md @@ -0,0 +1,14 @@ ++++ +title = "Release notes for Grafana 8.1.1" +[_build] +list = false ++++ + + + +# Release notes for Grafana 8.1.1 + +### Bug fixes + +* **CloudWatch Logs:** Fix crash when no region is selected. [#37639](https://github.com/grafana/grafana/pull/37639), [@aocenas](https://github.com/aocenas) + From b556bafc4d3127c490bfca4670b9a2169f302508 Mon Sep 17 00:00:00 2001 From: achatterjee-grafana <70489351+achatterjee-grafana@users.noreply.github.com> Date: Mon, 9 Aug 2021 14:37:21 -0400 Subject: [PATCH 10/31] Updated note as requested. Also adjusted the weight of some of the topics to list data sources alphabetically in TOC. (#37713) --- docs/sources/datasources/alertmanager.md | 6 ++---- docs/sources/datasources/elasticsearch.md | 2 +- docs/sources/datasources/google-cloud-monitoring/_index.md | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/docs/sources/datasources/alertmanager.md b/docs/sources/datasources/alertmanager.md index ccfbc2f974d..4c181b91057 100644 --- a/docs/sources/datasources/alertmanager.md +++ b/docs/sources/datasources/alertmanager.md @@ -3,16 +3,14 @@ title = "Alertmanager" description = "Guide for using Alertmanager in Grafana" keywords = ["grafana", "prometheus", "guide"] aliases = ["/docs/grafana/latest/features/datasources/alertmanager"] -weight = 1300 +weight = 150 +++ # Alertmanager data source Grafana includes built-in support for Prometheus Alertmanager. It is presently in alpha and not accessible unless [alpha plugins are enabled in Grafana settings](https://grafana.com/docs/grafana/latest/administration/configuration/#enable_alpha). Once you add it as a data source, you can use the [Grafana alerting UI](https://grafana.com/docs/grafana/latest/alerting/) to manage silences, contact points as well as notification policies. A drop down option in these pages allows you to switch between Grafana and any configured Alertmanager data sources . -> **Note:** New in Grafana 8.0. - -> **Note:** Currently only the [Cortex implementation of Prometheus alertmanager](https://cortexmetrics.io/docs/proposals/scalable-alertmanager/) is supported. +> **Note:** Currently, the [Cortex implementation of Prometheus Alertmanager](https://cortexmetrics.io/docs/proposals/scalable-alertmanager/) is required to edit rules. ## Provision the Alertmanager data source diff --git a/docs/sources/datasources/elasticsearch.md b/docs/sources/datasources/elasticsearch.md index 1c5eeb1d31e..b7aad264c7a 100644 --- a/docs/sources/datasources/elasticsearch.md +++ b/docs/sources/datasources/elasticsearch.md @@ -3,7 +3,7 @@ title = "Elasticsearch" description = "Guide for using Elasticsearch in Grafana" keywords = ["grafana", "elasticsearch", "guide"] aliases = ["/docs/grafana/latest/features/datasources/elasticsearch"] -weight = 400 +weight = 325 +++ # Using Elasticsearch in Grafana diff --git a/docs/sources/datasources/google-cloud-monitoring/_index.md b/docs/sources/datasources/google-cloud-monitoring/_index.md index e4764534b3f..c93ce340c77 100644 --- a/docs/sources/datasources/google-cloud-monitoring/_index.md +++ b/docs/sources/datasources/google-cloud-monitoring/_index.md @@ -3,7 +3,7 @@ title = "Google Cloud Monitoring" description = "Guide for using Google Cloud Monitoring in Grafana" keywords = ["grafana", "stackdriver", "google", "guide", "cloud", "monitoring"] aliases = ["/docs/grafana/latest/features/datasources/stackdriver", "/docs/grafana/next/datasources/cloudmonitoring/", "/docs/grafana/next/features/datasources/cloudmonitoring/"] -weight = 200 +weight = 350 +++ # Using Google Cloud Monitoring in Grafana From 7d503d43319ca1d12584fa2f905b8c5d7ff6fdce Mon Sep 17 00:00:00 2001 From: Leonard Gram Date: Mon, 9 Aug 2021 21:01:38 +0200 Subject: [PATCH 11/31] Update latest to v8.1.1 (#37715) --- latest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/latest.json b/latest.json index a8345d75e63..b03a91f50c7 100644 --- a/latest.json +++ b/latest.json @@ -1,4 +1,4 @@ { - "stable": "8.1.0", - "testing": "8.1.0" + "stable": "8.1.1", + "testing": "8.1.1" } From 33aeee60ff1d8cedbe64f736963fe2f612525018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Bedi?= Date: Tue, 10 Aug 2021 07:34:35 +0200 Subject: [PATCH 12/31] Toolkit: Fix matchMedia not found error (#37643) --- .../src/config/jest.plugin.config.ts | 2 +- packages/grafana-toolkit/src/config/matchMedia.js | 14 ++++++++++++++ .../features/alerting/unified/AmRoutes.test.tsx | 14 -------------- 3 files changed, 15 insertions(+), 15 deletions(-) create mode 100644 packages/grafana-toolkit/src/config/matchMedia.js diff --git a/packages/grafana-toolkit/src/config/jest.plugin.config.ts b/packages/grafana-toolkit/src/config/jest.plugin.config.ts index 86da5b70de6..f8a34d5b819 100644 --- a/packages/grafana-toolkit/src/config/jest.plugin.config.ts +++ b/packages/grafana-toolkit/src/config/jest.plugin.config.ts @@ -50,7 +50,7 @@ export const jestConfig = (baseDir: string = process.cwd()) => { const setupFile = getSetupFile(setupFilePath); const shimsFile = getSetupFile(shimsFilePath); - const setupFiles = [setupFile, shimsFile, 'jest-canvas-mock'].filter((f) => f); + const setupFiles = [setupFile, shimsFile, `${__dirname}/matchMedia.js`, 'jest-canvas-mock'].filter((f) => f); const defaultJestConfig = { preset: 'ts-jest', verbose: false, diff --git a/packages/grafana-toolkit/src/config/matchMedia.js b/packages/grafana-toolkit/src/config/matchMedia.js new file mode 100644 index 00000000000..f4489dec143 --- /dev/null +++ b/packages/grafana-toolkit/src/config/matchMedia.js @@ -0,0 +1,14 @@ +// https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom +Object.defineProperty(global, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // deprecated + removeListener: jest.fn(), // deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), +}); diff --git a/public/app/features/alerting/unified/AmRoutes.test.tsx b/public/app/features/alerting/unified/AmRoutes.test.tsx index 0f103cc2964..91a379a106e 100644 --- a/public/app/features/alerting/unified/AmRoutes.test.tsx +++ b/public/app/features/alerting/unified/AmRoutes.test.tsx @@ -15,20 +15,6 @@ import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from './utils/datasource'; import userEvent from '@testing-library/user-event'; import { selectOptionInTest } from '@grafana/ui'; -Object.defineProperty(window, 'matchMedia', { - writable: true, - value: jest.fn().mockImplementation((query) => ({ - matches: false, - media: query, - onchange: null, - addListener: jest.fn(), // deprecated - removeListener: jest.fn(), // deprecated - addEventListener: jest.fn(), - removeEventListener: jest.fn(), - dispatchEvent: jest.fn(), - })), -}); - jest.mock('./api/alertmanager'); jest.mock('./utils/config'); From 7e63118ea91bd9d3500c3b4fcdb11073042d7f8e Mon Sep 17 00:00:00 2001 From: Julien Duchesne Date: Tue, 10 Aug 2021 02:16:09 -0400 Subject: [PATCH 13/31] Run builds on single-build agents (#37702) This is an effort to reduce cache errors when multiple agents try to build the yarn cache at the same time https://github.com/grafana/deployment_tools/issues/13329 --- .drone.yml | 35 ++++++++++++++++++++++++++++++++++- scripts/lib.star | 21 +++++++++++++++------ 2 files changed, 49 insertions(+), 7 deletions(-) diff --git a/.drone.yml b/.drone.yml index 10a2ebb7746..aec33809cfa 100644 --- a/.drone.yml +++ b/.drone.yml @@ -235,6 +235,9 @@ services: MYSQL_ROOT_PASSWORD: rootpass MYSQL_USER: grafana +node: + type: no-parallel + trigger: event: - pull_request @@ -563,6 +566,9 @@ services: MYSQL_ROOT_PASSWORD: rootpass MYSQL_USER: grafana +node: + type: no-parallel + trigger: branch: - main @@ -663,6 +669,9 @@ steps: depends_on: - initialize +node: + type: no-parallel + trigger: branch: - main @@ -1005,6 +1014,9 @@ services: MYSQL_ROOT_PASSWORD: rootpass MYSQL_USER: grafana +node: + type: no-parallel + trigger: ref: - refs/tags/v* @@ -1477,6 +1489,9 @@ services: image_pull_secrets: - dockerconfigjson +node: + type: no-parallel + trigger: ref: - refs/tags/v* @@ -1617,6 +1632,9 @@ steps: depends_on: - initialize +node: + type: no-parallel + trigger: ref: - refs/tags/v* @@ -1948,6 +1966,9 @@ services: MYSQL_ROOT_PASSWORD: rootpass MYSQL_USER: grafana +node: + type: no-parallel + trigger: event: - custom @@ -2414,6 +2435,9 @@ services: image_pull_secrets: - dockerconfigjson +node: + type: no-parallel + trigger: event: - custom @@ -2554,6 +2578,9 @@ steps: depends_on: - initialize +node: + type: no-parallel + trigger: event: - custom @@ -2860,6 +2887,9 @@ services: MYSQL_ROOT_PASSWORD: rootpass MYSQL_USER: grafana +node: + type: no-parallel + trigger: ref: - refs/heads/v* @@ -3325,6 +3355,9 @@ services: image_pull_secrets: - dockerconfigjson +node: + type: no-parallel + trigger: ref: - refs/heads/v* @@ -3496,6 +3529,6 @@ get: --- kind: signature -hmac: 68edb93a18f2e16f8a9b2bf3d21073e181e56d2420feec37ae80b121fc2faeeb +hmac: 4f23649a1678c66fb96af929675bcf569cca3b208d425eace86150d981ee9fbb ... diff --git a/scripts/lib.star b/scripts/lib.star index d1935484414..1d24979514b 100644 --- a/scripts/lib.star +++ b/scripts/lib.star @@ -17,20 +17,28 @@ def pipeline( ): if platform != 'windows': platform_conf = { - 'os': 'linux', - 'arch': 'amd64', + 'platform': { + 'os': 'linux', + 'arch': 'amd64' + }, + # A shared cache is used on the host + # To avoid issues with parallel builds, we run this repo on single build agents + 'node': { + 'type': 'no-parallel' + } } else: platform_conf = { - 'os': 'windows', - 'arch': 'amd64', - 'version': '1809', + 'platform': { + 'os': 'windows', + 'arch': 'amd64', + 'version': '1809', + } } pipeline = { 'kind': 'pipeline', 'type': 'docker', - 'platform': platform_conf, 'name': name, 'trigger': trigger, 'services': services, @@ -39,6 +47,7 @@ def pipeline( ) + steps, 'depends_on': depends_on, } + pipeline.update(platform_conf) if edition in ('enterprise', 'enterprise2'): pipeline['image_pull_secrets'] = [pull_secret] From a02f9be0c673963ca56339a6cf65152b5d81d462 Mon Sep 17 00:00:00 2001 From: Ivana Huckova <30407135+ivanahuckova@users.noreply.github.com> Date: Tue, 10 Aug 2021 03:01:57 -0400 Subject: [PATCH 14/31] Explore: Fix showing of full log context (#37442) * Fix log context * Update to auto values insted of unset * Update comment * Fix redundant left margin for non-wrapped logs * Remove unused css styling * Adjust width and height --- .../src/components/Logs/LogRowContext.tsx | 51 ++++++++++++++----- .../src/components/Logs/LogRowMessage.tsx | 14 ++++- .../src/components/Logs/getLogRowStyles.ts | 3 +- public/app/features/explore/Logs.tsx | 7 +-- 4 files changed, 55 insertions(+), 20 deletions(-) diff --git a/packages/grafana-ui/src/components/Logs/LogRowContext.tsx b/packages/grafana-ui/src/components/Logs/LogRowContext.tsx index 0f1981f4cfa..f5f2a38667d 100644 --- a/packages/grafana-ui/src/components/Logs/LogRowContext.tsx +++ b/packages/grafana-ui/src/components/Logs/LogRowContext.tsx @@ -4,7 +4,7 @@ import { css, cx } from '@emotion/css'; import { Alert } from '../Alert/Alert'; import { LogRowContextRows, LogRowContextQueryErrors, HasMoreContextRows } from './LogRowContextProvider'; -import { useStyles } from '../../themes/ThemeContext'; +import { useStyles, useTheme } from '../../themes/ThemeContext'; import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar'; import { List } from '../List/List'; import { ClickOutsideWrapper } from '../ClickOutsideWrapper/ClickOutsideWrapper'; @@ -13,18 +13,41 @@ import { LogMessageAnsi } from './LogMessageAnsi'; interface LogRowContextProps { row: LogRowModel; context: LogRowContextRows; + wrapLogMessage: boolean; errors?: LogRowContextQueryErrors; hasMoreContextRows?: HasMoreContextRows; onOutsideClick: () => void; onLoadMoreContext: () => void; } -const getLogRowContextStyles = (theme: GrafanaTheme) => { +const getLogRowContextStyles = (theme: GrafanaTheme, wrapLogMessage?: boolean) => { + /** + * This is workaround for displaying uncropped context when we have unwrapping log messages. + * We are using margins to correctly position context. Because non-wrapped logs have always 1 line of log + * and 1 line of Show/Hide context switch. Therefore correct position can be reliably achieved by margins. + * We also adjust width to 75%. + */ + + const afterContext = wrapLogMessage + ? css` + top: -250px; + ` + : css` + margin-top: -250px; + width: 75%; + `; + + const beforeContext = wrapLogMessage + ? css` + top: 100%; + ` + : css` + margin-top: 40px; + width: 75%; + `; return { commonStyles: css` position: absolute; - width: calc(100% + 20px); - left: -13px; height: 250px; z-index: ${theme.zIndex.dropdown}; overflow: hidden; @@ -32,6 +55,7 @@ const getLogRowContextStyles = (theme: GrafanaTheme) => { box-shadow: 0 0 10px ${theme.colors.dropdownShadow}; border: 1px solid ${theme.colors.bg2}; border-radius: ${theme.border.radius.md}; + width: 100%; `, header: css` height: 30px; @@ -44,6 +68,8 @@ const getLogRowContextStyles = (theme: GrafanaTheme) => { height: 220px; padding: 10px; `, + afterContext, + beforeContext, }; }; @@ -56,7 +82,7 @@ interface LogRowContextGroupHeaderProps { } interface LogRowContextGroupProps extends LogRowContextGroupHeaderProps { rows: Array; - className: string; + className?: string; error?: string; } @@ -122,11 +148,11 @@ export const LogRowContextGroup: React.FunctionComponent +
{/* When displaying "after" context */} {shouldScrollToBottom && !error && }
- +
{!error && ( = ({ onOutsideClick, onLoadMoreContext, hasMoreContextRows, + wrapLogMessage, }) => { useEffect(() => { const handleEscKeyDown = (e: KeyboardEvent): void => { @@ -173,6 +200,8 @@ export const LogRowContext: React.FunctionComponent = ({ document.removeEventListener('keydown', handleEscKeyDown, false); }; }, [onOutsideClick]); + const theme = useTheme(); + const { afterContext, beforeContext } = getLogRowContextStyles(theme, wrapLogMessage); return ( @@ -184,9 +213,7 @@ export const LogRowContext: React.FunctionComponent = ({ rows={context.after} error={errors && errors.after} row={row} - className={css` - top: -250px; - `} + className={afterContext} shouldScrollToBottom canLoadMoreRows={hasMoreContextRows ? hasMoreContextRows.after : false} onLoadMoreContext={onLoadMoreContext} @@ -200,9 +227,7 @@ export const LogRowContext: React.FunctionComponent = ({ row={row} rows={context.before} error={errors && errors.before} - className={css` - top: 100%; - `} + className={beforeContext} /> )}
diff --git a/packages/grafana-ui/src/components/Logs/LogRowMessage.tsx b/packages/grafana-ui/src/components/Logs/LogRowMessage.tsx index c190de58ce7..96bd173f877 100644 --- a/packages/grafana-ui/src/components/Logs/LogRowMessage.tsx +++ b/packages/grafana-ui/src/components/Logs/LogRowMessage.tsx @@ -51,6 +51,10 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => { label: verticalScroll; white-space: pre; `, + contextNewline: css` + display: block; + margin-left: 0px; + `, }; }); @@ -124,12 +128,15 @@ class UnThemedLogRowMessage extends PureComponent { return ( -
+
{contextIsOpen && context && ( { @@ -143,7 +150,10 @@ class UnThemedLogRowMessage extends PureComponent { {renderLogMessage(hasAnsi, restructuredEntry, highlights, highlightClassName)} {showContextToggle?.(row) && ( - + {contextIsOpen ? 'Hide' : 'Show'} context )} diff --git a/packages/grafana-ui/src/components/Logs/getLogRowStyles.ts b/packages/grafana-ui/src/components/Logs/getLogRowStyles.ts index 9fd2b6d2539..0a0b1ebabb7 100644 --- a/packages/grafana-ui/src/components/Logs/getLogRowStyles.ts +++ b/packages/grafana-ui/src/components/Logs/getLogRowStyles.ts @@ -48,13 +48,13 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo font-family: ${theme.typography.fontFamily.monospace}; font-size: ${theme.typography.size.sm}; width: 100%; - overflow: hidden; `, context: css` label: context; visibility: hidden; white-space: nowrap; position: relative; + margin-left: 10px; `, logsRow: css` label: logs-row; @@ -66,7 +66,6 @@ export const getLogRowStyles = stylesFactory((theme: GrafanaTheme, logLevel?: Lo .log-row-context { visibility: visible; z-index: 1; - margin-left: 10px; text-decoration: underline; &:hover { color: ${theme.palette.yellow}; diff --git a/public/app/features/explore/Logs.tsx b/public/app/features/explore/Logs.tsx index b6850cb76bc..dd4e4874896 100644 --- a/public/app/features/explore/Logs.tsx +++ b/public/app/features/explore/Logs.tsx @@ -283,7 +283,7 @@ export class UnthemedLogs extends PureComponent { forceEscape, } = this.state; - const styles = getStyles(theme); + const styles = getStyles(theme, wrapLogMessage); const hasData = logRows && logRows.length > 0; const hasUnescapedContent = this.checkUnescapedContent(logRows); @@ -420,7 +420,7 @@ export class UnthemedLogs extends PureComponent { export const Logs = withTheme2(UnthemedLogs); -const getStyles = (theme: GrafanaTheme2) => { +const getStyles = (theme: GrafanaTheme2, wrapLogMessage: boolean) => { return { noData: css` > * { @@ -450,7 +450,8 @@ const getStyles = (theme: GrafanaTheme2) => { justify-content: space-between; `, logRows: css` - overflow-x: scroll; + overflow-x: ${wrapLogMessage ? 'unset' : 'scroll'}; + overflow-y: visible; width: 100%; `, infoText: css` From 377b323fafcbf07ba898cda31086fc95c209cbaa Mon Sep 17 00:00:00 2001 From: Serge Zaitsev Date: Tue, 10 Aug 2021 09:03:01 +0200 Subject: [PATCH 15/31] truncate float64 values to a lower precision to look the same on all platforms (#37677) --- .../testdata/usa-timeseries-wide.txt | 34 +-- .../testdata/usa-timeseries.txt | 204 +++++++++--------- .../testdata/usa-values-as-fields.txt | 32 +-- .../testdata/usa-values-as-labeled-fields.txt | 32 +-- .../testdata/usa-values-as-rows.txt | 34 +-- pkg/tsdb/testdatasource/usa_stats.go | 5 +- 6 files changed, 172 insertions(+), 169 deletions(-) diff --git a/pkg/tsdb/testdatasource/testdata/usa-timeseries-wide.txt b/pkg/tsdb/testdatasource/testdata/usa-timeseries-wide.txt index 53a51e8d091..e6a63a4a612 100644 --- a/pkg/tsdb/testdatasource/testdata/usa-timeseries-wide.txt +++ b/pkg/tsdb/testdatasource/testdata/usa-timeseries-wide.txt @@ -3,23 +3,23 @@ Frame[0] Name: Dimensions: 7 Fields by 10 Rows -+-------------------------------+----------------------+----------------------+----------------------+----------------------+----------------------+----------------------+ -| Name: Time | Name: foo | Name: foo | Name: foo | Name: bar | Name: bar | Name: bar | -| Labels: | Labels: state=CA | Labels: state=OR | Labels: state=NV | Labels: state=CA | Labels: state=OR | Labels: state=NV | -| Type: []time.Time | Type: []float64 | Type: []float64 | Type: []float64 | Type: []float64 | Type: []float64 | Type: []float64 | -+-------------------------------+----------------------+----------------------+----------------------+----------------------+----------------------+----------------------+ -| 2020-01-10 23:00:00 +0000 UTC | 0.7591864109375384 | 0.9882682601465907 | 0 | 0.6508732545187114 | -0.1527280131044415 | 1 | -| 2020-01-10 23:00:01 +0000 UTC | 0.9913874643906261 | 0.7446917214252602 | 0.5458434494486994 | 0.13096142733310906 | -0.6674086005144695 | 0.8378871813639024 | -| 2020-01-10 23:00:02 +0000 UTC | 0.9021552854179972 | 0.25966703475349645 | 0.9147104586490411 | -0.4314114520876468 | -0.9656982091017495 | 0.40410985738788996 | -| 2020-01-10 23:00:03 +0000 UTC | 0.520421234112239 | -0.309548361739801 | 0.9870048864743552 | -0.8539096785287623 | -0.9508837004303972 | -0.16069024262768705 | -| 2020-01-10 23:00:04 +0000 UTC | -0.03004672347354234 | -0.7784002433814474 | 0.7392870259917509 | -0.9995484952759943 | -0.6277683180152559 | -0.6733904463238785 | -| 2020-01-10 23:00:05 +0000 UTC | -0.5707727629931729 | -0.994874810059912 | 0.2518733583799049 | -0.8211080641579032 | -0.10111435263232425 | -0.9677602034277024 | -| 2020-01-10 23:00:06 +0000 UTC | -0.9264396396937303 | -0.8887854574406474 | -0.31720410936455373 | -0.37644334766887727 | 0.4583234781701883 | -0.9483572918485101 | -| 2020-01-10 23:00:07 +0000 UTC | -0.981731033820365 | -0.4945290734844293 | -0.7834358726049309 | 0.19027395311496903 | 0.8691610871861625 | -0.6214726329580013 | -| 2020-01-10 23:00:08 +0000 UTC | -0.7187200578767007 | 0.060066314471906294 | -0.9956576407880757 | 0.6952995601938146 | 0.998194388817009 | -0.09309061359945539 | -| 2020-01-10 23:00:09 +0000 UTC | -0.22268161314765392 | 0.5951866633399958 | -0.8850616758817763 | 0.9748912242737435 | 0.8035874786121313 | 0.46547376927743367 | -+-------------------------------+----------------------+----------------------+----------------------+----------------------+----------------------+----------------------+ ++-------------------------------+------------------+------------------+------------------+------------------+------------------+------------------+ +| Name: Time | Name: foo | Name: foo | Name: foo | Name: bar | Name: bar | Name: bar | +| Labels: | Labels: state=CA | Labels: state=OR | Labels: state=NV | Labels: state=CA | Labels: state=OR | Labels: state=NV | +| Type: []time.Time | Type: []float64 | Type: []float64 | Type: []float64 | Type: []float64 | Type: []float64 | Type: []float64 | ++-------------------------------+------------------+------------------+------------------+------------------+------------------+------------------+ +| 2020-01-10 23:00:00 +0000 UTC | 0.7591864109 | 0.9882682601 | 0 | 0.6508732545 | -0.1527280131 | 1 | +| 2020-01-10 23:00:01 +0000 UTC | 0.9913874643 | 0.7446917214 | 0.5458434494 | 0.1309614273 | -0.6674086005 | 0.8378871813 | +| 2020-01-10 23:00:02 +0000 UTC | 0.9021552854 | 0.2596670347 | 0.9147104586 | -0.431411452 | -0.9656982091 | 0.4041098573 | +| 2020-01-10 23:00:03 +0000 UTC | 0.5204212341 | -0.3095483617 | 0.9870048864 | -0.8539096785 | -0.9508837004 | -0.1606902426 | +| 2020-01-10 23:00:04 +0000 UTC | -0.0300467234 | -0.7784002433 | 0.7392870259 | -0.9995484952 | -0.627768318 | -0.6733904463 | +| 2020-01-10 23:00:05 +0000 UTC | -0.5707727629 | -0.99487481 | 0.2518733583 | -0.8211080641 | -0.1011143526 | -0.9677602034 | +| 2020-01-10 23:00:06 +0000 UTC | -0.9264396396 | -0.8887854574 | -0.3172041093 | -0.3764433476 | 0.4583234781 | -0.9483572918 | +| 2020-01-10 23:00:07 +0000 UTC | -0.9817310338 | -0.4945290734 | -0.7834358726 | 0.1902739531 | 0.8691610871 | -0.6214726329 | +| 2020-01-10 23:00:08 +0000 UTC | -0.7187200578 | 0.0600663144 | -0.9956576407 | 0.6952995601 | 0.9981943888 | -0.0930906135 | +| 2020-01-10 23:00:09 +0000 UTC | -0.2226816131 | 0.5951866633 | -0.8850616758 | 0.9748912242 | 0.8035874786 | 0.4654737692 | ++-------------------------------+------------------+------------------+------------------+------------------+------------------+------------------+ ====== TEST DATA RESPONSE (arrow base64) ====== -FRAME=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 +FRAME=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 diff --git a/pkg/tsdb/testdatasource/testdata/usa-timeseries.txt b/pkg/tsdb/testdatasource/testdata/usa-timeseries.txt index 7dcdc92daef..38fd2980802 100644 --- a/pkg/tsdb/testdatasource/testdata/usa-timeseries.txt +++ b/pkg/tsdb/testdatasource/testdata/usa-timeseries.txt @@ -3,138 +3,138 @@ Frame[0] Name: foo Dimensions: 2 Fields by 10 Rows -+-------------------------------+----------------------+ -| Name: Time | Name: Value | -| Labels: | Labels: state=CA | -| Type: []time.Time | Type: []float64 | -+-------------------------------+----------------------+ -| 2020-01-10 23:00:00 +0000 UTC | 0.7591864109375384 | -| 2020-01-10 23:00:01 +0000 UTC | 0.9913874643906261 | -| 2020-01-10 23:00:02 +0000 UTC | 0.9021552854179972 | -| 2020-01-10 23:00:03 +0000 UTC | 0.520421234112239 | -| 2020-01-10 23:00:04 +0000 UTC | -0.03004672347354234 | -| 2020-01-10 23:00:05 +0000 UTC | -0.5707727629931729 | -| 2020-01-10 23:00:06 +0000 UTC | -0.9264396396937303 | -| 2020-01-10 23:00:07 +0000 UTC | -0.981731033820365 | -| 2020-01-10 23:00:08 +0000 UTC | -0.7187200578767007 | -| 2020-01-10 23:00:09 +0000 UTC | -0.22268161314765392 | -+-------------------------------+----------------------+ ++-------------------------------+------------------+ +| Name: Time | Name: Value | +| Labels: | Labels: state=CA | +| Type: []time.Time | Type: []float64 | ++-------------------------------+------------------+ +| 2020-01-10 23:00:00 +0000 UTC | 0.7591864109 | +| 2020-01-10 23:00:01 +0000 UTC | 0.9913874643 | +| 2020-01-10 23:00:02 +0000 UTC | 0.9021552854 | +| 2020-01-10 23:00:03 +0000 UTC | 0.5204212341 | +| 2020-01-10 23:00:04 +0000 UTC | -0.0300467234 | +| 2020-01-10 23:00:05 +0000 UTC | -0.5707727629 | +| 2020-01-10 23:00:06 +0000 UTC | -0.9264396396 | +| 2020-01-10 23:00:07 +0000 UTC | -0.9817310338 | +| 2020-01-10 23:00:08 +0000 UTC | -0.7187200578 | +| 2020-01-10 23:00:09 +0000 UTC | -0.2226816131 | ++-------------------------------+------------------+ Frame[1] Name: foo Dimensions: 2 Fields by 10 Rows -+-------------------------------+----------------------+ -| Name: Time | Name: Value | -| Labels: | Labels: state=OR | -| Type: []time.Time | Type: []float64 | -+-------------------------------+----------------------+ -| 2020-01-10 23:00:00 +0000 UTC | 0.9882682601465907 | -| 2020-01-10 23:00:01 +0000 UTC | 0.7446917214252602 | -| 2020-01-10 23:00:02 +0000 UTC | 0.25966703475349645 | -| 2020-01-10 23:00:03 +0000 UTC | -0.309548361739801 | -| 2020-01-10 23:00:04 +0000 UTC | -0.7784002433814474 | -| 2020-01-10 23:00:05 +0000 UTC | -0.994874810059912 | -| 2020-01-10 23:00:06 +0000 UTC | -0.8887854574406474 | -| 2020-01-10 23:00:07 +0000 UTC | -0.4945290734844293 | -| 2020-01-10 23:00:08 +0000 UTC | 0.060066314471906294 | -| 2020-01-10 23:00:09 +0000 UTC | 0.5951866633399958 | -+-------------------------------+----------------------+ ++-------------------------------+------------------+ +| Name: Time | Name: Value | +| Labels: | Labels: state=OR | +| Type: []time.Time | Type: []float64 | ++-------------------------------+------------------+ +| 2020-01-10 23:00:00 +0000 UTC | 0.9882682601 | +| 2020-01-10 23:00:01 +0000 UTC | 0.7446917214 | +| 2020-01-10 23:00:02 +0000 UTC | 0.2596670347 | +| 2020-01-10 23:00:03 +0000 UTC | -0.3095483617 | +| 2020-01-10 23:00:04 +0000 UTC | -0.7784002433 | +| 2020-01-10 23:00:05 +0000 UTC | -0.99487481 | +| 2020-01-10 23:00:06 +0000 UTC | -0.8887854574 | +| 2020-01-10 23:00:07 +0000 UTC | -0.4945290734 | +| 2020-01-10 23:00:08 +0000 UTC | 0.0600663144 | +| 2020-01-10 23:00:09 +0000 UTC | 0.5951866633 | ++-------------------------------+------------------+ Frame[2] Name: foo Dimensions: 2 Fields by 10 Rows -+-------------------------------+----------------------+ -| Name: Time | Name: Value | -| Labels: | Labels: state=NV | -| Type: []time.Time | Type: []float64 | -+-------------------------------+----------------------+ -| 2020-01-10 23:00:00 +0000 UTC | 0 | -| 2020-01-10 23:00:01 +0000 UTC | 0.5458434494486994 | -| 2020-01-10 23:00:02 +0000 UTC | 0.9147104586490411 | -| 2020-01-10 23:00:03 +0000 UTC | 0.9870048864743552 | -| 2020-01-10 23:00:04 +0000 UTC | 0.7392870259917509 | -| 2020-01-10 23:00:05 +0000 UTC | 0.2518733583799049 | -| 2020-01-10 23:00:06 +0000 UTC | -0.31720410936455373 | -| 2020-01-10 23:00:07 +0000 UTC | -0.7834358726049309 | -| 2020-01-10 23:00:08 +0000 UTC | -0.9956576407880757 | -| 2020-01-10 23:00:09 +0000 UTC | -0.8850616758817763 | -+-------------------------------+----------------------+ ++-------------------------------+------------------+ +| Name: Time | Name: Value | +| Labels: | Labels: state=NV | +| Type: []time.Time | Type: []float64 | ++-------------------------------+------------------+ +| 2020-01-10 23:00:00 +0000 UTC | 0 | +| 2020-01-10 23:00:01 +0000 UTC | 0.5458434494 | +| 2020-01-10 23:00:02 +0000 UTC | 0.9147104586 | +| 2020-01-10 23:00:03 +0000 UTC | 0.9870048864 | +| 2020-01-10 23:00:04 +0000 UTC | 0.7392870259 | +| 2020-01-10 23:00:05 +0000 UTC | 0.2518733583 | +| 2020-01-10 23:00:06 +0000 UTC | -0.3172041093 | +| 2020-01-10 23:00:07 +0000 UTC | -0.7834358726 | +| 2020-01-10 23:00:08 +0000 UTC | -0.9956576407 | +| 2020-01-10 23:00:09 +0000 UTC | -0.8850616758 | ++-------------------------------+------------------+ Frame[3] Name: bar Dimensions: 2 Fields by 10 Rows -+-------------------------------+----------------------+ -| Name: Time | Name: Value | -| Labels: | Labels: state=CA | -| Type: []time.Time | Type: []float64 | -+-------------------------------+----------------------+ -| 2020-01-10 23:00:00 +0000 UTC | 0.6508732545187114 | -| 2020-01-10 23:00:01 +0000 UTC | 0.13096142733310906 | -| 2020-01-10 23:00:02 +0000 UTC | -0.4314114520876468 | -| 2020-01-10 23:00:03 +0000 UTC | -0.8539096785287623 | -| 2020-01-10 23:00:04 +0000 UTC | -0.9995484952759943 | -| 2020-01-10 23:00:05 +0000 UTC | -0.8211080641579032 | -| 2020-01-10 23:00:06 +0000 UTC | -0.37644334766887727 | -| 2020-01-10 23:00:07 +0000 UTC | 0.19027395311496903 | -| 2020-01-10 23:00:08 +0000 UTC | 0.6952995601938146 | -| 2020-01-10 23:00:09 +0000 UTC | 0.9748912242737435 | -+-------------------------------+----------------------+ ++-------------------------------+------------------+ +| Name: Time | Name: Value | +| Labels: | Labels: state=CA | +| Type: []time.Time | Type: []float64 | ++-------------------------------+------------------+ +| 2020-01-10 23:00:00 +0000 UTC | 0.6508732545 | +| 2020-01-10 23:00:01 +0000 UTC | 0.1309614273 | +| 2020-01-10 23:00:02 +0000 UTC | -0.431411452 | +| 2020-01-10 23:00:03 +0000 UTC | -0.8539096785 | +| 2020-01-10 23:00:04 +0000 UTC | -0.9995484952 | +| 2020-01-10 23:00:05 +0000 UTC | -0.8211080641 | +| 2020-01-10 23:00:06 +0000 UTC | -0.3764433476 | +| 2020-01-10 23:00:07 +0000 UTC | 0.1902739531 | +| 2020-01-10 23:00:08 +0000 UTC | 0.6952995601 | +| 2020-01-10 23:00:09 +0000 UTC | 0.9748912242 | ++-------------------------------+------------------+ Frame[4] Name: bar Dimensions: 2 Fields by 10 Rows -+-------------------------------+----------------------+ -| Name: Time | Name: Value | -| Labels: | Labels: state=OR | -| Type: []time.Time | Type: []float64 | -+-------------------------------+----------------------+ -| 2020-01-10 23:00:00 +0000 UTC | -0.1527280131044415 | -| 2020-01-10 23:00:01 +0000 UTC | -0.6674086005144695 | -| 2020-01-10 23:00:02 +0000 UTC | -0.9656982091017495 | -| 2020-01-10 23:00:03 +0000 UTC | -0.9508837004303972 | -| 2020-01-10 23:00:04 +0000 UTC | -0.6277683180152559 | -| 2020-01-10 23:00:05 +0000 UTC | -0.10111435263232425 | -| 2020-01-10 23:00:06 +0000 UTC | 0.4583234781701883 | -| 2020-01-10 23:00:07 +0000 UTC | 0.8691610871861625 | -| 2020-01-10 23:00:08 +0000 UTC | 0.998194388817009 | -| 2020-01-10 23:00:09 +0000 UTC | 0.8035874786121313 | -+-------------------------------+----------------------+ ++-------------------------------+------------------+ +| Name: Time | Name: Value | +| Labels: | Labels: state=OR | +| Type: []time.Time | Type: []float64 | ++-------------------------------+------------------+ +| 2020-01-10 23:00:00 +0000 UTC | -0.1527280131 | +| 2020-01-10 23:00:01 +0000 UTC | -0.6674086005 | +| 2020-01-10 23:00:02 +0000 UTC | -0.9656982091 | +| 2020-01-10 23:00:03 +0000 UTC | -0.9508837004 | +| 2020-01-10 23:00:04 +0000 UTC | -0.627768318 | +| 2020-01-10 23:00:05 +0000 UTC | -0.1011143526 | +| 2020-01-10 23:00:06 +0000 UTC | 0.4583234781 | +| 2020-01-10 23:00:07 +0000 UTC | 0.8691610871 | +| 2020-01-10 23:00:08 +0000 UTC | 0.9981943888 | +| 2020-01-10 23:00:09 +0000 UTC | 0.8035874786 | ++-------------------------------+------------------+ Frame[5] Name: bar Dimensions: 2 Fields by 10 Rows -+-------------------------------+----------------------+ -| Name: Time | Name: Value | -| Labels: | Labels: state=NV | -| Type: []time.Time | Type: []float64 | -+-------------------------------+----------------------+ -| 2020-01-10 23:00:00 +0000 UTC | 1 | -| 2020-01-10 23:00:01 +0000 UTC | 0.8378871813639024 | -| 2020-01-10 23:00:02 +0000 UTC | 0.40410985738788996 | -| 2020-01-10 23:00:03 +0000 UTC | -0.16069024262768705 | -| 2020-01-10 23:00:04 +0000 UTC | -0.6733904463238785 | -| 2020-01-10 23:00:05 +0000 UTC | -0.9677602034277024 | -| 2020-01-10 23:00:06 +0000 UTC | -0.9483572918485101 | -| 2020-01-10 23:00:07 +0000 UTC | -0.6214726329580013 | -| 2020-01-10 23:00:08 +0000 UTC | -0.09309061359945539 | -| 2020-01-10 23:00:09 +0000 UTC | 0.46547376927743367 | -+-------------------------------+----------------------+ ++-------------------------------+------------------+ +| Name: Time | Name: Value | +| Labels: | Labels: state=NV | +| Type: []time.Time | Type: []float64 | ++-------------------------------+------------------+ +| 2020-01-10 23:00:00 +0000 UTC | 1 | +| 2020-01-10 23:00:01 +0000 UTC | 0.8378871813 | +| 2020-01-10 23:00:02 +0000 UTC | 0.4041098573 | +| 2020-01-10 23:00:03 +0000 UTC | -0.1606902426 | +| 2020-01-10 23:00:04 +0000 UTC | -0.6733904463 | +| 2020-01-10 23:00:05 +0000 UTC | -0.9677602034 | +| 2020-01-10 23:00:06 +0000 UTC | -0.9483572918 | +| 2020-01-10 23:00:07 +0000 UTC | -0.6214726329 | +| 2020-01-10 23:00:08 +0000 UTC | -0.0930906135 | +| 2020-01-10 23:00:09 +0000 UTC | 0.4654737692 | ++-------------------------------+------------------+ ====== TEST DATA RESPONSE (arrow base64) ====== -FRAME=QVJST1cxAAD/////mAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJDQSJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAAAAAAP////+4AAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAoAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAWAAAAAoAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAIAAAAKAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAABg5zW9qOgVACqCcb2o6BUA9BytvajoFQC+t+i9qOgVAIhSJL6o6BUAUu1fvqjoFQAciJu+qOgVAOYi176o6BUAsL0Sv6joFQB6WE6/qOgVRGvRTEFL6D95Gyc0crnvPz8V2cJ03uw/Kv6Ubkqn4D9o6656kcSev4Qa0D3FQ+K/qXtGvmSl7b9vQXczV2rvv7Xo8TTB/+a/meHxwtSAzL8QAAAADAAUABIADAAIAAQADAAAABAAAAAsAAAAOAAAAAAAAwABAAAAqAEAAAAAAADAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJDQSJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAwAEAAEFSUk9XMQ== -FRAME=QVJST1cxAAD/////mAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJPUiJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAAAAAAP////+4AAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAoAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAWAAAAAoAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAIAAAAKAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAABg5zW9qOgVACqCcb2o6BUA9BytvajoFQC+t+i9qOgVAIhSJL6o6BUAUu1fvqjoFQAciJu+qOgVAOYi176o6BUAsL0Sv6joFQB6WE6/qOgVRSQgwuSf7z8u86O7g9TnP2Flh3tintA/DfuM7qPP0788spCgp+jovwFKmrID1u+/f8YbM+5w7L8CW2JFXabfv4cFfxADwa4/zPDB5sQL4z8QAAAADAAUABIADAAIAAQADAAAABAAAAAsAAAAOAAAAAAAAwABAAAAqAEAAAAAAADAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJPUiJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAwAEAAEFSUk9XMQ== -FRAME=QVJST1cxAAD/////mAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJOViJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAAAAAAP////+4AAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAoAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAWAAAAAoAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAIAAAAKAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAABg5zW9qOgVACqCcb2o6BUA9BytvajoFQC+t+i9qOgVAIhSJL6o6BUAUu1fvqjoFQAciJu+qOgVAOYi176o6BUAsL0Sv6joFQB6WE6/qOgVAAAAAAAAAACaxoOujHfhPwqeJt5ORe0/GsmMRYuV7z/Hu99DPajnP5xsPm+xHtA/CSr4dhJN1L+sPmsb6BHpv0pQpmlt3O+/pV0b3WxS7L8QAAAADAAUABIADAAIAAQADAAAABAAAAAsAAAAOAAAAAAAAwABAAAAqAEAAAAAAADAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJOViJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAwAEAAEFSUk9XMQ== -FRAME=QVJST1cxAAD/////mAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJDQSJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAAAAAAP////+4AAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAoAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAWAAAAAoAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAIAAAAKAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAABg5zW9qOgVACqCcb2o6BUA9BytvajoFQC+t+i9qOgVAIhSJL6o6BUAUu1fvqjoFQAciJu+qOgVAOYi176o6BUAsL0Sv6joFQB6WE6/qOgVZfe/JfTT5D+ScrcTWMPAPyuGdcc+nNu/5JrgYzpT67+4Pj8gTfzvvzRIQWuERuq/pzbC1qUX2L8uaPSa5VrIP2qU/tzkP+Y/XDitFE8y7z8QAAAADAAUABIADAAIAAQADAAAABAAAAAsAAAAOAAAAAAAAwABAAAAqAEAAAAAAADAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJDQSJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAwAEAAEFSUk9XMQ== -FRAME=QVJST1cxAAD/////mAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJPUiJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAAAAAAP////+4AAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAoAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAWAAAAAoAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAIAAAAKAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAABg5zW9qOgVACqCcb2o6BUA9BytvajoFQC+t+i9qOgVAIhSJL6o6BUAUu1fvqjoFQAciJu+qOgVAOYi176o6BUAsL0Sv6joFQB6WE6/qOgVuLq7bpeMw7+66whIaVvlv6W6PO7/5u6/jrx0p6Nt7r/75GqVrRbkv4dItlWh4rm/J7du/ytV3T+xc43pKtDrP+Oh4Fs18e8/jqeDFv226T8QAAAADAAUABIADAAIAAQADAAAABAAAAAsAAAAOAAAAAAAAwABAAAAqAEAAAAAAADAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJPUiJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAwAEAAEFSUk9XMQ== -FRAME=QVJST1cxAAD/////mAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJOViJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAAAAAAP////+4AAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAoAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAWAAAAAoAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAIAAAAKAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAABg5zW9qOgVACqCcb2o6BUA9BytvajoFQC+t+i9qOgVAIhSJL6o6BUAUu1fvqjoFQAciJu+qOgVAOYi176o6BUAsL0Sv6joFQB6WE6/qOgVAAAAAAAA8D80QjbH+M/qP7Y4Xpfv3Nk/8KRvdH+RxL/+ywwfaozlvwj0Aj/k9+6/BjMtZPFY7r9vPD2TGuPjv2Jn+VTJ1Le/ulAMflLK3T8QAAAADAAUABIADAAIAAQADAAAABAAAAAsAAAAOAAAAAAAAwABAAAAqAEAAAAAAADAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJOViJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAwAEAAEFSUk9XMQ== +FRAME=QVJST1cxAAD/////mAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJDQSJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAAAAAAP////+4AAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAoAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAWAAAAAoAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAIAAAAKAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAABg5zW9qOgVACqCcb2o6BUA9BytvajoFQC+t+i9qOgVAIhSJL6o6BUAUu1fvqjoFQAciJu+qOgVAOYi176o6BUAsL0Sv6joFQB6WE6/qOgVgULMTEFL6D/apho0crnvPwec1sJ03uw/i0+Tbkqn4D8Xemt5kcSev0lMwz3FQ+K/0Zk5vmSl7b/odHQzV2rvvwte5zTB/+a/6K7XwtSAzL8QAAAADAAUABIADAAIAAQADAAAABAAAAAsAAAAOAAAAAAAAwABAAAAqAEAAAAAAADAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJDQSJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAwAEAAEFSUk9XMQ== +FRAME=QVJST1cxAAD/////mAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJPUiJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAAAAAAP////+4AAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAoAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAWAAAAAoAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAIAAAAKAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAABg5zW9qOgVACqCcb2o6BUA9BytvajoFQC+t+i9qOgVAIhSJL6o6BUAUu1fvqjoFQAciJu+qOgVAOYi176o6BUAsL0Sv6joFQB6WE6/qOgVAb0ZwuSf7z9qeqC7g9TnP+eweHtintA/TgqC7qPP07+PgIWgp+jovwoOkrID1u+/WDAWM+5w7L/TJUtFXabfv+Ll4A8Dwa4/knG85sQL4z8QAAAADAAUABIADAAIAAQADAAAABAAAAAsAAAAOAAAAAAAAwABAAAAqAEAAAAAAADAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJPUiJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAwAEAAEFSUk9XMQ== +FRAME=QVJST1cxAAD/////mAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJOViJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAAAAAAP////+4AAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAoAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAWAAAAAoAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAIAAAAKAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAABg5zW9qOgVACqCcb2o6BUA9BytvajoFQC+t+i9qOgVAIhSJL6o6BUAUu1fvqjoFQAciJu+qOgVAOYi176o6BUAsL0Sv6joFQB6WE6/qOgVAAAAAAAAAAAkFX2ujHfhP4/gH95ORe0/9ZCCRYuV7z+UH9NDPajnP851KG+xHtA/eGvmdhJN1L8vkWob6BHpv2Y1mmlt3O+/ZSAQ3WxS7L8QAAAADAAUABIADAAIAAQADAAAABAAAAAsAAAAOAAAAAAAAwABAAAAqAEAAAAAAADAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJOViJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAwAEAAEFSUk9XMQ== +FRAME=QVJST1cxAAD/////mAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJDQSJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAAAAAAP////+4AAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAoAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAWAAAAAoAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAIAAAAKAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAABg5zW9qOgVACqCcb2o6BUA9BytvajoFQC+t+i9qOgVAIhSJL6o6BUAUu1fvqjoFQAciJu+qOgVAOYi176o6BUAsL0Sv6joFQB6WE6/qOgVDGW9JfTT5D/iPqUTWMPAP5JuXcc+nNu/6KbcYzpT67/ozDQgTfzvv+tSOWuERuq/2Eev1qUX2L96Leya5VrIP5yv8dzkP+Y/vRWjFE8y7z8QAAAADAAUABIADAAIAAQADAAAABAAAAAsAAAAOAAAAAAAAwABAAAAqAEAAAAAAADAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJDQSJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAwAEAAEFSUk9XMQ== +FRAME=QVJST1cxAAD/////mAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJPUiJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAAAAAAP////+4AAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAoAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAWAAAAAoAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAIAAAAKAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAABg5zW9qOgVACqCcb2o6BUA9BytvajoFQC+t+i9qOgVAIhSJL6o6BUAUu1fvqjoFQAciJu+qOgVAOYi176o6BUAsL0Sv6joFQB6WE6/qOgVokm5bpeMw7+g7gZIaVvlvxd9PO7/5u6/DY9wp6Nt7r82zGiVrRbkvw++klWh4rm/F2xb/ytV3T8enIHpKtDrP3BL3ls18e8/ufyBFv226T8QAAAADAAUABIADAAIAAQADAAAABAAAAAsAAAAOAAAAAAAAwABAAAAqAEAAAAAAADAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJPUiJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAwAEAAEFSUk9XMQ== +FRAME=QVJST1cxAAD/////mAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJOViJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAAAAAAP////+4AAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAoAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAWAAAAAoAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAFAAAAAAAAAAAAAAAAIAAAAKAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAAAAAABg5zW9qOgVACqCcb2o6BUA9BytvajoFQC+t+i9qOgVAIhSJL6o6BUAUu1fvqjoFQAciJu+qOgVAOYi176o6BUAsL0Sv6joFQB6WE6/qOgVAAAAAAAA8D/WeS3H+M/qPwEQRpfv3Nk/VWxgdH+RxL/Ygwkfaozlv1cl/z7k9+6/OYgmZPFY7r+yQzWTGuPjvy4NjFTJ1Le/0Qf3fVLK3T8QAAAADAAUABIADAAIAAQADAAAABAAAAAsAAAAOAAAAAAAAwABAAAAqAEAAAAAAADAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAAD4/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAABj///8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAgAAAKQAAAAEAAAAdv///xQAAABsAAAAbAAAAAAAAANsAAAAAgAAACwAAAAEAAAAaP///wgAAAAQAAAABQAAAFZhbHVlAAAABAAAAG5hbWUAAAAAjP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJOViJ9AAAGAAAAbGFiZWxzAAAAAAAAiv///wAAAgAFAAAAVmFsdWUAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABEAAAATAAAAAAAAApMAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAAEAAAAAQAAABUaW1lAAAAAAQAAABuYW1lAAAAAAAAAAAAAAYACAAGAAYAAAAAAAMABAAAAFRpbWUAAAAAwAEAAEFSUk9XMQ== diff --git a/pkg/tsdb/testdatasource/testdata/usa-values-as-fields.txt b/pkg/tsdb/testdatasource/testdata/usa-values-as-fields.txt index 8655d43df6d..7f3359e2f8d 100644 --- a/pkg/tsdb/testdatasource/testdata/usa-values-as-fields.txt +++ b/pkg/tsdb/testdatasource/testdata/usa-values-as-fields.txt @@ -3,28 +3,28 @@ Frame[0] Name: foo Dimensions: 3 Fields by 1 Rows -+--------------------+--------------------+----------------------+ -| Name: CA | Name: OR | Name: NV | -| Labels: | Labels: | Labels: | -| Type: []float64 | Type: []float64 | Type: []float64 | -+--------------------+--------------------+----------------------+ -| 0.3455559195129913 | 0.9373322369907638 | -0.48750602508751073 | -+--------------------+--------------------+----------------------+ ++-----------------+-----------------+-----------------+ +| Name: CA | Name: OR | Name: NV | +| Labels: | Labels: | Labels: | +| Type: []float64 | Type: []float64 | Type: []float64 | ++-----------------+-----------------+-----------------+ +| 0.3455559195 | 0.9373322369 | -0.487506025 | ++-----------------+-----------------+-----------------+ Frame[1] Name: bar Dimensions: 3 Fields by 1 Rows -+--------------------+--------------------+-------------------+ -| Name: CA | Name: OR | Name: NV | -| Labels: | Labels: | Labels: | -| Type: []float64 | Type: []float64 | Type: []float64 | -+--------------------+--------------------+-------------------+ -| 0.9383981598924473 | 0.3484369060502785 | 0.873119622676856 | -+--------------------+--------------------+-------------------+ ++-----------------+-----------------+-----------------+ +| Name: CA | Name: OR | Name: NV | +| Labels: | Labels: | Labels: | +| Type: []float64 | Type: []float64 | Type: []float64 | ++-----------------+-----------------+-----------------+ +| 0.9383981598 | 0.348436906 | 0.8731196226 | ++-----------------+-----------------+-----------------+ ====== TEST DATA RESPONSE (arrow base64) ====== -FRAME=QVJST1cxAAD/////sAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAADU/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAPT+//8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAwAAAMgAAABcAAAABAAAAFb///8UAAAAOAAAADgAAAAAAAADOAAAAAEAAAAEAAAARP///wgAAAAMAAAAAgAAAE5WAAAEAAAAbmFtZQAAAAAAAAAAOv///wAAAgACAAAATlYAAKr///8UAAAAOAAAADgAAAAAAAADOAAAAAEAAAAEAAAAmP///wgAAAAMAAAAAgAAAE9SAAAEAAAAbmFtZQAAAAAAAAAAjv///wAAAgACAAAAT1IAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABAAAAASAAAAAAAAANIAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAADAAAAAIAAABDQQAABAAAAG5hbWUAAAAAAAAAAAAABgAIAAYABgAAAAAAAgACAAAAQ0EAAP/////oAAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAGAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAeAAAAAEAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAACAAAAAAAAAAAAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAACPXT5OWHdY/S5TrLKD+7T/kpJZ4TDPfvxAAAAAMABQAEgAMAAgABAAMAAAAEAAAACwAAAA8AAAAAAADAAEAAADAAQAAAAAAAPAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAADU/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAPT+//8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAwAAAMgAAABcAAAABAAAAFb///8UAAAAOAAAADgAAAAAAAADOAAAAAEAAAAEAAAARP///wgAAAAMAAAAAgAAAE5WAAAEAAAAbmFtZQAAAAAAAAAAOv///wAAAgACAAAATlYAAKr///8UAAAAOAAAADgAAAAAAAADOAAAAAEAAAAEAAAAmP///wgAAAAMAAAAAgAAAE9SAAAEAAAAbmFtZQAAAAAAAAAAjv///wAAAgACAAAAT1IAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABAAAAASAAAAAAAAANIAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAADAAAAAIAAABDQQAABAAAAG5hbWUAAAAAAAAAAAAABgAIAAYABgAAAAAAAgACAAAAQ0EAAOABAABBUlJPVzE= -FRAME=QVJST1cxAAD/////sAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAADU/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAPT+//8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAwAAAMgAAABcAAAABAAAAFb///8UAAAAOAAAADgAAAAAAAADOAAAAAEAAAAEAAAARP///wgAAAAMAAAAAgAAAE5WAAAEAAAAbmFtZQAAAAAAAAAAOv///wAAAgACAAAATlYAAKr///8UAAAAOAAAADgAAAAAAAADOAAAAAEAAAAEAAAAmP///wgAAAAMAAAAAgAAAE9SAAAEAAAAbmFtZQAAAAAAAAAAjv///wAAAgACAAAAT1IAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABAAAAASAAAAAAAAANIAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAADAAAAAIAAABDQQAABAAAAG5hbWUAAAAAAAAAAAAABgAIAAYABgAAAAAAAgACAAAAQ0EAAP/////oAAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAGAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAeAAAAAEAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAACAAAAAAAAAAAAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAACKr65NbB+4/yyQNT8pM1j8akxyQmPDrPxAAAAAMABQAEgAMAAgABAAMAAAAEAAAACwAAAA8AAAAAAADAAEAAADAAQAAAAAAAPAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAADU/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAPT+//8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAwAAAMgAAABcAAAABAAAAFb///8UAAAAOAAAADgAAAAAAAADOAAAAAEAAAAEAAAARP///wgAAAAMAAAAAgAAAE5WAAAEAAAAbmFtZQAAAAAAAAAAOv///wAAAgACAAAATlYAAKr///8UAAAAOAAAADgAAAAAAAADOAAAAAEAAAAEAAAAmP///wgAAAAMAAAAAgAAAE9SAAAEAAAAbmFtZQAAAAAAAAAAjv///wAAAgACAAAAT1IAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABAAAAASAAAAAAAAANIAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAADAAAAAIAAABDQQAABAAAAG5hbWUAAAAAAAAAAAAABgAIAAYABgAAAAAAAgACAAAAQ0EAAOABAABBUlJPVzE= +FRAME=QVJST1cxAAD/////sAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAADU/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAPT+//8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAwAAAMgAAABcAAAABAAAAFb///8UAAAAOAAAADgAAAAAAAADOAAAAAEAAAAEAAAARP///wgAAAAMAAAAAgAAAE5WAAAEAAAAbmFtZQAAAAAAAAAAOv///wAAAgACAAAATlYAAKr///8UAAAAOAAAADgAAAAAAAADOAAAAAEAAAAEAAAAmP///wgAAAAMAAAAAgAAAE9SAAAEAAAAbmFtZQAAAAAAAAAAjv///wAAAgACAAAAT1IAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABAAAAASAAAAAAAAANIAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAADAAAAAIAAABDQQAABAAAAG5hbWUAAAAAAAAAAAAABgAIAAYABgAAAAAAAgACAAAAQ0EAAP/////oAAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAGAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAeAAAAAEAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAACAAAAAAAAAAAAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAPRETJOWHdY/0xrfLKD+7T/fln54TDPfvxAAAAAMABQAEgAMAAgABAAMAAAAEAAAACwAAAA8AAAAAAADAAEAAADAAQAAAAAAAPAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAADU/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAPT+//8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAwAAAMgAAABcAAAABAAAAFb///8UAAAAOAAAADgAAAAAAAADOAAAAAEAAAAEAAAARP///wgAAAAMAAAAAgAAAE5WAAAEAAAAbmFtZQAAAAAAAAAAOv///wAAAgACAAAATlYAAKr///8UAAAAOAAAADgAAAAAAAADOAAAAAEAAAAEAAAAmP///wgAAAAMAAAAAgAAAE9SAAAEAAAAbmFtZQAAAAAAAAAAjv///wAAAgACAAAAT1IAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABAAAAASAAAAAAAAANIAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAADAAAAAIAAABDQQAABAAAAG5hbWUAAAAAAAAAAAAABgAIAAYABgAAAAAAAgACAAAAQ0EAAOABAABBUlJPVzE= +FRAME=QVJST1cxAAD/////sAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAADU/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAPT+//8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAwAAAMgAAABcAAAABAAAAFb///8UAAAAOAAAADgAAAAAAAADOAAAAAEAAAAEAAAARP///wgAAAAMAAAAAgAAAE5WAAAEAAAAbmFtZQAAAAAAAAAAOv///wAAAgACAAAATlYAAKr///8UAAAAOAAAADgAAAAAAAADOAAAAAEAAAAEAAAAmP///wgAAAAMAAAAAgAAAE9SAAAEAAAAbmFtZQAAAAAAAAAAjv///wAAAgACAAAAT1IAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABAAAAASAAAAAAAAANIAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAADAAAAAIAAABDQQAABAAAAG5hbWUAAAAAAAAAAAAABgAIAAYABgAAAAAAAgACAAAAQ0EAAP/////oAAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAGAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAeAAAAAEAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAACAAAAAAAAAAAAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAG723pNbB+4/wlL/TspM1j/4AhKQmPDrPxAAAAAMABQAEgAMAAgABAAMAAAAEAAAACwAAAA8AAAAAAADAAEAAADAAQAAAAAAAPAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAADU/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAPT+//8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAwAAAMgAAABcAAAABAAAAFb///8UAAAAOAAAADgAAAAAAAADOAAAAAEAAAAEAAAARP///wgAAAAMAAAAAgAAAE5WAAAEAAAAbmFtZQAAAAAAAAAAOv///wAAAgACAAAATlYAAKr///8UAAAAOAAAADgAAAAAAAADOAAAAAEAAAAEAAAAmP///wgAAAAMAAAAAgAAAE9SAAAEAAAAbmFtZQAAAAAAAAAAjv///wAAAgACAAAAT1IAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAABAAAAASAAAAAAAAANIAAAAAQAAAAwAAAAIAAwACAAEAAgAAAAIAAAADAAAAAIAAABDQQAABAAAAG5hbWUAAAAAAAAAAAAABgAIAAYABgAAAAAAAgACAAAAQ0EAAOABAABBUlJPVzE= diff --git a/pkg/tsdb/testdatasource/testdata/usa-values-as-labeled-fields.txt b/pkg/tsdb/testdatasource/testdata/usa-values-as-labeled-fields.txt index 188181b1b47..c2503b1f5c2 100644 --- a/pkg/tsdb/testdatasource/testdata/usa-values-as-labeled-fields.txt +++ b/pkg/tsdb/testdatasource/testdata/usa-values-as-labeled-fields.txt @@ -3,28 +3,28 @@ Frame[0] Name: foo Dimensions: 3 Fields by 1 Rows -+--------------------+--------------------+----------------------+ -| Name: | Name: | Name: | -| Labels: state=CA | Labels: state=OR | Labels: state=NV | -| Type: []float64 | Type: []float64 | Type: []float64 | -+--------------------+--------------------+----------------------+ -| 0.3455559195129913 | 0.9373322369907638 | -0.48750602508751073 | -+--------------------+--------------------+----------------------+ ++------------------+------------------+------------------+ +| Name: | Name: | Name: | +| Labels: state=CA | Labels: state=OR | Labels: state=NV | +| Type: []float64 | Type: []float64 | Type: []float64 | ++------------------+------------------+------------------+ +| 0.3455559195 | 0.9373322369 | -0.487506025 | ++------------------+------------------+------------------+ Frame[1] Name: bar Dimensions: 3 Fields by 1 Rows -+--------------------+--------------------+-------------------+ -| Name: | Name: | Name: | -| Labels: state=CA | Labels: state=OR | Labels: state=NV | -| Type: []float64 | Type: []float64 | Type: []float64 | -+--------------------+--------------------+-------------------+ -| 0.9383981598924473 | 0.3484369060502785 | 0.873119622676856 | -+--------------------+--------------------+-------------------+ ++------------------+------------------+------------------+ +| Name: | Name: | Name: | +| Labels: state=CA | Labels: state=OR | Labels: state=NV | +| Type: []float64 | Type: []float64 | Type: []float64 | ++------------------+------------------+------------------+ +| 0.9383981598 | 0.348436906 | 0.8731196226 | ++------------------+------------------+------------------+ ====== TEST DATA RESPONSE (arrow base64) ====== -FRAME=QVJST1cxAAD/////QAIAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAABU/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAHT+//8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAwAAACQBAACMAAAABAAAAPr+//8UAAAAaAAAAGgAAAAAAAADaAAAAAIAAAAoAAAABAAAAMj+//8IAAAADAAAAAAAAAAAAAAABAAAAG5hbWUAAAAA6P7//wgAAAAYAAAADgAAAHsic3RhdGUiOiJOViJ9AAAGAAAAbGFiZWxzAAAAAAAA3v7//wAAAgAAAAAAAAAAAH7///8UAAAAaAAAAGgAAAAAAAADaAAAAAIAAAAoAAAABAAAAEz///8IAAAADAAAAAAAAAAAAAAABAAAAG5hbWUAAAAAbP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJPUiJ9AAAGAAAAbGFiZWxzAAAAAAAAYv///wAAAgAAAAAAAAASABgAFAAAABMADAAAAAgABAASAAAAFAAAAHAAAAB4AAAAAAAAA3gAAAACAAAAMAAAAAQAAADg////CAAAAAwAAAAAAAAAAAAAAAQAAABuYW1lAAAAAAgADAAIAAQACAAAAAgAAAAYAAAADgAAAHsic3RhdGUiOiJDQSJ9AAAGAAAAbGFiZWxzAAAAAAAAAAAGAAgABgAGAAAAAAACAAAAAAAAAAAAAAAAAP/////oAAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAGAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAeAAAAAEAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAACAAAAAAAAAAAAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAACPXT5OWHdY/S5TrLKD+7T/kpJZ4TDPfvxAAAAAMABQAEgAMAAgABAAMAAAAEAAAACwAAAA4AAAAAAADAAEAAABQAgAAAAAAAPAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAACgAMAAAACAAEAAoAAAAIAAAAUAAAAAIAAAAoAAAABAAAAFT+//8IAAAADAAAAAAAAAAAAAAABQAAAHJlZklkAAAAdP7//wgAAAAMAAAAAwAAAGZvbwAEAAAAbmFtZQAAAAADAAAAJAEAAIwAAAAEAAAA+v7//xQAAABoAAAAaAAAAAAAAANoAAAAAgAAACgAAAAEAAAAyP7//wgAAAAMAAAAAAAAAAAAAAAEAAAAbmFtZQAAAADo/v//CAAAABgAAAAOAAAAeyJzdGF0ZSI6Ik5WIn0AAAYAAABsYWJlbHMAAAAAAADe/v//AAACAAAAAAAAAAAAfv///xQAAABoAAAAaAAAAAAAAANoAAAAAgAAACgAAAAEAAAATP///wgAAAAMAAAAAAAAAAAAAAAEAAAAbmFtZQAAAABs////CAAAABgAAAAOAAAAeyJzdGF0ZSI6Ik9SIn0AAAYAAABsYWJlbHMAAAAAAABi////AAACAAAAAAAAABIAGAAUAAAAEwAMAAAACAAEABIAAAAUAAAAcAAAAHgAAAAAAAADeAAAAAIAAAAwAAAABAAAAOD///8IAAAADAAAAAAAAAAAAAAABAAAAG5hbWUAAAAACAAMAAgABAAIAAAACAAAABgAAAAOAAAAeyJzdGF0ZSI6IkNBIn0AAAYAAABsYWJlbHMAAAAAAAAAAAYACAAGAAYAAAAAAAIAAAAAAAAAAABoAgAAQVJST1cx -FRAME=QVJST1cxAAD/////QAIAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAABU/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAHT+//8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAwAAACQBAACMAAAABAAAAPr+//8UAAAAaAAAAGgAAAAAAAADaAAAAAIAAAAoAAAABAAAAMj+//8IAAAADAAAAAAAAAAAAAAABAAAAG5hbWUAAAAA6P7//wgAAAAYAAAADgAAAHsic3RhdGUiOiJOViJ9AAAGAAAAbGFiZWxzAAAAAAAA3v7//wAAAgAAAAAAAAAAAH7///8UAAAAaAAAAGgAAAAAAAADaAAAAAIAAAAoAAAABAAAAEz///8IAAAADAAAAAAAAAAAAAAABAAAAG5hbWUAAAAAbP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJPUiJ9AAAGAAAAbGFiZWxzAAAAAAAAYv///wAAAgAAAAAAAAASABgAFAAAABMADAAAAAgABAASAAAAFAAAAHAAAAB4AAAAAAAAA3gAAAACAAAAMAAAAAQAAADg////CAAAAAwAAAAAAAAAAAAAAAQAAABuYW1lAAAAAAgADAAIAAQACAAAAAgAAAAYAAAADgAAAHsic3RhdGUiOiJDQSJ9AAAGAAAAbGFiZWxzAAAAAAAAAAAGAAgABgAGAAAAAAACAAAAAAAAAAAAAAAAAP/////oAAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAGAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAeAAAAAEAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAACAAAAAAAAAAAAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAACKr65NbB+4/yyQNT8pM1j8akxyQmPDrPxAAAAAMABQAEgAMAAgABAAMAAAAEAAAACwAAAA4AAAAAAADAAEAAABQAgAAAAAAAPAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAACgAMAAAACAAEAAoAAAAIAAAAUAAAAAIAAAAoAAAABAAAAFT+//8IAAAADAAAAAAAAAAAAAAABQAAAHJlZklkAAAAdP7//wgAAAAMAAAAAwAAAGJhcgAEAAAAbmFtZQAAAAADAAAAJAEAAIwAAAAEAAAA+v7//xQAAABoAAAAaAAAAAAAAANoAAAAAgAAACgAAAAEAAAAyP7//wgAAAAMAAAAAAAAAAAAAAAEAAAAbmFtZQAAAADo/v//CAAAABgAAAAOAAAAeyJzdGF0ZSI6Ik5WIn0AAAYAAABsYWJlbHMAAAAAAADe/v//AAACAAAAAAAAAAAAfv///xQAAABoAAAAaAAAAAAAAANoAAAAAgAAACgAAAAEAAAATP///wgAAAAMAAAAAAAAAAAAAAAEAAAAbmFtZQAAAABs////CAAAABgAAAAOAAAAeyJzdGF0ZSI6Ik9SIn0AAAYAAABsYWJlbHMAAAAAAABi////AAACAAAAAAAAABIAGAAUAAAAEwAMAAAACAAEABIAAAAUAAAAcAAAAHgAAAAAAAADeAAAAAIAAAAwAAAABAAAAOD///8IAAAADAAAAAAAAAAAAAAABAAAAG5hbWUAAAAACAAMAAgABAAIAAAACAAAABgAAAAOAAAAeyJzdGF0ZSI6IkNBIn0AAAYAAABsYWJlbHMAAAAAAAAAAAYACAAGAAYAAAAAAAIAAAAAAAAAAABoAgAAQVJST1cx +FRAME=QVJST1cxAAD/////QAIAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAABU/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAHT+//8IAAAADAAAAAMAAABmb28ABAAAAG5hbWUAAAAAAwAAACQBAACMAAAABAAAAPr+//8UAAAAaAAAAGgAAAAAAAADaAAAAAIAAAAoAAAABAAAAMj+//8IAAAADAAAAAAAAAAAAAAABAAAAG5hbWUAAAAA6P7//wgAAAAYAAAADgAAAHsic3RhdGUiOiJOViJ9AAAGAAAAbGFiZWxzAAAAAAAA3v7//wAAAgAAAAAAAAAAAH7///8UAAAAaAAAAGgAAAAAAAADaAAAAAIAAAAoAAAABAAAAEz///8IAAAADAAAAAAAAAAAAAAABAAAAG5hbWUAAAAAbP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJPUiJ9AAAGAAAAbGFiZWxzAAAAAAAAYv///wAAAgAAAAAAAAASABgAFAAAABMADAAAAAgABAASAAAAFAAAAHAAAAB4AAAAAAAAA3gAAAACAAAAMAAAAAQAAADg////CAAAAAwAAAAAAAAAAAAAAAQAAABuYW1lAAAAAAgADAAIAAQACAAAAAgAAAAYAAAADgAAAHsic3RhdGUiOiJDQSJ9AAAGAAAAbGFiZWxzAAAAAAAAAAAGAAgABgAGAAAAAAACAAAAAAAAAAAAAAAAAP/////oAAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAGAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAeAAAAAEAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAACAAAAAAAAAAAAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAPRETJOWHdY/0xrfLKD+7T/fln54TDPfvxAAAAAMABQAEgAMAAgABAAMAAAAEAAAACwAAAA4AAAAAAADAAEAAABQAgAAAAAAAPAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAACgAMAAAACAAEAAoAAAAIAAAAUAAAAAIAAAAoAAAABAAAAFT+//8IAAAADAAAAAAAAAAAAAAABQAAAHJlZklkAAAAdP7//wgAAAAMAAAAAwAAAGZvbwAEAAAAbmFtZQAAAAADAAAAJAEAAIwAAAAEAAAA+v7//xQAAABoAAAAaAAAAAAAAANoAAAAAgAAACgAAAAEAAAAyP7//wgAAAAMAAAAAAAAAAAAAAAEAAAAbmFtZQAAAADo/v//CAAAABgAAAAOAAAAeyJzdGF0ZSI6Ik5WIn0AAAYAAABsYWJlbHMAAAAAAADe/v//AAACAAAAAAAAAAAAfv///xQAAABoAAAAaAAAAAAAAANoAAAAAgAAACgAAAAEAAAATP///wgAAAAMAAAAAAAAAAAAAAAEAAAAbmFtZQAAAABs////CAAAABgAAAAOAAAAeyJzdGF0ZSI6Ik9SIn0AAAYAAABsYWJlbHMAAAAAAABi////AAACAAAAAAAAABIAGAAUAAAAEwAMAAAACAAEABIAAAAUAAAAcAAAAHgAAAAAAAADeAAAAAIAAAAwAAAABAAAAOD///8IAAAADAAAAAAAAAAAAAAABAAAAG5hbWUAAAAACAAMAAgABAAIAAAACAAAABgAAAAOAAAAeyJzdGF0ZSI6IkNBIn0AAAYAAABsYWJlbHMAAAAAAAAAAAYACAAGAAYAAAAAAAIAAAAAAAAAAABoAgAAQVJST1cx +FRAME=QVJST1cxAAD/////QAIAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFAAAAACAAAAKAAAAAQAAABU/v//CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAHT+//8IAAAADAAAAAMAAABiYXIABAAAAG5hbWUAAAAAAwAAACQBAACMAAAABAAAAPr+//8UAAAAaAAAAGgAAAAAAAADaAAAAAIAAAAoAAAABAAAAMj+//8IAAAADAAAAAAAAAAAAAAABAAAAG5hbWUAAAAA6P7//wgAAAAYAAAADgAAAHsic3RhdGUiOiJOViJ9AAAGAAAAbGFiZWxzAAAAAAAA3v7//wAAAgAAAAAAAAAAAH7///8UAAAAaAAAAGgAAAAAAAADaAAAAAIAAAAoAAAABAAAAEz///8IAAAADAAAAAAAAAAAAAAABAAAAG5hbWUAAAAAbP///wgAAAAYAAAADgAAAHsic3RhdGUiOiJPUiJ9AAAGAAAAbGFiZWxzAAAAAAAAYv///wAAAgAAAAAAAAASABgAFAAAABMADAAAAAgABAASAAAAFAAAAHAAAAB4AAAAAAAAA3gAAAACAAAAMAAAAAQAAADg////CAAAAAwAAAAAAAAAAAAAAAQAAABuYW1lAAAAAAgADAAIAAQACAAAAAgAAAAYAAAADgAAAHsic3RhdGUiOiJDQSJ9AAAGAAAAbGFiZWxzAAAAAAAAAAAGAAgABgAGAAAAAAACAAAAAAAAAAAAAAAAAP/////oAAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAGAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAeAAAAAEAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAAgAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAACAAAAAAAAAAAAAAAAwAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAG723pNbB+4/wlL/TspM1j/4AhKQmPDrPxAAAAAMABQAEgAMAAgABAAMAAAAEAAAACwAAAA4AAAAAAADAAEAAABQAgAAAAAAAPAAAAAAAAAAGAAAAAAAAAAAAAAAAAAAAAAACgAMAAAACAAEAAoAAAAIAAAAUAAAAAIAAAAoAAAABAAAAFT+//8IAAAADAAAAAAAAAAAAAAABQAAAHJlZklkAAAAdP7//wgAAAAMAAAAAwAAAGJhcgAEAAAAbmFtZQAAAAADAAAAJAEAAIwAAAAEAAAA+v7//xQAAABoAAAAaAAAAAAAAANoAAAAAgAAACgAAAAEAAAAyP7//wgAAAAMAAAAAAAAAAAAAAAEAAAAbmFtZQAAAADo/v//CAAAABgAAAAOAAAAeyJzdGF0ZSI6Ik5WIn0AAAYAAABsYWJlbHMAAAAAAADe/v//AAACAAAAAAAAAAAAfv///xQAAABoAAAAaAAAAAAAAANoAAAAAgAAACgAAAAEAAAATP///wgAAAAMAAAAAAAAAAAAAAAEAAAAbmFtZQAAAABs////CAAAABgAAAAOAAAAeyJzdGF0ZSI6Ik9SIn0AAAYAAABsYWJlbHMAAAAAAABi////AAACAAAAAAAAABIAGAAUAAAAEwAMAAAACAAEABIAAAAUAAAAcAAAAHgAAAAAAAADeAAAAAIAAAAwAAAABAAAAOD///8IAAAADAAAAAAAAAAAAAAABAAAAG5hbWUAAAAACAAMAAgABAAIAAAACAAAABgAAAAOAAAAeyJzdGF0ZSI6IkNBIn0AAAYAAABsYWJlbHMAAAAAAAAAAAYACAAGAAYAAAAAAAIAAAAAAAAAAABoAgAAQVJST1cx diff --git a/pkg/tsdb/testdatasource/testdata/usa-values-as-rows.txt b/pkg/tsdb/testdatasource/testdata/usa-values-as-rows.txt index e9fb0e991d5..29748c7bf0b 100644 --- a/pkg/tsdb/testdatasource/testdata/usa-values-as-rows.txt +++ b/pkg/tsdb/testdatasource/testdata/usa-values-as-rows.txt @@ -3,23 +3,23 @@ Frame[0] Name: Dimensions: 4 Fields by 51 Rows -+----------------+----------------------+----------------------+---------------------+ -| Name: state | Name: foo | Name: bar | Name: baz | -| Labels: | Labels: | Labels: | Labels: | -| Type: []string | Type: []float64 | Type: []float64 | Type: []float64 | -+----------------+----------------------+----------------------+---------------------+ -| AL | 0.6779842417778559 | 0.7350764367743711 | 0.9223316213929472 | -| AK | 0.9096030926893556 | -0.41547829518515106 | -2.1892914822036755 | -| AZ | -0.11168671678088725 | -0.9937434665418967 | 0.11238988787472795 | -| AR | -0.9791366197808846 | -0.2032030506760749 | 4.818513386109159 | -| CA | -0.4979007493043646 | 0.8672340190756773 | -0.5741250208738828 | -| CO | 0.6691553056325918 | 0.74312258540819 | 0.9004642286104536 | -| CT | 0.914501128595007 | -0.4045833483949364 | -2.260352859856979 | -| DE | -0.09980837850296802 | -0.9950066771537809 | 0.10030925499763493 | -| DC | -0.976639481217665 | -0.21488444272885437 | 4.544952016140177 | -| ... | ... | ... | ... | -+----------------+----------------------+----------------------+---------------------+ ++----------------+-----------------+-----------------+-----------------+ +| Name: state | Name: foo | Name: bar | Name: baz | +| Labels: | Labels: | Labels: | Labels: | +| Type: []string | Type: []float64 | Type: []float64 | Type: []float64 | ++----------------+-----------------+-----------------+-----------------+ +| AL | 0.6779842417 | 0.7350764367 | 0.9223316213 | +| AK | 0.9096030926 | -0.4154782951 | -2.1892914822 | +| AZ | -0.1116867167 | -0.9937434665 | 0.1123898878 | +| AR | -0.9791366197 | -0.2032030506 | 4.8185133861 | +| CA | -0.4979007493 | 0.867234019 | -0.5741250208 | +| CO | 0.6691553056 | 0.7431225854 | 0.9004642286 | +| CT | 0.9145011285 | -0.4045833483 | -2.2603528598 | +| DE | -0.0998083785 | -0.9950066771 | 0.1003092549 | +| DC | -0.9766394812 | -0.2148844427 | 4.5449520161 | +| ... | ... | ... | ... | ++----------------+-----------------+-----------------+-----------------+ ====== TEST DATA RESPONSE (arrow base64) ====== -FRAME=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 +FRAME=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 diff --git a/pkg/tsdb/testdatasource/usa_stats.go b/pkg/tsdb/testdatasource/usa_stats.go index 729479f665e..57dee9aed72 100644 --- a/pkg/tsdb/testdatasource/usa_stats.go +++ b/pkg/tsdb/testdatasource/usa_stats.go @@ -192,7 +192,10 @@ func getStateValues(t time.Time, field string, query usaQuery) []float64 { values := make([]float64, len(query.States)) for i := range query.States { tv += incr - values[i] = fn(float64(int64(tv) % int64(pn))) + value := fn(float64(int64(tv) % int64(pn))) + // We shall truncate float64 to a certain precision, because otherwise we might + // get different cos/tan results across different CPU architectures and compilers. + values[i] = float64(int(value*1e10)) / 1e10 } return values } From 0dfac9c3aa3401e11ef279321175aba118b2baf6 Mon Sep 17 00:00:00 2001 From: Serge Zaitsev Date: Tue, 10 Aug 2021 09:03:22 +0200 Subject: [PATCH 16/31] Macaron: convert CSP middleware (#37672) --- pkg/api/http_server.go | 2 +- pkg/middleware/csp.go | 61 +++++++++++++++---------------- pkg/middleware/middleware_test.go | 2 +- 3 files changed, 32 insertions(+), 33 deletions(-) diff --git a/pkg/api/http_server.go b/pkg/api/http_server.go index 2fd0a608118..6dc9d5ef994 100644 --- a/pkg/api/http_server.go +++ b/pkg/api/http_server.go @@ -375,7 +375,7 @@ func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() { } m.Use(middleware.HandleNoCacheHeader) - m.Use(middleware.AddCSPHeader(hs.Cfg, hs.log)) + m.UseMiddleware(middleware.AddCSPHeader(hs.Cfg, hs.log)) for _, mw := range hs.middlewares { m.Use(mw) diff --git a/pkg/middleware/csp.go b/pkg/middleware/csp.go index 3fff0cbe04f..2ea9614dfe0 100644 --- a/pkg/middleware/csp.go +++ b/pkg/middleware/csp.go @@ -10,45 +10,44 @@ import ( "strings" "github.com/grafana/grafana/pkg/infra/log" - "github.com/grafana/grafana/pkg/models" + "github.com/grafana/grafana/pkg/services/contexthandler" "github.com/grafana/grafana/pkg/setting" - macaron "gopkg.in/macaron.v1" ) // AddCSPHeader adds the Content Security Policy header. -func AddCSPHeader(cfg *setting.Cfg, logger log.Logger) macaron.Handler { - return func(w http.ResponseWriter, req *http.Request, c *macaron.Context) { - if !cfg.CSPEnabled { - return - } +func AddCSPHeader(cfg *setting.Cfg, logger log.Logger) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + if !cfg.CSPEnabled { + next.ServeHTTP(rw, req) + return + } - logger.Debug("Adding CSP header to response", "cfg", fmt.Sprintf("%p", cfg)) + logger.Debug("Adding CSP header to response", "cfg", fmt.Sprintf("%p", cfg)) - ctx, ok := c.Data["ctx"].(*models.ReqContext) - if !ok { - panic("Failed to convert context into models.ReqContext") - } + ctx := contexthandler.FromContext(req.Context()) + if cfg.CSPTemplate == "" { + logger.Debug("CSP template not configured, so returning 500") + ctx.JsonApiErr(500, "CSP template has to be configured", nil) + return + } - if cfg.CSPTemplate == "" { - logger.Debug("CSP template not configured, so returning 500") - ctx.JsonApiErr(500, "CSP template has to be configured", nil) - return - } + var buf [16]byte + if _, err := io.ReadFull(rand.Reader, buf[:]); err != nil { + logger.Error("Failed to generate CSP nonce", "err", err) + ctx.JsonApiErr(500, "Failed to generate CSP nonce", err) + } - var buf [16]byte - if _, err := io.ReadFull(rand.Reader, buf[:]); err != nil { - logger.Error("Failed to generate CSP nonce", "err", err) - ctx.JsonApiErr(500, "Failed to generate CSP nonce", err) - } + nonce := base64.RawStdEncoding.EncodeToString(buf[:]) + val := strings.ReplaceAll(cfg.CSPTemplate, "$NONCE", fmt.Sprintf("'nonce-%s'", nonce)) - nonce := base64.RawStdEncoding.EncodeToString(buf[:]) - val := strings.ReplaceAll(cfg.CSPTemplate, "$NONCE", fmt.Sprintf("'nonce-%s'", nonce)) - - re := regexp.MustCompile(`^\w+:(//)?`) - rootPath := re.ReplaceAllString(cfg.AppURL, "") - val = strings.ReplaceAll(val, "$ROOT_PATH", rootPath) - w.Header().Set("Content-Security-Policy", val) - ctx.RequestNonce = nonce - logger.Debug("Successfully generated CSP nonce", "nonce", nonce) + re := regexp.MustCompile(`^\w+:(//)?`) + rootPath := re.ReplaceAllString(cfg.AppURL, "") + val = strings.ReplaceAll(val, "$ROOT_PATH", rootPath) + rw.Header().Set("Content-Security-Policy", val) + ctx.RequestNonce = nonce + logger.Debug("Successfully generated CSP nonce", "nonce", nonce) + next.ServeHTTP(rw, req) + }) } } diff --git a/pkg/middleware/middleware_test.go b/pkg/middleware/middleware_test.go index 30ea0b1aff1..95defe3376c 100644 --- a/pkg/middleware/middleware_test.go +++ b/pkg/middleware/middleware_test.go @@ -632,7 +632,7 @@ func middlewareScenario(t *testing.T, desc string, fn scenarioFunc, cbs ...func( sc.m = macaron.New() sc.m.Use(AddDefaultResponseHeaders(cfg)) - sc.m.Use(AddCSPHeader(cfg, logger)) + sc.m.UseMiddleware(AddCSPHeader(cfg, logger)) sc.m.Use(macaron.Renderer(macaron.RenderOptions{ Directory: viewsPath, Delims: macaron.Delims{Left: "[[", Right: "]]"}, From 488930dbe37a0c45c8bd369d6ffcc47a9193a46a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Farkas?= Date: Tue, 10 Aug 2021 09:07:23 +0200 Subject: [PATCH 17/31] influxdb: influxql: update provisioning example (#37701) --- docs/sources/datasources/influxdb/provision-influxdb.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/sources/datasources/influxdb/provision-influxdb.md b/docs/sources/datasources/influxdb/provision-influxdb.md index 1498906ce1a..f8be6fb0582 100644 --- a/docs/sources/datasources/influxdb/provision-influxdb.md +++ b/docs/sources/datasources/influxdb/provision-influxdb.md @@ -21,10 +21,11 @@ datasources: access: proxy database: site user: grafana - password: grafana url: http://localhost:8086 jsonData: httpMode: GET + secureJsonData: + password: grafana ``` ## InfluxDB 2.x for Flux example From 3e124c854e109214a12b241624bde324cf856a15 Mon Sep 17 00:00:00 2001 From: Domas Date: Tue, 10 Aug 2021 10:59:48 +0300 Subject: [PATCH 18/31] Alerting: interpolate variables when creating alert rule from dashboard panel (#37201) --- pkg/expr/nodes.go | 4 +- .../unified/PanelAlertTabContent.test.tsx | 273 ++++++++++++++++++ .../NewRuleFromPanelButton.tsx | 10 +- public/app/features/alerting/unified/mocks.ts | 44 ++- .../alerting/unified/utils/rule-form.ts | 98 +++++-- .../plugins/datasource/influxdb/datasource.ts | 2 +- public/app/types/unified-alerting-dto.ts | 7 +- 7 files changed, 401 insertions(+), 37 deletions(-) create mode 100644 public/app/features/alerting/unified/PanelAlertTabContent.test.tsx diff --git a/pkg/expr/nodes.go b/pkg/expr/nodes.go index f88d054e0a9..e8914c0e7ff 100644 --- a/pkg/expr/nodes.go +++ b/pkg/expr/nodes.go @@ -186,7 +186,7 @@ func (s *Service) buildDSNode(dp *simple.DirectedGraph, rn *rawNode, req *Reques } var floatIntervalMS float64 - if rawIntervalMS := rn.Query["intervalMs"]; ok { + if rawIntervalMS, ok := rn.Query["intervalMs"]; ok { if floatIntervalMS, ok = rawIntervalMS.(float64); !ok { return nil, fmt.Errorf("expected intervalMs to be an float64, got type %T for refId %v", rawIntervalMS, rn.RefID) } @@ -194,7 +194,7 @@ func (s *Service) buildDSNode(dp *simple.DirectedGraph, rn *rawNode, req *Reques } var floatMaxDP float64 - if rawMaxDP := rn.Query["maxDataPoints"]; ok { + if rawMaxDP, ok := rn.Query["maxDataPoints"]; ok { if floatMaxDP, ok = rawMaxDP.(float64); !ok { return nil, fmt.Errorf("expected maxDataPoints to be an float64, got type %T for refId %v", rawMaxDP, rn.RefID) } diff --git a/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx b/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx new file mode 100644 index 00000000000..f584e1d80c0 --- /dev/null +++ b/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx @@ -0,0 +1,273 @@ +import React from 'react'; +import { locationService, setDataSourceSrv } from '@grafana/runtime'; +import { configureStore } from 'app/store/configureStore'; +import { Provider } from 'react-redux'; +import { Router } from 'react-router-dom'; +import { render } from '@testing-library/react'; +import { PanelAlertTabContent } from './PanelAlertTabContent'; +import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; +import { + mockDataSource, + MockDataSourceSrv, + mockPromAlertingRule, + mockPromRuleGroup, + mockPromRuleNamespace, + mockRulerGrafanaRule, +} from './mocks'; +import { DataSourceType } from './utils/datasource'; +import { typeAsJestMock } from 'test/helpers/typeAsJestMock'; +import { getAllDataSources } from './utils/config'; +import { fetchRules } from './api/prometheus'; +import { fetchRulerRules } from './api/ruler'; +import { Annotation } from './utils/constants'; +import { byTestId } from 'testing-library-selector'; +import { PrometheusDatasource } from 'app/plugins/datasource/prometheus/datasource'; +import { DataSourceApi } from '@grafana/data'; +import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; + +jest.mock('./api/prometheus'); +jest.mock('./api/ruler'); +jest.mock('./utils/config'); + +const dataSources = { + prometheus: mockDataSource({ + name: 'Prometheus', + type: DataSourceType.Prometheus, + }), +}; +dataSources.prometheus.meta.alerting = true; + +const mocks = { + getAllDataSources: typeAsJestMock(getAllDataSources), + api: { + fetchRules: typeAsJestMock(fetchRules), + fetchRulerRules: typeAsJestMock(fetchRulerRules), + }, +}; + +const renderAlertTabContent = (dashboard: DashboardModel, panel: PanelModel) => { + const store = configureStore(); + + return render( + + + + + + ); +}; + +const rules = [ + mockPromRuleNamespace({ + name: 'default', + groups: [ + mockPromRuleGroup({ + name: 'mygroup', + rules: [ + mockPromAlertingRule({ + name: 'dashboardrule1', + annotations: { + [Annotation.dashboardUID]: '12', + [Annotation.panelID]: '34', + }, + }), + ], + }), + mockPromRuleGroup({ + name: 'othergroup', + rules: [ + mockPromAlertingRule({ + name: 'dashboardrule2', + annotations: { + [Annotation.dashboardUID]: '121', + [Annotation.panelID]: '341', + }, + }), + ], + }), + ], + }), +]; + +const rulerRules = { + default: [ + { + name: 'mygroup', + rules: [ + mockRulerGrafanaRule( + { + annotations: { + [Annotation.dashboardUID]: '12', + [Annotation.panelID]: '34', + }, + }, + { + title: 'dashboardrule1', + } + ), + ], + }, + { + name: 'othergroup', + rules: [ + mockRulerGrafanaRule( + { + annotations: { + [Annotation.dashboardUID]: '121', + [Annotation.panelID]: '341', + }, + }, + { + title: 'dashboardrule2', + } + ), + ], + }, + ], +}; + +const dashboard = { + uid: '12', + time: { + from: 'now-6h', + to: 'now', + }, + meta: { + canSave: true, + folderId: 1, + folderTitle: 'super folder', + }, +} as DashboardModel; +const panel = ({ + datasource: dataSources.prometheus.uid, + title: 'mypanel', + editSourceId: 34, + targets: [ + { + expr: 'sum(some_metric [$__interval])) by (app)', + refId: 'A', + }, + ], +} as any) as PanelModel; + +const ui = { + row: byTestId('row'), + createButton: byTestId('create-alert-rule-button'), +}; + +describe('PanelAlertTabContent', () => { + beforeEach(() => { + jest.resetAllMocks(); + mocks.getAllDataSources.mockReturnValue(Object.values(dataSources)); + const dsService = new MockDataSourceSrv(dataSources); + dsService.datasources[dataSources.prometheus.name] = new PrometheusDatasource( + dataSources.prometheus + ) as DataSourceApi; + setDataSourceSrv(dsService); + }); + + it('Will take into account panel maxDataPoints', async () => { + await renderAlertTabContent(dashboard, ({ + ...panel, + maxDataPoints: 100, + interval: '10s', + } as any) as PanelModel); + const button = await ui.createButton.find(); + const href = button.href; + const match = href.match(/alerting\/new\?defaults=(.*)&returnTo=/); + expect(match).toHaveLength(2); + const defaults = JSON.parse(decodeURIComponent(match![1])); + expect(defaults.queries[0].model).toEqual({ + expr: 'sum(some_metric [5m])) by (app)', + refId: 'A', + datasource: 'Prometheus', + interval: '', + intervalMs: 300000, + maxDataPoints: 100, + }); + }); + + it('Will take into account datasource minInterval', async () => { + ((getDatasourceSrv() as any) as MockDataSourceSrv).datasources[dataSources.prometheus.name].interval = '7m'; + + await renderAlertTabContent(dashboard, ({ + ...panel, + maxDataPoints: 100, + } as any) as PanelModel); + const button = await ui.createButton.find(); + const href = button.href; + const match = href.match(/alerting\/new\?defaults=(.*)&returnTo=/); + expect(match).toHaveLength(2); + const defaults = JSON.parse(decodeURIComponent(match![1])); + expect(defaults.queries[0].model).toEqual({ + expr: 'sum(some_metric [7m])) by (app)', + refId: 'A', + datasource: 'Prometheus', + interval: '', + intervalMs: 420000, + maxDataPoints: 100, + }); + }); + + it('Will render alerts belonging to panel and a button to create alert from panel queries', async () => { + mocks.api.fetchRules.mockResolvedValue(rules); + mocks.api.fetchRulerRules.mockResolvedValue(rulerRules); + + await renderAlertTabContent(dashboard, panel); + + const rows = await ui.row.findAll(); + expect(rows).toHaveLength(1); + expect(rows[0]).toHaveTextContent(/dashboardrule1/); + expect(rows[0]).not.toHaveTextContent(/dashboardrule2/); + const button = await ui.createButton.find(); + const href = button.href; + const match = href.match(/alerting\/new\?defaults=(.*)&returnTo=/); + expect(match).toHaveLength(2); + const defaults = JSON.parse(decodeURIComponent(match![1])); + expect(defaults).toEqual({ + type: 'grafana', + folder: { id: 1, title: 'super folder' }, + queries: [ + { + refId: 'A', + queryType: '', + relativeTimeRange: { from: 21600, to: 0 }, + datasourceUid: 'mock-ds-2', + model: { + expr: 'sum(some_metric [15s])) by (app)', + refId: 'A', + datasource: 'Prometheus', + interval: '', + intervalMs: 15000, + }, + }, + { + refId: 'B', + datasourceUid: '-100', + queryType: '', + model: { + refId: 'B', + hide: false, + type: 'classic_conditions', + datasource: '__expr__', + conditions: [ + { + type: 'query', + evaluator: { params: [3], type: 'gt' }, + operator: { type: 'and' }, + query: { params: ['A'] }, + reducer: { params: [], type: 'last' }, + }, + ], + }, + }, + ], + name: 'mypanel', + condition: 'B', + annotations: [ + { key: '__dashboardUid__', value: '12' }, + { key: '__panelId__', value: '34' }, + ], + }); + }); +}); diff --git a/public/app/features/alerting/unified/components/panel-alerts-tab/NewRuleFromPanelButton.tsx b/public/app/features/alerting/unified/components/panel-alerts-tab/NewRuleFromPanelButton.tsx index fb11e355d08..234dc3c3175 100644 --- a/public/app/features/alerting/unified/components/panel-alerts-tab/NewRuleFromPanelButton.tsx +++ b/public/app/features/alerting/unified/components/panel-alerts-tab/NewRuleFromPanelButton.tsx @@ -1,9 +1,10 @@ import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import React, { FC } from 'react'; -import { Alert, LinkButton } from '@grafana/ui'; +import { Alert, LinkButton, Button } from '@grafana/ui'; import { panelToRuleFormValues } from '../../utils/rule-form'; import { useLocation } from 'react-router-dom'; import { urlUtil } from '@grafana/data'; +import { useAsync } from 'react-use'; interface Props { panel: PanelModel; @@ -12,8 +13,11 @@ interface Props { } export const NewRuleFromPanelButton: FC = ({ dashboard, panel, className }) => { - const formValues = panelToRuleFormValues(panel, dashboard); + const { loading, value: formValues } = useAsync(() => panelToRuleFormValues(panel, dashboard), [panel, dashboard]); const location = useLocation(); + if (loading) { + return ; + } if (!formValues) { return ( @@ -29,7 +33,7 @@ export const NewRuleFromPanelButton: FC = ({ dashboard, panel, className }); return ( - + Create alert rule from this panel ); diff --git a/public/app/features/alerting/unified/mocks.ts b/public/app/features/alerting/unified/mocks.ts index 70dc72ad90a..bd8c0f0bc20 100644 --- a/public/app/features/alerting/unified/mocks.ts +++ b/public/app/features/alerting/unified/mocks.ts @@ -1,5 +1,11 @@ import { DataSourceApi, DataSourceInstanceSettings, DataSourcePluginMeta, ScopedVars } from '@grafana/data'; -import { PromAlertingRuleState, PromRuleType } from 'app/types/unified-alerting-dto'; +import { + GrafanaAlertStateDecision, + GrafanaRuleDefinition, + PromAlertingRuleState, + PromRuleType, + RulerGrafanaRuleDTO, +} from 'app/types/unified-alerting-dto'; import { AlertingRule, Alert, RecordingRule, RuleGroup, RuleNamespace } from 'app/types/unified-alerting'; import DatasourceSrv from 'app/features/plugins/datasource_srv'; import { DataSourceSrv, GetDataSourceListFilters } from '@grafana/runtime'; @@ -17,7 +23,7 @@ let nextDataSourceId = 1; export const mockDataSource = ( partial: Partial = {}, meta: Partial = {} -): DataSourceInstanceSettings => { +): DataSourceInstanceSettings => { const id = partial.id ?? nextDataSourceId++; return { @@ -54,6 +60,40 @@ export const mockPromAlert = (partial: Partial = {}): Alert => ({ ...partial, }); +export const mockRulerGrafanaRule = ( + partial: Partial = {}, + partialDef: Partial = {} +): RulerGrafanaRuleDTO => { + return { + for: '1m', + grafana_alert: { + uid: '123', + title: 'myalert', + namespace_uid: '123', + namespace_id: 1, + condition: 'A', + no_data_state: GrafanaAlertStateDecision.Alerting, + exec_err_state: GrafanaAlertStateDecision.Alerting, + data: [ + { + datasourceUid: '123', + refId: 'A', + queryType: 'huh', + model: {} as any, + }, + ], + ...partialDef, + }, + annotations: { + message: 'alert with severity "{{.warning}}}"', + }, + labels: { + severity: 'warning', + }, + ...partial, + }; +}; + export const mockPromAlertingRule = (partial: Partial = {}): AlertingRule => { return { type: PromRuleType.Alerting, diff --git a/public/app/features/alerting/unified/utils/rule-form.ts b/public/app/features/alerting/unified/utils/rule-form.ts index e5006b801ea..5ce60e559b7 100644 --- a/public/app/features/alerting/unified/utils/rule-form.ts +++ b/public/app/features/alerting/unified/utils/rule-form.ts @@ -1,11 +1,18 @@ -import { DataQuery, rangeUtil, RelativeTimeRange } from '@grafana/data'; +import { + DataQuery, + rangeUtil, + RelativeTimeRange, + ScopedVars, + getDefaultRelativeTimeRange, + TimeRange, + IntervalValues, +} from '@grafana/data'; import { getDataSourceSrv } from '@grafana/runtime'; import { contextSrv } from 'app/core/services/context_srv'; import { getNextRefIdChar } from 'app/core/utils/query'; import { DashboardModel, PanelModel } from 'app/features/dashboard/state'; import { ExpressionDatasourceID, ExpressionDatasourceUID } from 'app/features/expressions/ExpressionDatasource'; import { ExpressionQuery, ExpressionQueryType } from 'app/features/expressions/types'; -import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; import { RuleWithLocation } from 'app/types/unified-alerting'; import { Annotations, @@ -22,7 +29,6 @@ import { isGrafanaRulesSource } from './datasource'; import { arrayToRecord, recordToArray } from './misc'; import { isAlertingRulerRule, isGrafanaRulerRule } from './rules'; import { parseInterval } from './time'; -import { getDefaultRelativeTimeRange } from '../../../../../../packages/grafana-data'; export const getDefaultFormValues = (): RuleFormValues => Object.freeze({ @@ -193,60 +199,81 @@ const getDefaultExpression = (refId: string): AlertQuery => { }; }; -const dataQueriesToGrafanaQueries = ( +const dataQueriesToGrafanaQueries = async ( queries: DataQuery[], relativeTimeRange: RelativeTimeRange, - datasourceName?: string -): AlertQuery[] => { - return queries.reduce((queries, target) => { + scopedVars: ScopedVars | {}, + datasourceName?: string, + maxDataPoints?: number, + minInterval?: string +): Promise => { + const result: AlertQuery[] = []; + for (const target of queries) { const dsName = target.datasource || datasourceName; + const datasource = await getDataSourceSrv().get(dsName); + + const range = rangeUtil.relativeToTimeRange(relativeTimeRange); + const { interval, intervalMs } = getIntervals(range, minInterval ?? datasource.interval, maxDataPoints); + const queryVariables = { + __interval: { text: interval, value: interval }, + __interval_ms: { text: intervalMs, value: intervalMs }, + ...scopedVars, + }; + const interpolatedTarget = datasource.interpolateVariablesInQueries + ? await datasource.interpolateVariablesInQueries([target], queryVariables)[0] + : target; if (dsName) { // expressions if (dsName === ExpressionDatasourceID) { const newQuery: AlertQuery = { - refId: target.refId, + refId: interpolatedTarget.refId, queryType: '', relativeTimeRange, datasourceUid: ExpressionDatasourceUID, - model: target, + model: interpolatedTarget, }; - return [...queries, newQuery]; + result.push(newQuery); // queries } else { - const datasource = getDataSourceSrv().getInstanceSettings(target.datasource || datasourceName); - if (datasource && datasource.meta.alerting) { + const datasourceSettings = getDataSourceSrv().getInstanceSettings(dsName); + if (datasourceSettings && datasourceSettings.meta.alerting) { const newQuery: AlertQuery = { - refId: target.refId, - queryType: target.queryType ?? '', + refId: interpolatedTarget.refId, + queryType: interpolatedTarget.queryType ?? '', relativeTimeRange, - datasourceUid: datasource.uid, - model: target, + datasourceUid: datasourceSettings.uid, + model: { + ...interpolatedTarget, + maxDataPoints, + intervalMs, + }, }; - return [...queries, newQuery]; + result.push(newQuery); } } } - return queries; - }, []); + } + return result; }; -export const panelToRuleFormValues = ( +export const panelToRuleFormValues = async ( panel: PanelModel, dashboard: DashboardModel -): Partial | undefined => { +): Promise | undefined> => { const { targets } = panel; - - // it seems if default datasource is selected, datasource=null, hah - const datasourceName = - panel.datasource === null ? getDatasourceSrv().getInstanceSettings('default')?.name : panel.datasource; - if (!panel.editSourceId || !dashboard.uid) { return undefined; } const relativeTimeRange = rangeUtil.timeRangeToRelative(rangeUtil.convertRawToRange(dashboard.time)); - const queries = dataQueriesToGrafanaQueries(targets, relativeTimeRange, datasourceName); - + const queries = await dataQueriesToGrafanaQueries( + targets, + relativeTimeRange, + panel.scopedVars || {}, + panel.datasource ?? undefined, + panel.maxDataPoints ?? undefined, + panel.interval ?? undefined + ); // if no alerting capable queries are found, can't create a rule if (!queries.length || !queries.find((query) => query.datasourceUid !== ExpressionDatasourceUID)) { return undefined; @@ -269,6 +296,7 @@ export const panelToRuleFormValues = ( : undefined, queries, name: panel.title, + condition: queries[queries.length - 1].refId, annotations: [ { key: Annotation.dashboardUID, @@ -282,3 +310,17 @@ export const panelToRuleFormValues = ( }; return formValues; }; + +export function getIntervals(range: TimeRange, lowLimit?: string, resolution?: number): IntervalValues { + if (!resolution) { + if (lowLimit && rangeUtil.intervalToMs(lowLimit) > 1000) { + return { + interval: lowLimit, + intervalMs: rangeUtil.intervalToMs(lowLimit), + }; + } + return { interval: '1s', intervalMs: 1000 }; + } + + return rangeUtil.calculateInterval(range, resolution, lowLimit); +} diff --git a/public/app/plugins/datasource/influxdb/datasource.ts b/public/app/plugins/datasource/influxdb/datasource.ts index caa8bd0de92..abb555b050e 100644 --- a/public/app/plugins/datasource/influxdb/datasource.ts +++ b/public/app/plugins/datasource/influxdb/datasource.ts @@ -344,7 +344,7 @@ export default class InfluxDatasource extends DataSourceWithBackend Date: Tue, 10 Aug 2021 10:23:49 +0200 Subject: [PATCH 19/31] UI: FileDropzone component to handle file list overwrite (#37685) * UI: FileDropzone component to handle file list overwrite * FileListItem: use type=button everywhere * Update packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx Co-authored-by: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> * FileListItem: add aria-hidden and change cancel text * Update packages/grafana-ui/src/components/FileDropzone/FileListItem.test.tsx Co-authored-by: Alex Khomenko Co-authored-by: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> Co-authored-by: Alex Khomenko --- .../FileDropzone/FileDropzone.story.tsx | 4 ++++ .../components/FileDropzone/FileDropzone.test.tsx | 11 +++++++++++ .../src/components/FileDropzone/FileDropzone.tsx | 14 ++++++++++++-- .../components/FileDropzone/FileListItem.test.tsx | 4 ++-- .../src/components/FileDropzone/FileListItem.tsx | 15 ++++++++++++--- 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx index b4f5741c78e..9451ddfa1a8 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.story.tsx @@ -21,3 +21,7 @@ export default { export const Basic: Story = (args) => { return ; }; + +export const WithCustomFileList: Story = () => { + return
Custom rendered item {file.file.name}
} />; +}; diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx index 09074c95a15..2d589f69ef6 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.test.tsx @@ -107,6 +107,17 @@ describe('The FileDropzone component', () => { screen.getByText('Custom dropzone text'); }); + + it('should handle file list overwrite when fileListRenderer is passed', async () => { + render( null} />); + + dispatchEvt(screen.getByTestId('dropzone'), 'drop', mockData([file({})])); + + // need to await this in order to have the drop finished + await screen.findByTestId('dropzone'); + + expect(screen.queryByText('ping.json')).not.toBeInTheDocument(); + }); }); function dispatchEvt(node: HTMLElement, type: string, data: any) { diff --git a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx index 215d67c1642..3c49ffbc176 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileDropzone.tsx @@ -30,6 +30,11 @@ export interface FileDropzoneProps { * Use the onLoad function to get the result from FileReader. */ onLoad?: (result: string | ArrayBuffer | null) => void; + /** + * The fileListRenderer property can be used to overwrite the list of files. To not to show + * any list return null in the function. + */ + fileListRenderer?: (file: DropzoneFile, removeFile: (file: DropzoneFile) => void) => ReactNode; } export interface DropzoneFile { @@ -41,7 +46,7 @@ export interface DropzoneFile { retryUpload?: () => void; } -export function FileDropzone({ options, children, readAs, onLoad }: FileDropzoneProps) { +export function FileDropzone({ options, children, readAs, onLoad, fileListRenderer }: FileDropzoneProps) { const [files, setFiles] = useState([]); const setFileProperty = useCallback( @@ -133,7 +138,12 @@ export function FileDropzone({ options, children, readAs, onLoad }: FileDropzone const { getRootProps, getInputProps, isDragActive } = useDropzone({ ...options, onDrop }); const theme = useTheme2(); const styles = getStyles(theme, isDragActive); - const fileList = files.map((file) => ); + const fileList = files.map((file) => { + if (fileListRenderer) { + return fileListRenderer(file, removeFile); + } + return ; + }); return (
diff --git a/packages/grafana-ui/src/components/FileDropzone/FileListItem.test.tsx b/packages/grafana-ui/src/components/FileDropzone/FileListItem.test.tsx index 95b5caf5ae2..e1a0e75f2de 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileListItem.test.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileListItem.test.tsx @@ -30,7 +30,7 @@ describe('The FileListItem component', () => { it('should show a progressbar when the progress prop has a value', () => { render(); - expect(screen.queryByText('Cancel')).not.toBeInTheDocument(); + expect(screen.queryByText('Cancel upload')).not.toBeInTheDocument(); expect(screen.getByText('46%')).toBeInTheDocument(); expect(screen.getByRole('progressbar')).toBeInTheDocument(); }); @@ -45,7 +45,7 @@ describe('The FileListItem component', () => { const abortUpload = jest.fn(); render(); - fireEvent.click(screen.getByRole('button', { name: 'Cancel' })); + fireEvent.click(screen.getByRole('button', { name: /cancel/i })); expect(abortUpload).toBeCalledTimes(1); }); diff --git a/packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx b/packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx index 27255b55731..cf039248391 100644 --- a/packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx +++ b/packages/grafana-ui/src/components/FileDropzone/FileListItem.tsx @@ -24,11 +24,19 @@ export function FileListItem({ file: customFile, removeFile }: FileListItemProps <> {error.message} {retryUpload && ( - + )} {removeFile && ( removeFile(customFile)} tooltip={REMOVE_FILE} @@ -46,7 +54,7 @@ export function FileListItem({ file: customFile, removeFile }: FileListItemProps {Math.round((progress / file.size) * 100)}% {abortUpload && ( )} @@ -59,6 +67,7 @@ export function FileListItem({ file: customFile, removeFile }: FileListItemProps onClick={() => removeFile(customFile)} tooltip={REMOVE_FILE} aria-label={REMOVE_FILE} + type="button" tooltipPlacement="top" /> ) @@ -70,7 +79,7 @@ export function FileListItem({ file: customFile, removeFile }: FileListItemProps return (
- + {trimFileName(file.name)} {formattedValueToString(valueFormat)} From 06368abf4462026d1aeed098aee07b769ec0eaaf Mon Sep 17 00:00:00 2001 From: Jeremy Price Date: Tue, 10 Aug 2021 11:11:13 +0200 Subject: [PATCH 20/31] Accesscontrol fix permission name (#37717) * Fixes permission name for services:accesscontrol --- .../enterprise/access-control/permissions.md | 22 +++++++++---------- docs/sources/http_api/admin.md | 6 ++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/sources/enterprise/access-control/permissions.md b/docs/sources/enterprise/access-control/permissions.md index 6b0996b5474..c292502125f 100644 --- a/docs/sources/enterprise/access-control/permissions.md +++ b/docs/sources/enterprise/access-control/permissions.md @@ -39,7 +39,7 @@ The following list contains fine-grained access control actions. | `reports:send` | `reports:*` | Send a report email. | | `reports.settings:write` | n/a | Update report settings. | | `reports.settings:read` | n/a | Read report settings. | -| `provisioning:reload` | `service:accesscontrol` | Reload provisioning files. | +| `provisioning:reload` | `services:accesscontrol` | Reload provisioning files. | | `users:read` | `global:users:*` | Read or search user profiles. | | `users:write` | `global:users:*` | Update a user’s profile. | | `users.teams:read` | `global:users:*` | Read a user’s teams. | @@ -62,7 +62,7 @@ The following list contains fine-grained access control actions. | `ldap.user:sync` | n/a | Sync a user via LDAP. | | `ldap.status:read` | n/a | Verify the LDAP servers’ availability. | | `ldap.config:reload` | n/a | Reload the LDAP configuration. | -| `status:accesscontrol` | `service:accesscontrol` | Get access-control enabled status. | +| `status:accesscontrol` | `services:accesscontrol` | Get access-control enabled status. | | `settings:read` | `settings:**`
`settings:auth.saml:*`
`settings:auth.saml:enabled` (property level) | Read settings | | `settings:write` | `settings:**`
`settings:auth.saml:*`
`settings:auth.saml:enabled` (property level) | Update settings | | `server.stats:read` | n/a | Read server stats | @@ -72,12 +72,12 @@ The following list contains fine-grained access control actions. The following list contains fine-grained access control scopes. -| Scopes | Descriptions | -| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `roles:*` | Restrict an action to a set of roles. For example, `roles:*` matches any role, `roles:randomuid` matches only the role with UID `randomuid` and `roles:custom:reports:{editor,viewer}` matches both `custom:reports:editor` and `custom:reports:viewer` roles. | -| `permissions:delegate` | The scope is only applicable for roles associated with the Access Control itself and indicates that you can delegate your permissions only, or a subset of it, by creating a new role or making an assignment. | -| `reports:*` | Restrict an action to a set of reports. For example, `reports:*` matches any report and `reports:1` matches the report with id `1`. | -| `service:accesscontrol` | Restrict an action to target only the fine-grained access control service. For example, you can use this in conjunction with the `provisioning:reload` or the `status:accesscontrol` actions. | -| `global:users:*` | Restrict an action to a set of global users. | -| `users:*` | Restrict an action to a set of users from an organization. | -| `settings:**` | Restrict an action to a subset of settings. For example, `settings:**` matches all settings, `settings:auth.saml:*` matches all SAML settings, and `settings:auth.saml:enabled` matches the enable property on the SAML settings. | +| Scopes | Descriptions | +| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `roles:*` | Restrict an action to a set of roles. For example, `roles:*` matches any role, `roles:randomuid` matches only the role with UID `randomuid` and `roles:custom:reports:{editor,viewer}` matches both `custom:reports:editor` and `custom:reports:viewer` roles. | +| `permissions:delegate` | The scope is only applicable for roles associated with the Access Control itself and indicates that you can delegate your permissions only, or a subset of it, by creating a new role or making an assignment. | +| `reports:*` | Restrict an action to a set of reports. For example, `reports:*` matches any report and `reports:1` matches the report with id `1`. | +| `services:accesscontrol` | Restrict an action to target only the fine-grained access control service. For example, you can use this in conjunction with the `provisioning:reload` or the `status:accesscontrol` actions. | +| `global:users:*` | Restrict an action to a set of global users. | +| `users:*` | Restrict an action to a set of users from an organization. | +| `settings:**` | Restrict an action to a subset of settings. For example, `settings:**` matches all settings, `settings:auth.saml:*` matches all SAML settings, and `settings:auth.saml:enabled` matches the enable property on the SAML settings. | diff --git a/docs/sources/http_api/admin.md b/docs/sources/http_api/admin.md index 8a2fd007893..fb84bc295ff 100644 --- a/docs/sources/http_api/admin.md +++ b/docs/sources/http_api/admin.md @@ -612,9 +612,9 @@ Only works with Basic Authentication (username and password). See [introduction] See note in the [introduction]({{< ref "#admin-api" >}}) for an explanation. -| Action | Scope | Provision entity | -| ------------------- | --------------------- | ---------------- | -| provisioning:reload | service:accesscontrol | accesscontrol | +| Action | Scope | Provision entity | +| ------------------- | ---------------------- | ---------------- | +| provisioning:reload | services:accesscontrol | accesscontrol | **Example Request**: From 5b575ae91f22dce2a3c15b5e4dbc0721146ba8a1 Mon Sep 17 00:00:00 2001 From: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> Date: Tue, 10 Aug 2021 12:43:50 +0200 Subject: [PATCH 21/31] TimeRangeOption: Make entire list item clickable #37730 --- .../DateTimePickers/TimeRangePicker/TimeRangeOption.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeOption.tsx b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeOption.tsx index a622e8d6f0c..14627ea9589 100644 --- a/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeOption.tsx +++ b/packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeOption.tsx @@ -52,7 +52,7 @@ export const TimeRangeOption = memo(({ value, onSelect, selected = false, const id = uuidv4(); return ( -
  • +
  • onSelect(value)} className={cx(styles.container, selected && styles.selected)}> Date: Tue, 10 Aug 2021 13:29:46 +0200 Subject: [PATCH 22/31] Macaron: Strip down renderer middleware (#37627) * strip down macaron renderer * inline renderHTML * remove IndentJSON parameter * replace renderer with a html/template set * fix failing test * fix renderer paths in tests * make template reloading even simpler * unify ignored gzip path lookup * fix csp middleware usage --- pkg/api/avatar/avatar.go | 2 +- pkg/api/common_test.go | 5 +- pkg/api/frontendsettings_test.go | 6 +- pkg/api/http_server.go | 10 +- pkg/macaron/context.go | 46 +- pkg/macaron/macaron.go | 1 - pkg/macaron/render.go | 727 ++---------------------------- pkg/middleware/gziper.go | 90 ++-- pkg/middleware/middleware_test.go | 7 +- pkg/middleware/org_redirect.go | 2 +- pkg/middleware/rate_limit_test.go | 5 +- pkg/middleware/recovery.go | 2 +- pkg/middleware/recovery_test.go | 5 +- pkg/models/context.go | 2 +- 14 files changed, 145 insertions(+), 765 deletions(-) diff --git a/pkg/api/avatar/avatar.go b/pkg/api/avatar/avatar.go index 2c3952684c0..7ef583e0fe1 100644 --- a/pkg/api/avatar/avatar.go +++ b/pkg/api/avatar/avatar.go @@ -118,7 +118,7 @@ func (a *CacheServer) Handler(ctx *models.ReqContext) { if err := avatar.Encode(ctx.Resp); err != nil { log.Warnf("avatar encode error: %v", err) - ctx.WriteHeader(500) + ctx.Resp.WriteHeader(500) } } diff --git a/pkg/api/common_test.go b/pkg/api/common_test.go index db083c30e26..e5a95a0525e 100644 --- a/pkg/api/common_test.go +++ b/pkg/api/common_test.go @@ -217,10 +217,7 @@ func setupScenarioContext(t *testing.T, url string) *scenarioContext { require.Truef(t, exists, "Views should be in %q", viewsPath) sc.m = macaron.New() - sc.m.Use(macaron.Renderer(macaron.RenderOptions{ - Directory: viewsPath, - Delims: macaron.Delims{Left: "[[", Right: "]]"}, - })) + sc.m.UseMiddleware(macaron.Renderer(viewsPath, "[[", "]]")) sc.m.Use(getContextHandler(t, cfg).Middleware) return sc diff --git a/pkg/api/frontendsettings_test.go b/pkg/api/frontendsettings_test.go index bd9b4dfcbea..11c858be3a8 100644 --- a/pkg/api/frontendsettings_test.go +++ b/pkg/api/frontendsettings_test.go @@ -58,11 +58,7 @@ func setupTestEnvironment(t *testing.T, cfg *setting.Cfg) (*macaron.Macaron, *HT m := macaron.New() m.Use(getContextHandler(t, cfg).Middleware) - m.Use(macaron.Renderer(macaron.RenderOptions{ - Directory: filepath.Join(setting.StaticRootPath, "views"), - IndentJSON: true, - Delims: macaron.Delims{Left: "[[", Right: "]]"}, - })) + m.UseMiddleware(macaron.Renderer(filepath.Join(setting.StaticRootPath, "views"), "[[", "]]")) m.Get("/api/frontend/settings/", hs.GetFrontendSettings) return m, hs diff --git a/pkg/api/http_server.go b/pkg/api/http_server.go index 6dc9d5ef994..4e8be016ffa 100644 --- a/pkg/api/http_server.go +++ b/pkg/api/http_server.go @@ -335,7 +335,7 @@ func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() { m.Use(middleware.Logger(hs.Cfg)) if hs.Cfg.EnableGzip { - m.Use(middleware.Gziper()) + m.UseMiddleware(middleware.Gziper()) } m.Use(middleware.Recovery(hs.Cfg)) @@ -354,11 +354,7 @@ func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() { m.SetURLPrefix(hs.Cfg.AppSubURL) } - m.Use(macaron.Renderer(macaron.RenderOptions{ - Directory: filepath.Join(hs.Cfg.StaticRootPath, "views"), - IndentJSON: macaron.Env != macaron.PROD, - Delims: macaron.Delims{Left: "[[", Right: "]]"}, - })) + m.UseMiddleware(macaron.Renderer(filepath.Join(hs.Cfg.StaticRootPath, "views"), "[[", "]]")) // These endpoints are used for monitoring the Grafana instance // and should not be redirected or rejected. @@ -408,7 +404,7 @@ func (hs *HTTPServer) healthzHandler(ctx *macaron.Context) { return } - ctx.WriteHeader(200) + ctx.Resp.WriteHeader(200) _, err := ctx.Resp.Write([]byte("Ok")) if err != nil { hs.log.Error("could not write to response", "err", err) diff --git a/pkg/macaron/context.go b/pkg/macaron/context.go index 2920f834af8..a26b37aafdb 100644 --- a/pkg/macaron/context.go +++ b/pkg/macaron/context.go @@ -15,6 +15,8 @@ package macaron import ( + "encoding/json" + "html/template" "net/http" "net/url" "reflect" @@ -44,11 +46,11 @@ type Context struct { index int *Router - Req Request - Resp ResponseWriter - params Params - Render - Data map[string]interface{} + Req Request + Resp ResponseWriter + params Params + template *template.Template + Data map[string]interface{} } func (ctx *Context) handler() Handler { @@ -108,19 +110,31 @@ func (ctx *Context) RemoteAddr() string { return addr } -func (ctx *Context) renderHTML(status int, setName, tplName string, data ...interface{}) { - if len(data) <= 0 { - ctx.Render.HTMLSet(status, setName, tplName, ctx.Data) - } else if len(data) == 1 { - ctx.Render.HTMLSet(status, setName, tplName, data[0]) - } else { - ctx.Render.HTMLSet(status, setName, tplName, data[0], data[1].(HTMLOptions)) +const ( + headerContentType = "Content-Type" + contentTypeJSON = "application/json; charset=UTF-8" + contentTypeHTML = "text/html; charset=UTF-8" +) + +// HTML renders the HTML with default template set. +func (ctx *Context) HTML(status int, name string, data interface{}) { + ctx.Resp.Header().Set(headerContentType, contentTypeHTML) + ctx.Resp.WriteHeader(status) + if err := ctx.template.ExecuteTemplate(ctx.Resp, name, data); err != nil { + panic("Context.HTML:" + err.Error()) } } -// HTML renders the HTML with default template set. -func (ctx *Context) HTML(status int, name string, data ...interface{}) { - ctx.renderHTML(status, DEFAULT_TPL_SET_NAME, name, data...) +func (ctx *Context) JSON(status int, data interface{}) { + ctx.Resp.Header().Set(headerContentType, contentTypeJSON) + ctx.Resp.WriteHeader(status) + enc := json.NewEncoder(ctx.Resp) + if Env != PROD { + enc.SetIndent("", " ") + } + if err := enc.Encode(data); err != nil { + panic("Context.JSON: " + err.Error()) + } } // Redirect sends a redirect response @@ -142,7 +156,7 @@ func (ctx *Context) parseForm() { return } - contentType := ctx.Req.Header.Get(_CONTENT_TYPE) + contentType := ctx.Req.Header.Get(headerContentType) if (ctx.Req.Method == "POST" || ctx.Req.Method == "PUT") && len(contentType) > 0 && strings.Contains(contentType, "multipart/form-data") { _ = ctx.Req.ParseMultipartForm(MaxMemory) diff --git a/pkg/macaron/macaron.go b/pkg/macaron/macaron.go index 40701d7bfcd..ce44a6ebf26 100644 --- a/pkg/macaron/macaron.go +++ b/pkg/macaron/macaron.go @@ -182,7 +182,6 @@ func (m *Macaron) createContext(rw http.ResponseWriter, req *http.Request) *Cont index: 0, Router: m.Router, Resp: NewResponseWriter(req.Method, rw), - Render: &DummyRender{rw}, Data: make(map[string]interface{}), } req = req.WithContext(context.WithValue(req.Context(), macaronContextKey{}, c)) diff --git a/pkg/macaron/render.go b/pkg/macaron/render.go index 8aec82bee59..c6acbee5bb0 100644 --- a/pkg/macaron/render.go +++ b/pkg/macaron/render.go @@ -16,708 +16,57 @@ package macaron import ( - "bytes" - "encoding/json" - "encoding/xml" - "fmt" "html/template" - "io" - "io/ioutil" + "io/fs" "net/http" "os" - "path" "path/filepath" - "strings" - "sync" - "time" ) -const ( - _CONTENT_TYPE = "Content-Type" - _CONTENT_BINARY = "application/octet-stream" - _CONTENT_JSON = "application/json" - _CONTENT_HTML = "text/html" - _CONTENT_PLAIN = "text/plain" - _CONTENT_XHTML = "application/xhtml+xml" - _CONTENT_XML = "text/xml" - _DEFAULT_CHARSET = "UTF-8" -) - -var ( - // Provides a temporary buffer to execute templates into and catch errors. - bufpool = sync.Pool{ - New: func() interface{} { return new(bytes.Buffer) }, +// Renderer is a Middleware that injects a template renderer into the macaron context, enabling ctx.HTML calls in the handlers. +// If MACARON_ENV is set to "development" then templates will be recompiled on every request. For more performance, set the +// MACARON_ENV environment variable to "production". +func Renderer(dir, leftDelim, rightDelim string) func(http.Handler) http.Handler { + fs := os.DirFS(dir) + t, err := compileTemplates(fs, leftDelim, rightDelim) + if err != nil { + panic("Renderer: " + err.Error()) } - - // Included helper functions for use when rendering html - helperFuncs = template.FuncMap{ - "yield": func() (string, error) { - return "", fmt.Errorf("yield called with no layout defined") - }, - "current": func() (string, error) { - return "", nil - }, + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + ctx := FromContext(req.Context()) + if Env == DEV { + if t, err = compileTemplates(fs, leftDelim, rightDelim); err != nil { + panic("Context.HTML:" + err.Error()) + } + } + ctx.template = t + next.ServeHTTP(rw, req) + }) } -) - -type ( - // TemplateFile represents a interface of template file that has name and can be read. - TemplateFile interface { - Name() string - Data() []byte - Ext() string - } - // TemplateFileSystem represents a interface of template file system that able to list all files. - TemplateFileSystem interface { - ListFiles() []TemplateFile - Get(string) (io.Reader, error) - } - - // Delims represents a set of Left and Right delimiters for HTML template rendering - Delims struct { - // Left delimiter, defaults to {{ - Left string - // Right delimiter, defaults to }} - Right string - } - - // RenderOptions represents a struct for specifying configuration options for the Render middleware. - RenderOptions struct { - // Directory to load templates. Default is "templates". - Directory string - // Addtional directories to overwite templates. - AppendDirectories []string - // Layout template name. Will not render a layout if "". Default is to "". - Layout string - // Extensions to parse template files from. Defaults are [".tmpl", ".html"]. - Extensions []string - // Funcs is a slice of FuncMaps to apply to the template upon compilation. This is useful for helper functions. Default is []. - Funcs []template.FuncMap - // Delims sets the action delimiters to the specified strings in the Delims struct. - Delims Delims - // Appends the given charset to the Content-Type header. Default is "UTF-8". - Charset string - // Outputs human readable JSON. - IndentJSON bool - // Outputs human readable XML. - IndentXML bool - // Prefixes the JSON output with the given bytes. - PrefixJSON []byte - // Prefixes the XML output with the given bytes. - PrefixXML []byte - // Allows changing of output to XHTML instead of HTML. Default is "text/html" - HTMLContentType string - // TemplateFileSystem is the interface for supporting any implmentation of template file system. - TemplateFileSystem - } - - // HTMLOptions is a struct for overriding some rendering Options for specific HTML call - HTMLOptions struct { - // Layout template name. Overrides Options.Layout. - Layout string - } - - Render interface { - http.ResponseWriter - SetResponseWriter(http.ResponseWriter) - - JSON(int, interface{}) - JSONString(interface{}) (string, error) - RawData(int, []byte) // Serve content as binary - PlainText(int, []byte) // Serve content as plain text - HTML(int, string, interface{}, ...HTMLOptions) - HTMLSet(int, string, string, interface{}, ...HTMLOptions) - HTMLSetString(string, string, interface{}, ...HTMLOptions) (string, error) - HTMLString(string, interface{}, ...HTMLOptions) (string, error) - HTMLSetBytes(string, string, interface{}, ...HTMLOptions) ([]byte, error) - HTMLBytes(string, interface{}, ...HTMLOptions) ([]byte, error) - XML(int, interface{}) - Error(int, ...string) - Status(int) - SetTemplatePath(string, string) - HasTemplateSet(string) bool - } -) - -// TplFile implements TemplateFile interface. -type TplFile struct { - name string - data []byte - ext string } -// NewTplFile cerates new template file with given name and data. -func NewTplFile(name string, data []byte, ext string) *TplFile { - return &TplFile{name, data, ext} -} - -func (f *TplFile) Name() string { - return f.name -} - -func (f *TplFile) Data() []byte { - return f.data -} - -func (f *TplFile) Ext() string { - return f.ext -} - -// TplFileSystem implements TemplateFileSystem interface. -type TplFileSystem struct { - files []TemplateFile -} - -// NewTemplateFileSystem creates new template file system with given options. -func NewTemplateFileSystem(opt RenderOptions, omitData bool) TplFileSystem { - fs := TplFileSystem{} - fs.files = make([]TemplateFile, 0, 10) - - // Directories are composed in reverse order because later one overwrites previous ones, - // so once found, we can directly jump out of the loop. - dirs := make([]string, 0, len(opt.AppendDirectories)+1) - for i := len(opt.AppendDirectories) - 1; i >= 0; i-- { - dirs = append(dirs, opt.AppendDirectories[i]) - } - dirs = append(dirs, opt.Directory) - - var err error - for i := range dirs { - // Skip ones that does not exists for symlink test, - // but allow non-symlink ones added after start. - if _, err := os.Stat(dirs[i]); err != nil && os.IsNotExist(err) { - continue +func compileTemplates(filesystem fs.FS, leftDelim, rightDelim string) (*template.Template, error) { + t := template.New("") + t.Delims(leftDelim, rightDelim) + err := fs.WalkDir(filesystem, ".", func(path string, d fs.DirEntry, e error) error { + if e != nil { + return nil // skip unreadable or erroneous filesystem items } - - dirs[i], err = filepath.EvalSymlinks(dirs[i]) - if err != nil { - panic("EvalSymlinks(" + dirs[i] + "): " + err.Error()) + if d.IsDir() { + return nil } - } - lastDir := dirs[len(dirs)-1] - - // We still walk the last (original) directory because it's non-sense we load templates not exist in original directory. - if err = filepath.Walk(lastDir, func(path string, info os.FileInfo, _ error) error { - r, err := filepath.Rel(lastDir, path) + ext := filepath.Ext(path) + if ext != ".html" && ext != ".tmpl" { + return nil + } + data, err := fs.ReadFile(filesystem, path) if err != nil { return err } - - ext := GetExt(r) - - for _, extension := range opt.Extensions { - if ext != extension { - continue - } - - var data []byte - if !omitData { - // Loop over candidates of directory, break out once found. - // The file always exists because it's inside the walk function, - // and read original file is the worst case. - for i := range dirs { - path = filepath.Join(dirs[i], r) - if f, err := os.Stat(path); err != nil || f.IsDir() { - continue - } - - data, err = ioutil.ReadFile(path) - if err != nil { - return err - } - break - } - } - - name := filepath.ToSlash((r[0 : len(r)-len(ext)])) - fs.files = append(fs.files, NewTplFile(name, data, ext)) - } - - return nil - }); err != nil { - panic("NewTemplateFileSystem: " + err.Error()) - } - - return fs -} - -func (fs TplFileSystem) ListFiles() []TemplateFile { - return fs.files -} - -func (fs TplFileSystem) Get(name string) (io.Reader, error) { - for i := range fs.files { - if fs.files[i].Name()+fs.files[i].Ext() == name { - return bytes.NewReader(fs.files[i].Data()), nil - } - } - return nil, fmt.Errorf("file '%s' not found", name) -} - -func PrepareCharset(charset string) string { - if len(charset) != 0 { - return "; charset=" + charset - } - - return "; charset=" + _DEFAULT_CHARSET -} - -func GetExt(s string) string { - index := strings.Index(s, ".") - if index == -1 { - return "" - } - return s[index:] -} - -func compile(opt RenderOptions) *template.Template { - t := template.New(opt.Directory) - t.Delims(opt.Delims.Left, opt.Delims.Right) - // Parse an initial template in case we don't have any. - template.Must(t.Parse("Macaron")) - - if opt.TemplateFileSystem == nil { - opt.TemplateFileSystem = NewTemplateFileSystem(opt, false) - } - - for _, f := range opt.TemplateFileSystem.ListFiles() { - tmpl := t.New(f.Name()) - for _, funcs := range opt.Funcs { - tmpl.Funcs(funcs) - } - // Bomb out if parse fails. We don't want any silent server starts. - template.Must(tmpl.Funcs(helperFuncs).Parse(string(f.Data()))) - } - - return t -} - -const ( - DEFAULT_TPL_SET_NAME = "DEFAULT" -) - -// TemplateSet represents a template set of type *template.Template. -type TemplateSet struct { - lock sync.RWMutex - sets map[string]*template.Template - dirs map[string]string -} - -// NewTemplateSet initializes a new empty template set. -func NewTemplateSet() *TemplateSet { - return &TemplateSet{ - sets: make(map[string]*template.Template), - dirs: make(map[string]string), - } -} - -func (ts *TemplateSet) Set(name string, opt *RenderOptions) *template.Template { - t := compile(*opt) - - ts.lock.Lock() - defer ts.lock.Unlock() - - ts.sets[name] = t - ts.dirs[name] = opt.Directory - return t -} - -func (ts *TemplateSet) Get(name string) *template.Template { - ts.lock.RLock() - defer ts.lock.RUnlock() - - return ts.sets[name] -} - -func (ts *TemplateSet) GetDir(name string) string { - ts.lock.RLock() - defer ts.lock.RUnlock() - - return ts.dirs[name] -} - -func prepareRenderOptions(options []RenderOptions) RenderOptions { - var opt RenderOptions - if len(options) > 0 { - opt = options[0] - } - - // Defaults. - if len(opt.Directory) == 0 { - opt.Directory = "templates" - } - if len(opt.Extensions) == 0 { - opt.Extensions = []string{".tmpl", ".html"} - } - if len(opt.HTMLContentType) == 0 { - opt.HTMLContentType = _CONTENT_HTML - } - - return opt -} - -func ParseTplSet(tplSet string) (tplName string, tplDir string) { - tplSet = strings.TrimSpace(tplSet) - if len(tplSet) == 0 { - panic("empty template set argument") - } - infos := strings.Split(tplSet, ":") - if len(infos) == 1 { - tplDir = infos[0] - tplName = path.Base(tplDir) - } else { - tplName = infos[0] - tplDir = infos[1] - } - - dir, err := os.Stat(tplDir) - if err != nil || !dir.IsDir() { - panic("template set path does not exist or is not a directory") - } - return tplName, tplDir -} - -func renderHandler(opt RenderOptions, tplSets []string) Handler { - cs := PrepareCharset(opt.Charset) - ts := NewTemplateSet() - ts.Set(DEFAULT_TPL_SET_NAME, &opt) - - var tmpOpt RenderOptions - for _, tplSet := range tplSets { - tplName, tplDir := ParseTplSet(tplSet) - tmpOpt = opt - tmpOpt.Directory = tplDir - ts.Set(tplName, &tmpOpt) - } - - return func(ctx *Context) { - r := &TplRender{ - ResponseWriter: ctx.Resp, - TemplateSet: ts, - Opt: &opt, - CompiledCharset: cs, - } - ctx.Data["TmplLoadTimes"] = func() string { - if r.startTime.IsZero() { - return "" - } - return fmt.Sprint(time.Since(r.startTime).Nanoseconds()/1e6) + "ms" - } - - ctx.Render = r - ctx.MapTo(r, (*Render)(nil)) - } -} - -// Renderer is a Middleware that maps a macaron.Render service into the Macaron handler chain. -// An single variadic macaron.RenderOptions struct can be optionally provided to configure -// HTML rendering. The default directory for templates is "templates" and the default -// file extension is ".tmpl" and ".html". -// -// If MACARON_ENV is set to "" or "development" then templates will be recompiled on every request. For more performance, set the -// MACARON_ENV environment variable to "production". -func Renderer(options ...RenderOptions) Handler { - return renderHandler(prepareRenderOptions(options), []string{}) -} - -func Renderers(options RenderOptions, tplSets ...string) Handler { - return renderHandler(prepareRenderOptions([]RenderOptions{options}), tplSets) -} - -type TplRender struct { - http.ResponseWriter - *TemplateSet - Opt *RenderOptions - CompiledCharset string - - startTime time.Time -} - -func (r *TplRender) SetResponseWriter(rw http.ResponseWriter) { - r.ResponseWriter = rw -} - -func (r *TplRender) JSON(status int, v interface{}) { - var ( - result []byte - err error - ) - if r.Opt.IndentJSON { - result, err = json.MarshalIndent(v, "", " ") - } else { - result, err = json.Marshal(v) - } - if err != nil { - http.Error(r, err.Error(), 500) - return - } - - // json rendered fine, write out the result - r.Header().Set(_CONTENT_TYPE, _CONTENT_JSON+r.CompiledCharset) - r.WriteHeader(status) - if len(r.Opt.PrefixJSON) > 0 { - _, _ = r.Write(r.Opt.PrefixJSON) - } - _, _ = r.Write(result) -} - -func (r *TplRender) JSONString(v interface{}) (string, error) { - var result []byte - var err error - if r.Opt.IndentJSON { - result, err = json.MarshalIndent(v, "", " ") - } else { - result, err = json.Marshal(v) - } - if err != nil { - return "", err - } - return string(result), nil -} - -func (r *TplRender) XML(status int, v interface{}) { - var result []byte - var err error - if r.Opt.IndentXML { - result, err = xml.MarshalIndent(v, "", " ") - } else { - result, err = xml.Marshal(v) - } - if err != nil { - http.Error(r, err.Error(), 500) - return - } - - // XML rendered fine, write out the result - r.Header().Set(_CONTENT_TYPE, _CONTENT_XML+r.CompiledCharset) - r.WriteHeader(status) - if len(r.Opt.PrefixXML) > 0 { - _, _ = r.Write(r.Opt.PrefixXML) - } - _, _ = r.Write(result) -} - -func (r *TplRender) data(status int, contentType string, v []byte) { - if r.Header().Get(_CONTENT_TYPE) == "" { - r.Header().Set(_CONTENT_TYPE, contentType) - } - r.WriteHeader(status) - _, _ = r.Write(v) -} - -func (r *TplRender) RawData(status int, v []byte) { - r.data(status, _CONTENT_BINARY, v) -} - -func (r *TplRender) PlainText(status int, v []byte) { - r.data(status, _CONTENT_PLAIN, v) -} - -func (r *TplRender) execute(t *template.Template, name string, data interface{}) (*bytes.Buffer, error) { - buf := bufpool.Get().(*bytes.Buffer) - return buf, t.ExecuteTemplate(buf, name, data) -} - -func (r *TplRender) addYield(t *template.Template, tplName string, data interface{}) { - funcs := template.FuncMap{ - "yield": func() (template.HTML, error) { - buf, err := r.execute(t, tplName, data) - // return safe html here since we are rendering our own template - return template.HTML(buf.String()), err - }, - "current": func() (string, error) { - return tplName, nil - }, - } - t.Funcs(funcs) -} - -func (r *TplRender) renderBytes(setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) (*bytes.Buffer, error) { - t := r.TemplateSet.Get(setName) - if Env == DEV { - opt := *r.Opt - opt.Directory = r.TemplateSet.GetDir(setName) - t = r.TemplateSet.Set(setName, &opt) - } - if t == nil { - return nil, fmt.Errorf("html/template: template \"%s\" is undefined", tplName) - } - - opt := r.prepareHTMLOptions(htmlOpt) - - if len(opt.Layout) > 0 { - r.addYield(t, tplName, data) - tplName = opt.Layout - } - - out, err := r.execute(t, tplName, data) - if err != nil { - return nil, err - } - - return out, nil -} - -func (r *TplRender) renderHTML(status int, setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) { - r.startTime = time.Now() - - out, err := r.renderBytes(setName, tplName, data, htmlOpt...) - if err != nil { - http.Error(r, err.Error(), http.StatusInternalServerError) - return - } - - r.Header().Set(_CONTENT_TYPE, r.Opt.HTMLContentType+r.CompiledCharset) - r.WriteHeader(status) - - if _, err := out.WriteTo(r); err != nil { - out.Reset() - } - bufpool.Put(out) -} - -func (r *TplRender) HTML(status int, name string, data interface{}, htmlOpt ...HTMLOptions) { - r.renderHTML(status, DEFAULT_TPL_SET_NAME, name, data, htmlOpt...) -} - -func (r *TplRender) HTMLSet(status int, setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) { - r.renderHTML(status, setName, tplName, data, htmlOpt...) -} - -func (r *TplRender) HTMLSetBytes(setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) ([]byte, error) { - out, err := r.renderBytes(setName, tplName, data, htmlOpt...) - if err != nil { - return []byte(""), err - } - return out.Bytes(), nil -} - -func (r *TplRender) HTMLBytes(name string, data interface{}, htmlOpt ...HTMLOptions) ([]byte, error) { - return r.HTMLSetBytes(DEFAULT_TPL_SET_NAME, name, data, htmlOpt...) -} - -func (r *TplRender) HTMLSetString(setName, tplName string, data interface{}, htmlOpt ...HTMLOptions) (string, error) { - p, err := r.HTMLSetBytes(setName, tplName, data, htmlOpt...) - return string(p), err -} - -func (r *TplRender) HTMLString(name string, data interface{}, htmlOpt ...HTMLOptions) (string, error) { - p, err := r.HTMLBytes(name, data, htmlOpt...) - return string(p), err -} - -// Error writes the given HTTP status to the current ResponseWriter -func (r *TplRender) Error(status int, message ...string) { - r.WriteHeader(status) - if len(message) > 0 { - _, _ = r.Write([]byte(message[0])) - } -} - -func (r *TplRender) Status(status int) { - r.WriteHeader(status) -} - -func (r *TplRender) prepareHTMLOptions(htmlOpt []HTMLOptions) HTMLOptions { - if len(htmlOpt) > 0 { - return htmlOpt[0] - } - - return HTMLOptions{ - Layout: r.Opt.Layout, - } -} - -func (r *TplRender) SetTemplatePath(setName, dir string) { - if len(setName) == 0 { - setName = DEFAULT_TPL_SET_NAME - } - opt := *r.Opt - opt.Directory = dir - r.TemplateSet.Set(setName, &opt) -} - -func (r *TplRender) HasTemplateSet(name string) bool { - return r.TemplateSet.Get(name) != nil -} - -// DummyRender is used when user does not choose any real render to use. -// This way, we can print out friendly message which asks them to register one, -// instead of ugly and confusing 'nil pointer' panic. -type DummyRender struct { - http.ResponseWriter -} - -func renderNotRegistered() { - panic("middleware render hasn't been registered") -} - -func (r *DummyRender) SetResponseWriter(http.ResponseWriter) { - renderNotRegistered() -} - -func (r *DummyRender) JSON(int, interface{}) { - renderNotRegistered() -} - -func (r *DummyRender) JSONString(interface{}) (string, error) { - renderNotRegistered() - return "", nil -} - -func (r *DummyRender) RawData(int, []byte) { - renderNotRegistered() -} - -func (r *DummyRender) PlainText(int, []byte) { - renderNotRegistered() -} - -func (r *DummyRender) HTML(int, string, interface{}, ...HTMLOptions) { - renderNotRegistered() -} - -func (r *DummyRender) HTMLSet(int, string, string, interface{}, ...HTMLOptions) { - renderNotRegistered() -} - -func (r *DummyRender) HTMLSetString(string, string, interface{}, ...HTMLOptions) (string, error) { - renderNotRegistered() - return "", nil -} - -func (r *DummyRender) HTMLString(string, interface{}, ...HTMLOptions) (string, error) { - renderNotRegistered() - return "", nil -} - -func (r *DummyRender) HTMLSetBytes(string, string, interface{}, ...HTMLOptions) ([]byte, error) { - renderNotRegistered() - return nil, nil -} - -func (r *DummyRender) HTMLBytes(string, interface{}, ...HTMLOptions) ([]byte, error) { - renderNotRegistered() - return nil, nil -} - -func (r *DummyRender) XML(int, interface{}) { - renderNotRegistered() -} - -func (r *DummyRender) Error(int, ...string) { - renderNotRegistered() -} - -func (r *DummyRender) Status(int) { - renderNotRegistered() -} - -func (r *DummyRender) SetTemplatePath(string, string) { - renderNotRegistered() -} - -func (r *DummyRender) HasTemplateSet(string) bool { - renderNotRegistered() - return false + basename := path[:len(path)-len(ext)] + _, err = t.New(basename).Parse(string(data)) + return err + }) + return t, err } diff --git a/pkg/middleware/gziper.go b/pkg/middleware/gziper.go index 5427edd1aef..d0248b345b8 100644 --- a/pkg/middleware/gziper.go +++ b/pkg/middleware/gziper.go @@ -1,43 +1,81 @@ package middleware import ( + "bufio" + "compress/gzip" + "fmt" + "net" + "net/http" "strings" - "github.com/go-macaron/gzip" - "github.com/grafana/grafana/pkg/infra/log" - "gopkg.in/macaron.v1" + macaron "gopkg.in/macaron.v1" ) -const resourcesPath = "/resources" - -var gzipIgnoredPathPrefixes = []string{ - "/api/datasources/proxy", // Ignore datasource proxy requests. - "/api/plugin-proxy/", - "/metrics", - "/api/live/ws", // WebSocket does not support gzip compression. - "/api/live/push", // WebSocket does not support gzip compression. +type gzipResponseWriter struct { + w *gzip.Writer + macaron.ResponseWriter } -func Gziper() macaron.Handler { - gziperLogger := log.New("gziper") - gziper := gzip.Gziper() +func (grw *gzipResponseWriter) WriteHeader(c int) { + grw.Header().Del("Content-Length") + grw.ResponseWriter.WriteHeader(c) +} - return func(ctx *macaron.Context) { - requestPath := ctx.Req.URL.RequestURI() +func (grw gzipResponseWriter) Write(p []byte) (int, error) { + if grw.Header().Get("Content-Type") == "" { + grw.Header().Set("Content-Type", http.DetectContentType(p)) + } + grw.Header().Del("Content-Length") + return grw.w.Write(p) +} - for _, pathPrefix := range gzipIgnoredPathPrefixes { - if strings.HasPrefix(requestPath, pathPrefix) { +func (grw gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) { + if hijacker, ok := grw.ResponseWriter.(http.Hijacker); ok { + return hijacker.Hijack() + } + return nil, nil, fmt.Errorf("GZIP ResponseWriter doesn't implement the Hijacker interface") +} + +type matcher func(s string) bool + +func prefix(p string) matcher { return func(s string) bool { return strings.HasPrefix(s, p) } } +func substr(p string) matcher { return func(s string) bool { return strings.Contains(s, p) } } + +var gzipIgnoredPaths = []matcher{ + prefix("/api/datasources"), + prefix("/api/plugins"), + prefix("/api/plugin-proxy/"), + prefix("/metrics"), + prefix("/api/live/ws"), // WebSocket does not support gzip compression. + prefix("/api/live/push"), // WebSocket does not support gzip compression. + substr("/resources"), +} + +func Gziper() func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + requestPath := req.URL.RequestURI() + + for _, pathMatcher := range gzipIgnoredPaths { + if pathMatcher(requestPath) { + fmt.Println("skip path", requestPath) + next.ServeHTTP(rw, req) + return + } + } + + if !strings.Contains(req.Header.Get("Accept-Encoding"), "gzip") { + next.ServeHTTP(rw, req) return } - } - // ignore resources - if (strings.HasPrefix(requestPath, "/api/datasources/") || strings.HasPrefix(requestPath, "/api/plugins/")) && strings.Contains(requestPath, resourcesPath) { - return - } + grw := &gzipResponseWriter{gzip.NewWriter(rw), rw.(macaron.ResponseWriter)} + grw.Header().Set("Content-Encoding", "gzip") + grw.Header().Set("Vary", "Accept-Encoding") - if _, err := ctx.Invoke(gziper); err != nil { - gziperLogger.Error("Invoking gzip handler failed", "err", err) - } + next.ServeHTTP(grw, req) + // We can't really handle close errors at this point and we can't report them to the caller + _ = grw.w.Close() + }) } } diff --git a/pkg/middleware/middleware_test.go b/pkg/middleware/middleware_test.go index 95defe3376c..f7cbdf5102e 100644 --- a/pkg/middleware/middleware_test.go +++ b/pkg/middleware/middleware_test.go @@ -111,7 +111,7 @@ func TestMiddlewareContext(t *testing.T) { Settings: map[string]interface{}{}, NavTree: []*dtos.NavLink{}, } - t.Log("Calling HTML", "data", data, "render", c.Render) + t.Log("Calling HTML", "data", data) c.HTML(200, "index-template", data) t.Log("Returned HTML with code 200") } @@ -633,10 +633,7 @@ func middlewareScenario(t *testing.T, desc string, fn scenarioFunc, cbs ...func( sc.m = macaron.New() sc.m.Use(AddDefaultResponseHeaders(cfg)) sc.m.UseMiddleware(AddCSPHeader(cfg, logger)) - sc.m.Use(macaron.Renderer(macaron.RenderOptions{ - Directory: viewsPath, - Delims: macaron.Delims{Left: "[[", Right: "]]"}, - })) + sc.m.UseMiddleware(macaron.Renderer(viewsPath, "[[", "]]")) ctxHdlr := getContextHandler(t, cfg) sc.sqlStore = ctxHdlr.SQLStore diff --git a/pkg/middleware/org_redirect.go b/pkg/middleware/org_redirect.go index cb1813ade7f..59cbddf58e9 100644 --- a/pkg/middleware/org_redirect.go +++ b/pkg/middleware/org_redirect.go @@ -37,7 +37,7 @@ func OrgRedirect(cfg *setting.Cfg) macaron.Handler { if ctx.IsApiRequest() { ctx.JsonApiErr(404, "Not found", nil) } else { - ctx.Error(404, "Not found") + http.Error(ctx.Resp, "Not found", http.StatusNotFound) } return diff --git a/pkg/middleware/rate_limit_test.go b/pkg/middleware/rate_limit_test.go index c78bbe9136a..109a2e1220c 100644 --- a/pkg/middleware/rate_limit_test.go +++ b/pkg/middleware/rate_limit_test.go @@ -32,10 +32,7 @@ func rateLimiterScenario(t *testing.T, desc string, rps int, burst int, fn rateL cfg := setting.NewCfg() m := macaron.New() - m.Use(macaron.Renderer(macaron.RenderOptions{ - Directory: "", - Delims: macaron.Delims{Left: "[[", Right: "]]"}, - })) + m.UseMiddleware(macaron.Renderer("../../public/views", "[[", "]]")) m.Use(getContextHandler(t, cfg).Middleware) m.Get("/foo", RateLimit(rps, burst, func() time.Time { return currentTime }), defaultHandler) diff --git a/pkg/middleware/recovery.go b/pkg/middleware/recovery.go index 336a3425da9..88a4f8b32e0 100644 --- a/pkg/middleware/recovery.go +++ b/pkg/middleware/recovery.go @@ -158,7 +158,7 @@ func Recovery(cfg *setting.Cfg) macaron.Handler { c.JSON(500, resp) } else { - c.HTML(500, cfg.ErrTemplateName) + c.HTML(500, cfg.ErrTemplateName, c.Data) } } }() diff --git a/pkg/middleware/recovery_test.go b/pkg/middleware/recovery_test.go index 0bc002b8b5d..c62079372b2 100644 --- a/pkg/middleware/recovery_test.go +++ b/pkg/middleware/recovery_test.go @@ -65,10 +65,7 @@ func recoveryScenario(t *testing.T, desc string, url string, fn scenarioFunc) { sc.m.Use(Recovery(cfg)) sc.m.Use(AddDefaultResponseHeaders(cfg)) - sc.m.Use(macaron.Renderer(macaron.RenderOptions{ - Directory: viewsPath, - Delims: macaron.Delims{Left: "[[", Right: "]]"}, - })) + sc.m.UseMiddleware(macaron.Renderer(viewsPath, "[[", "]]")) sc.userAuthTokenService = auth.NewFakeUserAuthTokenService() sc.remoteCacheService = remotecache.NewFakeStore(t) diff --git a/pkg/models/context.go b/pkg/models/context.go index 42f7036551e..a3bb6838985 100644 --- a/pkg/models/context.go +++ b/pkg/models/context.go @@ -36,7 +36,7 @@ func (ctx *ReqContext) Handle(cfg *setting.Cfg, status int, title string, err er ctx.Data["AppSubUrl"] = cfg.AppSubURL ctx.Data["Theme"] = "dark" - ctx.HTML(status, cfg.ErrTemplateName) + ctx.HTML(status, cfg.ErrTemplateName, ctx.Data) } func (ctx *ReqContext) IsApiRequest() bool { From 476a2275051c8586cea3df2d246020c12554ea6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Farkas?= Date: Tue, 10 Aug 2021 14:18:29 +0200 Subject: [PATCH 23/31] influxdb: check for invalid program-flow (#37474) --- public/app/plugins/datasource/influxdb/datasource.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/public/app/plugins/datasource/influxdb/datasource.ts b/public/app/plugins/datasource/influxdb/datasource.ts index abb555b050e..fb03acd1457 100644 --- a/public/app/plugins/datasource/influxdb/datasource.ts +++ b/public/app/plugins/datasource/influxdb/datasource.ts @@ -182,10 +182,12 @@ export default class InfluxDatasource extends DataSourceWithBackend { + // this only works in flux-mode, it should not be called in non-flux-mode + if (!this.isFlux) { + throw new Error('applyTemplateVariables called in influxql-mode. this should never happen'); + } + return { ...query, query: this.templateSrv.replace(query.query ?? '', scopedVars), // The raw query text From fa731f16bf43018141ce9adff09286c6b1988253 Mon Sep 17 00:00:00 2001 From: Tobias Skarhed <1438972+tskarhed@users.noreply.github.com> Date: Tue, 10 Aug 2021 16:55:25 +0200 Subject: [PATCH 24/31] DashboardLinks: Screen reader accessibility #37682 --- .../src/selectors/components.ts | 6 +-- .../SubMenu/DashboardLinksDashboard.tsx | 39 ++++++++++++------- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/packages/grafana-e2e-selectors/src/selectors/components.ts b/packages/grafana-e2e-selectors/src/selectors/components.ts index 7997356efb2..d032d9c5b74 100644 --- a/packages/grafana-e2e-selectors/src/selectors/components.ts +++ b/packages/grafana-e2e-selectors/src/selectors/components.ts @@ -213,9 +213,9 @@ export const Components = { items: 'Search items', }, DashboardLinks: { - container: 'Dashboard link container', - dropDown: 'Dashboard link dropdown', - link: 'Dashboard link', + container: 'data-testid Dashboard link container', + dropDown: 'data-testid Dashboard link dropdown', + link: 'data-testid Dashboard link', }, LoadingIndicator: { icon: 'Loading indicator', diff --git a/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx b/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx index b783570759b..203af35cf60 100644 --- a/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx +++ b/public/app/features/dashboard/components/SubMenu/DashboardLinksDashboard.tsx @@ -1,5 +1,5 @@ import React, { useRef, useState, useLayoutEffect } from 'react'; -import { Icon, Tooltip } from '@grafana/ui'; +import { Icon, ToolbarButton, Tooltip, useStyles2 } from '@grafana/ui'; import { sanitize, sanitizeUrl } from '@grafana/data/src/text/sanitize'; import { getBackendSrv } from 'app/core/services/backend_srv'; import { getLinkSrv } from '../../../panel/panellinks/link_srv'; @@ -7,6 +7,7 @@ import { DashboardLink } from '../../state/DashboardModel'; import { DashboardSearchHit } from 'app/features/search/types'; import { selectors } from '@grafana/e2e-selectors'; import { useAsync } from 'react-use'; +import { css, cx } from '@emotion/css'; interface Props { link: DashboardLink; @@ -21,33 +22,45 @@ export const DashboardLinksDashboard: React.FC = (props) => { const [opened, setOpened] = useState(0); const resolvedLinks = useResolvedLinks(props, opened); + const buttonStyle = useStyles2( + (theme) => + css` + color: ${theme.colors.text.primary}; + ` + ); + useLayoutEffect(() => { setDropdownCssClass(getDropdownLocationCssClass(listRef.current)); }, [resolvedLinks]); if (link.asDropdown) { return ( - + <> - setOpened(Date.now())} - className="gf-form-label gf-form-label--dashlink" + className={cx('gf-form-label gf-form-label--dashlink', buttonStyle)} data-placement="bottom" data-toggle="dropdown" + aria-expanded={!!opened} + aria-controls="dropdown-list" + aria-haspopup="menu" > - + {linkInfo.title} - -
      + +