diff --git a/conf/provisioning/dashboards/sample.yaml b/conf/provisioning/dashboards/sample.yaml
index d70bd42563486..6f3ac570ca428 100644
--- a/conf/provisioning/dashboards/sample.yaml
+++ b/conf/provisioning/dashboards/sample.yaml
@@ -5,6 +5,7 @@ apiVersion: 1
# - name: 'default'
# orgId: 1
# folder: ''
+# folderUid: ''
# type: file
# options:
# path: /var/lib/grafana/dashboards
diff --git a/devenv/dashboards.yaml b/devenv/dashboards.yaml
index 3e0e21ef4fefa..98c726408de48 100644
--- a/devenv/dashboards.yaml
+++ b/devenv/dashboards.yaml
@@ -3,6 +3,7 @@ apiVersion: 1
providers:
- name: 'gdev dashboards'
folder: 'gdev dashboards'
+ folderUid: ''
type: file
updateIntervalSeconds: 60
options:
diff --git a/docs/sources/administration/provisioning.md b/docs/sources/administration/provisioning.md
index 1ac1c8e396619..aa84863bf7ae1 100644
--- a/docs/sources/administration/provisioning.md
+++ b/docs/sources/administration/provisioning.md
@@ -30,33 +30,19 @@ Checkout the [configuration](/installation/configuration) page for more informat
### Using Environment Variables
-All options in the configuration file (listed below) can be overridden
-using environment variables using the syntax:
+It is possible to use environment variable interpolation in all 3 provisioning config types. Allowed syntax
+is either `$ENV_VAR_NAME` or `${ENV_VAR_NAME}` and can be used only for values not for keys or bigger parts
+of the configs. It is not available in the dashboards definition files just the dashboard provisioning
+configuration.
+Example:
-```bash
-GF__
-```
-
-Where the section name is the text within the brackets. Everything
-should be upper case and `.` should be replaced by `_`. For example, given these configuration settings:
-
-```bash
-# default section
-instance_name = ${HOSTNAME}
-
-[security]
-admin_user = admin
-
-[auth.google]
-client_secret = 0ldS3cretKey
-```
-
-Overriding will be done like so:
-
-```bash
-export GF_DEFAULT_INSTANCE_NAME=my-instance
-export GF_SECURITY_ADMIN_USER=true
-export GF_AUTH_GOOGLE_CLIENT_SECRET=newS3cretKey
+```yaml
+datasources:
+- name: Graphite
+ url: http://localhost:$PORT
+ user: $USER
+ secureJsonData:
+ password: $PASSWORD
```
@@ -203,13 +189,24 @@ The dashboard provider config file looks somewhat like this:
apiVersion: 1
providers:
+ # provider name
- name: 'default'
+ # org id. will default to orgId 1 if not specified
orgId: 1
+ # name of the dashboard folder. Required
folder: ''
+ # folder UID. will be automatically generated if not specified
+ folderUid: ''
+ # provider type. Required
type: file
+ # disable dashboard deletion
disableDeletion: false
- updateIntervalSeconds: 10 #how often Grafana will scan for changed dashboards
+ # enable dashboard editing
+ editable: true
+ # how often Grafana will scan for changed dashboards
+ updateIntervalSeconds: 10
options:
+ # path to dashboard files on disk. Required
path: /var/lib/grafana/dashboards
```
diff --git a/docs/sources/features/datasources/cloudwatch.md b/docs/sources/features/datasources/cloudwatch.md
index 9c7fd5207c31c..7a00b377122e8 100644
--- a/docs/sources/features/datasources/cloudwatch.md
+++ b/docs/sources/features/datasources/cloudwatch.md
@@ -29,9 +29,10 @@ Name | Description
------------ | -------------
*Name* | The data source name. This is how you refer to the data source in panels & queries.
*Default* | Default data source means that it will be pre-selected for new panels.
-*Credentials* profile name | Specify the name of the profile to use (if you use `~/.aws/credentials` file), leave blank for default.
*Default Region* | Used in query editor to set region (can be changed on per query basis)
*Custom Metrics namespace* | Specify the CloudWatch namespace of Custom metrics
+*Auth Provider* | Specify the provider to get credentials.
+*Credentials* profile name | Specify the name of the profile to use (if you use `~/.aws/credentials` file), leave blank for default.
*Assume Role Arn* | Specify the ARN of the role to assume
## Authentication
@@ -85,6 +86,16 @@ Here is a minimal policy example:
}
```
+### AWS credentials
+If Auth Provider is `Credentials file`, Grafana try to get credentials by following order.
+
+- Environment variables. (`AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`)
+- Hard-code credentials.
+- Shared credentials file.
+- IAM role for Amazon EC2.
+
+Checkout AWS docs on [Configuring the AWS SDK for Go](https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/configuring-sdk.html)
+
### AWS credentials file
Create a file at `~/.aws/credentials`. That is the `HOME` path for user running grafana-server.
diff --git a/packages/grafana-ui/.storybook/config.ts b/packages/grafana-ui/.storybook/config.ts
index b87604438d723..98a4ee8bd9e04 100644
--- a/packages/grafana-ui/.storybook/config.ts
+++ b/packages/grafana-ui/.storybook/config.ts
@@ -2,7 +2,17 @@ import { configure, addDecorator } from '@storybook/react';
import { withKnobs } from '@storybook/addon-knobs';
import { withTheme } from '../src/utils/storybook/withTheme';
import { withPaddedStory } from '../src/utils/storybook/withPaddedStory';
-
+import 'jquery';
+import '../../../public/vendor/flot/jquery.flot.js';
+import '../../../public/vendor/flot/jquery.flot.selection';
+import '../../../public/vendor/flot/jquery.flot.time';
+import '../../../public/vendor/flot/jquery.flot.stack';
+import '../../../public/vendor/flot/jquery.flot.pie';
+import '../../../public/vendor/flot/jquery.flot.stackpercent';
+import '../../../public/vendor/flot/jquery.flot.fillbelow';
+import '../../../public/vendor/flot/jquery.flot.crosshair';
+import '../../../public/vendor/flot/jquery.flot.dashes';
+import '../../../public/vendor/flot/jquery.flot.gauge';
// @ts-ignore
import lightTheme from '../../../public/sass/grafana.light.scss';
// @ts-ignore
diff --git a/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx b/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx
index 945e3d825d812..f2f6b236e14b4 100644
--- a/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx
+++ b/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx
@@ -2,6 +2,7 @@ import React, { Component } from 'react';
import isNil from 'lodash/isNil';
import classNames from 'classnames';
import Scrollbars from 'react-custom-scrollbars';
+import { cx, css } from 'emotion';
interface Props {
className?: string;
@@ -10,8 +11,8 @@ interface Props {
autoHideDuration?: number;
autoHeightMax?: string;
hideTracksWhenNotNeeded?: boolean;
- renderTrackHorizontal?: React.FunctionComponent;
- renderTrackVertical?: React.FunctionComponent;
+ hideHorizontalTrack?: boolean;
+ hideVerticalTrack?: boolean;
scrollTop?: number;
setScrollTop: (event: any) => void;
autoHeightMin?: number | string;
@@ -79,8 +80,8 @@ export class CustomScrollbar extends Component {
autoHide,
autoHideTimeout,
hideTracksWhenNotNeeded,
- renderTrackHorizontal,
- renderTrackVertical,
+ hideHorizontalTrack,
+ hideVerticalTrack,
} = this.props;
return (
@@ -96,8 +97,28 @@ export class CustomScrollbar extends Component {
// Before these where set to inhert but that caused problems with cut of legends in firefox
autoHeightMax={autoHeightMax}
autoHeightMin={autoHeightMin}
- renderTrackHorizontal={renderTrackHorizontal || (props =>
)}
- renderTrackVertical={renderTrackVertical || (props =>
)}
+ renderTrackHorizontal={props => (
+
+ )}
+ renderTrackVertical={props => (
+
+ )}
renderThumbHorizontal={props =>
}
renderThumbVertical={props =>
}
renderView={props =>
}
diff --git a/packages/grafana-ui/src/components/CustomScrollbar/__snapshots__/CustomScrollbar.test.tsx.snap b/packages/grafana-ui/src/components/CustomScrollbar/__snapshots__/CustomScrollbar.test.tsx.snap
index dd3f59ad1e199..b348f7dd8bd06 100644
--- a/packages/grafana-ui/src/components/CustomScrollbar/__snapshots__/CustomScrollbar.test.tsx.snap
+++ b/packages/grafana-ui/src/components/CustomScrollbar/__snapshots__/CustomScrollbar.test.tsx.snap
@@ -37,7 +37,7 @@ exports[`CustomScrollbar renders correctly 1`] = `
{
const ticks = width / 100;
const min = timeRange.from.valueOf();
const max = timeRange.to.valueOf();
-
+ const yaxes = uniqBy(
+ series.map(s => {
+ return {
+ show: true,
+ index: s.yAxis,
+ position: s.yAxis === 1 ? 'left' : 'right',
+ };
+ }),
+ yAxisConfig => yAxisConfig.index
+ );
const flotOptions = {
legend: {
show: false,
@@ -80,6 +90,7 @@ export class Graph extends PureComponent
{
ticks: ticks,
timeformat: timeFormat(ticks, min, max),
},
+ yaxes,
grid: {
minBorderMargin: 0,
markings: [],
diff --git a/packages/grafana-ui/src/components/Graph/GraphLegend.story.tsx b/packages/grafana-ui/src/components/Graph/GraphLegend.story.tsx
new file mode 100644
index 0000000000000..1acc4d50a36b9
--- /dev/null
+++ b/packages/grafana-ui/src/components/Graph/GraphLegend.story.tsx
@@ -0,0 +1,105 @@
+import React from 'react';
+import { storiesOf } from '@storybook/react';
+
+import { GraphLegend } from './GraphLegend';
+import { action } from '@storybook/addon-actions';
+import { select, number } from '@storybook/addon-knobs';
+import { withHorizontallyCenteredStory } from '../../utils/storybook/withCenteredStory';
+import { generateLegendItems } from '../Legend/Legend.story';
+import { LegendPlacement, LegendDisplayMode } from '../Legend/Legend';
+
+const GraphLegendStories = storiesOf('Visualizations/Graph/GraphLegend', module);
+GraphLegendStories.addDecorator(withHorizontallyCenteredStory);
+
+const getStoriesKnobs = (isList = false) => {
+ const statsToDisplay = select(
+ 'Stats to display',
+ {
+ none: [],
+ 'single (min)': [{ text: '10ms', title: 'min', numeric: 10 }],
+ 'multiple (min, max)': [
+ { text: '10ms', title: 'min', numeric: 10 },
+ { text: '100ms', title: 'max', numeric: 100 },
+ ],
+ },
+ []
+ );
+
+ const numberOfSeries = number('Number of series', 3);
+
+ const containerWidth = select(
+ 'Container width',
+ {
+ Small: '200px',
+ Medium: '500px',
+ 'Full width': '100%',
+ },
+ '100%'
+ );
+
+ const legendPlacement = select(
+ 'Legend placement',
+ {
+ under: 'under',
+ right: 'right',
+ },
+ 'under'
+ );
+
+ return {
+ statsToDisplay,
+ numberOfSeries,
+ containerWidth,
+ legendPlacement,
+ };
+};
+
+GraphLegendStories.add('list', () => {
+ const { statsToDisplay, numberOfSeries, containerWidth, legendPlacement } = getStoriesKnobs(true);
+ return (
+
+ {
+ action('Series label clicked')(item, event);
+ }}
+ onSeriesColorChange={(label, color) => {
+ action('Series color changed')(label, color);
+ }}
+ onSeriesAxisToggle={(label, useRightYAxis) => {
+ action('Series axis toggle')(label, useRightYAxis);
+ }}
+ onToggleSort={sortBy => {
+ action('Toggle legend sort')(sortBy);
+ }}
+ placement={legendPlacement}
+ />
+
+ );
+});
+
+GraphLegendStories.add('table', () => {
+ const { statsToDisplay, numberOfSeries, containerWidth, legendPlacement } = getStoriesKnobs();
+ return (
+
+ {
+ action('Series label clicked')(item);
+ }}
+ onSeriesColorChange={(label, color) => {
+ action('Series color changed')(label, color);
+ }}
+ onSeriesAxisToggle={(label, useRightYAxis) => {
+ action('Series axis toggle')(label, useRightYAxis);
+ }}
+ onToggleSort={sortBy => {
+ action('Toggle legend sort')(sortBy);
+ }}
+ placement={legendPlacement}
+ />
+
+ );
+});
diff --git a/packages/grafana-ui/src/components/Graph/GraphLegend.tsx b/packages/grafana-ui/src/components/Graph/GraphLegend.tsx
new file mode 100644
index 0000000000000..451acf4bac805
--- /dev/null
+++ b/packages/grafana-ui/src/components/Graph/GraphLegend.tsx
@@ -0,0 +1,118 @@
+import React, { useContext } from 'react';
+import { LegendProps, LegendItem, LegendDisplayMode } from '../Legend/Legend';
+import { GraphLegendListItem, GraphLegendTableRow } from './GraphLegendItem';
+import { SeriesColorChangeHandler, SeriesAxisToggleHandler } from './GraphWithLegend';
+import { LegendTable } from '../Legend/LegendTable';
+import { LegendList } from '../Legend/LegendList';
+import union from 'lodash/union';
+import sortBy from 'lodash/sortBy';
+import { ThemeContext } from '../../themes/ThemeContext';
+import { css } from 'emotion';
+import { selectThemeVariant } from '../../themes/index';
+
+interface GraphLegendProps extends LegendProps {
+ displayMode: LegendDisplayMode;
+ sortBy?: string;
+ sortDesc?: boolean;
+ onSeriesColorChange: SeriesColorChangeHandler;
+ onSeriesAxisToggle?: SeriesAxisToggleHandler;
+ onToggleSort: (sortBy: string) => void;
+ onLabelClick: (item: LegendItem, event: React.MouseEvent) => void;
+}
+
+export const GraphLegend: React.FunctionComponent = ({
+ items,
+ displayMode,
+ sortBy: sortKey,
+ sortDesc,
+ onToggleSort,
+ onSeriesAxisToggle,
+ placement,
+ className,
+ ...graphLegendItemProps
+}) => {
+ const theme = useContext(ThemeContext);
+
+ if (displayMode === LegendDisplayMode.Table) {
+ const columns = items
+ .map(item => {
+ if (item.displayValues) {
+ return item.displayValues.map(i => i.title);
+ }
+ return [];
+ })
+ .reduce(
+ (acc, current) => {
+ return union(acc, current.filter(item => !!item));
+ },
+ ['']
+ ) as string[];
+
+ const sortedItems = sortKey
+ ? sortBy(items, item => {
+ if (item.displayValues) {
+ const stat = item.displayValues.filter(stat => stat.title === sortKey)[0];
+ return stat && stat.numeric;
+ }
+ return undefined;
+ })
+ : items;
+
+ const legendTableEvenRowBackground = selectThemeVariant(
+ {
+ dark: theme.colors.dark6,
+ light: theme.colors.gray5,
+ },
+ theme.type
+ );
+
+ return (
+ (
+ {
+ if (onSeriesAxisToggle) {
+ onSeriesAxisToggle(item.label, item.yAxis === 1 ? 2 : 1);
+ }
+ }}
+ className={css`
+ background: ${index % 2 === 0 ? legendTableEvenRowBackground : 'none'};
+ `}
+ {...graphLegendItemProps}
+ />
+ )}
+ onToggleSort={onToggleSort}
+ />
+ );
+ }
+ return (
+ (
+ {
+ if (onSeriesAxisToggle) {
+ onSeriesAxisToggle(item.label, item.yAxis === 1 ? 2 : 1);
+ }
+ }}
+ {...graphLegendItemProps}
+ />
+ )}
+ />
+ );
+};
diff --git a/packages/grafana-ui/src/components/Graph/GraphLegendItem.tsx b/packages/grafana-ui/src/components/Graph/GraphLegendItem.tsx
new file mode 100644
index 0000000000000..e116287d4d21e
--- /dev/null
+++ b/packages/grafana-ui/src/components/Graph/GraphLegendItem.tsx
@@ -0,0 +1,117 @@
+import React, { useContext } from 'react';
+import { css, cx } from 'emotion';
+import { LegendSeriesIcon } from '../Legend/LegendSeriesIcon';
+import { LegendItem } from '../Legend/Legend';
+import { SeriesColorChangeHandler } from './GraphWithLegend';
+import { LegendStatsList } from '../Legend/LegendStatsList';
+import { ThemeContext } from '../../themes/ThemeContext';
+
+export interface GraphLegendItemProps {
+ key?: React.Key;
+ item: LegendItem;
+ className?: string;
+ onLabelClick: (item: LegendItem, event: React.MouseEvent) => void;
+ onSeriesColorChange: SeriesColorChangeHandler;
+ onToggleAxis: () => void;
+}
+
+export const GraphLegendListItem: React.FunctionComponent = ({
+ item,
+ onSeriesColorChange,
+ onToggleAxis,
+ onLabelClick,
+}) => {
+ return (
+ <>
+ onSeriesColorChange(item.label, color)}
+ onToggleAxis={onToggleAxis}
+ yAxis={item.yAxis}
+ />
+ onLabelClick(item, event)}
+ className={css`
+ cursor: pointer;
+ white-space: nowrap;
+ `}
+ >
+ {item.label}
+
+
+ {item.displayValues && }
+ >
+ );
+};
+
+export const GraphLegendTableRow: React.FunctionComponent = ({
+ item,
+ onSeriesColorChange,
+ onToggleAxis,
+ onLabelClick,
+ className,
+}) => {
+ const theme = useContext(ThemeContext);
+
+ return (
+
+
+
+ onSeriesColorChange(item.label, color)}
+ onToggleAxis={onToggleAxis}
+ yAxis={item.yAxis}
+ />
+ onLabelClick(item, event)}
+ className={css`
+ cursor: pointer;
+ white-space: nowrap;
+ `}
+ >
+ {item.label}{' '}
+ {item.yAxis === 2 && (
+
+ (right y-axis)
+
+ )}
+
+
+
+ {item.displayValues &&
+ item.displayValues.map((stat, index) => {
+ return (
+
+ {stat.text}
+
+ );
+ })}
+
+ );
+};
diff --git a/packages/grafana-ui/src/components/Graph/GraphWithLegend.story.tsx b/packages/grafana-ui/src/components/Graph/GraphWithLegend.story.tsx
new file mode 100644
index 0000000000000..c0fbf52d38fd6
--- /dev/null
+++ b/packages/grafana-ui/src/components/Graph/GraphWithLegend.story.tsx
@@ -0,0 +1,87 @@
+import React from 'react';
+import { storiesOf } from '@storybook/react';
+
+import { select, text } from '@storybook/addon-knobs';
+import { withHorizontallyCenteredStory } from '../../utils/storybook/withCenteredStory';
+import { GraphWithLegend } from './GraphWithLegend';
+
+import { mockGraphWithLegendData } from './mockGraphWithLegendData';
+import { action } from '@storybook/addon-actions';
+import { LegendPlacement, LegendDisplayMode } from '../Legend/Legend';
+const GraphWithLegendStories = storiesOf('Visualizations/Graph/GraphWithLegend', module);
+GraphWithLegendStories.addDecorator(withHorizontallyCenteredStory);
+
+const getStoriesKnobs = () => {
+ const containerWidth = select(
+ 'Container width',
+ {
+ Small: '200px',
+ Medium: '500px',
+ 'Full width': '100%',
+ },
+ '100%'
+ );
+ const containerHeight = select(
+ 'Container height',
+ {
+ Small: '200px',
+ Medium: '400px',
+ 'Full height': '100%',
+ },
+ '400px'
+ );
+
+ const rightAxisSeries = text('Right y-axis series, i.e. A,C', '');
+
+ const legendPlacement = select(
+ 'Legend placement',
+ {
+ under: 'under',
+ right: 'right',
+ },
+ 'under'
+ );
+ const renderLegendAsTable = select(
+ 'Render legend as',
+ {
+ list: false,
+ table: true,
+ },
+ false
+ );
+
+ return {
+ containerWidth,
+ containerHeight,
+ rightAxisSeries,
+ legendPlacement,
+ renderLegendAsTable,
+ };
+};
+
+GraphWithLegendStories.add('default', () => {
+ const { containerWidth, containerHeight, rightAxisSeries, legendPlacement, renderLegendAsTable } = getStoriesKnobs();
+
+ const props = mockGraphWithLegendData({
+ onSeriesColorChange: action('Series color changed'),
+ onSeriesAxisToggle: action('Series y-axis changed'),
+ displayMode: renderLegendAsTable ? LegendDisplayMode.Table : LegendDisplayMode.List,
+ });
+ const series = props.series.map(s => {
+ if (
+ rightAxisSeries
+ .split(',')
+ .map(s => s.trim())
+ .indexOf(s.label.split('-')[0]) > -1
+ ) {
+ s.yAxis = 2;
+ }
+
+ return s;
+ });
+ return (
+
+ ,
+
+ );
+});
diff --git a/packages/grafana-ui/src/components/Graph/GraphWithLegend.tsx b/packages/grafana-ui/src/components/Graph/GraphWithLegend.tsx
new file mode 100644
index 0000000000000..162c24758eae7
--- /dev/null
+++ b/packages/grafana-ui/src/components/Graph/GraphWithLegend.tsx
@@ -0,0 +1,125 @@
+// Libraries
+import _ from 'lodash';
+import React from 'react';
+
+import { css } from 'emotion';
+import { Graph, GraphProps } from './Graph';
+import { LegendRenderOptions, LegendItem, LegendDisplayMode } from '../Legend/Legend';
+import { GraphLegend } from './GraphLegend';
+import { CustomScrollbar } from '../CustomScrollbar/CustomScrollbar';
+import { GraphSeriesValue } from '../../types/graph';
+
+export type SeriesOptionChangeHandler = (label: string, option: TOption) => void;
+export type SeriesColorChangeHandler = SeriesOptionChangeHandler;
+export type SeriesAxisToggleHandler = SeriesOptionChangeHandler;
+
+export interface GraphWithLegendProps extends GraphProps, LegendRenderOptions {
+ isLegendVisible: boolean;
+ displayMode: LegendDisplayMode;
+ sortLegendBy?: string;
+ sortLegendDesc?: boolean;
+ onSeriesColorChange: SeriesColorChangeHandler;
+ onSeriesAxisToggle?: SeriesAxisToggleHandler;
+ onSeriesToggle?: (label: string, event: React.MouseEvent) => void;
+ onToggleSort: (sortBy: string) => void;
+}
+
+const getGraphWithLegendStyles = ({ placement }: GraphWithLegendProps) => ({
+ wrapper: css`
+ display: flex;
+ flex-direction: ${placement === 'under' ? 'column' : 'row'};
+ height: 100%;
+ `,
+ graphContainer: css`
+ min-height: 65%;
+ flex-grow: 1;
+ `,
+ legendContainer: css`
+ padding: 10px 0;
+ max-height: ${placement === 'under' ? '35%' : 'none'};
+ `,
+});
+
+const shouldHideLegendItem = (data: GraphSeriesValue[][], hideEmpty = false, hideZero = false) => {
+ const isZeroOnlySeries = data.reduce((acc, current) => acc + (current[1] || 0), 0) === 0;
+ const isNullOnlySeries = !data.reduce((acc, current) => acc && current[1] !== null, true);
+
+ return (hideEmpty && isNullOnlySeries) || (hideZero && isZeroOnlySeries);
+};
+
+export const GraphWithLegend: React.FunctionComponent = (props: GraphWithLegendProps) => {
+ const {
+ series,
+ timeRange,
+ width,
+ height,
+ showBars,
+ showLines,
+ showPoints,
+ sortLegendBy,
+ sortLegendDesc,
+ isLegendVisible,
+ displayMode,
+ placement,
+ onSeriesAxisToggle,
+ onSeriesColorChange,
+ onSeriesToggle,
+ onToggleSort,
+ hideEmpty,
+ hideZero,
+ } = props;
+ const { graphContainer, wrapper, legendContainer } = getGraphWithLegendStyles(props);
+
+ const legendItems = series.reduce((acc, s) => {
+ return shouldHideLegendItem(s.data, hideEmpty, hideZero)
+ ? acc
+ : acc.concat([
+ {
+ label: s.label,
+ color: s.color,
+ isVisible: s.isVisible,
+ yAxis: s.yAxis,
+ displayValues: s.info || [],
+ },
+ ]);
+ }, []);
+
+ return (
+
+
+ !!s.isVisible)}
+ timeRange={timeRange}
+ showLines={showLines}
+ showPoints={showPoints}
+ showBars={showBars}
+ width={width}
+ height={height}
+ key={isLegendVisible ? 'legend-visible' : 'legend-invisible'}
+ />
+
+
+ {isLegendVisible && (
+
+
+ {
+ if (onSeriesToggle) {
+ onSeriesToggle(item.label, event);
+ }
+ }}
+ onSeriesColorChange={onSeriesColorChange}
+ onSeriesAxisToggle={onSeriesAxisToggle}
+ onToggleSort={onToggleSort}
+ />
+
+
+ )}
+
+ );
+};
diff --git a/packages/grafana-ui/src/components/Graph/mockGraphWithLegendData.ts b/packages/grafana-ui/src/components/Graph/mockGraphWithLegendData.ts
new file mode 100644
index 0000000000000..2e150eb04ea53
--- /dev/null
+++ b/packages/grafana-ui/src/components/Graph/mockGraphWithLegendData.ts
@@ -0,0 +1,3316 @@
+import { GraphWithLegendProps } from './GraphWithLegend';
+import moment from 'moment';
+import { LegendDisplayMode } from '../Legend/Legend';
+// import { LegendList } from '../Legend/LegendList';
+
+export const mockGraphWithLegendData = ({
+ displayMode,
+ onSeriesColorChange,
+ onSeriesAxisToggle,
+}: Partial): GraphWithLegendProps => ({
+ series: [
+ {
+ label: 'A-series',
+ data: [
+ [1554793274247, 20.313880709398614],
+ [1554793294247, 20.08104852830009],
+ [1554793314247, 19.992843162258378],
+ [1554793334247, 20.41499645651864],
+ [1554793354247, 20.121418991609794],
+ [1554793374247, 19.680864164371194],
+ [1554793394247, 19.246572984138286],
+ [1554793414247, 19.46125180187392],
+ [1554793434247, 19.039716655273562],
+ [1554793454247, 18.92237339584932],
+ [1554793474247, 19.032006074688397],
+ [1554793494247, 18.554026324427063],
+ [1554793514247, 18.638230492753188],
+ [1554793534247, 18.30793730234939],
+ [1554793554247, 18.19449466810041],
+ [1554793574247, 18.344646319460164],
+ [1554793594247, 18.11110436496195],
+ [1554793614247, 18.22114686279577],
+ [1554793634247, 17.963238261916597],
+ [1554793654247, 18.066099068004895],
+ [1554793674247, 17.820666244047295],
+ [1554793694247, 17.658322234243347],
+ [1554793714247, 17.446542397799462],
+ [1554793734247, 17.371388468792254],
+ [1554793754247, 17.217876617816966],
+ [1554793774247, 17.257521109488476],
+ [1554793794247, 17.58336498893354],
+ [1554793814247, 17.59090539787382],
+ [1554793834247, 17.87356599440561],
+ [1554793854247, 17.4806967502818],
+ [1554793874247, 17.92887698327966],
+ [1554793894247, 17.905603390367062],
+ [1554793914247, 18.3347835049674],
+ [1554793934247, 18.25272866220099],
+ [1554793954247, 17.864277261462757],
+ [1554793974247, 18.152124227305972],
+ [1554793994247, 18.259495538365456],
+ [1554794014247, 18.489018553448787],
+ [1554794034247, 18.821247189702426],
+ [1554794054247, 19.08003017107941],
+ [1554794074247, 19.491262702076856],
+ [1554794094247, 19.1827682465781],
+ [1554794114247, 19.182869096769963],
+ [1554794134247, 19.095115140924634],
+ [1554794154247, 19.05299994112004],
+ [1554794174247, 18.590606725871183],
+ [1554794194247, 19.07931422785976],
+ [1554794214247, 19.477891144970496],
+ [1554794234247, 19.21897148797869],
+ [1554794254247, 18.77220964737733],
+ [1554794274247, 18.803310056748714],
+ [1554794294247, 18.88481860551549],
+ [1554794314247, 19.194980590780798],
+ [1554794334247, 19.13519891641105],
+ [1554794354247, 19.22496773205921],
+ [1554794374247, 18.735469623659885],
+ [1554794394247, 19.021576009377863],
+ [1554794414247, 19.246289879789813],
+ [1554794434247, 19.105419144705216],
+ [1554794454247, 19.571674122877262],
+ [1554794474247, 19.891144340237346],
+ [1554794494247, 19.676557234305022],
+ [1554794514247, 19.345971553425187],
+ [1554794534247, 19.048466632282935],
+ [1554794554247, 18.570617820383877],
+ [1554794574247, 18.734467617535582],
+ [1554794594247, 19.04927504415475],
+ [1554794614247, 19.166389592466707],
+ [1554794634247, 18.794409779030502],
+ [1554794654247, 19.181010534033533],
+ [1554794674247, 19.37350362803945],
+ [1554794694247, 18.950932112848196],
+ [1554794714247, 18.488019913458178],
+ [1554794734247, 18.86684581263146],
+ [1554794754247, 18.983697195043614],
+ [1554794774247, 18.531710787820366],
+ [1554794794247, 19.01566943622132],
+ [1554794814247, 19.40748484804793],
+ [1554794834247, 19.435103380796],
+ [1554794854247, 19.39782995665856],
+ [1554794874247, 19.438254903387058],
+ [1554794894247, 19.10031735117575],
+ [1554794914247, 18.980821678099883],
+ [1554794934247, 18.834722745415952],
+ [1554794954247, 18.373878360320436],
+ [1554794974247, 18.84943998519851],
+ [1554794994247, 19.106939136485085],
+ [1554795014247, 19.052362017480817],
+ [1554795034247, 18.648880645925313],
+ [1554795054247, 18.8814523423611],
+ [1554795074247, 18.857826541729597],
+ [1554795094247, 19.008845156827967],
+ [1554795114247, 19.28178805280102],
+ [1554795134247, 19.602626486969534],
+ [1554795154247, 19.985163722852473],
+ [1554795174247, 20.322606652974994],
+ [1554795194247, 20.586587642388157],
+ [1554795214247, 20.39315542962396],
+ [1554795234247, 20.842997727238604],
+ [1554795254247, 20.479452567602156],
+ [1554795274247, 20.56819178541087],
+ [1554795294247, 20.317663197821815],
+ [1554795314247, 20.188138468315195],
+ [1554795334247, 19.705561316215853],
+ [1554795354247, 19.479509927065397],
+ [1554795374247, 19.447752179188306],
+ [1554795394247, 19.181232835157697],
+ [1554795414247, 19.459427085329224],
+ [1554795434247, 19.05132746752971],
+ [1554795454247, 18.841056436711025],
+ [1554795474247, 18.831360086228283],
+ [1554795494247, 18.86658975782061],
+ [1554795514247, 18.698033676789784],
+ [1554795534247, 18.929839598501857],
+ [1554795554247, 19.390241447580827],
+ [1554795574247, 19.339437395648535],
+ [1554795594247, 19.666634660902492],
+ [1554795614247, 19.767170656886673],
+ [1554795634247, 19.911342704118248],
+ [1554795654247, 20.37312718893495],
+ [1554795674247, 20.43933881511363],
+ [1554795694247, 20.653859896728182],
+ [1554795714247, 20.77646124725375],
+ [1554795734247, 20.98307062620013],
+ [1554795754247, 20.76453112065912],
+ [1554795774247, 20.705974067242977],
+ [1554795794247, 20.260579571260333],
+ [1554795814247, 20.662046577866715],
+ [1554795834247, 20.2449850759113],
+ [1554795854247, 19.756051593693513],
+ [1554795874247, 19.619517424157557],
+ [1554795894247, 19.29791716902326],
+ [1554795914247, 19.179238038293985],
+ [1554795934247, 19.46627554259614],
+ [1554795954247, 19.66575441011187],
+ [1554795974247, 19.940391553759927],
+ [1554795994247, 20.298913074442243],
+ [1554796014247, 20.13096011323593],
+ [1554796034247, 20.23340372021052],
+ [1554796054247, 20.585390686449408],
+ [1554796074247, 20.997775066783095],
+ [1554796094247, 21.04685139350083],
+ [1554796114247, 20.778323773832028],
+ [1554796134247, 20.72898684239931],
+ [1554796154247, 20.746854320861416],
+ [1554796174247, 21.080311484818665],
+ [1554796194247, 21.318217286443893],
+ [1554796214247, 21.54956043220836],
+ [1554796234247, 21.271074017912362],
+ [1554796254247, 21.116019947184835],
+ [1554796274247, 20.62448718389609],
+ [1554796294247, 20.721537234112986],
+ [1554796314247, 20.36305734406211],
+ [1554796334247, 20.42644876993651],
+ [1554796354247, 20.16545544539798],
+ [1554796374247, 20.26968616779487],
+ [1554796394247, 20.3397829790123],
+ [1554796414247, 20.03067628549628],
+ [1554796434247, 20.131150696804713],
+ [1554796454247, 19.996918423173987],
+ [1554796474247, 20.3383860035356],
+ [1554796494247, 19.874575784832267],
+ [1554796514247, 19.874280591895396],
+ [1554796534247, 19.555747916068814],
+ [1554796554247, 19.512322604239518],
+ [1554796574247, 19.971727883913204],
+ [1554796594247, 19.972663038357112],
+ [1554796614247, 20.215750537357355],
+ [1554796634247, 19.811615680952983],
+ [1554796654247, 19.420570259916218],
+ [1554796674247, 19.78388048792971],
+ [1554796694247, 19.809444584661886],
+ [1554796714247, 19.744609482332653],
+ [1554796734247, 20.039793233334624],
+ [1554796754247, 19.656750321018873],
+ [1554796774247, 19.655016503008568],
+ [1554796794247, 19.91706698974138],
+ [1554796814247, 20.023553168738367],
+ [1554796834247, 20.077071328813926],
+ [1554796854247, 19.88531080019798],
+ [1554796874247, 20.274356827283746],
+ [1554796894247, 19.871521517855285],
+ [1554796914247, 19.849189625281237],
+ [1554796934247, 19.545290760324306],
+ [1554796954247, 19.18091527224302],
+ [1554796974247, 19.452336236879457],
+ [1554796994247, 19.146012613561403],
+ [1554797014247, 19.354033871521427],
+ [1554797034247, 19.374660496846577],
+ [1554797054247, 19.545775904269995],
+ [1554797074247, 19.466624079433085],
+ [1554797094247, 19.024037215414324],
+ [1554797114247, 18.676381124829952],
+ [1554797134247, 18.607609672523235],
+ [1554797154247, 18.45093227466119],
+ [1554797174247, 18.497642680307425],
+ [1554797194247, 18.84995936205565],
+ [1554797214247, 19.254794470921848],
+ [1554797234247, 19.118449528190986],
+ [1554797254247, 19.30669615290519],
+ [1554797274247, 19.289538518091465],
+ [1554797294247, 19.402478297163942],
+ [1554797314247, 19.142856488362764],
+ [1554797334247, 18.86825661399161],
+ [1554797354247, 18.439007909998104],
+ [1554797374247, 18.776471890064464],
+ [1554797394247, 18.491952005082823],
+ [1554797414247, 18.44926487148877],
+ [1554797434247, 18.610300172432634],
+ [1554797454247, 18.800869256547237],
+ [1554797474247, 19.155873759250404],
+ [1554797494247, 19.31190799141301],
+ [1554797514247, 18.825285394687576],
+ [1554797534247, 19.095824434613274],
+ [1554797554247, 19.578941846370167],
+ [1554797574247, 19.53513022972872],
+ [1554797594247, 19.3934810416622],
+ [1554797614247, 19.763910623076562],
+ [1554797634247, 19.804650392017304],
+ [1554797654247, 20.20814902135129],
+ [1554797674247, 20.42627007519049],
+ [1554797694247, 20.511388593346943],
+ [1554797714247, 20.433559812648035],
+ [1554797734247, 20.020788343527283],
+ [1554797754247, 19.82882881602156],
+ [1554797774247, 19.956206997916635],
+ [1554797794247, 19.56420055511053],
+ [1554797814247, 19.58095464334045],
+ [1554797834247, 19.102116442251454],
+ [1554797854247, 19.321044748170134],
+ [1554797874247, 19.278620558285734],
+ [1554797894247, 19.084803610335157],
+ [1554797914247, 19.163238894440624],
+ [1554797934247, 19.025819265964852],
+ [1554797954247, 18.738817306013523],
+ [1554797974247, 18.510704203480046],
+ [1554797994247, 18.92399476064368],
+ [1554798014247, 18.440467253152406],
+ [1554798034247, 18.283511925716606],
+ [1554798054247, 18.19183485113992],
+ [1554798074247, 17.83694725296019],
+ [1554798094247, 18.017076994342407],
+ [1554798114247, 18.413747553873502],
+ [1554798134247, 18.005072087426772],
+ [1554798154247, 17.65050119520046],
+ [1554798174247, 17.457829234397302],
+ [1554798194247, 17.275106596433275],
+ [1554798214247, 17.004692080070477],
+ [1554798234247, 17.22971019286104],
+ [1554798254247, 16.894301628540166],
+ [1554798274247, 16.44401141001666],
+ [1554798294247, 16.09012511787796],
+ [1554798314247, 15.833370717085522],
+ [1554798334247, 15.678198461092794],
+ [1554798354247, 15.617087273922538],
+ [1554798374247, 15.642521752347575],
+ [1554798394247, 15.824114909605015],
+ [1554798414247, 15.83242331224305],
+ [1554798434247, 16.26807306007194],
+ [1554798454247, 15.873706905242111],
+ [1554798474247, 16.164271858937447],
+ [1554798494247, 16.273629141890627],
+ [1554798514247, 15.837914408005892],
+ [1554798534247, 16.05357618383023],
+ [1554798554247, 16.358538521510823],
+ [1554798574247, 16.625077510565273],
+ [1554798594247, 16.235680011268176],
+ [1554798614247, 16.61406857262163],
+ [1554798634247, 16.158350150979114],
+ [1554798654247, 15.812238103859952],
+ [1554798674247, 15.650024480664284],
+ [1554798694247, 15.154774996351108],
+ [1554798714247, 15.08214977373202],
+ [1554798734247, 15.227710040181536],
+ [1554798754247, 15.373882728706388],
+ [1554798774247, 15.107453513219458],
+ [1554798794247, 14.849139739563727],
+ [1554798814247, 14.814129962471274],
+ [1554798834247, 14.542311965505606],
+ [1554798854247, 14.427101844163694],
+ [1554798874247, 14.74888608186797],
+ [1554798894247, 14.792451034664934],
+ [1554798914247, 15.175048493928175],
+ [1554798934247, 15.014974152971416],
+ [1554798954247, 15.268983047378917],
+ [1554798974247, 15.282030183678799],
+ [1554798994247, 15.602132376241688],
+ [1554799014247, 15.23005106786267],
+ [1554799034247, 15.636887587953181],
+ [1554799054247, 15.805420273666],
+ [1554799074247, 16.048541268247742],
+ [1554799094247, 15.838719939306882],
+ [1554799114247, 15.708752782909732],
+ [1554799134247, 16.066680817193237],
+ [1554799154247, 16.08650897981167],
+ [1554799174247, 16.256833754570117],
+ [1554799194247, 16.58911099339985],
+ [1554799214247, 16.649537934236353],
+ [1554799234247, 16.887066362197004],
+ [1554799254247, 16.47612075923721],
+ [1554799274247, 16.295702450730463],
+ [1554799294247, 15.959097792634903],
+ [1554799314247, 15.576774485820334],
+ [1554799334247, 15.903959111453402],
+ [1554799354247, 15.850548648128646],
+ [1554799374247, 15.988279814202075],
+ [1554799394247, 16.04008606971051],
+ [1554799414247, 16.334614032926087],
+ [1554799434247, 16.487440096615437],
+ [1554799454247, 16.075387529551623],
+ [1554799474247, 16.01349775782911],
+ [1554799494247, 16.40687699618258],
+ [1554799514247, 16.776868163518795],
+ [1554799534247, 17.185567067824188],
+ [1554799554247, 17.015084468455086],
+ [1554799574247, 17.088300049509055],
+ [1554799594247, 17.08802703704262],
+ [1554799614247, 17.451986823807108],
+ [1554799634247, 16.95292997178481],
+ [1554799654247, 16.51059402590916],
+ [1554799674247, 16.60084209687119],
+ [1554799694247, 17.06600437213062],
+ [1554799714247, 17.233540826974814],
+ [1554799734247, 16.945799567917064],
+ [1554799754247, 17.37443597552288],
+ [1554799774247, 16.90064599344329],
+ [1554799794247, 17.22123127821873],
+ [1554799814247, 16.954378456750387],
+ [1554799834247, 17.148060018111345],
+ [1554799854247, 17.090794394519804],
+ [1554799874247, 17.35099506839045],
+ [1554799894247, 17.62732436629698],
+ [1554799914247, 17.576380903908223],
+ [1554799934247, 17.5787616954438],
+ [1554799954247, 17.89583025685836],
+ [1554799974247, 18.376038600962016],
+ [1554799994247, 17.91345499687831],
+ [1554800014247, 17.564064762434413],
+ [1554800034247, 18.034917870957752],
+ [1554800054247, 18.105816481120268],
+ [1554800074247, 17.77072863251834],
+ [1554800094247, 17.992278168519807],
+ [1554800114247, 18.07420472728541],
+ [1554800134247, 18.022893864572822],
+ [1554800154247, 18.511067946730545],
+ [1554800174247, 18.53868749198732],
+ [1554800194247, 18.4665014110292],
+ [1554800214247, 18.93261420838234],
+ [1554800234247, 18.62757758529829],
+ [1554800254247, 18.82704470974516],
+ [1554800274247, 18.617547568653528],
+ [1554800294247, 18.73952779241911],
+ [1554800314247, 18.444297284601785],
+ [1554800334247, 18.406712402146002],
+ [1554800354247, 18.53724765698832],
+ [1554800374247, 18.68355494811299],
+ [1554800394247, 19.05074641300459],
+ [1554800414247, 19.410594032681672],
+ [1554800434247, 19.13445258188613],
+ [1554800454247, 18.759185011234695],
+ [1554800474247, 18.68542467209139],
+ [1554800494247, 19.06896639146912],
+ [1554800514247, 18.6051957309167],
+ [1554800534247, 18.42031016075946],
+ [1554800554247, 18.348974546182863],
+ [1554800574247, 18.20505247170292],
+ [1554800594247, 18.69452503019689],
+ [1554800614247, 18.934944507853064],
+ [1554800634247, 18.66230144695166],
+ [1554800654247, 18.771678982276487],
+ [1554800674247, 18.902003446382544],
+ [1554800694247, 18.817100898765727],
+ [1554800714247, 18.59223352705925],
+ [1554800734247, 18.25969133611703],
+ [1554800754247, 17.831061793894364],
+ [1554800774247, 17.6728034881081],
+ [1554800794247, 17.233411759672073],
+ [1554800814247, 16.8450149813612],
+ [1554800834247, 16.755767493272042],
+ [1554800854247, 16.41492274775498],
+ [1554800874247, 16.334526892010413],
+ [1554800894247, 16.29889828198967],
+ [1554800914247, 16.122001485153216],
+ [1554800934247, 15.738121737315627],
+ [1554800954247, 16.182985021379192],
+ [1554800974247, 15.77999826616122],
+ [1554800994247, 15.870712900527263],
+ [1554801014247, 16.220417258476434],
+ [1554801034247, 15.824531476775649],
+ [1554801054247, 15.385318138167277],
+ [1554801074247, 15.402539411608153],
+ [1554801094247, 15.435752247259211],
+ [1554801114247, 15.141629819254383],
+ [1554801134247, 14.871864320006623],
+ [1554801154247, 14.873766246615965],
+ [1554801174247, 15.345995441924948],
+ [1554801194247, 15.557439903201686],
+ [1554801214247, 15.555467370168937],
+ [1554801234247, 15.767954832856459],
+ [1554801254247, 15.724226707330411],
+ [1554801274247, 16.141832734977395],
+ [1554801294247, 16.078874676735936],
+ [1554801314247, 16.520447865480683],
+ [1554801334247, 16.852278087210898],
+ [1554801354247, 16.391326466348595],
+ [1554801374247, 16.83676425276248],
+ [1554801394247, 17.326748972037034],
+ [1554801414247, 17.48254647807906],
+ [1554801434247, 17.785717992907795],
+ [1554801454247, 18.161130877112615],
+ [1554801474247, 18.65474919931944],
+ [1554801494247, 19.151368669051376],
+ [1554801514247, 19.51103704690084],
+ [1554801534247, 19.244060870618746],
+ [1554801554247, 18.762678457259234],
+ [1554801574247, 18.283405636211146],
+ [1554801594247, 18.2058134112917],
+ [1554801614247, 18.318742517158878],
+ [1554801634247, 18.125680497027943],
+ [1554801654247, 17.859067813647037],
+ [1554801674247, 17.430770939942565],
+ [1554801694247, 17.48829025285418],
+ [1554801714247, 17.41660346714896],
+ [1554801734247, 17.267176902967986],
+ [1554801754247, 17.134933206965716],
+ [1554801774247, 16.859998621613713],
+ [1554801794247, 17.17957666828268],
+ [1554801814247, 16.85553452636789],
+ [1554801834247, 17.021618900377234],
+ [1554801854247, 17.28697744467099],
+ [1554801874247, 17.026404541469358],
+ [1554801894247, 16.74964033058671],
+ [1554801914247, 17.1446553563511],
+ [1554801934247, 16.686389751463988],
+ [1554801954247, 16.813825821001483],
+ [1554801974247, 17.00642230043151],
+ [1554801994247, 17.377258024761936],
+ [1554802014247, 17.50127422146399],
+ [1554802034247, 17.3817548239187],
+ [1554802054247, 17.291601771428926],
+ [1554802074247, 17.221925959717726],
+ [1554802094247, 17.465156492221098],
+ [1554802114247, 17.356019827095594],
+ [1554802134247, 17.779054323656062],
+ [1554802154247, 18.062316118223833],
+ [1554802174247, 17.86066337329332],
+ [1554802194247, 17.642699917109947],
+ [1554802214247, 17.889975752328375],
+ [1554802234247, 18.20280332736594],
+ [1554802254247, 18.128064273603368],
+ [1554802274247, 18.341350547206854],
+ [1554802294247, 18.69202676598315],
+ [1554802314247, 18.997182695237544],
+ [1554802334247, 18.56932097324519],
+ [1554802354247, 18.127417617110936],
+ [1554802374247, 18.563591061578247],
+ [1554802394247, 18.935739093711494],
+ [1554802414247, 19.328009657837754],
+ [1554802434247, 19.051987873183407],
+ [1554802454247, 19.302136515646502],
+ [1554802474247, 19.444975293950954],
+ [1554802494247, 19.056805905772976],
+ [1554802514247, 19.489349320985696],
+ [1554802534247, 19.029312427568964],
+ [1554802554247, 18.66188283167321],
+ [1554802574247, 18.966232924802636],
+ [1554802594247, 19.333887271116005],
+ [1554802614247, 19.49454092865925],
+ [1554802634247, 19.225058732253423],
+ [1554802654247, 19.50584851870466],
+ [1554802674247, 19.825454559183065],
+ [1554802694247, 20.275633981781876],
+ [1554802714247, 19.796255964131436],
+ [1554802734247, 19.51553115747093],
+ [1554802754247, 19.168722344585948],
+ [1554802774247, 19.259002618369472],
+ [1554802794247, 19.41016958266869],
+ [1554802814247, 19.907823260030593],
+ [1554802834247, 19.631151352570843],
+ [1554802854247, 19.905244374936135],
+ [1554802874247, 19.798764882824536],
+ [1554802894247, 20.008082677788725],
+ [1554802914247, 20.064688572823655],
+ [1554802934247, 19.98935102323253],
+ [1554802954247, 19.685443067226227],
+ [1554802974247, 19.24365424044176],
+ [1554802994247, 19.67853298503077],
+ [1554803014247, 19.417464736403762],
+ [1554803034247, 19.099948997361082],
+ [1554803054247, 18.884888830958005],
+ [1554803074247, 19.275934909503246],
+ [1554803094247, 18.857388403280176],
+ [1554803114247, 18.395179891885807],
+ [1554803134247, 18.15582485375867],
+ [1554803154247, 18.461384373169917],
+ [1554803174247, 18.65820855056107],
+ [1554803194247, 18.780890910474543],
+ [1554803214247, 18.934246513949834],
+ [1554803234247, 18.940994398971654],
+ [1554803254247, 18.80380381297457],
+ [1554803274247, 18.975556784451616],
+ [1554803294247, 18.937892650321324],
+ [1554803314247, 19.208253250171996],
+ [1554803334247, 19.479912061820972],
+ [1554803354247, 19.817839292405047],
+ [1554803374247, 20.216166795485478],
+ [1554803394247, 20.037801151725823],
+ [1554803414247, 20.089230983878828],
+ [1554803434247, 19.82509936207721],
+ [1554803454247, 19.499858580193926],
+ [1554803474247, 19.241945160507615],
+ [1554803494247, 19.59878062745236],
+ [1554803514247, 19.769393970536225],
+ [1554803534247, 19.618300805498567],
+ [1554803554247, 19.308561167940837],
+ [1554803574247, 18.97105055750365],
+ [1554803594247, 18.686699428116373],
+ [1554803614247, 18.678264142459323],
+ [1554803634247, 18.20910669657999],
+ [1554803654247, 18.400110408790137],
+ [1554803674247, 18.586150272944028],
+ [1554803694247, 19.04398053920283],
+ [1554803714247, 18.668729219956465],
+ [1554803734247, 18.98873600767759],
+ [1554803754247, 18.56574832702069],
+ [1554803774247, 18.79337113112325],
+ [1554803794247, 18.593258461416298],
+ [1554803814247, 18.800523265764216],
+ [1554803834247, 18.65948976366625],
+ [1554803854247, 18.817685852229896],
+ [1554803874247, 18.340420869044404],
+ [1554803894247, 18.18299492246204],
+ [1554803914247, 17.802066447573516],
+ [1554803934247, 18.071547724968173],
+ [1554803954247, 18.049751013799774],
+ [1554803974247, 17.87610824900385],
+ [1554803994247, 18.070504699571167],
+ [1554804014247, 18.27223858743518],
+ [1554804034247, 18.659606010902305],
+ [1554804054247, 18.39868265036132],
+ [1554804074247, 18.629068097966716],
+ [1554804094247, 18.337125728095433],
+ [1554804114247, 17.95304427209962],
+ [1554804134247, 18.116835197158572],
+ [1554804154247, 17.98894688777001],
+ [1554804174247, 18.487042644098864],
+ [1554804194247, 18.48570091736673],
+ [1554804214247, 18.512055466874543],
+ [1554804234247, 18.333051234583998],
+ [1554804254247, 18.603280990702924],
+ [1554804274247, 18.40207930027631],
+ [1554804294247, 17.971588925595327],
+ [1554804314247, 17.961758137993403],
+ [1554804334247, 18.226019089234516],
+ [1554804354247, 18.35225998608116],
+ [1554804374247, 18.639765096991333],
+ [1554804394247, 18.550712331665693],
+ [1554804414247, 18.692217967806517],
+ [1554804434247, 19.050071777223973],
+ [1554804454247, 19.37757827497838],
+ [1554804474247, 19.256081586202434],
+ [1554804494247, 18.90425477864548],
+ [1554804514247, 19.328915814839135],
+ [1554804534247, 18.94477208210245],
+ [1554804554247, 18.921554398027723],
+ [1554804574247, 19.2492095289071],
+ [1554804594247, 19.24109165045788],
+ [1554804614247, 19.204718006137995],
+ [1554804634247, 19.314243927875925],
+ [1554804654247, 18.93826896103946],
+ [1554804674247, 18.843386261025607],
+ [1554804694247, 18.452727827390838],
+ [1554804714247, 18.31288494939828],
+ [1554804734247, 18.28969441044889],
+ [1554804754247, 18.279839879184603],
+ [1554804774247, 17.89656879221293],
+ [1554804794247, 17.779765781544064],
+ [1554804814247, 18.047473543757114],
+ [1554804834247, 17.581871597783845],
+ [1554804854247, 17.788255131385938],
+ [1554804874247, 17.73564406039265],
+ [1554804894247, 17.85521468570053],
+ [1554804914247, 17.93504986472167],
+ [1554804934247, 18.346975101938344],
+ [1554804954247, 18.746813567661178],
+ [1554804974247, 18.513442964330473],
+ [1554804994247, 18.689558935359702],
+ [1554805014247, 18.81268731017689],
+ [1554805034247, 18.92030204915925],
+ [1554805054247, 18.525588855553714],
+ [1554805074247, 18.39543929691923],
+ [1554805094247, 18.724426995823144],
+ [1554805114247, 18.97615036082755],
+ [1554805134247, 18.735574008669783],
+ [1554805154247, 18.51218532804814],
+ [1554805174247, 19.002998946420824],
+ [1554805194247, 19.327807288989124],
+ [1554805214247, 19.782716047902646],
+ [1554805234247, 20.0799405830441],
+ [1554805254247, 20.309169195940356],
+ [1554805274247, 20.424494554101425],
+ [1554805294247, 20.016587666434507],
+ [1554805314247, 19.90717258752296],
+ [1554805334247, 19.705116713312897],
+ [1554805354247, 19.714068611166343],
+ [1554805374247, 20.092668883679085],
+ [1554805394247, 20.45876075819353],
+ [1554805414247, 19.978968126702078],
+ [1554805434247, 19.726344289707207],
+ [1554805454247, 19.67555531958179],
+ [1554805474247, 19.248318379398153],
+ [1554805494247, 18.92559402301265],
+ [1554805514247, 19.05593780593657],
+ [1554805534247, 18.78655877710173],
+ [1554805554247, 18.72278713083883],
+ [1554805574247, 18.883178543004075],
+ [1554805594247, 19.214524420867246],
+ [1554805614247, 19.312331181864046],
+ [1554805634247, 19.36197097685949],
+ [1554805654247, 18.873989064227487],
+ [1554805674247, 18.50980867117683],
+ [1554805694247, 18.591329413843802],
+ [1554805714247, 18.440948189650424],
+ [1554805734247, 18.49790909406058],
+ [1554805754247, 18.22993181565998],
+ [1554805774247, 18.176792706963482],
+ [1554805794247, 17.742068630596],
+ [1554805814247, 18.127171061480716],
+ [1554805834247, 18.61113434280144],
+ [1554805854247, 18.266545971249155],
+ [1554805874247, 18.051239661919034],
+ [1554805894247, 18.121586360148203],
+ [1554805914247, 18.28596328116828],
+ [1554805934247, 18.03804682147004],
+ [1554805954247, 17.92912894978805],
+ [1554805974247, 18.248018885767422],
+ [1554805994247, 18.170264071486372],
+ [1554806014247, 18.047108689907635],
+ [1554806034247, 18.379913022515094],
+ [1554806054247, 18.7985656956094],
+ [1554806074247, 18.456930330499166],
+ [1554806094247, 18.295835868859527],
+ [1554806114247, 18.19306037002757],
+ [1554806134247, 17.93075614519311],
+ [1554806154247, 17.57537661265962],
+ [1554806174247, 17.182737877206783],
+ [1554806194247, 17.608978667641548],
+ [1554806214247, 18.091581656416327],
+ [1554806234247, 18.12482889513131],
+ [1554806254247, 18.185538016887143],
+ [1554806274247, 18.20938728273094],
+ [1554806294247, 18.57802459483719],
+ [1554806314247, 18.27478663407127],
+ [1554806334247, 18.18309828031528],
+ [1554806354247, 18.046046587405275],
+ [1554806374247, 18.110230133577016],
+ [1554806394247, 17.77958854513807],
+ [1554806414247, 17.755552238573014],
+ [1554806434247, 17.93407403212182],
+ [1554806454247, 17.834950651753168],
+ [1554806474247, 17.62487333533259],
+ [1554806494247, 17.818756369279967],
+ [1554806514247, 17.39004492227227],
+ [1554806534247, 17.193372581431124],
+ [1554806554247, 16.95129928749413],
+ [1554806574247, 17.016306124404707],
+ [1554806594247, 16.712795603328992],
+ [1554806614247, 16.53416774729842],
+ [1554806634247, 16.291809836675082],
+ [1554806654247, 16.672668617071984],
+ [1554806674247, 16.873191162896983],
+ [1554806694247, 17.10782981368545],
+ [1554806714247, 16.727951485311106],
+ [1554806734247, 16.96036493957726],
+ [1554806754247, 16.514521429647758],
+ [1554806774247, 16.084114804956304],
+ [1554806794247, 16.30254578168955],
+ [1554806814247, 16.534087254833164],
+ [1554806834247, 16.056953526055793],
+ [1554806854247, 15.584026045940329],
+ [1554806874247, 15.618649451155633],
+ [1554806894247, 15.538672348396526],
+ [1554806914247, 15.9620988253781],
+ [1554806934247, 16.43967579598588],
+ [1554806954247, 16.828110677544426],
+ [1554806974247, 16.71539758814196],
+ [1554806994247, 16.91114798772243],
+ [1554807014247, 16.970190521091418],
+ [1554807034247, 16.652980147832025],
+ [1554807054247, 16.95589224983671],
+ [1554807074247, 17.42272242301996],
+ [1554807094247, 17.268816017793508],
+ [1554807114247, 16.977764959290678],
+ [1554807134247, 17.30696723687278],
+ [1554807154247, 16.809909430780127],
+ [1554807174247, 16.834741273519402],
+ [1554807194247, 16.417886405774215],
+ [1554807214247, 16.762016909140442],
+ [1554807234247, 17.138100938886808],
+ [1554807254247, 17.230621881528826],
+ [1554807274247, 17.72741817378255],
+ [1554807294247, 17.776039783674833],
+ [1554807314247, 17.87884125809111],
+ [1554807334247, 17.38224934430264],
+ [1554807354247, 17.412052920655796],
+ [1554807374247, 17.75691024403483],
+ [1554807394247, 17.435099479511265],
+ [1554807414247, 17.151274766857476],
+ [1554807434247, 17.593342658698447],
+ [1554807454247, 17.334653653522253],
+ [1554807474247, 17.476092698124962],
+ [1554807494247, 17.630521911429216],
+ [1554807514247, 18.00861111106235],
+ [1554807534247, 18.17241595532054],
+ [1554807554247, 18.19384073799544],
+ [1554807574247, 18.17660445507042],
+ [1554807594247, 17.889367920812205],
+ [1554807614247, 17.662933364897235],
+ [1554807634247, 17.996510291559048],
+ [1554807654247, 18.10999075434485],
+ [1554807674247, 18.08907251127535],
+ [1554807694247, 18.362301935391887],
+ [1554807714247, 18.73675882969702],
+ [1554807734247, 18.777242368554464],
+ [1554807754247, 18.728454583314942],
+ [1554807774247, 18.67778255980091],
+ [1554807794247, 18.21170532262526],
+ [1554807814247, 18.336013592669683],
+ [1554807834247, 18.486708118751547],
+ [1554807854247, 18.481457501410357],
+ [1554807874247, 18.580337444483],
+ [1554807894247, 18.585776154287643],
+ [1554807914247, 18.277367743334594],
+ [1554807934247, 18.4748120256564],
+ [1554807954247, 17.988109644084805],
+ [1554807974247, 17.50359155734211],
+ [1554807994247, 17.054621181707596],
+ [1554808014247, 17.050657416275882],
+ [1554808034247, 17.53340725427101],
+ [1554808054247, 17.2823824698551],
+ [1554808074247, 17.230073631700503],
+ [1554808094247, 17.660070302810404],
+ [1554808114247, 17.715497232909698],
+ [1554808134247, 17.89362479407042],
+ [1554808154247, 17.675851255462916],
+ [1554808174247, 17.798916844787072],
+ [1554808194247, 17.370179004365454],
+ [1554808214247, 16.935754571814158],
+ [1554808234247, 16.575111172315417],
+ [1554808254247, 16.957750516945833],
+ [1554808274247, 16.906067262875016],
+ [1554808294247, 17.147262833877377],
+ [1554808314247, 17.25481302019992],
+ [1554808334247, 16.88623932971355],
+ [1554808354247, 16.826900270442206],
+ [1554808374247, 17.10501975118114],
+ [1554808394247, 17.374628130862487],
+ [1554808414247, 17.07918741156744],
+ [1554808434247, 17.23444863499987],
+ [1554808454247, 16.810847489538],
+ [1554808474247, 17.113170666785386],
+ [1554808494247, 17.034661603204178],
+ [1554808514247, 17.423832159197985],
+ [1554808534247, 17.384975048960655],
+ [1554808554247, 17.157321849221564],
+ [1554808574247, 17.295587749135628],
+ [1554808594247, 17.422000437377765],
+ [1554808614247, 17.569027537150625],
+ [1554808634247, 17.802041495838445],
+ [1554808654247, 17.424428662815046],
+ [1554808674247, 17.75925159046375],
+ [1554808694247, 18.22257416365628],
+ [1554808714247, 18.044788857332886],
+ [1554808734247, 17.71747698325384],
+ [1554808754247, 17.42290034812379],
+ [1554808774247, 17.78912609157009],
+ [1554808794247, 18.1697394821823],
+ [1554808814247, 18.370976940779865],
+ [1554808834247, 18.29486854059247],
+ [1554808854247, 18.551667794503583],
+ [1554808874247, 18.39828137765856],
+ [1554808894247, 18.25110684354119],
+ [1554808914247, 18.424132243647602],
+ [1554808934247, 17.928269310694105],
+ [1554808954247, 17.891590956635838],
+ [1554808974247, 17.615722459795265],
+ [1554808994247, 17.772868766141663],
+ [1554809014247, 17.3521751556697],
+ [1554809034247, 17.11182923580405],
+ [1554809054247, 17.305146213842725],
+ [1554809074247, 17.492812063228744],
+ [1554809094247, 17.15927912926812],
+ [1554809114247, 17.121703806114706],
+ [1554809134247, 17.501420046950543],
+ [1554809154247, 17.66727157116937],
+ [1554809174247, 17.812646877248156],
+ [1554809194247, 17.8037690723927],
+ [1554809214247, 17.80162956689889],
+ [1554809234247, 18.086665506982694],
+ [1554809254247, 18.03889674669137],
+ [1554809274247, 17.677390098732573],
+ [1554809294247, 17.879679198772564],
+ [1554809314247, 17.584585692982444],
+ [1554809334247, 17.959637391545176],
+ [1554809354247, 17.70704655382901],
+ [1554809374247, 17.689773136209624],
+ [1554809394247, 17.647501038318484],
+ [1554809414247, 18.10854669233636],
+ [1554809434247, 18.547843706612916],
+ [1554809454247, 18.982618348379056],
+ [1554809474247, 19.409752361871913],
+ [1554809494247, 19.86787108134553],
+ [1554809514247, 19.444411700870905],
+ [1554809534247, 19.89027726349466],
+ [1554809554247, 20.055647760029323],
+ [1554809574247, 20.332601604977377],
+ [1554809594247, 20.186961614150928],
+ [1554809614247, 19.91407780746553],
+ [1554809634247, 20.06820779595699],
+ [1554809654247, 20.080243472499426],
+ [1554809674247, 19.87713706193293],
+ [1554809694247, 19.681250241399276],
+ [1554809714247, 19.407668380876753],
+ [1554809734247, 19.56481750238362],
+ [1554809754247, 20.004756709116997],
+ [1554809774247, 19.535665690455815],
+ [1554809794247, 19.703425271030913],
+ [1554809814247, 19.54778722171676],
+ [1554809834247, 19.420410850783384],
+ [1554809854247, 19.753529304758832],
+ [1554809874247, 19.982263471778904],
+ [1554809894247, 19.648157753690636],
+ [1554809914247, 19.603042433340118],
+ [1554809934247, 19.589539301758066],
+ [1554809954247, 19.754466582431032],
+ [1554809974247, 20.200289417535693],
+ [1554809994247, 20.535073990717688],
+ [1554810014247, 20.96943211675856],
+ [1554810034247, 20.603270299687363],
+ [1554810054247, 20.173587705343607],
+ [1554810074247, 20.49979443254795],
+ [1554810094247, 20.822318394334552],
+ [1554810114247, 20.71823032496461],
+ [1554810134247, 20.536638182114388],
+ [1554810154247, 20.16245224098834],
+ [1554810174247, 20.365654035559984],
+ [1554810194247, 20.750786422033908],
+ [1554810214247, 20.88604429258989],
+ [1554810234247, 21.18290294700043],
+ [1554810254247, 20.96277049586266],
+ [1554810274247, 21.32180279162898],
+ [1554810294247, 21.0016299534294],
+ [1554810314247, 20.515341526228337],
+ [1554810334247, 20.780007817271024],
+ [1554810354247, 21.129163926216105],
+ [1554810374247, 20.934017218027808],
+ [1554810394247, 20.510533890923607],
+ [1554810414247, 20.960082138122935],
+ [1554810434247, 20.872825242653533],
+ [1554810454247, 21.292186812890325],
+ [1554810474247, 21.760142931714785],
+ [1554810494247, 21.306646483526887],
+ [1554810514247, 21.437367768346387],
+ [1554810534247, 20.988811366969344],
+ [1554810554247, 20.826107468511292],
+ [1554810574247, 21.013480581344588],
+ [1554810594247, 20.878538074356992],
+ [1554810614247, 20.445714347430684],
+ [1554810634247, 20.54588524875655],
+ [1554810654247, 20.934978857440115],
+ [1554810674247, 21.105549392177977],
+ [1554810694247, 21.207736265000023],
+ [1554810714247, 21.203503866950733],
+ [1554810734247, 21.429431725814705],
+ [1554810754247, 21.89991339950124],
+ [1554810774247, 21.83477989894718],
+ [1554810794247, 21.78661197761795],
+ [1554810814247, 22.13335025227573],
+ [1554810834247, 22.516701040475297],
+ [1554810854247, 22.310167692370655],
+ [1554810874247, 22.475935327328717],
+ [1554810894247, 22.8694841788587],
+ [1554810914247, 23.05226599324635],
+ [1554810934247, 22.866715279406986],
+ [1554810954247, 23.008981145929027],
+ [1554810974247, 23.36750693188728],
+ [1554810994247, 23.48291778171053],
+ [1554811014247, 23.240930373151908],
+ [1554811034247, 22.944886738114114],
+ [1554811054247, 23.158830075240527],
+ [1554811074247, 23.596562495280565],
+ [1554811094247, 23.40021118468351],
+ [1554811114247, 23.42527640835139],
+ [1554811134247, 23.881198207863623],
+ [1554811154247, 24.090637642151574],
+ [1554811174247, 23.847092938048707],
+ [1554811194247, 23.572586528171684],
+ [1554811214247, 24.047730244352827],
+ [1554811234247, 24.28476980671547],
+ [1554811254247, 24.220078573950836],
+ [1554811274247, 24.46310903911906],
+ [1554811294247, 24.466900483058215],
+ [1554811314247, 24.792636886264376],
+ [1554811334247, 24.409607815763987],
+ [1554811354247, 24.04038145482966],
+ [1554811374247, 23.94228680381039],
+ [1554811394247, 23.783424741152356],
+ [1554811414247, 23.99408856096362],
+ [1554811434247, 24.47637383884743],
+ [1554811454247, 24.51629571775181],
+ [1554811474247, 24.22032496180614],
+ [1554811494247, 23.999718831088842],
+ [1554811514247, 24.05610267025658],
+ [1554811534247, 24.266273560654778],
+ [1554811554247, 23.899707062230714],
+ [1554811574247, 23.449757627088108],
+ [1554811594247, 23.275400835189835],
+ [1554811614247, 23.358131530933832],
+ [1554811634247, 22.858872033834462],
+ [1554811654247, 23.155103991605444],
+ [1554811674247, 23.546405884685615],
+ [1554811694247, 23.90917052403149],
+ [1554811714247, 23.543095226841295],
+ [1554811734247, 23.06667148021866],
+ [1554811754247, 23.299268579089393],
+ [1554811774247, 22.996973766301174],
+ [1554811794247, 22.96294946666954],
+ [1554811814247, 23.416145844721562],
+ [1554811834247, 23.445491666152734],
+ [1554811854247, 23.78238653255798],
+ [1554811874247, 23.970608966935178],
+ [1554811894247, 24.0777671680898],
+ [1554811914247, 24.00485380564156],
+ [1554811934247, 23.615361773996426],
+ [1554811954247, 24.042391986475458],
+ [1554811974247, 24.30736210082872],
+ [1554811994247, 24.553424136396035],
+ [1554812014247, 24.071551516329688],
+ [1554812034247, 23.912887651146793],
+ [1554812054247, 24.058433667682323],
+ [1554812074247, 24.38218660318733],
+ [1554812094247, 23.95689725397855],
+ [1554812114247, 24.317964378479104],
+ [1554812134247, 24.5559033202204],
+ [1554812154247, 24.94115173656496],
+ [1554812174247, 24.53212651671396],
+ [1554812194247, 24.33543858114263],
+ [1554812214247, 24.054507222611196],
+ [1554812234247, 24.345650133921207],
+ [1554812254247, 24.146007669420054],
+ [1554812274247, 23.826238279851083],
+ [1554812294247, 23.337278633231435],
+ [1554812314247, 23.391970698372745],
+ [1554812334247, 23.854408022629926],
+ [1554812354247, 23.74054371722396],
+ [1554812374247, 23.358933571121483],
+ [1554812394247, 23.53597766617613],
+ [1554812414247, 23.214915406643048],
+ [1554812434247, 22.72418254100616],
+ [1554812454247, 23.124702432769304],
+ [1554812474247, 22.646160083682506],
+ [1554812494247, 22.95948496526543],
+ [1554812514247, 22.908704358394786],
+ [1554812534247, 23.24272599646963],
+ [1554812554247, 22.948667210920263],
+ [1554812574247, 22.88147470162189],
+ [1554812594247, 23.335409408552557],
+ [1554812614247, 23.2645912633166],
+ [1554812634247, 23.172964825433606],
+ [1554812654247, 22.792339297136],
+ [1554812674247, 22.451584230344984],
+ [1554812694247, 22.256332645514753],
+ [1554812714247, 22.70493151367683],
+ [1554812734247, 23.19120036442452],
+ [1554812754247, 22.98024145197298],
+ [1554812774247, 23.310399865487852],
+ [1554812794247, 23.423185487024213],
+ [1554812814247, 23.08331352748343],
+ [1554812834247, 22.843268303245647],
+ [1554812854247, 22.796590167015605],
+ [1554812874247, 22.680223263419595],
+ [1554812894247, 22.1936616130379],
+ [1554812914247, 22.276714302075444],
+ [1554812934247, 22.478761618242125],
+ [1554812954247, 22.744794053235506],
+ [1554812974247, 22.533635764779486],
+ [1554812994247, 22.856595863520614],
+ [1554813014247, 23.297624790450946],
+ [1554813034247, 23.744759897505187],
+ [1554813054247, 23.78062656641052],
+ [1554813074247, 23.670312262657962],
+ [1554813094247, 23.94875247338334],
+ [1554813114247, 24.159246180951172],
+ [1554813134247, 23.729042572247714],
+ [1554813154247, 23.851976354313422],
+ [1554813174247, 24.33054746691777],
+ [1554813194247, 24.431817667166843],
+ [1554813214247, 24.900251155368196],
+ [1554813234247, 25.38279196750522],
+ [1554813254247, 25.122592302324744],
+ [1554813274247, 25.477135073121406],
+ [1554813294247, 25.129731525812613],
+ [1554813314247, 25.09671010378041],
+ [1554813334247, 24.90703450812979],
+ [1554813354247, 24.410500684901685],
+ [1554813374247, 24.81457973663616],
+ [1554813394247, 24.468295893431918],
+ [1554813414247, 24.899199539507308],
+ [1554813434247, 24.85172339452315],
+ [1554813454247, 25.344326207633387],
+ [1554813474247, 25.17219266393189],
+ [1554813494247, 24.693990881064718],
+ [1554813514247, 24.388403883062693],
+ [1554813534247, 24.326079764182648],
+ [1554813554247, 24.411873941334573],
+ [1554813574247, 24.270472386262604],
+ [1554813594247, 24.324012831628146],
+ [1554813614247, 24.099857615227467],
+ [1554813634247, 24.21954267428356],
+ [1554813654247, 24.650473211711404],
+ [1554813674247, 24.44907260287802],
+ [1554813694247, 24.107046790019766],
+ [1554813714247, 24.510413313602093],
+ [1554813734247, 24.88113783461183],
+ [1554813754247, 24.73526251148137],
+ [1554813774247, 25.149750677672976],
+ [1554813794247, 25.014564303805702],
+ [1554813814247, 25.026928370829886],
+ [1554813834247, 24.86256716448043],
+ [1554813854247, 24.560488758456557],
+ [1554813874247, 24.615621474980536],
+ [1554813894247, 24.138639002410695],
+ [1554813914247, 23.940103271596822],
+ [1554813934247, 24.06200449551318],
+ [1554813954247, 24.159453290017183],
+ [1554813974247, 24.214708220020334],
+ [1554813994247, 23.94120965407676],
+ [1554814014247, 23.95298355113604],
+ [1554814034247, 24.314485240167457],
+ [1554814054247, 24.335912954173985],
+ [1554814074247, 24.52467444905973],
+ [1554814094247, 24.385124477285046],
+ [1554814114247, 24.700108123691678],
+ [1554814134247, 24.90576677567081],
+ [1554814154247, 24.99310554556539],
+ [1554814174247, 25.195800841696705],
+ [1554814194247, 25.278335915127883],
+ [1554814214247, 25.414083468286634],
+ [1554814234247, 25.52353974423631],
+ [1554814254247, 25.295016469723016],
+ [1554814274247, 25.419288424881053],
+ [1554814294247, 25.126441819261434],
+ [1554814314247, 24.681588328242032],
+ [1554814334247, 24.810238455213636],
+ [1554814354247, 24.410339756314695],
+ [1554814374247, 24.396192731458672],
+ [1554814394247, 24.325590744742602],
+ [1554814414247, 24.00219866428782],
+ [1554814434247, 23.57700638622354],
+ [1554814454247, 23.539308621824333],
+ [1554814474247, 23.190753289360014],
+ [1554814494247, 23.00850401336011],
+ [1554814514247, 23.137994435866098],
+ [1554814534247, 23.197808317385363],
+ [1554814554247, 22.756545947551],
+ [1554814574247, 22.942948839743238],
+ [1554814594247, 23.072813723042167],
+ [1554814614247, 22.881504025565448],
+ [1554814634247, 23.138709943466257],
+ [1554814654247, 23.06237555382352],
+ [1554814674247, 23.10019915491298],
+ [1554814694247, 23.51780549910103],
+ [1554814714247, 23.274386831939132],
+ [1554814734247, 22.780534530293703],
+ [1554814754247, 22.64347728787694],
+ [1554814774247, 22.578901585680992],
+ [1554814794247, 22.73474307069496],
+ [1554814814247, 22.3017582734572],
+ [1554814834247, 22.23466427843663],
+ [1554814854247, 22.21301416289505],
+ ],
+ color: '#7EB26D',
+ info: [
+ { title: 'min', text: '14.42', numeric: 14.427101844163694 },
+ { title: 'max', text: '18.42', numeric: 18.427101844163694 },
+ ],
+ isVisible: true,
+ yAxis: 1,
+ },
+ {
+ label: 'B-series',
+ data: [
+ [1554793274247, 9.248820139157093],
+ [1554793294247, 9.273875054706759],
+ [1554793314247, 9.352176032498832],
+ [1554793334247, 9.807948429334353],
+ [1554793354247, 9.607817141399979],
+ [1554793374247, 9.827775726389026],
+ [1554793394247, 9.386666730812092],
+ [1554793414247, 9.372938370724333],
+ [1554793434247, 9.783904274932814],
+ [1554793454247, 9.93568291865629],
+ [1554793474247, 10.285904951141445],
+ [1554793494247, 10.356151800899413],
+ [1554793514247, 10.087924134921929],
+ [1554793534247, 10.130969065761265],
+ [1554793554247, 10.039871466196065],
+ [1554793574247, 10.48196042129985],
+ [1554793594247, 10.81294570657847],
+ [1554793614247, 10.425308181694218],
+ [1554793634247, 10.630859250874947],
+ [1554793654247, 10.735866163433657],
+ [1554793674247, 10.414049311911526],
+ [1554793694247, 10.443991943278128],
+ [1554793714247, 10.295408470211672],
+ [1554793734247, 10.614658355598694],
+ [1554793754247, 11.076290920269997],
+ [1554793774247, 11.425597202690865],
+ [1554793794247, 11.262277454840875],
+ [1554793814247, 11.17043615581524],
+ [1554793834247, 11.275581328847908],
+ [1554793854247, 11.481598266537757],
+ [1554793874247, 11.953363680050632],
+ [1554793894247, 12.422008588787305],
+ [1554793914247, 12.069849672231994],
+ [1554793934247, 11.943803466171598],
+ [1554793954247, 12.075583775000037],
+ [1554793974247, 12.068750850266534],
+ [1554793994247, 11.936651489454178],
+ [1554794014247, 11.996688750970568],
+ [1554794034247, 12.052434480528358],
+ [1554794054247, 12.536599186046683],
+ [1554794074247, 13.023718202899493],
+ [1554794094247, 12.966075141324536],
+ [1554794114247, 12.540756307703582],
+ [1554794134247, 12.712148183846951],
+ [1554794154247, 12.256702310766554],
+ [1554794174247, 12.212372314019388],
+ [1554794194247, 12.247568287118359],
+ [1554794214247, 12.010251845188867],
+ [1554794234247, 11.7115171988383],
+ [1554794254247, 11.981072233758754],
+ [1554794274247, 11.970827657632446],
+ [1554794294247, 12.117812031971802],
+ [1554794314247, 11.885655481089309],
+ [1554794334247, 12.139423837249328],
+ [1554794354247, 12.629111619970866],
+ [1554794374247, 12.838751307157468],
+ [1554794394247, 12.698782425513922],
+ [1554794414247, 12.228729591764855],
+ [1554794434247, 12.212858609888734],
+ [1554794454247, 12.549516160357083],
+ [1554794474247, 12.12789035051455],
+ [1554794494247, 11.843341194402191],
+ [1554794514247, 11.70830817970737],
+ [1554794534247, 11.512228940393427],
+ [1554794554247, 11.395363965811262],
+ [1554794574247, 11.86036846413425],
+ [1554794594247, 12.06123558542618],
+ [1554794614247, 12.204159715000836],
+ [1554794634247, 12.271910337675797],
+ [1554794654247, 12.282439537392525],
+ [1554794674247, 12.03790201620353],
+ [1554794694247, 11.829464424427744],
+ [1554794714247, 11.493890332653676],
+ [1554794734247, 11.413793733691467],
+ [1554794754247, 10.917571315788575],
+ [1554794774247, 10.502250358068137],
+ [1554794794247, 10.943314534163564],
+ [1554794814247, 11.371349945440832],
+ [1554794834247, 10.976930007662157],
+ [1554794854247, 10.499203550344646],
+ [1554794874247, 10.8294008121535],
+ [1554794894247, 10.830849260190083],
+ [1554794914247, 10.679528914904482],
+ [1554794934247, 11.124683240448253],
+ [1554794954247, 11.007602273533589],
+ [1554794974247, 11.291030570800228],
+ [1554794994247, 10.878973316312234],
+ [1554795014247, 10.783601804652415],
+ [1554795034247, 10.433756430969048],
+ [1554795054247, 10.024756414413504],
+ [1554795074247, 9.73857829270142],
+ [1554795094247, 9.501542190816165],
+ [1554795114247, 9.236454777535167],
+ [1554795134247, 9.703872577154437],
+ [1554795154247, 9.63913490209853],
+ [1554795174247, 9.380130864761673],
+ [1554795194247, 9.416021803813496],
+ [1554795214247, 9.427268719159454],
+ [1554795234247, 9.628563778508864],
+ [1554795254247, 9.31603705937074],
+ [1554795274247, 9.288467805990262],
+ [1554795294247, 9.445118597922967],
+ [1554795314247, 9.532344831308432],
+ [1554795334247, 9.079446462804185],
+ [1554795354247, 9.170228355998656],
+ [1554795374247, 9.086782779998948],
+ [1554795394247, 9.167605210581598],
+ [1554795414247, 9.337226400746871],
+ [1554795434247, 9.742704787869735],
+ [1554795454247, 9.737360720830406],
+ [1554795474247, 10.137939689453866],
+ [1554795494247, 9.700801043894144],
+ [1554795514247, 9.768218908003545],
+ [1554795534247, 9.75411192216661],
+ [1554795554247, 9.995651363958773],
+ [1554795574247, 9.6245144237306],
+ [1554795594247, 9.226961963966849],
+ [1554795614247, 8.753654850082542],
+ [1554795634247, 8.47135391545531],
+ [1554795654247, 8.183973941349567],
+ [1554795674247, 8.489931082159094],
+ [1554795694247, 8.817639566937025],
+ [1554795714247, 8.830670343882522],
+ [1554795734247, 8.892737303950666],
+ [1554795754247, 8.617048476643877],
+ [1554795774247, 8.956785057895],
+ [1554795794247, 8.9991406285351],
+ [1554795814247, 9.356203855221441],
+ [1554795834247, 8.99285081187721],
+ [1554795854247, 8.808922317600796],
+ [1554795874247, 9.159210350271348],
+ [1554795894247, 9.18335663931962],
+ [1554795914247, 9.373201449339069],
+ [1554795934247, 8.968119468638838],
+ [1554795954247, 8.576562756144522],
+ [1554795974247, 8.2637127277604],
+ [1554795994247, 8.721724203921328],
+ [1554796014247, 8.48997462768482],
+ [1554796034247, 8.923630475037411],
+ [1554796054247, 8.87332008767114],
+ [1554796074247, 8.600691352718252],
+ [1554796094247, 9.06144030038234],
+ [1554796114247, 8.573016788676542],
+ [1554796134247, 8.681863903053694],
+ [1554796154247, 8.286195763190447],
+ [1554796174247, 8.760651174815626],
+ [1554796194247, 8.782606476359007],
+ [1554796214247, 8.9825170729235],
+ [1554796234247, 8.50917994378477],
+ [1554796254247, 8.745078588661844],
+ [1554796274247, 8.486368444624361],
+ [1554796294247, 8.333749227691007],
+ [1554796314247, 7.920482802236725],
+ [1554796334247, 8.118910114704367],
+ [1554796354247, 8.052092789154447],
+ [1554796374247, 8.541526055677005],
+ [1554796394247, 8.532160960797517],
+ [1554796414247, 8.035315149728314],
+ [1554796434247, 8.153626777679058],
+ [1554796454247, 8.33489217274486],
+ [1554796474247, 8.63434786317988],
+ [1554796494247, 9.072612270861644],
+ [1554796514247, 9.15410238978958],
+ [1554796534247, 9.33569542338061],
+ [1554796554247, 9.617098624150145],
+ [1554796574247, 10.022020147992146],
+ [1554796594247, 9.96942587043037],
+ [1554796614247, 9.638489822305603],
+ [1554796634247, 9.148499945010006],
+ [1554796654247, 9.046323760634762],
+ [1554796674247, 8.950899003863489],
+ [1554796694247, 9.011582132180608],
+ [1554796714247, 8.821456019019363],
+ [1554796734247, 9.317497357412448],
+ [1554796754247, 8.933797285164973],
+ [1554796774247, 8.696553723087488],
+ [1554796794247, 8.486435423924668],
+ [1554796814247, 8.143914447574895],
+ [1554796834247, 7.663636585550101],
+ [1554796854247, 7.512977158724448],
+ [1554796874247, 7.3230605728686795],
+ [1554796894247, 6.9231107879457525],
+ [1554796914247, 6.982154895754249],
+ [1554796934247, 6.736558799914573],
+ [1554796954247, 6.62557430103121],
+ [1554796974247, 6.5962473119591],
+ [1554796994247, 7.009103777604233],
+ [1554797014247, 7.181557924155956],
+ [1554797034247, 7.354116677397331],
+ [1554797054247, 7.12587782475754],
+ [1554797074247, 6.866345342957572],
+ [1554797094247, 7.17115251468767],
+ [1554797114247, 6.722184764408618],
+ [1554797134247, 6.696153361069251],
+ [1554797154247, 6.9207740284137085],
+ [1554797174247, 6.6119572131599895],
+ [1554797194247, 6.815945935756884],
+ [1554797214247, 6.95466363827982],
+ [1554797234247, 6.7285014667012355],
+ [1554797254247, 6.891818567042779],
+ [1554797274247, 6.89849891212912],
+ [1554797294247, 6.460695100547899],
+ [1554797314247, 6.0069925335796475],
+ [1554797334247, 6.2603322238560875],
+ [1554797354247, 5.977611497076692],
+ [1554797374247, 5.942359898081184],
+ [1554797394247, 5.562777480448413],
+ [1554797414247, 5.841398822617335],
+ [1554797434247, 5.818365744964448],
+ [1554797454247, 5.571787499171553],
+ [1554797474247, 5.579907439786188],
+ [1554797494247, 5.398124887811567],
+ [1554797514247, 5.89247467855865],
+ [1554797534247, 6.109491399069382],
+ [1554797554247, 5.695647549392316],
+ [1554797574247, 5.869284172406741],
+ [1554797594247, 5.690239022459525],
+ [1554797614247, 5.450820783424683],
+ [1554797634247, 5.524583351054576],
+ [1554797654247, 5.36614969566086],
+ [1554797674247, 5.204730683218754],
+ [1554797694247, 5.427484119934154],
+ [1554797714247, 5.565761968712947],
+ [1554797734247, 5.932909999509335],
+ [1554797754247, 5.610458298441828],
+ [1554797774247, 5.324880465000206],
+ [1554797794247, 5.419125551757933],
+ [1554797814247, 5.02300209165337],
+ [1554797834247, 5.352305000126072],
+ [1554797854247, 5.36748698339688],
+ [1554797874247, 5.258792248781452],
+ [1554797894247, 5.125077286167015],
+ [1554797914247, 5.492028016529195],
+ [1554797934247, 5.568653332100721],
+ [1554797954247, 5.825704870348322],
+ [1554797974247, 6.27267451715126],
+ [1554797994247, 6.001452331648551],
+ [1554798014247, 5.8585768410841235],
+ [1554798034247, 5.819201114148435],
+ [1554798054247, 5.618753511565376],
+ [1554798074247, 5.24963457018995],
+ [1554798094247, 5.50387501275164],
+ [1554798114247, 5.84091043365146],
+ [1554798134247, 5.821629272116871],
+ [1554798154247, 6.210352707759286],
+ [1554798174247, 5.952483297516694],
+ [1554798194247, 6.031666355548255],
+ [1554798214247, 5.790748754808771],
+ [1554798234247, 5.594603662397832],
+ [1554798254247, 5.811695120800497],
+ [1554798274247, 5.837715057496696],
+ [1554798294247, 6.249345269583456],
+ [1554798314247, 5.934712699943487],
+ [1554798334247, 6.376771693988007],
+ [1554798354247, 6.1569566425758575],
+ [1554798374247, 5.711519906753933],
+ [1554798394247, 5.869137479992213],
+ [1554798414247, 5.560979081989093],
+ [1554798434247, 5.882435554334975],
+ [1554798454247, 5.388570139180064],
+ [1554798474247, 5.659073675509275],
+ [1554798494247, 5.5982211991238415],
+ [1554798514247, 5.6870744245787845],
+ [1554798534247, 5.600717003335124],
+ [1554798554247, 5.340048174168355],
+ [1554798574247, 5.095171088107014],
+ [1554798594247, 5.405805007535655],
+ [1554798614247, 5.271225976449607],
+ [1554798634247, 4.982494391562869],
+ [1554798654247, 5.2276371554858265],
+ [1554798674247, 5.442769621857752],
+ [1554798694247, 5.044185095640327],
+ [1554798714247, 4.79576810257608],
+ [1554798734247, 4.453831871416357],
+ [1554798754247, 4.618243387467281],
+ [1554798774247, 4.57918370988977],
+ [1554798794247, 4.4832728526544745],
+ [1554798814247, 4.024337135722461],
+ [1554798834247, 3.851845907034049],
+ [1554798854247, 3.542163220970746],
+ [1554798874247, 3.9690958016116413],
+ [1554798894247, 4.158181186559055],
+ [1554798914247, 4.079568209963879],
+ [1554798934247, 3.634349523153986],
+ [1554798954247, 3.3598575963443826],
+ [1554798974247, 3.16802878490503],
+ [1554798994247, 3.0133968929917563],
+ [1554799014247, 3.3437902298453492],
+ [1554799034247, 3.675049740942942],
+ [1554799054247, 3.467177915984232],
+ [1554799074247, 3.3518871913608907],
+ [1554799094247, 3.1957041604556817],
+ [1554799114247, 2.927123761256529],
+ [1554799134247, 3.2523340095072575],
+ [1554799154247, 3.015290599561679],
+ [1554799174247, 2.9890942934718248],
+ [1554799194247, 3.143167106507552],
+ [1554799214247, 3.5681222443713825],
+ [1554799234247, 3.2396432204688566],
+ [1554799254247, 3.24901159853982],
+ [1554799274247, 3.3625936643841348],
+ [1554799294247, 3.3339645808631038],
+ [1554799314247, 3.4205949091651635],
+ [1554799334247, 3.593597781275604],
+ [1554799354247, 3.4861342898248844],
+ [1554799374247, 3.8907746271806865],
+ [1554799394247, 4.111342004275268],
+ [1554799414247, 4.5959477789863366],
+ [1554799434247, 4.262140254359245],
+ [1554799454247, 4.134177960593391],
+ [1554799474247, 3.6575368680515146],
+ [1554799494247, 3.937414100768729],
+ [1554799514247, 4.078725112633452],
+ [1554799534247, 3.6451505190142974],
+ [1554799554247, 3.8471615375736894],
+ [1554799574247, 4.115159681991413],
+ [1554799594247, 3.9742174075208],
+ [1554799614247, 3.685238600479783],
+ [1554799634247, 4.103333280579201],
+ [1554799654247, 4.018245494514007],
+ [1554799674247, 4.446780576803342],
+ [1554799694247, 4.793421236531562],
+ [1554799714247, 4.554098466596562],
+ [1554799734247, 5.0417143849764425],
+ [1554799754247, 4.973734699399603],
+ [1554799774247, 5.193809388225786],
+ [1554799794247, 5.586071096427007],
+ [1554799814247, 5.778047979188536],
+ [1554799834247, 6.192594160585018],
+ [1554799854247, 5.927676977504205],
+ [1554799874247, 5.7050333060389695],
+ [1554799894247, 6.1718889065434634],
+ [1554799914247, 5.966274359120673],
+ [1554799934247, 5.5056942032960166],
+ [1554799954247, 5.160442061460211],
+ [1554799974247, 4.96018368853153],
+ [1554799994247, 4.691238462710444],
+ [1554800014247, 4.532492207601897],
+ [1554800034247, 4.07403732545026],
+ [1554800054247, 4.220770009365944],
+ [1554800074247, 4.0290646354752635],
+ [1554800094247, 3.8737691030982773],
+ [1554800114247, 4.238658311988558],
+ [1554800134247, 4.221236984114166],
+ [1554800154247, 4.6669293808298375],
+ [1554800174247, 4.843390965598206],
+ [1554800194247, 5.060187956069504],
+ [1554800214247, 4.868078717632957],
+ [1554800234247, 4.679175899389998],
+ [1554800254247, 4.777389196992289],
+ [1554800274247, 5.145363815002936],
+ [1554800294247, 4.781852858563081],
+ [1554800314247, 4.971885981820668],
+ [1554800334247, 4.646445194315369],
+ [1554800354247, 5.020517271418575],
+ [1554800374247, 4.7023153801084225],
+ [1554800394247, 4.876203872672264],
+ [1554800414247, 4.925017187669332],
+ [1554800434247, 4.663330164585453],
+ [1554800454247, 4.737769778515407],
+ [1554800474247, 4.3073255475285555],
+ [1554800494247, 3.903303008949847],
+ [1554800514247, 4.329087565576297],
+ [1554800534247, 3.977267569905087],
+ [1554800554247, 3.8740696509486328],
+ [1554800574247, 3.6792996433238767],
+ [1554800594247, 3.972924170147491],
+ [1554800614247, 3.7307104568781844],
+ [1554800634247, 3.867618350171384],
+ [1554800654247, 4.221917146372988],
+ [1554800674247, 4.3589781205929],
+ [1554800694247, 4.263474974513956],
+ [1554800714247, 3.836080641849756],
+ [1554800734247, 3.443769259025261],
+ [1554800754247, 3.3972787053685054],
+ [1554800774247, 3.7643724876162024],
+ [1554800794247, 4.170506414878274],
+ [1554800814247, 4.441115469873164],
+ [1554800834247, 4.371381466672394],
+ [1554800854247, 4.2168701882977295],
+ [1554800874247, 4.235647487408082],
+ [1554800894247, 3.9459791663426493],
+ [1554800914247, 4.017151772199118],
+ [1554800934247, 4.367278988021905],
+ [1554800954247, 4.342883446992778],
+ [1554800974247, 4.329662881338973],
+ [1554800994247, 4.283512014326498],
+ [1554801014247, 4.5715550079307645],
+ [1554801034247, 4.8311393525220945],
+ [1554801054247, 4.485030491381298],
+ [1554801074247, 4.34901947903894],
+ [1554801094247, 4.754091657245004],
+ [1554801114247, 4.8317691761516635],
+ [1554801134247, 5.204902590034885],
+ [1554801154247, 5.132781976138682],
+ [1554801174247, 5.034906361767744],
+ [1554801194247, 4.767543856573749],
+ [1554801214247, 5.094041902089003],
+ [1554801234247, 4.929546085290836],
+ [1554801254247, 4.697829514794909],
+ [1554801274247, 5.025374415167784],
+ [1554801294247, 5.096887871269491],
+ [1554801314247, 5.364791455663852],
+ [1554801334247, 5.561817762992182],
+ [1554801354247, 5.469314840240021],
+ [1554801374247, 5.95262630215483],
+ [1554801394247, 6.213311956412662],
+ [1554801414247, 5.715304095448328],
+ [1554801434247, 6.08523588145186],
+ [1554801454247, 5.857696643773423],
+ [1554801474247, 6.268212934058957],
+ [1554801494247, 6.5603945673698],
+ [1554801514247, 6.125495029826776],
+ [1554801534247, 6.110878886315267],
+ [1554801554247, 5.775584198941563],
+ [1554801574247, 6.001104024362178],
+ [1554801594247, 6.0476835587793705],
+ [1554801614247, 5.955664108319069],
+ [1554801634247, 5.955184743612128],
+ [1554801654247, 5.9330618446677414],
+ [1554801674247, 5.8424118755201855],
+ [1554801694247, 5.62553004227859],
+ [1554801714247, 6.0869222772786395],
+ [1554801734247, 5.803355849422298],
+ [1554801754247, 5.387776194851587],
+ [1554801774247, 5.40981853663267],
+ [1554801794247, 5.351276314268535],
+ [1554801814247, 5.788250432657768],
+ [1554801834247, 6.103420102386489],
+ [1554801854247, 6.211025937006611],
+ [1554801874247, 5.8449537650030825],
+ [1554801894247, 5.365170741934555],
+ [1554801914247, 4.887574074342324],
+ [1554801934247, 4.897693584588608],
+ [1554801954247, 5.318243270154184],
+ [1554801974247, 4.9396552679865025],
+ [1554801994247, 5.32527754563186],
+ [1554802014247, 4.886074615684099],
+ [1554802034247, 4.847379978693837],
+ [1554802054247, 4.504956591530262],
+ [1554802074247, 4.307454044981433],
+ [1554802094247, 3.867514732543229],
+ [1554802114247, 4.090981756269712],
+ [1554802134247, 4.578287695242435],
+ [1554802154247, 4.639711326460183],
+ [1554802174247, 4.245817171069919],
+ [1554802194247, 4.633160402543173],
+ [1554802214247, 5.112224969641575],
+ [1554802234247, 5.0089061103738945],
+ [1554802254247, 4.822364064588437],
+ [1554802274247, 5.212440187109399],
+ [1554802294247, 4.929867512296385],
+ [1554802314247, 5.245183785839094],
+ [1554802334247, 5.008463578035349],
+ [1554802354247, 5.1378596145435935],
+ [1554802374247, 5.033798588757337],
+ [1554802394247, 5.476424927294858],
+ [1554802414247, 5.972598629566117],
+ [1554802434247, 6.370358278045766],
+ [1554802454247, 5.893722712045765],
+ [1554802474247, 5.993207071076519],
+ [1554802494247, 5.930735938671154],
+ [1554802514247, 5.448559121598676],
+ [1554802534247, 5.207154019732361],
+ [1554802554247, 4.853297326279563],
+ [1554802574247, 5.04987559253604],
+ [1554802594247, 4.847597124701677],
+ [1554802614247, 5.146928442837356],
+ [1554802634247, 4.699178752084193],
+ [1554802654247, 4.6411064164223825],
+ [1554802674247, 4.665072535289884],
+ [1554802694247, 4.529885143860296],
+ [1554802714247, 4.996514308630512],
+ [1554802734247, 5.22226329518542],
+ [1554802754247, 5.575602394914211],
+ [1554802774247, 5.422257363444805],
+ [1554802794247, 5.855827664152273],
+ [1554802814247, 5.58414729075323],
+ [1554802834247, 5.103587756899033],
+ [1554802854247, 4.686442663523442],
+ [1554802874247, 4.351199700286399],
+ [1554802894247, 4.446556476531035],
+ [1554802914247, 4.877022325792788],
+ [1554802934247, 5.06408000687434],
+ [1554802954247, 4.891564589262834],
+ [1554802974247, 5.286434271773061],
+ [1554802994247, 5.524908643196997],
+ [1554803014247, 5.924389675102854],
+ [1554803034247, 5.547245691246638],
+ [1554803054247, 5.202222179374266],
+ [1554803074247, 5.168745154790057],
+ [1554803094247, 4.675315213121577],
+ [1554803114247, 4.470816264658528],
+ [1554803134247, 4.738579106980465],
+ [1554803154247, 4.369706105812872],
+ [1554803174247, 4.62735842629406],
+ [1554803194247, 4.153751390299434],
+ [1554803214247, 4.136048104401695],
+ [1554803234247, 3.7990691391221483],
+ [1554803254247, 3.8795830766275676],
+ [1554803274247, 3.772500704071465],
+ [1554803294247, 3.9319620260590384],
+ [1554803314247, 3.559929630866206],
+ [1554803334247, 3.6113629367099938],
+ [1554803354247, 3.7376027498577726],
+ [1554803374247, 3.5578753439899113],
+ [1554803394247, 4.018133755965429],
+ [1554803414247, 4.288623643831334],
+ [1554803434247, 4.318645979671817],
+ [1554803454247, 4.749471110335788],
+ [1554803474247, 4.372628054764743],
+ [1554803494247, 4.622094039373034],
+ [1554803514247, 4.244606535531101],
+ [1554803534247, 3.816516521086009],
+ [1554803554247, 4.017892070701937],
+ [1554803574247, 3.89079416050709],
+ [1554803594247, 4.261198695219943],
+ [1554803614247, 4.428362341587736],
+ [1554803634247, 4.880986638912973],
+ [1554803654247, 5.0299660882410775],
+ [1554803674247, 5.411982269567302],
+ [1554803694247, 5.194408289760711],
+ [1554803714247, 5.012769948412448],
+ [1554803734247, 5.0072233733100004],
+ [1554803754247, 5.401394397533787],
+ [1554803774247, 5.326562162713341],
+ [1554803794247, 5.623163927554523],
+ [1554803814247, 5.5559453288335785],
+ [1554803834247, 5.577487170979451],
+ [1554803854247, 6.045429148567111],
+ [1554803874247, 5.7407369273358855],
+ [1554803894247, 5.9662724514162395],
+ [1554803914247, 5.626123193057087],
+ [1554803934247, 5.827530375461689],
+ [1554803954247, 6.219201754092099],
+ [1554803974247, 6.300657792657276],
+ [1554803994247, 6.542166827712119],
+ [1554804014247, 6.303296215678175],
+ [1554804034247, 6.252832131614809],
+ [1554804054247, 6.001141932163406],
+ [1554804074247, 6.452357078229282],
+ [1554804094247, 6.5222239382705745],
+ [1554804114247, 6.320907147559073],
+ [1554804134247, 6.811884397530322],
+ [1554804154247, 7.032984930368987],
+ [1554804174247, 6.715498474732585],
+ [1554804194247, 6.672161634739476],
+ [1554804214247, 6.994547337932146],
+ [1554804234247, 6.858854183936963],
+ [1554804254247, 6.633667847711406],
+ [1554804274247, 6.52885680764893],
+ [1554804294247, 6.2708537451521265],
+ [1554804314247, 6.325984685221548],
+ [1554804334247, 6.265281332886626],
+ [1554804354247, 5.790005511484586],
+ [1554804374247, 5.909314128865535],
+ [1554804394247, 6.019228158579621],
+ [1554804414247, 5.767753759200176],
+ [1554804434247, 5.877389216946951],
+ [1554804454247, 6.344658548950036],
+ [1554804474247, 6.2725006803076315],
+ [1554804494247, 6.159015121408378],
+ [1554804514247, 6.177644730506093],
+ [1554804534247, 6.574127902942029],
+ [1554804554247, 6.279446561068236],
+ [1554804574247, 6.532293875875611],
+ [1554804594247, 6.546265619012084],
+ [1554804614247, 6.669672237291822],
+ [1554804634247, 6.458459577608597],
+ [1554804654247, 6.3181910426234555],
+ [1554804674247, 6.330484950381867],
+ [1554804694247, 6.704701222610657],
+ [1554804714247, 6.296604674112797],
+ [1554804734247, 6.045934293115862],
+ [1554804754247, 5.626761485544506],
+ [1554804774247, 5.984868539333273],
+ [1554804794247, 5.782143366601749],
+ [1554804814247, 5.881833269531409],
+ [1554804834247, 6.341620115867811],
+ [1554804854247, 6.190837619933998],
+ [1554804874247, 5.7755446957461265],
+ [1554804894247, 5.927590146263014],
+ [1554804914247, 6.229025865781088],
+ [1554804934247, 5.9289926927844325],
+ [1554804954247, 6.283677647437369],
+ [1554804974247, 5.887290894902884],
+ [1554804994247, 5.60516096881941],
+ [1554805014247, 5.124922711378898],
+ [1554805034247, 5.022411278302609],
+ [1554805054247, 5.441282885351261],
+ [1554805074247, 5.211041708475881],
+ [1554805094247, 5.315539280767537],
+ [1554805114247, 4.860316378001272],
+ [1554805134247, 4.597541762813888],
+ [1554805154247, 4.701388340442914],
+ [1554805174247, 4.8857311808651795],
+ [1554805194247, 4.911170700334517],
+ [1554805214247, 4.7607973589457275],
+ [1554805234247, 5.2374533806100105],
+ [1554805254247, 5.635862787165801],
+ [1554805274247, 5.190782427510569],
+ [1554805294247, 5.040752906711101],
+ [1554805314247, 5.431677208644257],
+ [1554805334247, 5.276048739941259],
+ [1554805354247, 5.175810345425181],
+ [1554805374247, 5.448545682460811],
+ [1554805394247, 5.168286373993526],
+ [1554805414247, 4.915522433549292],
+ [1554805434247, 5.2403189761702755],
+ [1554805454247, 5.549674728141264],
+ [1554805474247, 5.346700869868238],
+ [1554805494247, 5.188114699782227],
+ [1554805514247, 5.054805968686958],
+ [1554805534247, 4.921991599219343],
+ [1554805554247, 5.252967706754598],
+ [1554805574247, 5.528822819853359],
+ [1554805594247, 5.163180135702445],
+ [1554805614247, 5.459094564903271],
+ [1554805634247, 5.205802999429608],
+ [1554805654247, 5.654372323923422],
+ [1554805674247, 6.005308016326213],
+ [1554805694247, 6.225307598518053],
+ [1554805714247, 6.265609851224129],
+ [1554805734247, 6.464569754513396],
+ [1554805754247, 6.213421273189288],
+ [1554805774247, 6.109005465627603],
+ [1554805794247, 6.388571590681015],
+ [1554805814247, 5.940826816262089],
+ [1554805834247, 6.152567556318539],
+ [1554805854247, 5.6778725758159245],
+ [1554805874247, 5.5459357762000145],
+ [1554805894247, 5.245881317787439],
+ [1554805914247, 5.16962721413826],
+ [1554805934247, 5.07586323530142],
+ [1554805954247, 5.079999397697077],
+ [1554805974247, 5.110929127356195],
+ [1554805994247, 5.4651260693748345],
+ [1554806014247, 5.333693563931255],
+ [1554806034247, 5.107568465043172],
+ [1554806054247, 5.549034075311475],
+ [1554806074247, 5.680774155981773],
+ [1554806094247, 5.449462358103411],
+ [1554806114247, 5.296928229571512],
+ [1554806134247, 4.801889842979068],
+ [1554806154247, 5.266423958416515],
+ [1554806174247, 5.394775355310104],
+ [1554806194247, 4.986628678003934],
+ [1554806214247, 4.927257141199989],
+ [1554806234247, 4.736707861872728],
+ [1554806254247, 5.217522955513845],
+ [1554806274247, 5.159523886652105],
+ [1554806294247, 5.1343440103709375],
+ [1554806314247, 5.4355027352491065],
+ [1554806334247, 4.989476007458429],
+ [1554806354247, 4.962491244463504],
+ [1554806374247, 5.234929203969406],
+ [1554806394247, 5.354611454712647],
+ [1554806414247, 5.819971337557214],
+ [1554806434247, 5.4537351462427655],
+ [1554806454247, 5.675427728347797],
+ [1554806474247, 5.717239078112083],
+ [1554806494247, 5.9665112054249505],
+ [1554806514247, 6.330042031470756],
+ [1554806534247, 6.554062137484854],
+ [1554806554247, 6.98908148194185],
+ [1554806574247, 6.550888018972389],
+ [1554806594247, 6.76067898332396],
+ [1554806614247, 6.766932559585224],
+ [1554806634247, 6.884507789101927],
+ [1554806654247, 6.982112269213111],
+ [1554806674247, 6.612531075414423],
+ [1554806694247, 6.831170284034089],
+ [1554806714247, 6.564458211861151],
+ [1554806734247, 6.5928702335259555],
+ [1554806754247, 6.307307819202318],
+ [1554806774247, 6.14296202627164],
+ [1554806794247, 5.850517533316699],
+ [1554806814247, 6.013477089375544],
+ [1554806834247, 5.788350959514567],
+ [1554806854247, 6.213462521998331],
+ [1554806874247, 6.135358062071788],
+ [1554806894247, 6.5090674301724265],
+ [1554806914247, 6.366207234773551],
+ [1554806934247, 6.717787701154512],
+ [1554806954247, 6.938004745742623],
+ [1554806974247, 6.608685270420923],
+ [1554806994247, 6.616342669591905],
+ [1554807014247, 7.111245244027054],
+ [1554807034247, 6.8382135174842515],
+ [1554807054247, 7.233472706615843],
+ [1554807074247, 7.086607581699311],
+ [1554807094247, 7.469047250077706],
+ [1554807114247, 7.230352648399958],
+ [1554807134247, 7.227645424764407],
+ [1554807154247, 7.4153920798629915],
+ [1554807174247, 7.026938941179673],
+ [1554807194247, 6.834372496767788],
+ [1554807214247, 6.632614720484994],
+ [1554807234247, 6.9176209603808205],
+ [1554807254247, 7.093991324735687],
+ [1554807274247, 7.49838324274419],
+ [1554807294247, 7.248815237417004],
+ [1554807314247, 7.59741703470027],
+ [1554807334247, 7.767235801748564],
+ [1554807354247, 7.798699694025993],
+ [1554807374247, 8.022398085783173],
+ [1554807394247, 8.219990876891334],
+ [1554807414247, 8.112971309076434],
+ [1554807434247, 8.391034098841457],
+ [1554807454247, 8.363882609872281],
+ [1554807474247, 7.971781311420273],
+ [1554807494247, 7.523868567624482],
+ [1554807514247, 7.597999604461199],
+ [1554807534247, 7.98131948849502],
+ [1554807554247, 8.211001366222089],
+ [1554807574247, 8.339946777071436],
+ [1554807594247, 8.321908649004829],
+ [1554807614247, 8.283911248846037],
+ [1554807634247, 7.95287844789605],
+ [1554807654247, 7.907639543478707],
+ [1554807674247, 7.8725971247401745],
+ [1554807694247, 7.510817707264657],
+ [1554807714247, 7.453138721251027],
+ [1554807734247, 7.945662384008237],
+ [1554807754247, 7.689782595310916],
+ [1554807774247, 7.222797934226393],
+ [1554807794247, 7.198697752316905],
+ [1554807814247, 7.134050929634677],
+ [1554807834247, 6.8576983886263525],
+ [1554807854247, 6.813355504109371],
+ [1554807874247, 6.871596166448773],
+ [1554807894247, 6.4936669876216335],
+ [1554807914247, 6.856768002872756],
+ [1554807934247, 6.49860793254361],
+ [1554807954247, 6.293200026824586],
+ [1554807974247, 5.947670166407878],
+ [1554807994247, 6.022336570265149],
+ [1554808014247, 6.518767909482903],
+ [1554808034247, 6.239492464787651],
+ [1554808054247, 6.727058806972739],
+ [1554808074247, 7.121308144408187],
+ [1554808094247, 6.782001741160709],
+ [1554808114247, 6.911079377114777],
+ [1554808134247, 6.8930569721432065],
+ [1554808154247, 7.026120004477112],
+ [1554808174247, 7.426405016599918],
+ [1554808194247, 7.101843615788554],
+ [1554808214247, 6.682553980564458],
+ [1554808234247, 6.489957896759141],
+ [1554808254247, 6.935104685760811],
+ [1554808274247, 7.272271426738921],
+ [1554808294247, 6.896043753021477],
+ [1554808314247, 6.453354071271065],
+ [1554808334247, 6.6400664095774005],
+ [1554808354247, 6.43533378238653],
+ [1554808374247, 6.892462502509553],
+ [1554808394247, 6.815418828468179],
+ [1554808414247, 6.884193266819189],
+ [1554808434247, 6.626443732396062],
+ [1554808454247, 6.9516516783657165],
+ [1554808474247, 7.049560022739215],
+ [1554808494247, 7.1055987133330785],
+ [1554808514247, 6.750008467983265],
+ [1554808534247, 7.207166348519568],
+ [1554808554247, 6.7168905957818845],
+ [1554808574247, 7.13070327526958],
+ [1554808594247, 7.079731512657319],
+ [1554808614247, 7.510314201924746],
+ [1554808634247, 7.706230930087699],
+ [1554808654247, 7.81411401302101],
+ [1554808674247, 7.478003760714301],
+ [1554808694247, 7.922427996204289],
+ [1554808714247, 7.907863457551709],
+ [1554808734247, 8.248186807433832],
+ [1554808754247, 8.576712081296638],
+ [1554808774247, 8.214689808808208],
+ [1554808794247, 8.663946930276753],
+ [1554808814247, 8.194761986653258],
+ [1554808834247, 8.575717709102516],
+ [1554808854247, 8.345850007916788],
+ [1554808874247, 8.612381234175777],
+ [1554808894247, 8.758703497768783],
+ [1554808914247, 8.45228506635527],
+ [1554808934247, 8.365323711621404],
+ [1554808954247, 8.772268719879923],
+ [1554808974247, 8.414503354013195],
+ [1554808994247, 8.33575391274245],
+ [1554809014247, 7.847212876502609],
+ [1554809034247, 7.820165181384834],
+ [1554809054247, 7.749613823906183],
+ [1554809074247, 8.171181374434301],
+ [1554809094247, 8.012821172876176],
+ [1554809114247, 7.632473633132171],
+ [1554809134247, 7.927346280103529],
+ [1554809154247, 8.38222644684866],
+ [1554809174247, 8.873146858741773],
+ [1554809194247, 9.139361430999534],
+ [1554809214247, 8.773999973423352],
+ [1554809234247, 8.503974910333003],
+ [1554809254247, 8.851608924895134],
+ [1554809274247, 9.258358922834823],
+ [1554809294247, 9.004521432325152],
+ [1554809314247, 8.663646594659093],
+ [1554809334247, 9.062943096024762],
+ [1554809354247, 8.927196322628053],
+ [1554809374247, 8.860884892690317],
+ [1554809394247, 8.72560917543646],
+ [1554809414247, 8.62396089915321],
+ [1554809434247, 8.767613126137167],
+ [1554809454247, 9.055419594223759],
+ [1554809474247, 8.569888672466254],
+ [1554809494247, 8.736703861623493],
+ [1554809514247, 8.94976206317658],
+ [1554809534247, 8.521394791609685],
+ [1554809554247, 8.3698829938199],
+ [1554809574247, 8.645533125455511],
+ [1554809594247, 8.389932129633864],
+ [1554809614247, 8.119152603087166],
+ [1554809634247, 8.119883595476143],
+ [1554809654247, 8.070896546230118],
+ [1554809674247, 8.11029896993352],
+ [1554809694247, 8.060761966261271],
+ [1554809714247, 8.50921225305014],
+ [1554809734247, 8.725356063040449],
+ [1554809754247, 8.727934761508802],
+ [1554809774247, 8.356828269208117],
+ [1554809794247, 8.637691261479478],
+ [1554809814247, 8.500996427635334],
+ [1554809834247, 8.343058481731683],
+ [1554809854247, 8.091250360224562],
+ [1554809874247, 7.706923991641506],
+ [1554809894247, 7.994107748320774],
+ [1554809914247, 7.675799246882235],
+ [1554809934247, 7.197886464997558],
+ [1554809954247, 7.188277445993742],
+ [1554809974247, 7.036209963564159],
+ [1554809994247, 6.947875119270903],
+ [1554810014247, 7.044499042781682],
+ [1554810034247, 6.663631394974621],
+ [1554810054247, 6.544553868473274],
+ [1554810074247, 6.244585802324538],
+ [1554810094247, 5.790424680888914],
+ [1554810114247, 5.597125792706711],
+ [1554810134247, 5.838197514962413],
+ [1554810154247, 5.569538296626776],
+ [1554810174247, 5.622066021193228],
+ [1554810194247, 5.6709480376132335],
+ [1554810214247, 5.3826562886664515],
+ [1554810234247, 5.495003785016907],
+ [1554810254247, 5.129314033185204],
+ [1554810274247, 4.709722774580275],
+ [1554810294247, 5.058233056559091],
+ [1554810314247, 5.149581150382685],
+ [1554810334247, 5.313471284226376],
+ [1554810354247, 5.724599134003778],
+ [1554810374247, 5.329889761110913],
+ [1554810394247, 5.746948046516922],
+ [1554810414247, 5.627652937866056],
+ [1554810434247, 5.142896397418332],
+ [1554810454247, 5.046133901694889],
+ [1554810474247, 5.507954638298896],
+ [1554810494247, 5.685628153810458],
+ [1554810514247, 6.159063025037185],
+ [1554810534247, 6.586439421400087],
+ [1554810554247, 6.882778595688622],
+ [1554810574247, 7.2490121652682395],
+ [1554810594247, 6.992372134925944],
+ [1554810614247, 6.866722248884183],
+ [1554810634247, 6.490212612921014],
+ [1554810654247, 6.104505357845294],
+ [1554810674247, 6.367774595212844],
+ [1554810694247, 6.083761787710358],
+ [1554810714247, 5.737294108204808],
+ [1554810734247, 6.102847667978216],
+ [1554810754247, 6.318239116092701],
+ [1554810774247, 5.920431833139119],
+ [1554810794247, 5.509946128359078],
+ [1554810814247, 5.124840200214926],
+ [1554810834247, 5.49899101103313],
+ [1554810854247, 5.470314709501598],
+ [1554810874247, 5.375614537897641],
+ [1554810894247, 5.3648225965695495],
+ [1554810914247, 5.135118670963028],
+ [1554810934247, 5.3362339554547065],
+ [1554810954247, 5.218712068436682],
+ [1554810974247, 5.412912108653002],
+ [1554810994247, 5.470415053122083],
+ [1554811014247, 5.728323741298232],
+ [1554811034247, 5.6932642393444075],
+ [1554811054247, 5.749008578598318],
+ [1554811074247, 6.09970432098925],
+ [1554811094247, 6.071920828705983],
+ [1554811114247, 5.828661341760444],
+ [1554811134247, 5.524965142249962],
+ [1554811154247, 5.575358061295394],
+ [1554811174247, 5.446919825099063],
+ [1554811194247, 5.93800790342962],
+ [1554811214247, 6.071568697482172],
+ [1554811234247, 6.310969859015277],
+ [1554811254247, 5.821955584869536],
+ [1554811274247, 6.199421058701339],
+ [1554811294247, 6.674118388812211],
+ [1554811314247, 6.673227102219742],
+ [1554811334247, 6.195363115639559],
+ [1554811354247, 5.820263795090813],
+ [1554811374247, 5.915530667539109],
+ [1554811394247, 6.331135066773232],
+ [1554811414247, 5.948853295013205],
+ [1554811434247, 5.451153941151292],
+ [1554811454247, 5.3919812114719905],
+ [1554811474247, 4.933551578138852],
+ [1554811494247, 5.099962987800049],
+ [1554811514247, 5.4460689354241545],
+ [1554811534247, 5.298376393189034],
+ [1554811554247, 5.051670370021742],
+ [1554811574247, 5.065328716862751],
+ [1554811594247, 4.942328036504453],
+ [1554811614247, 5.430221059400023],
+ [1554811634247, 5.338449689010827],
+ [1554811654247, 5.5716140235693805],
+ [1554811674247, 5.57866789314628],
+ [1554811694247, 5.090129632378411],
+ [1554811714247, 5.3389428704372515],
+ [1554811734247, 5.640001527104899],
+ [1554811754247, 5.8258428437827146],
+ [1554811774247, 6.045096248760302],
+ [1554811794247, 6.013981734904431],
+ [1554811814247, 5.915532054198841],
+ [1554811834247, 6.034610673432962],
+ [1554811854247, 6.414970154241204],
+ [1554811874247, 6.867945955465651],
+ [1554811894247, 6.933730078574364],
+ [1554811914247, 6.875497349505578],
+ [1554811934247, 6.809570407471085],
+ [1554811954247, 6.750819417545482],
+ [1554811974247, 7.028896424987769],
+ [1554811994247, 7.487999347921053],
+ [1554812014247, 7.200375020912814],
+ [1554812034247, 6.729037158447847],
+ [1554812054247, 6.2332135753766265],
+ [1554812074247, 6.2788869958132345],
+ [1554812094247, 6.551210083494132],
+ [1554812114247, 6.948556190676634],
+ [1554812134247, 6.810029771056861],
+ [1554812154247, 6.36992272456798],
+ [1554812174247, 6.144755770243405],
+ [1554812194247, 5.819900475823894],
+ [1554812214247, 5.842632687609575],
+ [1554812234247, 6.0229913623019105],
+ [1554812254247, 5.59543607823725],
+ [1554812274247, 5.240974306421704],
+ [1554812294247, 4.961540573276396],
+ [1554812314247, 5.063113720528529],
+ [1554812334247, 4.701806251073283],
+ [1554812354247, 4.383406380737377],
+ [1554812374247, 4.551643367095542],
+ [1554812394247, 4.501437131078793],
+ [1554812414247, 4.5896287936775515],
+ [1554812434247, 4.396798361915996],
+ [1554812454247, 4.094488884344564],
+ [1554812474247, 3.763950671274415],
+ [1554812494247, 3.3649910218348174],
+ [1554812514247, 2.9420483196562572],
+ [1554812534247, 2.4690716873035665],
+ [1554812554247, 2.40032467067903],
+ [1554812574247, 2.3999430459174027],
+ [1554812594247, 1.9716754362118059],
+ [1554812614247, 2.22897786032354],
+ [1554812634247, 1.936502183061513],
+ [1554812654247, 1.6697202952760788],
+ [1554812674247, 1.6161425233220745],
+ [1554812694247, 1.2979508442614471],
+ [1554812714247, 1.7795512009915573],
+ [1554812734247, 1.9775676458236746],
+ [1554812754247, 1.9857859272271818],
+ [1554812774247, 1.9712956178036478],
+ [1554812794247, 1.9954131810535451],
+ [1554812814247, 1.6639380475508858],
+ [1554812834247, 1.2921332932291232],
+ [1554812854247, 1.5623317516730828],
+ [1554812874247, 1.5630008010336873],
+ [1554812894247, 1.2945730371419555],
+ [1554812914247, 1.1345153304204763],
+ [1554812934247, 0.6485479592305394],
+ [1554812954247, 0.9712442704296393],
+ [1554812974247, 0.47564130406558597],
+ [1554812994247, 0.20444990972474225],
+ [1554813014247, -0.047090913437836],
+ [1554813034247, 0.2921861763460779],
+ [1554813054247, -0.15467934586406012],
+ [1554813074247, -0.3425495302000647],
+ [1554813094247, -0.19797787217917812],
+ [1554813114247, 0.24356265774967373],
+ [1554813134247, 0.6623693719986659],
+ [1554813154247, 1.0886329481274146],
+ [1554813174247, 0.7905383067051148],
+ [1554813194247, 0.43695310832152934],
+ [1554813214247, 0.5450623072818498],
+ [1554813234247, 0.9831498244033907],
+ [1554813254247, 0.5367271614005622],
+ [1554813274247, 0.34521375260155496],
+ [1554813294247, 0.49674059769702794],
+ [1554813314247, 0.8545220988091075],
+ [1554813334247, 1.1454002559545144],
+ [1554813354247, 1.5939691226426291],
+ [1554813374247, 1.2925743210955847],
+ [1554813394247, 1.202697680270512],
+ [1554813414247, 0.8248346749243624],
+ [1554813434247, 1.0508182706093616],
+ [1554813454247, 0.8933882588609936],
+ [1554813474247, 1.0868459054070774],
+ [1554813494247, 1.215067537959666],
+ [1554813514247, 1.6859453420595623],
+ [1554813534247, 1.8408803337528425],
+ [1554813554247, 1.503566069541031],
+ [1554813574247, 1.5025754914986305],
+ [1554813594247, 1.757013848848623],
+ [1554813614247, 1.8005931714680625],
+ [1554813634247, 1.993059816901711],
+ [1554813654247, 1.733598878547323],
+ [1554813674247, 1.7996930998117175],
+ [1554813694247, 1.7718023286326967],
+ [1554813714247, 1.9424689430549809],
+ [1554813734247, 1.8262152184502831],
+ [1554813754247, 1.8579680942725383],
+ [1554813774247, 1.9147990478151855],
+ [1554813794247, 1.5793884871771346],
+ [1554813814247, 1.7840058908387082],
+ [1554813834247, 1.524252777720136],
+ [1554813854247, 1.4086013386788108],
+ [1554813874247, 1.6938093491734791],
+ [1554813894247, 1.5204801601796416],
+ [1554813914247, 1.3677304479303785],
+ [1554813934247, 0.9070965699397421],
+ [1554813954247, 0.9001093789228389],
+ [1554813974247, 1.3596888033017467],
+ [1554813994247, 1.4244525184581716],
+ [1554814014247, 1.0681045937169595],
+ [1554814034247, 1.5021342501361263],
+ [1554814054247, 1.4735658199316348],
+ [1554814074247, 1.4142680194453459],
+ [1554814094247, 1.5307344331738741],
+ [1554814114247, 1.7600295139395037],
+ [1554814134247, 1.309541539278152],
+ [1554814154247, 0.8147628448203794],
+ [1554814174247, 1.2615036691775383],
+ [1554814194247, 1.7594036318960855],
+ [1554814214247, 1.3904263592100619],
+ [1554814234247, 1.088464774283428],
+ [1554814254247, 1.261188919478455],
+ [1554814274247, 0.7793099148276835],
+ [1554814294247, 0.7216892684946898],
+ [1554814314247, 0.5979274119186977],
+ [1554814334247, 0.7518018696509412],
+ [1554814354247, 0.877188700342351],
+ [1554814374247, 0.9674514096611574],
+ [1554814394247, 1.1939480091418346],
+ [1554814414247, 1.4909691399213152],
+ [1554814434247, 1.3506310992415735],
+ [1554814454247, 1.0871979315135374],
+ [1554814474247, 0.8619366874699526],
+ [1554814494247, 0.46428502886042183],
+ [1554814514247, 0.7896726455955152],
+ [1554814534247, 1.1538665346611536],
+ [1554814554247, 0.9916800353742865],
+ [1554814574247, 0.5090921441099303],
+ [1554814594247, 0.8273292250812865],
+ [1554814614247, 0.881693750857172],
+ [1554814634247, 0.8101430303449187],
+ [1554814654247, 1.0941807855302021],
+ [1554814674247, 0.9874142260877046],
+ [1554814694247, 0.8635324695445575],
+ [1554814714247, 0.9077447503631652],
+ [1554814734247, 0.6122162804684913],
+ [1554814754247, 0.15771010809450015],
+ [1554814774247, -0.13091442032472111],
+ [1554814794247, -0.2896902546208621],
+ [1554814814247, 0.09852909084992972],
+ [1554814834247, 0.39703026948260606],
+ [1554814854247, 0.2283837169989657],
+ ],
+ color: '#EAB839',
+ info: [
+ { title: 'min', text: '14.42', numeric: 14.427101844163694 },
+ { title: 'max', text: '18.42', numeric: 18.427101844163694 },
+ ],
+ isVisible: true,
+ yAxis: 1,
+ },
+ {
+ label: 'C-series',
+ data: [
+ [1554793274247, 49.69913267127473],
+ [1554793294247, 49.33359410789192],
+ [1554793314247, 49.78163348684188],
+ [1554793334247, 50.17676830260008],
+ [1554793354247, 50.40926697029897],
+ [1554793374247, 50.063754605356486],
+ [1554793394247, 50.076999844329656],
+ [1554793414247, 49.948006752209906],
+ [1554793434247, 49.62287160565001],
+ [1554793454247, 50.03914976018486],
+ [1554793474247, 50.36736533496234],
+ [1554793494247, 50.21324796822654],
+ [1554793514247, 49.99112476335388],
+ [1554793534247, 49.84106879158749],
+ [1554793554247, 49.412375094520144],
+ [1554793574247, 49.78349539263808],
+ [1554793594247, 50.25259706652223],
+ [1554793614247, 49.888060632553064],
+ [1554793634247, 49.464424676361375],
+ [1554793654247, 49.095492684839165],
+ [1554793674247, 49.06868173776792],
+ [1554793694247, 48.574525936741985],
+ [1554793714247, 48.216592532164306],
+ [1554793734247, 47.98607300294584],
+ [1554793754247, 47.83078553622775],
+ [1554793774247, 47.93338669184849],
+ [1554793794247, 48.31669530028857],
+ [1554793814247, 47.82408913984656],
+ [1554793834247, 47.863721900360474],
+ [1554793854247, 47.51177912971504],
+ [1554793874247, 47.757151295055756],
+ [1554793894247, 47.95834636268655],
+ [1554793914247, 47.61863670851333],
+ [1554793934247, 47.93496547494361],
+ [1554793954247, 48.27168892260189],
+ [1554793974247, 48.44358577552156],
+ [1554793994247, 48.29808350161488],
+ [1554794014247, 48.10007721078963],
+ [1554794034247, 48.2714717233677],
+ [1554794054247, 48.05508995997583],
+ [1554794074247, 47.868813005942215],
+ [1554794094247, 47.876025343915664],
+ [1554794114247, 48.32683862002359],
+ [1554794134247, 48.342512548370195],
+ [1554794154247, 48.38648493951903],
+ [1554794174247, 48.199354522690825],
+ [1554794194247, 48.492498553794455],
+ [1554794214247, 48.380215201095],
+ [1554794234247, 48.115635145152744],
+ [1554794254247, 48.490793461399434],
+ [1554794274247, 48.900207945175495],
+ [1554794294247, 49.22861321463161],
+ [1554794314247, 49.4870357160768],
+ [1554794334247, 49.09749063286741],
+ [1554794354247, 49.092467346240014],
+ [1554794374247, 49.48778572019057],
+ [1554794394247, 49.979432673247885],
+ [1554794414247, 50.071201766907855],
+ [1554794434247, 49.9744124782064],
+ [1554794454247, 49.55016977456924],
+ [1554794474247, 49.06533151723648],
+ [1554794494247, 49.261080300725936],
+ [1554794514247, 49.26585857314833],
+ [1554794534247, 49.2429751536119],
+ [1554794554247, 49.346043390042986],
+ [1554794574247, 48.95990675036499],
+ [1554794594247, 49.12651334454535],
+ [1554794614247, 49.29857292163306],
+ [1554794634247, 49.186770426141514],
+ [1554794654247, 48.79264174796861],
+ [1554794674247, 48.88789309162548],
+ [1554794694247, 49.04173033445755],
+ [1554794714247, 49.403693322860484],
+ [1554794734247, 49.21528708472506],
+ [1554794754247, 49.349890005123356],
+ [1554794774247, 49.82581895338948],
+ [1554794794247, 50.10348602630898],
+ [1554794814247, 50.5396830040285],
+ [1554794834247, 50.152316888567],
+ [1554794854247, 49.849522224408226],
+ [1554794874247, 49.839186901052365],
+ [1554794894247, 49.51423985768722],
+ [1554794914247, 49.47484962979224],
+ [1554794934247, 49.69559173812953],
+ [1554794954247, 50.061967708930766],
+ [1554794974247, 49.72554084142337],
+ [1554794994247, 50.203775891826396],
+ [1554795014247, 50.46185209673081],
+ [1554795034247, 50.47156978415908],
+ [1554795054247, 50.501613750647564],
+ [1554795074247, 50.94633357030688],
+ [1554795094247, 51.210166610968514],
+ [1554795114247, 51.10160382793679],
+ [1554795134247, 51.1997077763274],
+ [1554795154247, 51.487603830051704],
+ [1554795174247, 51.36947130848638],
+ [1554795194247, 51.506665895696045],
+ [1554795214247, 51.47614904037313],
+ [1554795234247, 50.98365689110939],
+ [1554795254247, 50.85070473835243],
+ [1554795274247, 50.43383257691916],
+ [1554795294247, 50.232766901028626],
+ [1554795314247, 50.07161209496396],
+ [1554795334247, 49.837713407554816],
+ [1554795354247, 50.143606201515325],
+ [1554795374247, 50.345131163346394],
+ [1554795394247, 50.18313221599123],
+ [1554795414247, 49.84883601334913],
+ [1554795434247, 49.5272710525089],
+ [1554795454247, 49.215130902407815],
+ [1554795474247, 48.97804448667156],
+ [1554795494247, 49.31482206869563],
+ [1554795514247, 49.53974601218905],
+ [1554795534247, 49.07096949398067],
+ [1554795554247, 48.71727129896322],
+ [1554795574247, 48.93720156267952],
+ [1554795594247, 49.392801702481954],
+ [1554795614247, 49.216552679751196],
+ [1554795634247, 49.23021526312906],
+ [1554795654247, 49.36899096723609],
+ [1554795674247, 49.09191616409923],
+ [1554795694247, 49.15661848532974],
+ [1554795714247, 49.13503380602352],
+ [1554795734247, 49.55044458774344],
+ [1554795754247, 49.46886788033894],
+ [1554795774247, 49.30135034486024],
+ [1554795794247, 49.297518995279404],
+ [1554795814247, 48.925566481922225],
+ [1554795834247, 49.27559370678866],
+ [1554795854247, 49.332340911077424],
+ [1554795874247, 49.26076465409638],
+ [1554795894247, 49.53767640806078],
+ [1554795914247, 49.8030905200301],
+ [1554795934247, 49.32264966726677],
+ [1554795954247, 49.544792317070254],
+ [1554795974247, 49.21562164942147],
+ [1554795994247, 49.07254074465956],
+ [1554796014247, 49.18878762024898],
+ [1554796034247, 49.2306235947342],
+ [1554796054247, 49.62054143705226],
+ [1554796074247, 49.63187621927985],
+ [1554796094247, 49.98017604831396],
+ [1554796114247, 49.7600715923475],
+ [1554796134247, 49.27655228840302],
+ [1554796154247, 49.62483387018148],
+ [1554796174247, 49.21209572522005],
+ [1554796194247, 48.744631547286936],
+ [1554796214247, 48.63286811583694],
+ [1554796234247, 49.12296413252627],
+ [1554796254247, 48.910115698414295],
+ [1554796274247, 48.96613678532863],
+ [1554796294247, 49.05941150019551],
+ [1554796314247, 49.508439412178774],
+ [1554796334247, 49.16173498832025],
+ [1554796354247, 49.45053302619814],
+ [1554796374247, 49.00286141334283],
+ [1554796394247, 49.30217759710238],
+ [1554796414247, 49.501741513928174],
+ [1554796434247, 49.4972198005734],
+ [1554796454247, 49.16075824584829],
+ [1554796474247, 49.37241873098192],
+ [1554796494247, 49.63656657285561],
+ [1554796514247, 49.43718574292024],
+ [1554796534247, 49.48756155841603],
+ [1554796554247, 49.24303681625806],
+ [1554796574247, 49.382518871358485],
+ [1554796594247, 49.02247723343229],
+ [1554796614247, 49.27667512613039],
+ [1554796634247, 49.64825856084839],
+ [1554796654247, 49.321745040753285],
+ [1554796674247, 48.91447440186897],
+ [1554796694247, 48.81302425720652],
+ [1554796714247, 48.905546629260954],
+ [1554796734247, 49.07774732856527],
+ [1554796754247, 49.227140342516535],
+ [1554796774247, 49.72198806496772],
+ [1554796794247, 49.48668530730508],
+ [1554796814247, 49.46590246465986],
+ [1554796834247, 48.99586979519719],
+ [1554796854247, 48.798302244243935],
+ [1554796874247, 48.61059457103293],
+ [1554796894247, 48.93616700832869],
+ [1554796914247, 49.36797907473593],
+ [1554796934247, 49.47791061560138],
+ [1554796954247, 49.05321495421578],
+ [1554796974247, 49.193714250569805],
+ [1554796994247, 49.16178917646284],
+ [1554797014247, 49.61296666235341],
+ [1554797034247, 49.12291229001563],
+ [1554797054247, 48.95504159499004],
+ [1554797074247, 49.32814845656858],
+ [1554797094247, 48.943532330596284],
+ [1554797114247, 48.46180988614885],
+ [1554797134247, 48.11959030750559],
+ [1554797154247, 48.09494703813437],
+ [1554797174247, 47.983429675390965],
+ [1554797194247, 47.56241734828039],
+ [1554797214247, 47.979661755353014],
+ [1554797234247, 48.123073042355],
+ [1554797254247, 48.27362205867366],
+ [1554797274247, 48.71404324003502],
+ [1554797294247, 48.89226743535597],
+ [1554797314247, 49.29328058894711],
+ [1554797334247, 49.084461777558545],
+ [1554797354247, 48.83021345179746],
+ [1554797374247, 48.91026000597451],
+ [1554797394247, 48.99484128183615],
+ [1554797414247, 48.86756007189439],
+ [1554797434247, 48.479138233845504],
+ [1554797454247, 48.374298022845906],
+ [1554797474247, 48.286981712867664],
+ [1554797494247, 48.198201299191574],
+ [1554797514247, 47.77195291962695],
+ [1554797534247, 47.738964722883075],
+ [1554797554247, 48.13659961076256],
+ [1554797574247, 47.915605075289456],
+ [1554797594247, 48.30049282619518],
+ [1554797614247, 48.23976344811622],
+ [1554797634247, 48.165658285800426],
+ [1554797654247, 47.86756846582645],
+ [1554797674247, 48.29556200780647],
+ [1554797694247, 48.29145743008182],
+ [1554797714247, 47.8840989961646],
+ [1554797734247, 48.00901203088797],
+ [1554797754247, 47.641268558534534],
+ [1554797774247, 47.85700504489876],
+ [1554797794247, 47.754409771890366],
+ [1554797814247, 47.46442119094209],
+ [1554797834247, 47.37778670338178],
+ [1554797854247, 47.69125754568886],
+ [1554797874247, 47.65675109438546],
+ [1554797894247, 47.35188105593815],
+ [1554797914247, 46.99017604656002],
+ [1554797934247, 46.49962289247365],
+ [1554797954247, 46.50698076300431],
+ [1554797974247, 46.529341299373776],
+ [1554797994247, 46.14246130646399],
+ [1554798014247, 46.64128938702536],
+ [1554798034247, 46.71332038658063],
+ [1554798054247, 46.22766299792843],
+ [1554798074247, 46.655383290728864],
+ [1554798094247, 46.45705284677324],
+ [1554798114247, 46.45713571405586],
+ [1554798134247, 46.86151766756407],
+ [1554798154247, 46.90672301003809],
+ [1554798174247, 46.51535856335299],
+ [1554798194247, 46.10570297530587],
+ [1554798214247, 46.33418626714916],
+ [1554798234247, 46.003003880616205],
+ [1554798254247, 46.2925486741529],
+ [1554798274247, 46.39633084477583],
+ [1554798294247, 46.16591301596327],
+ [1554798314247, 46.416551590010194],
+ [1554798334247, 46.45425310871843],
+ [1554798354247, 46.0032881844452],
+ [1554798374247, 45.82313918899386],
+ [1554798394247, 46.219193352046396],
+ [1554798414247, 45.8586762819549],
+ [1554798434247, 46.040014378177375],
+ [1554798454247, 46.236218833624115],
+ [1554798474247, 46.45926020739284],
+ [1554798494247, 46.897768102161415],
+ [1554798514247, 47.36566794657619],
+ [1554798534247, 47.2382175292508],
+ [1554798554247, 47.50315436537415],
+ [1554798574247, 47.195192237664564],
+ [1554798594247, 47.63493540272602],
+ [1554798614247, 47.507004471059325],
+ [1554798634247, 47.97730627271725],
+ [1554798654247, 47.84750321321647],
+ [1554798674247, 47.779067424183054],
+ [1554798694247, 47.51070588382222],
+ [1554798714247, 47.31024519328251],
+ [1554798734247, 47.38794688477116],
+ [1554798754247, 47.32981223758303],
+ [1554798774247, 47.72299840553466],
+ [1554798794247, 47.95529996227096],
+ [1554798814247, 48.31157095625241],
+ [1554798834247, 48.023368909559515],
+ [1554798854247, 47.72332648683902],
+ [1554798874247, 47.8896007675284],
+ [1554798894247, 47.52159434109153],
+ [1554798914247, 47.36082882158501],
+ [1554798934247, 47.25781883471349],
+ [1554798954247, 47.345951933554566],
+ [1554798974247, 46.94903667465156],
+ [1554798994247, 47.39688904725867],
+ [1554799014247, 47.52423404078518],
+ [1554799034247, 47.0397640935533],
+ [1554799054247, 47.46602364797375],
+ [1554799074247, 47.111211461266905],
+ [1554799094247, 47.601388184562914],
+ [1554799114247, 47.68148443042845],
+ [1554799134247, 47.58525617262463],
+ [1554799154247, 47.78701709976165],
+ [1554799174247, 48.036966778117275],
+ [1554799194247, 47.970336996592096],
+ [1554799214247, 47.759473765364],
+ [1554799234247, 47.34751038233216],
+ [1554799254247, 47.57114234065436],
+ [1554799274247, 47.907061454075155],
+ [1554799294247, 48.084671942100634],
+ [1554799314247, 47.681986292923746],
+ [1554799334247, 47.95817351464097],
+ [1554799354247, 48.04032430472102],
+ [1554799374247, 47.97074694936207],
+ [1554799394247, 48.053606942051346],
+ [1554799414247, 48.03665265330263],
+ [1554799434247, 48.40213107480879],
+ [1554799454247, 48.66966744616825],
+ [1554799474247, 48.37860616360151],
+ [1554799494247, 48.69223531031285],
+ [1554799514247, 48.897104105650236],
+ [1554799534247, 48.72228611537678],
+ [1554799554247, 49.20245075823246],
+ [1554799574247, 49.08271267686173],
+ [1554799594247, 49.01995415573646],
+ [1554799614247, 49.405566345327166],
+ [1554799634247, 49.338088388754954],
+ [1554799654247, 49.42610506682994],
+ [1554799674247, 49.26870188087562],
+ [1554799694247, 48.99504223682648],
+ [1554799714247, 49.13641512533093],
+ [1554799734247, 48.68046815153081],
+ [1554799754247, 48.23884835789657],
+ [1554799774247, 48.34490487390389],
+ [1554799794247, 47.8621097886342],
+ [1554799814247, 48.10324901149713],
+ [1554799834247, 47.65769254778163],
+ [1554799854247, 48.04863600220461],
+ [1554799874247, 48.504658322467876],
+ [1554799894247, 48.84155760382869],
+ [1554799914247, 48.78203918293767],
+ [1554799934247, 48.69555264932167],
+ [1554799954247, 48.534953659795086],
+ [1554799974247, 48.32753840030407],
+ [1554799994247, 48.319124059010136],
+ [1554800014247, 48.08900748459846],
+ [1554800034247, 48.41592904647356],
+ [1554800054247, 48.654168369087024],
+ [1554800074247, 48.174716148384945],
+ [1554800094247, 47.838563784529015],
+ [1554800114247, 47.688834110534465],
+ [1554800134247, 48.01330592764464],
+ [1554800154247, 47.66787416286568],
+ [1554800174247, 47.480850102022586],
+ [1554800194247, 47.831846287590565],
+ [1554800214247, 47.41691220431661],
+ [1554800234247, 47.8412914393716],
+ [1554800254247, 47.83510232228141],
+ [1554800274247, 47.773877998469274],
+ [1554800294247, 47.515405390707095],
+ [1554800314247, 47.993473718819686],
+ [1554800334247, 48.34644356161968],
+ [1554800354247, 48.36355857235089],
+ [1554800374247, 48.57236022294879],
+ [1554800394247, 48.90877596270302],
+ [1554800414247, 49.062335690183524],
+ [1554800434247, 48.90760032123759],
+ [1554800454247, 48.40792258975594],
+ [1554800474247, 48.15638977565654],
+ [1554800494247, 48.514039980655234],
+ [1554800514247, 48.95574910285047],
+ [1554800534247, 48.99709284602056],
+ [1554800554247, 49.38005823887513],
+ [1554800574247, 49.65241792934206],
+ [1554800594247, 49.95055381158393],
+ [1554800614247, 50.28428874387261],
+ [1554800634247, 50.47285733412508],
+ [1554800654247, 50.35112364359045],
+ [1554800674247, 50.5519475699319],
+ [1554800694247, 50.61198314523461],
+ [1554800714247, 51.027913008897656],
+ [1554800734247, 50.822749098517605],
+ [1554800754247, 51.234030918977524],
+ [1554800774247, 51.207186361081156],
+ [1554800794247, 51.05369641506709],
+ [1554800814247, 51.20809949100641],
+ [1554800834247, 51.00097254666107],
+ [1554800854247, 50.502863733149596],
+ [1554800874247, 50.079695380284896],
+ [1554800894247, 49.86342104655181],
+ [1554800914247, 49.46833918185673],
+ [1554800934247, 49.6119576574696],
+ [1554800954247, 49.963978699045946],
+ [1554800974247, 49.59214014681593],
+ [1554800994247, 50.08518436521155],
+ [1554801014247, 50.40915968570567],
+ [1554801034247, 50.602524820648696],
+ [1554801054247, 50.985501356814034],
+ [1554801074247, 50.60559150837181],
+ [1554801094247, 50.485487661329294],
+ [1554801114247, 50.867623335094024],
+ [1554801134247, 50.96489864591541],
+ [1554801154247, 51.15309133118275],
+ [1554801174247, 51.24579939680081],
+ [1554801194247, 51.424479415888285],
+ [1554801214247, 51.5588899009813],
+ [1554801234247, 51.54490468599705],
+ [1554801254247, 51.40662689618962],
+ [1554801274247, 51.75006583094692],
+ [1554801294247, 52.20228577285978],
+ [1554801314247, 52.348547272368506],
+ [1554801334247, 52.39186508724331],
+ [1554801354247, 52.542927652025924],
+ [1554801374247, 52.27966546246372],
+ [1554801394247, 52.20452443809642],
+ [1554801414247, 51.915875146571814],
+ [1554801434247, 51.85700055331651],
+ [1554801454247, 51.41503493304628],
+ [1554801474247, 51.91375992161767],
+ [1554801494247, 51.64979593631921],
+ [1554801514247, 51.59721672310636],
+ [1554801534247, 51.36646019351009],
+ [1554801554247, 51.17970052059037],
+ [1554801574247, 51.51534040387782],
+ [1554801594247, 51.88251684232427],
+ [1554801614247, 51.703014931819474],
+ [1554801634247, 51.547017299912504],
+ [1554801654247, 51.275856922468904],
+ [1554801674247, 51.71448641006434],
+ [1554801694247, 51.576144190557336],
+ [1554801714247, 51.354383834775916],
+ [1554801734247, 51.04396571574281],
+ [1554801754247, 50.876641592142796],
+ [1554801774247, 51.336655229980316],
+ [1554801794247, 50.867416279953595],
+ [1554801814247, 51.130911647942355],
+ [1554801834247, 51.18234874849458],
+ [1554801854247, 51.50380094567395],
+ [1554801874247, 51.828265541951005],
+ [1554801894247, 51.41901070104453],
+ [1554801914247, 50.99815354555354],
+ [1554801934247, 51.32753225892714],
+ [1554801954247, 51.59398074693891],
+ [1554801974247, 51.83542718732424],
+ [1554801994247, 51.927373369486894],
+ [1554802014247, 52.34926003699012],
+ [1554802034247, 52.33484803971464],
+ [1554802054247, 52.32711385955333],
+ [1554802074247, 51.83460572908414],
+ [1554802094247, 51.71984751064315],
+ [1554802114247, 51.77033331018975],
+ [1554802134247, 51.350955694201005],
+ [1554802154247, 51.65773417914936],
+ [1554802174247, 51.48342088576234],
+ [1554802194247, 51.16267545464356],
+ [1554802214247, 51.323530207826956],
+ [1554802234247, 51.567191168336976],
+ [1554802254247, 51.13294706734198],
+ [1554802274247, 50.79800554137457],
+ [1554802294247, 51.04722627688948],
+ [1554802314247, 51.318544212080354],
+ [1554802334247, 51.532386858163754],
+ [1554802354247, 51.47703791469364],
+ [1554802374247, 51.78920946190912],
+ [1554802394247, 51.85211680399902],
+ [1554802414247, 51.99320526572213],
+ [1554802434247, 51.57547183300737],
+ [1554802454247, 51.97761981686591],
+ [1554802474247, 51.87004631283087],
+ [1554802494247, 52.158068947935384],
+ [1554802514247, 51.94930117584308],
+ [1554802534247, 51.53478371041338],
+ [1554802554247, 51.17882972197612],
+ [1554802574247, 50.701283694457466],
+ [1554802594247, 50.90473753625081],
+ [1554802614247, 50.65241735456049],
+ [1554802634247, 50.438246098999585],
+ [1554802654247, 50.37870735226924],
+ [1554802674247, 50.85584471285298],
+ [1554802694247, 51.274089045530395],
+ [1554802714247, 51.59978276742954],
+ [1554802734247, 51.562936160576584],
+ [1554802754247, 51.42151903058987],
+ [1554802774247, 51.894976900116355],
+ [1554802794247, 51.83169631691224],
+ [1554802814247, 51.79801425800586],
+ [1554802834247, 51.479633959435034],
+ [1554802854247, 51.70290776584143],
+ [1554802874247, 51.757226685563765],
+ [1554802894247, 52.03704183387305],
+ [1554802914247, 52.3819953868567],
+ [1554802934247, 51.88287073947722],
+ [1554802954247, 52.10125989403958],
+ [1554802974247, 51.872702036903526],
+ [1554802994247, 52.009175627089505],
+ [1554803014247, 52.50785086552939],
+ [1554803034247, 52.36391362787773],
+ [1554803054247, 52.77582474643076],
+ [1554803074247, 53.14634835172726],
+ [1554803094247, 53.571861564649836],
+ [1554803114247, 53.34550413497026],
+ [1554803134247, 53.53080010106201],
+ [1554803154247, 53.73421984607534],
+ [1554803174247, 53.56007952437269],
+ [1554803194247, 53.131414787142056],
+ [1554803214247, 52.94547963572799],
+ [1554803234247, 53.14281647882233],
+ [1554803254247, 52.73823765064605],
+ [1554803274247, 52.956467351101274],
+ [1554803294247, 53.35534255411743],
+ [1554803314247, 53.192930959674406],
+ [1554803334247, 53.32694937486834],
+ [1554803354247, 53.15027458209927],
+ [1554803374247, 53.5587680311651],
+ [1554803394247, 53.568883926439334],
+ [1554803414247, 53.80781403307825],
+ [1554803434247, 54.170116862726246],
+ [1554803454247, 53.79726949862653],
+ [1554803474247, 54.118793890386996],
+ [1554803494247, 54.19522192357821],
+ [1554803514247, 53.93837314058516],
+ [1554803534247, 53.61455261022302],
+ [1554803554247, 53.25549925605131],
+ [1554803574247, 53.30871660112379],
+ [1554803594247, 53.025228370296],
+ [1554803614247, 52.715005370790905],
+ [1554803634247, 52.26518145403466],
+ [1554803654247, 51.77433258023653],
+ [1554803674247, 51.92907944820857],
+ [1554803694247, 51.799802420253314],
+ [1554803714247, 52.23576201540642],
+ [1554803734247, 51.94765338498968],
+ [1554803754247, 51.65532307329866],
+ [1554803774247, 51.95953898434276],
+ [1554803794247, 52.30572709425199],
+ [1554803814247, 52.50628901507423],
+ [1554803834247, 52.18392152073497],
+ [1554803854247, 52.37085384093291],
+ [1554803874247, 51.958905637529526],
+ [1554803894247, 52.33884893220496],
+ [1554803914247, 51.945176746826625],
+ [1554803934247, 52.2903551152492],
+ [1554803954247, 52.45484660570278],
+ [1554803974247, 52.26531643836918],
+ [1554803994247, 51.83132366758987],
+ [1554804014247, 51.72448213626581],
+ [1554804034247, 51.387397812656125],
+ [1554804054247, 51.482075969410865],
+ [1554804074247, 51.516830773532355],
+ [1554804094247, 51.48614199714788],
+ [1554804114247, 51.1107772949971],
+ [1554804134247, 51.58592082858312],
+ [1554804154247, 52.01002593365593],
+ [1554804174247, 52.05010430476184],
+ [1554804194247, 51.69390021751488],
+ [1554804214247, 52.10787479914773],
+ [1554804234247, 52.17172758152165],
+ [1554804254247, 51.78777541365326],
+ [1554804274247, 51.67579928345696],
+ [1554804294247, 51.94442819030671],
+ [1554804314247, 51.80897520694817],
+ [1554804334247, 51.67986689129912],
+ [1554804354247, 51.55210735174368],
+ [1554804374247, 51.77569039319583],
+ [1554804394247, 51.45788841681898],
+ [1554804414247, 51.87269232666622],
+ [1554804434247, 51.82302735551395],
+ [1554804454247, 52.31024585013042],
+ [1554804474247, 51.93060365264004],
+ [1554804494247, 52.40571312978707],
+ [1554804514247, 52.39673639936394],
+ [1554804534247, 52.18557628791588],
+ [1554804554247, 52.60978266763105],
+ [1554804574247, 52.16131048329209],
+ [1554804594247, 52.505784425001984],
+ [1554804614247, 52.32401176586753],
+ [1554804634247, 52.30325652498879],
+ [1554804654247, 52.28613876880225],
+ [1554804674247, 52.080496843116386],
+ [1554804694247, 51.61527428444171],
+ [1554804714247, 51.83680620548246],
+ [1554804734247, 52.30374804621723],
+ [1554804754247, 52.67939694931608],
+ [1554804774247, 52.94943544533422],
+ [1554804794247, 53.24374366240067],
+ [1554804814247, 52.768273806147725],
+ [1554804834247, 53.074934594212785],
+ [1554804854247, 52.8116690446343],
+ [1554804874247, 52.420101586577],
+ [1554804894247, 52.375842717401966],
+ [1554804914247, 52.3698756882421],
+ [1554804934247, 51.87583553645484],
+ [1554804954247, 51.54912664248644],
+ [1554804974247, 51.990562270095786],
+ [1554804994247, 52.090483035778746],
+ [1554805014247, 51.67299602002489],
+ [1554805034247, 51.378645555389255],
+ [1554805054247, 51.18008092332962],
+ [1554805074247, 50.90350661363346],
+ [1554805094247, 50.85344076579689],
+ [1554805114247, 50.75969452484323],
+ [1554805134247, 51.15665586466479],
+ [1554805154247, 51.311445500103396],
+ [1554805174247, 51.236856143793126],
+ [1554805194247, 51.17414261055051],
+ [1554805214247, 51.108641060373124],
+ [1554805234247, 50.75890985719905],
+ [1554805254247, 50.48058630203468],
+ [1554805274247, 50.76721935252362],
+ [1554805294247, 50.5330383603889],
+ [1554805314247, 50.26520598051574],
+ [1554805334247, 50.60944764624979],
+ [1554805354247, 50.74484810624328],
+ [1554805374247, 51.01668313286863],
+ [1554805394247, 51.05429730952428],
+ [1554805414247, 51.39068964671044],
+ [1554805434247, 51.317735823836614],
+ [1554805454247, 51.25736086149264],
+ [1554805474247, 50.922379102839166],
+ [1554805494247, 50.98179933241315],
+ [1554805514247, 51.374526290084134],
+ [1554805534247, 51.40831930835523],
+ [1554805554247, 51.443173852379545],
+ [1554805574247, 51.4683090318251],
+ [1554805594247, 51.709059003470124],
+ [1554805614247, 52.19184281346864],
+ [1554805634247, 52.35070138588975],
+ [1554805654247, 51.97957436658507],
+ [1554805674247, 51.91458431154472],
+ [1554805694247, 52.41026984953236],
+ [1554805714247, 52.275201030560105],
+ [1554805734247, 52.18307838063212],
+ [1554805754247, 52.060069338900774],
+ [1554805774247, 51.61450171082168],
+ [1554805794247, 52.09853956209946],
+ [1554805814247, 52.588843625759424],
+ [1554805834247, 52.80348947533139],
+ [1554805854247, 53.28197181050794],
+ [1554805874247, 53.70501200876997],
+ [1554805894247, 53.89498917310595],
+ [1554805914247, 53.99791259724504],
+ [1554805934247, 53.62968839158572],
+ [1554805954247, 53.99473243614239],
+ [1554805974247, 53.97607431885154],
+ [1554805994247, 54.1654752913762],
+ [1554806014247, 54.29381284957149],
+ [1554806034247, 54.26736760766921],
+ [1554806054247, 54.72579383573786],
+ [1554806074247, 54.87585753445682],
+ [1554806094247, 54.90114957236757],
+ [1554806114247, 54.45131273475261],
+ [1554806134247, 54.00663438718738],
+ [1554806154247, 54.36866367166484],
+ [1554806174247, 54.455988047905954],
+ [1554806194247, 54.53444237413403],
+ [1554806214247, 54.259447240560334],
+ [1554806234247, 54.739815020637415],
+ [1554806254247, 54.53713835073127],
+ [1554806274247, 54.207215355017205],
+ [1554806294247, 54.5440608018207],
+ [1554806314247, 54.358821571481016],
+ [1554806334247, 54.72879724971994],
+ [1554806354247, 54.90023956328739],
+ [1554806374247, 54.74057764265007],
+ [1554806394247, 54.75935443450963],
+ [1554806414247, 55.02078995986204],
+ [1554806434247, 55.47735667708813],
+ [1554806454247, 55.728823396928945],
+ [1554806474247, 56.163253634213675],
+ [1554806494247, 55.8515954825293],
+ [1554806514247, 56.129890392645194],
+ [1554806534247, 55.74162749726028],
+ [1554806554247, 56.21329274387774],
+ [1554806574247, 55.998639128941015],
+ [1554806594247, 56.17167173612524],
+ [1554806614247, 56.37502616405982],
+ [1554806634247, 56.163483013167344],
+ [1554806654247, 55.84694130467721],
+ [1554806674247, 55.45846837023379],
+ [1554806694247, 55.04755139168062],
+ [1554806714247, 55.023136962195196],
+ [1554806734247, 55.03318249113286],
+ [1554806754247, 55.15746201013343],
+ [1554806774247, 54.69192101415061],
+ [1554806794247, 54.84111015085251],
+ [1554806814247, 54.58742405929199],
+ [1554806834247, 54.97799911256185],
+ [1554806854247, 54.764821076597485],
+ [1554806874247, 54.78776554693746],
+ [1554806894247, 54.36349387408045],
+ [1554806914247, 53.89745720207634],
+ [1554806934247, 54.17384926356723],
+ [1554806954247, 53.846082255988286],
+ [1554806974247, 53.90613692731394],
+ [1554806994247, 53.87258573355891],
+ [1554807014247, 54.17549073728332],
+ [1554807034247, 53.68618357720563],
+ [1554807054247, 53.513969787757105],
+ [1554807074247, 53.0552099855896],
+ [1554807094247, 52.765588324483865],
+ [1554807114247, 52.658001079532866],
+ [1554807134247, 53.07486561753133],
+ [1554807154247, 52.69459960292874],
+ [1554807174247, 52.98255693457559],
+ [1554807194247, 53.20218278203097],
+ [1554807214247, 52.97957847809027],
+ [1554807234247, 53.203425156589425],
+ [1554807254247, 53.12562342353098],
+ [1554807274247, 52.98722273991035],
+ [1554807294247, 52.82655589418688],
+ [1554807314247, 52.52987556980093],
+ [1554807334247, 52.491534753287645],
+ [1554807354247, 52.55176305705825],
+ [1554807374247, 52.13841375230353],
+ [1554807394247, 51.834840312920164],
+ [1554807414247, 52.184416639498664],
+ [1554807434247, 51.72479740399346],
+ [1554807454247, 52.155588780091456],
+ [1554807474247, 51.843576760185535],
+ [1554807494247, 51.63505755687057],
+ [1554807514247, 51.328848338540325],
+ [1554807534247, 51.17434126071598],
+ [1554807554247, 51.22528683963288],
+ [1554807574247, 51.45420767833925],
+ [1554807594247, 51.22268991224942],
+ [1554807614247, 50.79238198146152],
+ [1554807634247, 50.45484627009857],
+ [1554807654247, 50.85902478247322],
+ [1554807674247, 51.05110301744823],
+ [1554807694247, 51.441065782940804],
+ [1554807714247, 51.72675194566211],
+ [1554807734247, 51.34741055949714],
+ [1554807754247, 50.920382272281294],
+ [1554807774247, 50.70536279085003],
+ [1554807794247, 50.55798114104046],
+ [1554807814247, 50.725557394433494],
+ [1554807834247, 50.60243126287948],
+ [1554807854247, 50.14375392566316],
+ [1554807874247, 50.2002531691062],
+ [1554807894247, 50.200943028986934],
+ [1554807914247, 49.93557347736677],
+ [1554807934247, 50.3241686237509],
+ [1554807954247, 50.74023874549823],
+ [1554807974247, 50.381498198272375],
+ [1554807994247, 50.52372793713143],
+ [1554808014247, 50.59619769171313],
+ [1554808034247, 50.89556341815888],
+ [1554808054247, 50.86443137192155],
+ [1554808074247, 50.63167033746789],
+ [1554808094247, 50.13964173171047],
+ [1554808114247, 50.25093231733134],
+ [1554808134247, 50.08498877315317],
+ [1554808154247, 50.11947998142],
+ [1554808174247, 49.987009677804366],
+ [1554808194247, 49.840080913269475],
+ [1554808214247, 50.209998565510354],
+ [1554808234247, 50.531756264070935],
+ [1554808254247, 50.74837122490037],
+ [1554808274247, 50.7311698620495],
+ [1554808294247, 50.26107114525714],
+ [1554808314247, 50.57160680670211],
+ [1554808334247, 50.658461548491324],
+ [1554808354247, 50.32651326535061],
+ [1554808374247, 50.661562835023595],
+ [1554808394247, 50.44958975353214],
+ [1554808414247, 50.22399999500883],
+ [1554808434247, 50.58871685273966],
+ [1554808454247, 50.6742183549089],
+ [1554808474247, 50.32618916949026],
+ [1554808494247, 49.97104996971649],
+ [1554808514247, 50.435289475414216],
+ [1554808534247, 50.60512926447027],
+ [1554808554247, 50.73020639421864],
+ [1554808574247, 50.99932725118429],
+ [1554808594247, 51.34816166255093],
+ [1554808614247, 51.26324189269789],
+ [1554808634247, 50.85324941286893],
+ [1554808654247, 50.72520384570293],
+ [1554808674247, 51.089644509784655],
+ [1554808694247, 51.542456610721025],
+ [1554808714247, 51.777359837645164],
+ [1554808734247, 52.135547900174195],
+ [1554808754247, 52.28862099588846],
+ [1554808774247, 51.997792836163434],
+ [1554808794247, 52.305297731262264],
+ [1554808814247, 52.221352299608874],
+ [1554808834247, 52.02839560401225],
+ [1554808854247, 51.63103387134092],
+ [1554808874247, 51.54216467728416],
+ [1554808894247, 51.55386052088342],
+ [1554808914247, 51.17586087923488],
+ [1554808934247, 50.76208251333271],
+ [1554808954247, 50.317727703878695],
+ [1554808974247, 50.090846251422974],
+ [1554808994247, 50.06945817010757],
+ [1554809014247, 50.02269714272485],
+ [1554809034247, 49.9014869250931],
+ [1554809054247, 49.54981076067255],
+ [1554809074247, 49.84951930203291],
+ [1554809094247, 49.47499972389107],
+ [1554809114247, 49.62465014644696],
+ [1554809134247, 49.24747194031203],
+ [1554809154247, 49.069372398247346],
+ [1554809174247, 49.51527762106267],
+ [1554809194247, 49.55929829562035],
+ [1554809214247, 49.14007484550787],
+ [1554809234247, 49.55967463057968],
+ [1554809254247, 49.92414029604148],
+ [1554809274247, 50.28248263822046],
+ [1554809294247, 50.43547187450998],
+ [1554809314247, 50.01088683196451],
+ [1554809334247, 49.677926301450555],
+ [1554809354247, 49.97511400319861],
+ [1554809374247, 50.224853104822266],
+ [1554809394247, 50.220580489563496],
+ [1554809414247, 50.32549316137843],
+ [1554809434247, 50.81418718936579],
+ [1554809454247, 51.28120757217762],
+ [1554809474247, 51.465547229465],
+ [1554809494247, 51.37421458009423],
+ [1554809514247, 51.04893929102602],
+ [1554809534247, 50.66827537100915],
+ [1554809554247, 51.010305384682916],
+ [1554809574247, 50.74651884448325],
+ [1554809594247, 50.61682216706967],
+ [1554809614247, 50.45361096216425],
+ [1554809634247, 50.90490891959407],
+ [1554809654247, 50.622456452782494],
+ [1554809674247, 50.50344283767147],
+ [1554809694247, 50.46493050792487],
+ [1554809714247, 50.35998380458337],
+ [1554809734247, 50.1328954252928],
+ [1554809754247, 49.84079495406359],
+ [1554809774247, 50.13123680838925],
+ [1554809794247, 50.20403867276622],
+ [1554809814247, 50.004272675190784],
+ [1554809834247, 49.723751138918296],
+ [1554809854247, 49.49859072862423],
+ [1554809874247, 49.538307673194836],
+ [1554809894247, 49.62089922968913],
+ [1554809914247, 49.82385421066983],
+ [1554809934247, 49.84161674017104],
+ [1554809954247, 49.526737636369795],
+ [1554809974247, 49.931126418386356],
+ [1554809994247, 49.53343714924538],
+ [1554810014247, 49.42313707765715],
+ [1554810034247, 49.16979485487088],
+ [1554810054247, 49.652563787202645],
+ [1554810074247, 49.48023797398182],
+ [1554810094247, 49.966840603633734],
+ [1554810114247, 49.472083383816674],
+ [1554810134247, 49.37956146522102],
+ [1554810154247, 48.913166987107715],
+ [1554810174247, 48.70672990770373],
+ [1554810194247, 49.1880143597863],
+ [1554810214247, 49.49138355568559],
+ [1554810234247, 49.0630916077481],
+ [1554810254247, 48.85748269209717],
+ [1554810274247, 49.28639478935244],
+ [1554810294247, 49.13826091989152],
+ [1554810314247, 48.983630923627935],
+ [1554810334247, 48.68240787752351],
+ [1554810354247, 48.36663230019177],
+ [1554810374247, 48.52948288449895],
+ [1554810394247, 48.82498752624838],
+ [1554810414247, 49.10206080290292],
+ [1554810434247, 48.8130786016997],
+ [1554810454247, 48.663637941429585],
+ [1554810474247, 48.78385244438397],
+ [1554810494247, 48.5385370554751],
+ [1554810514247, 48.65982342796413],
+ [1554810534247, 48.2793032813205],
+ [1554810554247, 48.368720363392434],
+ [1554810574247, 47.95631221866125],
+ [1554810594247, 48.04947801392955],
+ [1554810614247, 47.92730902313688],
+ [1554810634247, 47.791227561595186],
+ [1554810654247, 47.696413872767344],
+ [1554810674247, 48.003461905264565],
+ [1554810694247, 48.41866753821385],
+ [1554810714247, 48.3323818553399],
+ [1554810734247, 48.55875807089029],
+ [1554810754247, 48.69664614708888],
+ [1554810774247, 48.39911556887364],
+ [1554810794247, 48.11355417510691],
+ [1554810814247, 47.68051884606699],
+ [1554810834247, 47.1839923323315],
+ [1554810854247, 47.521145818447444],
+ [1554810874247, 47.435239847122254],
+ [1554810894247, 47.80415137706029],
+ [1554810914247, 47.63696258266796],
+ [1554810934247, 48.03428238075079],
+ [1554810954247, 47.94997360430622],
+ [1554810974247, 47.55449851528431],
+ [1554810994247, 47.78824911083491],
+ [1554811014247, 47.4893779355486],
+ [1554811034247, 47.64650668855729],
+ [1554811054247, 47.22649114069579],
+ [1554811074247, 47.10626496382279],
+ [1554811094247, 46.853256635084975],
+ [1554811114247, 46.58521435687729],
+ [1554811134247, 46.46807667444405],
+ [1554811154247, 46.59110720595821],
+ [1554811174247, 46.47156843975408],
+ [1554811194247, 46.30570534424654],
+ [1554811214247, 46.327884115808345],
+ [1554811234247, 45.87249321102525],
+ [1554811254247, 45.93662730816857],
+ [1554811274247, 45.830703114024715],
+ [1554811294247, 45.7471098907337],
+ [1554811314247, 45.97554190426588],
+ [1554811334247, 45.83195232100273],
+ [1554811354247, 46.311066254110614],
+ [1554811374247, 46.502026295217874],
+ [1554811394247, 46.85743404788076],
+ [1554811414247, 47.058397205858235],
+ [1554811434247, 46.71734957659286],
+ [1554811454247, 47.00406489994063],
+ [1554811474247, 46.908589679853144],
+ [1554811494247, 46.46429522803091],
+ [1554811514247, 46.35314410074062],
+ [1554811534247, 46.08606779214885],
+ [1554811554247, 45.59440554131089],
+ [1554811574247, 46.01004712520209],
+ [1554811594247, 46.33290514899631],
+ [1554811614247, 45.90387315090703],
+ [1554811634247, 45.804826673859495],
+ [1554811654247, 45.58814979542495],
+ [1554811674247, 45.6383366715778],
+ [1554811694247, 46.098869094510555],
+ [1554811714247, 46.27645434323368],
+ [1554811734247, 46.38377282639434],
+ [1554811754247, 46.60623046278854],
+ [1554811774247, 46.853513275876644],
+ [1554811794247, 46.81150563219055],
+ [1554811814247, 46.325544759803684],
+ [1554811834247, 46.39222319511721],
+ [1554811854247, 46.05237287548122],
+ [1554811874247, 46.357861427033505],
+ [1554811894247, 45.872808350625355],
+ [1554811914247, 45.73033158647349],
+ [1554811934247, 46.181966738488526],
+ [1554811954247, 46.61144780966708],
+ [1554811974247, 46.944186256067475],
+ [1554811994247, 46.446866815105544],
+ [1554812014247, 46.87455438198626],
+ [1554812034247, 46.49680004841036],
+ [1554812054247, 46.110314234703566],
+ [1554812074247, 45.72718212902214],
+ [1554812094247, 45.855039988603075],
+ [1554812114247, 45.831083020621925],
+ [1554812134247, 45.934195744884576],
+ [1554812154247, 45.793162191919734],
+ [1554812174247, 45.595669324309405],
+ [1554812194247, 45.34395417586054],
+ [1554812214247, 45.48878147415903],
+ [1554812234247, 45.18708811432028],
+ [1554812254247, 45.68654757702763],
+ [1554812274247, 45.25733330257729],
+ [1554812294247, 44.802476591068185],
+ [1554812314247, 44.90227449426073],
+ [1554812334247, 44.77621515016869],
+ [1554812354247, 44.43700939403772],
+ [1554812374247, 44.89535195708861],
+ [1554812394247, 44.66555490148931],
+ [1554812414247, 44.77656357009823],
+ [1554812434247, 45.0781456336617],
+ [1554812454247, 45.02266276801925],
+ [1554812474247, 45.17853761454366],
+ [1554812494247, 45.206345465197174],
+ [1554812514247, 44.74293332634654],
+ [1554812534247, 45.12058926393326],
+ [1554812554247, 45.484527330308026],
+ [1554812574247, 45.72220471641109],
+ [1554812594247, 46.13939152292791],
+ [1554812614247, 46.00759269422592],
+ [1554812634247, 46.15320023087146],
+ [1554812654247, 46.31453520052207],
+ [1554812674247, 46.63327463975146],
+ [1554812694247, 46.74008671110519],
+ [1554812714247, 46.43464466851368],
+ [1554812734247, 46.09437986713492],
+ [1554812754247, 45.76744795370013],
+ [1554812774247, 46.15933621956665],
+ [1554812794247, 46.49926171251873],
+ [1554812814247, 46.26031394263079],
+ [1554812834247, 46.40700021317878],
+ [1554812854247, 46.019356637458465],
+ [1554812874247, 45.663769053656914],
+ [1554812894247, 46.11543163861163],
+ [1554812914247, 46.01937845681326],
+ [1554812934247, 46.053876490893266],
+ [1554812954247, 46.49976036351762],
+ [1554812974247, 46.48642420084204],
+ [1554812994247, 46.33380830950621],
+ [1554813014247, 46.46158553555841],
+ [1554813034247, 45.974232040531696],
+ [1554813054247, 45.84763240974679],
+ [1554813074247, 46.06094295457176],
+ [1554813094247, 45.57542828478516],
+ [1554813114247, 45.107768244929794],
+ [1554813134247, 45.29289069830043],
+ [1554813154247, 45.50682878428712],
+ [1554813174247, 45.48588008195146],
+ [1554813194247, 44.98951523195182],
+ [1554813214247, 44.682577096293755],
+ [1554813234247, 44.84745376781998],
+ [1554813254247, 44.58220779177513],
+ [1554813274247, 44.34705935598955],
+ [1554813294247, 43.91212590970287],
+ [1554813314247, 44.04615663810462],
+ [1554813334247, 43.78133590063513],
+ [1554813354247, 43.41643624560887],
+ [1554813374247, 43.63708147900446],
+ [1554813394247, 43.38739883558116],
+ [1554813414247, 43.64690789208579],
+ [1554813434247, 43.240387286772794],
+ [1554813454247, 43.02887852514058],
+ [1554813474247, 42.64466609459708],
+ [1554813494247, 42.59509438582544],
+ [1554813514247, 42.800700150025904],
+ [1554813534247, 42.99279809120495],
+ [1554813554247, 42.71212019392293],
+ [1554813574247, 42.26453618628849],
+ [1554813594247, 42.156627021840094],
+ [1554813614247, 42.18984321867831],
+ [1554813634247, 42.29340892976422],
+ [1554813654247, 42.593900952016476],
+ [1554813674247, 42.2330620746611],
+ [1554813694247, 41.86806010030196],
+ [1554813714247, 41.92031494441884],
+ [1554813734247, 41.77029002001442],
+ [1554813754247, 41.62068939271727],
+ [1554813774247, 41.27522742225526],
+ [1554813794247, 41.59092178660088],
+ [1554813814247, 41.197602991055604],
+ [1554813834247, 40.894310341221576],
+ [1554813854247, 40.9605769039487],
+ [1554813874247, 40.924569026392284],
+ [1554813894247, 40.6219617605231],
+ [1554813914247, 40.66747690052986],
+ [1554813934247, 40.3502087650845],
+ [1554813954247, 40.75856493329949],
+ [1554813974247, 40.77424153954944],
+ [1554813994247, 40.765533525784875],
+ [1554814014247, 40.7150752518103],
+ [1554814034247, 41.07494126786947],
+ [1554814054247, 41.50291852374512],
+ [1554814074247, 41.247377467265686],
+ [1554814094247, 41.60383347544849],
+ [1554814114247, 41.21723434866782],
+ [1554814134247, 41.17362119491221],
+ [1554814154247, 41.5483199633518],
+ [1554814174247, 41.26881119300047],
+ [1554814194247, 41.11926507536818],
+ [1554814214247, 41.279830040613255],
+ [1554814234247, 41.37424366244724],
+ [1554814254247, 41.23223435709267],
+ [1554814274247, 41.22891130945054],
+ [1554814294247, 40.84273309880227],
+ [1554814314247, 40.77105807274393],
+ [1554814334247, 40.86144344756839],
+ [1554814354247, 40.53399404435103],
+ [1554814374247, 40.89965536321252],
+ [1554814394247, 40.551632896315354],
+ [1554814414247, 40.27233656089394],
+ [1554814434247, 39.79467584395313],
+ [1554814454247, 39.5446056978286],
+ [1554814474247, 39.21168731652927],
+ [1554814494247, 39.53512815542741],
+ [1554814514247, 39.99562353822233],
+ [1554814534247, 39.85823942167259],
+ [1554814554247, 40.124808305253865],
+ [1554814574247, 40.356725295094996],
+ [1554814594247, 39.88169507281861],
+ [1554814614247, 40.09602202671889],
+ [1554814634247, 40.32994988463872],
+ [1554814654247, 40.6652027871041],
+ [1554814674247, 40.33146187156191],
+ [1554814694247, 39.89510766819647],
+ [1554814714247, 40.282027306139604],
+ [1554814734247, 40.34382349011193],
+ [1554814754247, 40.74449254471113],
+ [1554814774247, 40.605736246604756],
+ [1554814794247, 40.71323696936045],
+ [1554814814247, 40.98756203169225],
+ [1554814834247, 41.15554546599332],
+ [1554814854247, 40.97696657263369],
+ ],
+ color: '#6ED0E0',
+ info: [
+ { title: 'min', text: '14.42', numeric: 14.427101844163694 },
+ { title: 'max', text: '18.42', numeric: 18.427101844163694 },
+ ],
+ isVisible: true,
+ yAxis: 1,
+ },
+ ],
+ timeRange: {
+ from: moment('2019-04-09T07:01:14.247Z'),
+ to: moment('2019-04-09T13:01:14.247Z'),
+ raw: {
+ from: 'now-6h',
+ to: 'now',
+ },
+ },
+ width: 944,
+ height: 294,
+ isLegendVisible: true,
+ showBars: false,
+ showLines: true,
+ showPoints: false,
+ placement: 'under',
+ onSeriesColorChange: (label, color) => {
+ if (onSeriesColorChange) {
+ onSeriesColorChange(label, color);
+ }
+ },
+ onSeriesAxisToggle: (label, yAxis) => {
+ if (onSeriesAxisToggle) {
+ onSeriesAxisToggle(label, yAxis);
+ }
+ },
+ onToggleSort: () => {},
+ displayMode: displayMode || LegendDisplayMode.List,
+});
diff --git a/packages/grafana-ui/src/components/Legend/Legend.story.tsx b/packages/grafana-ui/src/components/Legend/Legend.story.tsx
new file mode 100644
index 0000000000000..3cd561f03014a
--- /dev/null
+++ b/packages/grafana-ui/src/components/Legend/Legend.story.tsx
@@ -0,0 +1,142 @@
+import React from 'react';
+import { storiesOf } from '@storybook/react';
+import { LegendList, LegendPlacement, LegendItem, LegendTable } from './Legend';
+import tinycolor from 'tinycolor2';
+import { DisplayValue } from '../../types/index';
+import { number, select, text } from '@storybook/addon-knobs';
+import { action } from '@storybook/addon-actions';
+import { GraphLegendListItem, GraphLegendTableRow, GraphLegendItemProps } from '../Graph/GraphLegendItem';
+
+export const generateLegendItems = (numberOfSeries: number, statsToDisplay?: DisplayValue[]): LegendItem[] => {
+ const alphabet = 'abcdefghijklmnopqrstuvwxyz'.split('');
+
+ return [...new Array(numberOfSeries)].map((item, i) => {
+ return {
+ label: `${alphabet[i].toUpperCase()}-series`,
+ color: tinycolor.fromRatio({ h: i / alphabet.length, s: 1, v: 1 }).toHexString(),
+ isVisible: true,
+ yAxis: 1,
+ displayValues: statsToDisplay || [],
+ };
+ });
+};
+
+const getStoriesKnobs = (table = false) => {
+ const numberOfSeries = number('Number of series', 3);
+ const containerWidth = select(
+ 'Container width',
+ {
+ Small: '200px',
+ Medium: '500px',
+ 'Full width': '100%',
+ },
+ '100%'
+ );
+
+ const rawRenderer = (item: LegendItem) => (
+ <>
+ Label: {item.label} , Color: {item.color} , isVisible:{' '}
+ {item.isVisible ? 'yes' : 'no'}
+ >
+ );
+
+ const customRenderer = (component: React.ComponentType) => (item: LegendItem) =>
+ React.createElement(component, {
+ item,
+ onLabelClick: action('GraphLegendItem label clicked'),
+ onSeriesColorChange: action('Series color changed'),
+ onToggleAxis: action('Y-axis toggle'),
+ });
+
+ const typeSpecificRenderer = table
+ ? {
+ 'Custom renderer(GraphLegendTablerow)': 'custom-tabe',
+ }
+ : {
+ 'Custom renderer(GraphLegendListItem)': 'custom-list',
+ };
+ const legendItemRenderer = select(
+ 'Item rendered',
+ {
+ 'Raw renderer': 'raw',
+ ...typeSpecificRenderer,
+ },
+ 'raw'
+ );
+
+ const rightAxisSeries = text('Right y-axis series, i.e. A,C', '');
+
+ const legendPlacement = select(
+ 'Legend placement',
+ {
+ under: 'under',
+ right: 'right',
+ },
+ 'under'
+ );
+
+ return {
+ numberOfSeries,
+ containerWidth,
+ itemRenderer:
+ legendItemRenderer === 'raw'
+ ? rawRenderer
+ : customRenderer(legendItemRenderer === 'custom-list' ? GraphLegendListItem : GraphLegendTableRow),
+ rightAxisSeries,
+ legendPlacement,
+ };
+};
+
+const LegendStories = storiesOf('UI/Legend/Legend', module);
+
+LegendStories.add('list', () => {
+ const { numberOfSeries, itemRenderer, containerWidth, rightAxisSeries, legendPlacement } = getStoriesKnobs();
+ let items = generateLegendItems(numberOfSeries);
+
+ items = items.map(i => {
+ if (
+ rightAxisSeries
+ .split(',')
+ .map(s => s.trim())
+ .indexOf(i.label.split('-')[0]) > -1
+ ) {
+ i.yAxis = 2;
+ }
+
+ return i;
+ });
+ return (
+
+
+
+ );
+});
+
+LegendStories.add('table', () => {
+ const { numberOfSeries, itemRenderer, containerWidth, rightAxisSeries, legendPlacement } = getStoriesKnobs(true);
+ let items = generateLegendItems(numberOfSeries);
+
+ items = items.map(i => {
+ if (
+ rightAxisSeries
+ .split(',')
+ .map(s => s.trim())
+ .indexOf(i.label.split('-')[0]) > -1
+ ) {
+ i.yAxis = 2;
+ }
+
+ return {
+ ...i,
+ info: [
+ { title: 'min', text: '14.42', numeric: 14.427101844163694 },
+ { title: 'max', text: '18.42', numeric: 18.427101844163694 },
+ ],
+ };
+ });
+ return (
+
+
+
+ );
+});
diff --git a/packages/grafana-ui/src/components/Legend/Legend.tsx b/packages/grafana-ui/src/components/Legend/Legend.tsx
new file mode 100644
index 0000000000000..6f417f7257463
--- /dev/null
+++ b/packages/grafana-ui/src/components/Legend/Legend.tsx
@@ -0,0 +1,43 @@
+import { DisplayValue } from '../../types/index';
+
+import { LegendList } from './LegendList';
+import { LegendTable } from './LegendTable';
+
+export enum LegendDisplayMode {
+ List = 'list',
+ Table = 'table',
+}
+export interface LegendBasicOptions {
+ isVisible: boolean;
+ asTable: boolean;
+}
+
+export interface LegendRenderOptions {
+ placement: LegendPlacement;
+ hideEmpty?: boolean;
+ hideZero?: boolean;
+}
+
+export type LegendPlacement = 'under' | 'right' | 'over'; // Over used by piechart
+
+export interface LegendOptions extends LegendBasicOptions, LegendRenderOptions {}
+
+export interface LegendItem {
+ label: string;
+ color: string;
+ isVisible: boolean;
+ yAxis: number;
+ displayValues?: DisplayValue[];
+}
+
+export interface LegendComponentProps {
+ className?: string;
+ items: LegendItem[];
+ placement: LegendPlacement;
+ // Function to render given item
+ itemRenderer?: (item: LegendItem, index: number) => JSX.Element;
+}
+
+export interface LegendProps extends LegendComponentProps {}
+
+export { LegendList, LegendTable };
diff --git a/packages/grafana-ui/src/components/Legend/LegendList.tsx b/packages/grafana-ui/src/components/Legend/LegendList.tsx
new file mode 100644
index 0000000000000..d103aa3ed8067
--- /dev/null
+++ b/packages/grafana-ui/src/components/Legend/LegendList.tsx
@@ -0,0 +1,66 @@
+import React, { useContext } from 'react';
+import { LegendComponentProps, LegendItem } from './Legend';
+import { InlineList } from '../List/InlineList';
+import { List } from '../List/List';
+import { css, cx } from 'emotion';
+import { ThemeContext } from '../../themes/ThemeContext';
+
+export const LegendList: React.FunctionComponent = ({
+ items,
+ itemRenderer,
+ placement,
+ className,
+}) => {
+ const theme = useContext(ThemeContext);
+
+ const renderItem = (item: LegendItem, index: number) => {
+ return (
+
+ {itemRenderer ? itemRenderer(item, index) : item.label}
+
+ );
+ };
+
+ const getItemKey = (item: LegendItem) => item.label;
+
+ const styles = {
+ wrapper: cx(
+ css`
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+ width: 100%;
+ `,
+ className
+ ),
+ section: css`
+ display: flex;
+ `,
+ sectionRight: css`
+ justify-content: flex-end;
+ flex-grow: 1;
+ `,
+ };
+
+ return placement === 'under' ? (
+
+
+ item.yAxis === 1)} renderItem={renderItem} getItemKey={getItemKey} />
+
+
+ item.yAxis !== 1)} renderItem={renderItem} getItemKey={getItemKey} />
+
+
+ ) : (
+
+ );
+};
+
+LegendList.displayName = 'LegendList';
diff --git a/packages/grafana-ui/src/components/Legend/LegendSeriesIcon.tsx b/packages/grafana-ui/src/components/Legend/LegendSeriesIcon.tsx
new file mode 100644
index 0000000000000..1913c2e500d25
--- /dev/null
+++ b/packages/grafana-ui/src/components/Legend/LegendSeriesIcon.tsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import { SeriesColorPicker } from '../ColorPicker/ColorPicker';
+import { SeriesIcon } from './SeriesIcon';
+
+interface LegendSeriesIconProps {
+ color: string;
+ yAxis: number;
+ onColorChange: (color: string) => void;
+ onToggleAxis?: () => void;
+}
+
+export const LegendSeriesIcon: React.FunctionComponent = ({
+ yAxis,
+ color,
+ onColorChange,
+ onToggleAxis,
+}) => {
+ return (
+
+ {({ ref, showColorPicker, hideColorPicker }) => (
+
+
+
+ )}
+
+ );
+};
+
+LegendSeriesIcon.displayName = 'LegendSeriesIcon';
diff --git a/packages/grafana-ui/src/components/Legend/LegendStatsList.tsx b/packages/grafana-ui/src/components/Legend/LegendStatsList.tsx
new file mode 100644
index 0000000000000..b53f3cc2a536c
--- /dev/null
+++ b/packages/grafana-ui/src/components/Legend/LegendStatsList.tsx
@@ -0,0 +1,28 @@
+import React from 'react';
+import { InlineList } from '../List/InlineList';
+import { css } from 'emotion';
+import { DisplayValue } from '../../types/displayValue';
+import capitalize from 'lodash/capitalize';
+
+const LegendItemStat: React.FunctionComponent<{ stat: DisplayValue }> = ({ stat }) => {
+ return (
+
+ {stat.title && `${capitalize(stat.title)}:`} {stat.text}
+
+ );
+};
+
+LegendItemStat.displayName = 'LegendItemStat';
+
+export const LegendStatsList: React.FunctionComponent<{ stats: DisplayValue[] }> = ({ stats }) => {
+ if (stats.length === 0) {
+ return null;
+ }
+ return } />;
+};
+
+LegendStatsList.displayName = 'LegendStatsList';
diff --git a/packages/grafana-ui/src/components/Legend/LegendTable.tsx b/packages/grafana-ui/src/components/Legend/LegendTable.tsx
new file mode 100644
index 0000000000000..38a6bd1497b96
--- /dev/null
+++ b/packages/grafana-ui/src/components/Legend/LegendTable.tsx
@@ -0,0 +1,83 @@
+import React, { useContext } from 'react';
+import { css, cx } from 'emotion';
+import { LegendComponentProps } from './Legend';
+import { ThemeContext } from '../../themes/ThemeContext';
+
+interface LegendTableProps extends LegendComponentProps {
+ columns: string[];
+ sortBy?: string;
+ sortDesc?: boolean;
+ onToggleSort?: (sortBy: string) => void;
+}
+
+export const LegendTable: React.FunctionComponent = ({
+ items,
+ columns,
+ sortBy,
+ sortDesc,
+ itemRenderer,
+ className,
+ onToggleSort,
+}) => {
+ const theme = useContext(ThemeContext);
+
+ return (
+
+
+
+ {columns.map(columnHeader => {
+ return (
+ {
+ if (onToggleSort) {
+ onToggleSort(columnHeader);
+ }
+ }}
+ >
+ {columnHeader}
+ {sortBy === columnHeader && (
+
+ )}
+
+ );
+ })}
+
+
+
+ {items.map((item, index) => {
+ return itemRenderer ? (
+ itemRenderer(item, index)
+ ) : (
+
+ {item.label}
+
+ );
+ })}
+
+
+ );
+};
diff --git a/packages/grafana-ui/src/components/Legend/SeriesIcon.tsx b/packages/grafana-ui/src/components/Legend/SeriesIcon.tsx
new file mode 100644
index 0000000000000..091d79f7fd0d0
--- /dev/null
+++ b/packages/grafana-ui/src/components/Legend/SeriesIcon.tsx
@@ -0,0 +1,5 @@
+import React from 'react';
+
+export const SeriesIcon: React.FunctionComponent<{ color: string }> = ({ color }) => {
+ return ;
+};
diff --git a/packages/grafana-ui/src/components/List/AbstractList.test.tsx b/packages/grafana-ui/src/components/List/AbstractList.test.tsx
new file mode 100644
index 0000000000000..f38b7cd2988e5
--- /dev/null
+++ b/packages/grafana-ui/src/components/List/AbstractList.test.tsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import { AbstractList } from './AbstractList';
+
+describe('AbstractList', () => {
+ it('renders items using renderItem prop function', () => {
+ const items = [{ name: 'Item 1', id: 'item1' }, { name: 'Item 2', id: 'item2' }, { name: 'Item 3', id: 'item3' }];
+
+ const list = shallow(
+ (
+
+
{item.name}
+ {item.id}
+
+ )}
+ />
+ );
+
+ expect(list).toMatchSnapshot();
+ });
+
+ it('allows custom item key', () => {
+ const items = [{ name: 'Item 1', id: 'item1' }, { name: 'Item 2', id: 'item2' }, { name: 'Item 3', id: 'item3' }];
+
+ const list = shallow(
+ item.id}
+ renderItem={item => (
+
+
{item.name}
+ {item.id}
+
+ )}
+ />
+ );
+
+ expect(list).toMatchSnapshot();
+ });
+});
diff --git a/packages/grafana-ui/src/components/List/AbstractList.tsx b/packages/grafana-ui/src/components/List/AbstractList.tsx
new file mode 100644
index 0000000000000..7c978753276a4
--- /dev/null
+++ b/packages/grafana-ui/src/components/List/AbstractList.tsx
@@ -0,0 +1,53 @@
+import React from 'react';
+import { cx, css } from 'emotion';
+
+export interface ListProps {
+ items: T[];
+ renderItem: (item: T, index: number) => JSX.Element;
+ getItemKey?: (item: T) => string;
+ className?: string;
+}
+
+interface AbstractListProps extends ListProps {
+ inline?: boolean;
+}
+
+export class AbstractList extends React.PureComponent> {
+ constructor(props: AbstractListProps) {
+ super(props);
+ this.getListStyles = this.getListStyles.bind(this);
+ }
+
+ getListStyles() {
+ const { inline, className } = this.props;
+ return {
+ list: cx([
+ css`
+ list-style-type: none;
+ margin: 0;
+ padding: 0;
+ `,
+ className,
+ ]),
+ item: css`
+ display: ${(inline && 'inline-block') || 'block'};
+ `,
+ };
+ }
+
+ render() {
+ const { items, renderItem, getItemKey } = this.props;
+ const styles = this.getListStyles();
+ return (
+
+ {items.map((item, i) => {
+ return (
+
+ {renderItem(item, i)}
+
+ );
+ })}
+
+ );
+ }
+}
diff --git a/packages/grafana-ui/src/components/List/InlineList.tsx b/packages/grafana-ui/src/components/List/InlineList.tsx
new file mode 100644
index 0000000000000..aadfd84046f8a
--- /dev/null
+++ b/packages/grafana-ui/src/components/List/InlineList.tsx
@@ -0,0 +1,8 @@
+import React from 'react';
+import { ListProps, AbstractList } from './AbstractList';
+
+export class InlineList extends React.PureComponent> {
+ render() {
+ return ;
+ }
+}
diff --git a/packages/grafana-ui/src/components/List/List.story.tsx b/packages/grafana-ui/src/components/List/List.story.tsx
new file mode 100644
index 0000000000000..3911039b5225e
--- /dev/null
+++ b/packages/grafana-ui/src/components/List/List.story.tsx
@@ -0,0 +1,68 @@
+import React from 'react';
+import { storiesOf } from '@storybook/react';
+import { number, select } from '@storybook/addon-knobs';
+import { List } from './List';
+import { css, cx } from 'emotion';
+import tinycolor from 'tinycolor2';
+import { InlineList } from './InlineList';
+
+const ListStories = storiesOf('UI/List', module);
+
+const generateListItems = (numberOfItems: number) => {
+ return [...new Array(numberOfItems)].map((item, i) => {
+ return {
+ name: `Item-${i}`,
+ id: `item-${i}`,
+ };
+ });
+};
+
+const getStoriesKnobs = (inline = false) => {
+ const numberOfItems = number('Number of items', 3);
+ const rawRenderer = (item: any) => <>{item.name}>;
+ const customRenderer = (item: any, index: number) => (
+
+ {item.name}
+
+ );
+
+ const itemRenderer = select(
+ 'Item rendered',
+ {
+ 'Raw renderer': 'raw',
+ 'Custom renderer': 'custom',
+ },
+ 'raw'
+ );
+
+ return {
+ numberOfItems,
+ renderItem: itemRenderer === 'raw' ? rawRenderer : customRenderer,
+ };
+};
+
+ListStories.add('default', () => {
+ const { numberOfItems, renderItem } = getStoriesKnobs();
+ return
;
+});
+
+ListStories.add('inline', () => {
+ const { numberOfItems, renderItem } = getStoriesKnobs(true);
+ return ;
+});
diff --git a/packages/grafana-ui/src/components/List/List.tsx b/packages/grafana-ui/src/components/List/List.tsx
new file mode 100644
index 0000000000000..1fcc7d9ae0138
--- /dev/null
+++ b/packages/grafana-ui/src/components/List/List.tsx
@@ -0,0 +1,8 @@
+import React from 'react';
+import { ListProps, AbstractList } from './AbstractList';
+
+export class List extends React.PureComponent> {
+ render() {
+ return ;
+ }
+}
diff --git a/packages/grafana-ui/src/components/List/__snapshots__/AbstractList.test.tsx.snap b/packages/grafana-ui/src/components/List/__snapshots__/AbstractList.test.tsx.snap
new file mode 100644
index 0000000000000..b4c30ebce0683
--- /dev/null
+++ b/packages/grafana-ui/src/components/List/__snapshots__/AbstractList.test.tsx.snap
@@ -0,0 +1,93 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AbstractList allows custom item key 1`] = `
+
+
+
+
+ Item 1
+
+
+ item1
+
+
+
+
+
+
+ Item 2
+
+
+ item2
+
+
+
+
+
+
+ Item 3
+
+
+ item3
+
+
+
+
+`;
+
+exports[`AbstractList renders items using renderItem prop function 1`] = `
+
+
+
+
+ Item 1
+
+
+ item1
+
+
+
+
+
+
+ Item 2
+
+
+ item2
+
+
+
+
+
+
+ Item 3
+
+
+ item3
+
+
+
+
+`;
diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts
index c3dbfa9e9bb23..7a64318c128d3 100644
--- a/packages/grafana-ui/src/components/index.ts
+++ b/packages/grafana-ui/src/components/index.ts
@@ -22,7 +22,7 @@ export { SecretFormField } from './SecretFormFied/SecretFormField';
export { LoadingPlaceholder } from './LoadingPlaceholder/LoadingPlaceholder';
export { ColorPicker, SeriesColorPicker } from './ColorPicker/ColorPicker';
export { SeriesColorPickerPopover, SeriesColorPickerPopoverWithTheme } from './ColorPicker/SeriesColorPickerPopover';
-export { ThresholdsEditor } from './ThresholdsEditor/ThresholdsEditor';
+
export { PanelOptionsGroup } from './PanelOptionsGroup/PanelOptionsGroup';
export { PanelOptionsGrid } from './PanelOptionsGrid/PanelOptionsGrid';
export { ValueMappingsEditor } from './ValueMappingsEditor/ValueMappingsEditor';
@@ -44,8 +44,12 @@ export { TableInputCSV } from './Table/TableInputCSV';
export { BigValue } from './BigValue/BigValue';
export { Gauge } from './Gauge/Gauge';
export { Graph } from './Graph/Graph';
+export { GraphWithLegend } from './Graph/GraphWithLegend';
export { BarGauge } from './BarGauge/BarGauge';
export { VizRepeater } from './VizRepeater/VizRepeater';
+export { LegendOptions, LegendBasicOptions, LegendRenderOptions, LegendList, LegendTable } from './Legend/Legend';
+// Panel editors
+export { ThresholdsEditor } from './ThresholdsEditor/ThresholdsEditor';
export { ClickOutsideWrapper } from './ClickOutsideWrapper/ClickOutsideWrapper';
export * from './SingleStatShared/shared';
export { CallToActionCard } from './CallToActionCard/CallToActionCard';
diff --git a/packages/grafana-ui/src/types/graph.ts b/packages/grafana-ui/src/types/graph.ts
index 0e2c2361a6942..e8b2d4e1141c7 100644
--- a/packages/grafana-ui/src/types/graph.ts
+++ b/packages/grafana-ui/src/types/graph.ts
@@ -8,4 +8,6 @@ export interface GraphSeriesXY {
color: string;
data: GraphSeriesValue[][]; // [x,y][]
info?: DisplayValue[]; // Legend info
+ isVisible: boolean;
+ yAxis: number;
}
diff --git a/packages/grafana-ui/src/types/index.ts b/packages/grafana-ui/src/types/index.ts
index ab8c05138f97a..bf3b5e2995fdc 100644
--- a/packages/grafana-ui/src/types/index.ts
+++ b/packages/grafana-ui/src/types/index.ts
@@ -9,3 +9,4 @@ export * from './threshold';
export * from './input';
export * from './logs';
export * from './displayValue';
+export * from './utils';
diff --git a/packages/grafana-ui/src/types/panel.ts b/packages/grafana-ui/src/types/panel.ts
index daea7e2bf0db8..c06ea7acd42bb 100644
--- a/packages/grafana-ui/src/types/panel.ts
+++ b/packages/grafana-ui/src/types/panel.ts
@@ -1,4 +1,4 @@
-import { ComponentClass } from 'react';
+import { ComponentClass, ComponentType } from 'react';
import { LoadingState, SeriesData } from './data';
import { TimeRange } from './time';
import { ScopedVars, DataQueryRequest, DataQueryError, LegacyResponseData } from './datasource';
@@ -21,6 +21,7 @@ export interface PanelProps {
timeRange: TimeRange;
options: T;
+ onOptionsChange: (options: T) => void;
renderCounter: number;
width: number;
height: number;
@@ -53,13 +54,13 @@ export type PanelTypeChangedHandler = (
) => Partial;
export class ReactPanelPlugin {
- panel: ComponentClass>;
+ panel: ComponentType>;
editor?: ComponentClass>;
defaults?: TOptions;
onPanelMigration?: PanelMigrationHandler;
onPanelTypeChanged?: PanelTypeChangedHandler;
- constructor(panel: ComponentClass>) {
+ constructor(panel: ComponentType>) {
this.panel = panel;
}
diff --git a/packages/grafana-ui/src/types/utils.ts b/packages/grafana-ui/src/types/utils.ts
new file mode 100644
index 0000000000000..06c797ae5fad2
--- /dev/null
+++ b/packages/grafana-ui/src/types/utils.ts
@@ -0,0 +1,2 @@
+export type Omit = Pick>;
+export type Subtract = Omit;
diff --git a/packages/grafana-ui/src/utils/index.ts b/packages/grafana-ui/src/utils/index.ts
index dbd2f8a3e62e9..5d5a7b32c60eb 100644
--- a/packages/grafana-ui/src/utils/index.ts
+++ b/packages/grafana-ui/src/utils/index.ts
@@ -12,4 +12,5 @@ export * from './logs';
export * from './labels';
export { getMappedValue } from './valueMappings';
export * from './validate';
+export { getFlotPairs } from './flotPairs';
export * from './object';
diff --git a/packages/grafana-ui/src/utils/storybook/UseState.tsx b/packages/grafana-ui/src/utils/storybook/UseState.tsx
index fb9bf06bfb210..6dc3ff342f736 100644
--- a/packages/grafana-ui/src/utils/storybook/UseState.tsx
+++ b/packages/grafana-ui/src/utils/storybook/UseState.tsx
@@ -28,7 +28,6 @@ export class UseState extends React.Component, { value: T
}
handleStateUpdate = (nextState: T) => {
- console.log(nextState);
this.setState({ value: nextState });
};
diff --git a/pkg/api/playlist_play.go b/pkg/api/playlist_play.go
index 2757f245060f6..21c91a1288da6 100644
--- a/pkg/api/playlist_play.go
+++ b/pkg/api/playlist_play.go
@@ -55,7 +55,7 @@ func populateDashboardsByTag(orgID int64, signedInUser *m.SignedInUser, dashboar
Slug: item.Slug,
Title: item.Title,
Uri: item.Uri,
- Url: m.GetDashboardUrl(item.Uid, item.Slug),
+ Url: item.Url,
Order: dashboardTagOrder[tag],
})
}
diff --git a/pkg/models/stats.go b/pkg/models/stats.go
index 0edd204ec032f..994170786b045 100644
--- a/pkg/models/stats.go
+++ b/pkg/models/stats.go
@@ -51,16 +51,23 @@ type GetAlertNotifierUsageStatsQuery struct {
}
type AdminStats struct {
- Users int `json:"users"`
- Orgs int `json:"orgs"`
- Dashboards int `json:"dashboards"`
- Snapshots int `json:"snapshots"`
- Tags int `json:"tags"`
- Datasources int `json:"datasources"`
- Playlists int `json:"playlists"`
- Stars int `json:"stars"`
- Alerts int `json:"alerts"`
- ActiveUsers int `json:"activeUsers"`
+ Orgs int `json:"orgs"`
+ Dashboards int `json:"dashboards"`
+ Snapshots int `json:"snapshots"`
+ Tags int `json:"tags"`
+ Datasources int `json:"datasources"`
+ Playlists int `json:"playlists"`
+ Stars int `json:"stars"`
+ Alerts int `json:"alerts"`
+ Users int `json:"users"`
+ Admins int `json:"admins"`
+ Editors int `json:"editors"`
+ Viewers int `json:"viewers"`
+ ActiveUsers int `json:"activeUsers"`
+ ActiveAdmins int `json:"activeAdmins"`
+ ActiveEditors int `json:"activeEditors"`
+ ActiveViewers int `json:"activeViewers"`
+ ActiveSessions int `json:"activeSessions"`
}
type GetAdminStatsQuery struct {
diff --git a/pkg/services/provisioning/dashboards/config_reader.go b/pkg/services/provisioning/dashboards/config_reader.go
index c57ca1c55e153..50cedc079e331 100644
--- a/pkg/services/provisioning/dashboards/config_reader.go
+++ b/pkg/services/provisioning/dashboards/config_reader.go
@@ -24,10 +24,15 @@ func (cr *configReader) parseConfigs(file os.FileInfo) ([]*DashboardsAsConfig, e
}
apiVersion := &ConfigVersion{ApiVersion: 0}
- yaml.Unmarshal(yamlFile, &apiVersion)
- if apiVersion.ApiVersion > 0 {
+ // We ignore the error here because it errors out for version 0 which does not have apiVersion
+ // specified (so 0 is default). This can also error in case the apiVersion is not an integer but at the moment
+ // this does not handle that case and would still go on as if version = 0.
+ // TODO: return appropriate error in case the apiVersion is specified but isn't integer (or even if it is
+ // integer > max version?).
+ _ = yaml.Unmarshal(yamlFile, &apiVersion)
+ if apiVersion.ApiVersion > 0 {
v1 := &DashboardAsConfigV1{}
err := yaml.Unmarshal(yamlFile, &v1)
if err != nil {
@@ -37,7 +42,6 @@ func (cr *configReader) parseConfigs(file os.FileInfo) ([]*DashboardsAsConfig, e
if v1 != nil {
return v1.mapToDashboardAsConfig(), nil
}
-
} else {
var v0 []*DashboardsAsConfigV0
err := yaml.Unmarshal(yamlFile, &v0)
@@ -78,13 +82,23 @@ func (cr *configReader) readConfig() ([]*DashboardsAsConfig, error) {
}
}
- for i := range dashboards {
- if dashboards[i].OrgId == 0 {
- dashboards[i].OrgId = 1
+ uidUsage := map[string]uint8{}
+ for _, dashboard := range dashboards {
+ if dashboard.OrgId == 0 {
+ dashboard.OrgId = 1
}
- if dashboards[i].UpdateIntervalSeconds == 0 {
- dashboards[i].UpdateIntervalSeconds = 10
+ if dashboard.UpdateIntervalSeconds == 0 {
+ dashboard.UpdateIntervalSeconds = 10
+ }
+ if len(dashboard.FolderUid) > 0 {
+ uidUsage[dashboard.FolderUid] += 1
+ }
+ }
+
+ for uid, times := range uidUsage {
+ if times > 1 {
+ cr.log.Error("the same 'folderUid' is used more than once", "folderUid", uid)
}
}
diff --git a/pkg/services/provisioning/dashboards/config_reader_test.go b/pkg/services/provisioning/dashboards/config_reader_test.go
index d386e42349d88..18d8022d62d04 100644
--- a/pkg/services/provisioning/dashboards/config_reader_test.go
+++ b/pkg/services/provisioning/dashboards/config_reader_test.go
@@ -1,6 +1,7 @@
package dashboards
import (
+ "os"
"testing"
"github.com/grafana/grafana/pkg/log"
@@ -18,8 +19,10 @@ func TestDashboardsAsConfig(t *testing.T) {
logger := log.New("test-logger")
Convey("Can read config file version 1 format", func() {
+ _ = os.Setenv("TEST_VAR", "general")
cfgProvider := configReader{path: simpleDashboardConfig, log: logger}
cfg, err := cfgProvider.readConfig()
+ _ = os.Unsetenv("TEST_VAR")
So(err, ShouldBeNil)
validateDashboardAsConfig(t, cfg)
@@ -66,6 +69,7 @@ func validateDashboardAsConfig(t *testing.T, cfg []*DashboardsAsConfig) {
So(ds.Type, ShouldEqual, "file")
So(ds.OrgId, ShouldEqual, 2)
So(ds.Folder, ShouldEqual, "developers")
+ So(ds.FolderUid, ShouldEqual, "xyz")
So(ds.Editable, ShouldBeTrue)
So(len(ds.Options), ShouldEqual, 1)
So(ds.Options["path"], ShouldEqual, "/var/lib/grafana/dashboards")
@@ -77,6 +81,7 @@ func validateDashboardAsConfig(t *testing.T, cfg []*DashboardsAsConfig) {
So(ds2.Type, ShouldEqual, "file")
So(ds2.OrgId, ShouldEqual, 1)
So(ds2.Folder, ShouldEqual, "")
+ So(ds2.FolderUid, ShouldEqual, "")
So(ds2.Editable, ShouldBeFalse)
So(len(ds2.Options), ShouldEqual, 1)
So(ds2.Options["path"], ShouldEqual, "/var/lib/grafana/dashboards")
diff --git a/pkg/services/provisioning/dashboards/file_reader.go b/pkg/services/provisioning/dashboards/file_reader.go
index dd5f27dc2727c..b12057c963bdb 100644
--- a/pkg/services/provisioning/dashboards/file_reader.go
+++ b/pkg/services/provisioning/dashboards/file_reader.go
@@ -78,6 +78,7 @@ func (fr *fileReader) ReadAndListen(ctx context.Context) error {
}
}
+// startWalkingDisk finds and saves dashboards on disk.
func (fr *fileReader) startWalkingDisk() error {
resolvedPath := fr.resolvePath(fr.Path)
if _, err := os.Stat(resolvedPath); err != nil {
@@ -119,6 +120,7 @@ func (fr *fileReader) startWalkingDisk() error {
return nil
}
+// handleMissingDashboardFiles will unprovision or delete dashboards which are missing on disk.
func (fr *fileReader) handleMissingDashboardFiles(provisionedDashboardRefs map[string]*models.DashboardProvisioning, filesFoundOnDisk map[string]os.FileInfo) {
// find dashboards to delete since json file is missing
var dashboardToDelete []int64
@@ -151,6 +153,7 @@ func (fr *fileReader) handleMissingDashboardFiles(provisionedDashboardRefs map[s
}
}
+// saveDashboard saves or updates the dashboard provisioning file at path.
func (fr *fileReader) saveDashboard(path string, folderId int64, fileInfo os.FileInfo, provisionedDashboardRefs map[string]*models.DashboardProvisioning) (provisioningMetadata, error) {
provisioningMetadata := provisioningMetadata{}
resolvedFileInfo, err := resolveSymlink(fileInfo, path)
@@ -189,7 +192,7 @@ func (fr *fileReader) saveDashboard(path string, folderId int64, fileInfo os.Fil
dash.Dashboard.SetId(provisionedData.DashboardId)
}
- fr.log.Debug("saving new dashboard", "provisoner", fr.Cfg.Name, "file", path, "folderId", dash.Dashboard.FolderId)
+ fr.log.Debug("saving new dashboard", "provisioner", fr.Cfg.Name, "file", path, "folderId", dash.Dashboard.FolderId)
dp := &models.DashboardProvisioning{
ExternalId: path,
Name: fr.Cfg.Name,
@@ -234,6 +237,8 @@ func getOrCreateFolderId(cfg *DashboardsAsConfig, service dashboards.DashboardPr
dash.Dashboard.IsFolder = true
dash.Overwrite = true
dash.OrgId = cfg.OrgId
+ // set dashboard folderUid if given
+ dash.Dashboard.SetUid(cfg.FolderUid)
dbDash, err := service.SaveFolderForProvisionedDashboards(dash)
if err != nil {
return 0, err
diff --git a/pkg/services/provisioning/dashboards/testdata/test-configs/dashboards-from-disk/dev-dashboards.yaml b/pkg/services/provisioning/dashboards/testdata/test-configs/dashboards-from-disk/dev-dashboards.yaml
index c43c4a14c5366..42b6ecd75a5e2 100644
--- a/pkg/services/provisioning/dashboards/testdata/test-configs/dashboards-from-disk/dev-dashboards.yaml
+++ b/pkg/services/provisioning/dashboards/testdata/test-configs/dashboards-from-disk/dev-dashboards.yaml
@@ -1,9 +1,10 @@
apiVersion: 1
providers:
-- name: 'general dashboards'
+- name: '$TEST_VAR dashboards'
orgId: 2
folder: 'developers'
+ folderUid: 'xyz'
editable: true
disableDeletion: true
updateIntervalSeconds: 15
diff --git a/pkg/services/provisioning/dashboards/testdata/test-configs/version-0/version-0.yaml b/pkg/services/provisioning/dashboards/testdata/test-configs/version-0/version-0.yaml
index 8b7b8991759f0..253031ef1ceaa 100644
--- a/pkg/services/provisioning/dashboards/testdata/test-configs/version-0/version-0.yaml
+++ b/pkg/services/provisioning/dashboards/testdata/test-configs/version-0/version-0.yaml
@@ -1,6 +1,7 @@
- name: 'general dashboards'
org_id: 2
folder: 'developers'
+ folderUid: 'xyz'
editable: true
disableDeletion: true
updateIntervalSeconds: 15
diff --git a/pkg/services/provisioning/dashboards/types.go b/pkg/services/provisioning/dashboards/types.go
index a658b816c7d37..547e5a4427c26 100644
--- a/pkg/services/provisioning/dashboards/types.go
+++ b/pkg/services/provisioning/dashboards/types.go
@@ -1,6 +1,7 @@
package dashboards
import (
+ "github.com/grafana/grafana/pkg/services/provisioning/values"
"time"
"github.com/grafana/grafana/pkg/components/simplejson"
@@ -14,6 +15,7 @@ type DashboardsAsConfig struct {
Type string
OrgId int64
Folder string
+ FolderUid string
Editable bool
Options map[string]interface{}
DisableDeletion bool
@@ -25,6 +27,7 @@ type DashboardsAsConfigV0 struct {
Type string `json:"type" yaml:"type"`
OrgId int64 `json:"org_id" yaml:"org_id"`
Folder string `json:"folder" yaml:"folder"`
+ FolderUid string `json:"folderUid" yaml:"folderUid"`
Editable bool `json:"editable" yaml:"editable"`
Options map[string]interface{} `json:"options" yaml:"options"`
DisableDeletion bool `json:"disableDeletion" yaml:"disableDeletion"`
@@ -40,14 +43,15 @@ type DashboardAsConfigV1 struct {
}
type DashboardProviderConfigs struct {
- Name string `json:"name" yaml:"name"`
- Type string `json:"type" yaml:"type"`
- OrgId int64 `json:"orgId" yaml:"orgId"`
- Folder string `json:"folder" yaml:"folder"`
- Editable bool `json:"editable" yaml:"editable"`
- Options map[string]interface{} `json:"options" yaml:"options"`
- DisableDeletion bool `json:"disableDeletion" yaml:"disableDeletion"`
- UpdateIntervalSeconds int64 `json:"updateIntervalSeconds" yaml:"updateIntervalSeconds"`
+ Name values.StringValue `json:"name" yaml:"name"`
+ Type values.StringValue `json:"type" yaml:"type"`
+ OrgId values.Int64Value `json:"orgId" yaml:"orgId"`
+ Folder values.StringValue `json:"folder" yaml:"folder"`
+ FolderUid values.StringValue `json:"folderUid" yaml:"folderUid"`
+ Editable values.BoolValue `json:"editable" yaml:"editable"`
+ Options values.JSONValue `json:"options" yaml:"options"`
+ DisableDeletion values.BoolValue `json:"disableDeletion" yaml:"disableDeletion"`
+ UpdateIntervalSeconds values.Int64Value `json:"updateIntervalSeconds" yaml:"updateIntervalSeconds"`
}
func createDashboardJson(data *simplejson.Json, lastModified time.Time, cfg *DashboardsAsConfig, folderId int64) (*dashboards.SaveDashboardDTO, error) {
@@ -75,6 +79,7 @@ func mapV0ToDashboardAsConfig(v0 []*DashboardsAsConfigV0) []*DashboardsAsConfig
Type: v.Type,
OrgId: v.OrgId,
Folder: v.Folder,
+ FolderUid: v.FolderUid,
Editable: v.Editable,
Options: v.Options,
DisableDeletion: v.DisableDeletion,
@@ -90,14 +95,15 @@ func (dc *DashboardAsConfigV1) mapToDashboardAsConfig() []*DashboardsAsConfig {
for _, v := range dc.Providers {
r = append(r, &DashboardsAsConfig{
- Name: v.Name,
- Type: v.Type,
- OrgId: v.OrgId,
- Folder: v.Folder,
- Editable: v.Editable,
- Options: v.Options,
- DisableDeletion: v.DisableDeletion,
- UpdateIntervalSeconds: v.UpdateIntervalSeconds,
+ Name: v.Name.Value(),
+ Type: v.Type.Value(),
+ OrgId: v.OrgId.Value(),
+ Folder: v.Folder.Value(),
+ FolderUid: v.FolderUid.Value(),
+ Editable: v.Editable.Value(),
+ Options: v.Options.Value(),
+ DisableDeletion: v.DisableDeletion.Value(),
+ UpdateIntervalSeconds: v.UpdateIntervalSeconds.Value(),
})
}
diff --git a/pkg/services/provisioning/datasources/config_reader_test.go b/pkg/services/provisioning/datasources/config_reader_test.go
index 07c8d68e75c14..6aba826221415 100644
--- a/pkg/services/provisioning/datasources/config_reader_test.go
+++ b/pkg/services/provisioning/datasources/config_reader_test.go
@@ -1,6 +1,7 @@
package datasources
import (
+ "os"
"testing"
"github.com/grafana/grafana/pkg/bus"
@@ -146,8 +147,10 @@ func TestDatasourceAsConfig(t *testing.T) {
})
Convey("can read all properties from version 1", func() {
+ _ = os.Setenv("TEST_VAR", "name")
cfgProvifer := &configReader{log: log.New("test logger")}
cfg, err := cfgProvifer.readConfig(allProperties)
+ _ = os.Unsetenv("TEST_VAR")
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
diff --git a/pkg/services/provisioning/datasources/testdata/all-properties/all-properties.yaml b/pkg/services/provisioning/datasources/testdata/all-properties/all-properties.yaml
index b92b81f70792d..abd1253f8399f 100644
--- a/pkg/services/provisioning/datasources/testdata/all-properties/all-properties.yaml
+++ b/pkg/services/provisioning/datasources/testdata/all-properties/all-properties.yaml
@@ -1,7 +1,7 @@
apiVersion: 1
datasources:
- - name: name
+ - name: $TEST_VAR
type: type
access: proxy
orgId: 2
diff --git a/pkg/services/provisioning/datasources/types.go b/pkg/services/provisioning/datasources/types.go
index f619fd5f0054b..bbd072052dd70 100644
--- a/pkg/services/provisioning/datasources/types.go
+++ b/pkg/services/provisioning/datasources/types.go
@@ -4,6 +4,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/services/provisioning/values"
)
type ConfigVersion struct {
@@ -64,8 +65,8 @@ type DeleteDatasourceConfigV0 struct {
}
type DeleteDatasourceConfigV1 struct {
- OrgId int64 `json:"orgId" yaml:"orgId"`
- Name string `json:"name" yaml:"name"`
+ OrgId values.Int64Value `json:"orgId" yaml:"orgId"`
+ Name values.StringValue `json:"name" yaml:"name"`
}
type DataSourceFromConfigV0 struct {
@@ -89,23 +90,23 @@ type DataSourceFromConfigV0 struct {
}
type DataSourceFromConfigV1 struct {
- OrgId int64 `json:"orgId" yaml:"orgId"`
- Version int `json:"version" yaml:"version"`
- Name string `json:"name" yaml:"name"`
- Type string `json:"type" yaml:"type"`
- Access string `json:"access" yaml:"access"`
- Url string `json:"url" yaml:"url"`
- Password string `json:"password" yaml:"password"`
- User string `json:"user" yaml:"user"`
- Database string `json:"database" yaml:"database"`
- BasicAuth bool `json:"basicAuth" yaml:"basicAuth"`
- BasicAuthUser string `json:"basicAuthUser" yaml:"basicAuthUser"`
- BasicAuthPassword string `json:"basicAuthPassword" yaml:"basicAuthPassword"`
- WithCredentials bool `json:"withCredentials" yaml:"withCredentials"`
- IsDefault bool `json:"isDefault" yaml:"isDefault"`
- JsonData map[string]interface{} `json:"jsonData" yaml:"jsonData"`
- SecureJsonData map[string]string `json:"secureJsonData" yaml:"secureJsonData"`
- Editable bool `json:"editable" yaml:"editable"`
+ OrgId values.Int64Value `json:"orgId" yaml:"orgId"`
+ Version values.IntValue `json:"version" yaml:"version"`
+ Name values.StringValue `json:"name" yaml:"name"`
+ Type values.StringValue `json:"type" yaml:"type"`
+ Access values.StringValue `json:"access" yaml:"access"`
+ Url values.StringValue `json:"url" yaml:"url"`
+ Password values.StringValue `json:"password" yaml:"password"`
+ User values.StringValue `json:"user" yaml:"user"`
+ Database values.StringValue `json:"database" yaml:"database"`
+ BasicAuth values.BoolValue `json:"basicAuth" yaml:"basicAuth"`
+ BasicAuthUser values.StringValue `json:"basicAuthUser" yaml:"basicAuthUser"`
+ BasicAuthPassword values.StringValue `json:"basicAuthPassword" yaml:"basicAuthPassword"`
+ WithCredentials values.BoolValue `json:"withCredentials" yaml:"withCredentials"`
+ IsDefault values.BoolValue `json:"isDefault" yaml:"isDefault"`
+ JsonData values.JSONValue `json:"jsonData" yaml:"jsonData"`
+ SecureJsonData values.StringMapValue `json:"secureJsonData" yaml:"secureJsonData"`
+ Editable values.BoolValue `json:"editable" yaml:"editable"`
}
func (cfg *DatasourcesAsConfigV1) mapToDatasourceFromConfig(apiVersion int64) *DatasourcesAsConfig {
@@ -119,36 +120,47 @@ func (cfg *DatasourcesAsConfigV1) mapToDatasourceFromConfig(apiVersion int64) *D
for _, ds := range cfg.Datasources {
r.Datasources = append(r.Datasources, &DataSourceFromConfig{
- OrgId: ds.OrgId,
- Name: ds.Name,
- Type: ds.Type,
- Access: ds.Access,
- Url: ds.Url,
- Password: ds.Password,
- User: ds.User,
- Database: ds.Database,
- BasicAuth: ds.BasicAuth,
- BasicAuthUser: ds.BasicAuthUser,
- BasicAuthPassword: ds.BasicAuthPassword,
- WithCredentials: ds.WithCredentials,
- IsDefault: ds.IsDefault,
- JsonData: ds.JsonData,
- SecureJsonData: ds.SecureJsonData,
- Editable: ds.Editable,
- Version: ds.Version,
+ OrgId: ds.OrgId.Value(),
+ Name: ds.Name.Value(),
+ Type: ds.Type.Value(),
+ Access: ds.Access.Value(),
+ Url: ds.Url.Value(),
+ Password: ds.Password.Value(),
+ User: ds.User.Value(),
+ Database: ds.Database.Value(),
+ BasicAuth: ds.BasicAuth.Value(),
+ BasicAuthUser: ds.BasicAuthUser.Value(),
+ BasicAuthPassword: ds.BasicAuthPassword.Value(),
+ WithCredentials: ds.WithCredentials.Value(),
+ IsDefault: ds.IsDefault.Value(),
+ JsonData: ds.JsonData.Value(),
+ SecureJsonData: ds.SecureJsonData.Value(),
+ Editable: ds.Editable.Value(),
+ Version: ds.Version.Value(),
})
- if ds.Password != "" {
- cfg.log.Warn("[Deprecated] the use of password field is deprecated. Please use secureJsonData.password", "datasource name", ds.Name)
+
+ // Using Raw value for the warnings here so that even if it uses env interpolation and the env var is empty
+ // it will still warn
+ if len(ds.Password.Raw) > 0 {
+ cfg.log.Warn(
+ "[Deprecated] the use of password field is deprecated. Please use secureJsonData.password",
+ "datasource name",
+ ds.Name.Value(),
+ )
}
- if ds.BasicAuthPassword != "" {
- cfg.log.Warn("[Deprecated] the use of basicAuthPassword field is deprecated. Please use secureJsonData.basicAuthPassword", "datasource name", ds.Name)
+ if len(ds.BasicAuthPassword.Raw) > 0 {
+ cfg.log.Warn(
+ "[Deprecated] the use of basicAuthPassword field is deprecated. Please use secureJsonData.basicAuthPassword",
+ "datasource name",
+ ds.Name.Value(),
+ )
}
}
for _, ds := range cfg.DeleteDatasources {
r.DeleteDatasources = append(r.DeleteDatasources, &DeleteDatasourceConfig{
- OrgId: ds.OrgId,
- Name: ds.Name,
+ OrgId: ds.OrgId.Value(),
+ Name: ds.Name.Value(),
})
}
diff --git a/pkg/services/provisioning/notifiers/alert_notifications.go b/pkg/services/provisioning/notifiers/alert_notifications.go
index 7b595a3d32f24..3659a73832ee5 100644
--- a/pkg/services/provisioning/notifiers/alert_notifications.go
+++ b/pkg/services/provisioning/notifiers/alert_notifications.go
@@ -131,39 +131,6 @@ func (dc *NotificationProvisioner) mergeNotifications(notificationToMerge []*not
return nil
}
-func (cfg *notificationsAsConfig) mapToNotificationFromConfig() *notificationsAsConfig {
- r := ¬ificationsAsConfig{}
- if cfg == nil {
- return r
- }
-
- for _, notification := range cfg.Notifications {
- r.Notifications = append(r.Notifications, ¬ificationFromConfig{
- Uid: notification.Uid,
- OrgId: notification.OrgId,
- OrgName: notification.OrgName,
- Name: notification.Name,
- Type: notification.Type,
- IsDefault: notification.IsDefault,
- Settings: notification.Settings,
- DisableResolveMessage: notification.DisableResolveMessage,
- Frequency: notification.Frequency,
- SendReminder: notification.SendReminder,
- })
- }
-
- for _, notification := range cfg.DeleteNotifications {
- r.DeleteNotifications = append(r.DeleteNotifications, &deleteNotificationConfig{
- Uid: notification.Uid,
- OrgId: notification.OrgId,
- OrgName: notification.OrgName,
- Name: notification.Name,
- })
- }
-
- return r
-}
-
func (dc *NotificationProvisioner) applyChanges(configPath string) error {
configs, err := dc.cfgProvider.readConfig(configPath)
if err != nil {
diff --git a/pkg/services/provisioning/notifiers/config_reader.go b/pkg/services/provisioning/notifiers/config_reader.go
index c1b4cbf9f29b5..896d5105cedba 100644
--- a/pkg/services/provisioning/notifiers/config_reader.go
+++ b/pkg/services/provisioning/notifiers/config_reader.go
@@ -63,7 +63,7 @@ func (cr *configReader) parseNotificationConfig(path string, file os.FileInfo) (
return nil, err
}
- var cfg *notificationsAsConfig
+ var cfg *notificationsAsConfigV0
err = yaml.Unmarshal(yamlFile, &cfg)
if err != nil {
return nil, err
diff --git a/pkg/services/provisioning/notifiers/config_reader_test.go b/pkg/services/provisioning/notifiers/config_reader_test.go
index 87645ee7d31b4..d705bd0d93d9d 100644
--- a/pkg/services/provisioning/notifiers/config_reader_test.go
+++ b/pkg/services/provisioning/notifiers/config_reader_test.go
@@ -1,6 +1,7 @@
package notifiers
import (
+ "os"
"testing"
"github.com/grafana/grafana/pkg/log"
@@ -43,8 +44,10 @@ func TestNotificationAsConfig(t *testing.T) {
})
Convey("Can read correct properties", func() {
+ _ = os.Setenv("TEST_VAR", "default")
cfgProvifer := &configReader{log: log.New("test logger")}
cfg, err := cfgProvifer.readConfig(correct_properties)
+ _ = os.Unsetenv("TEST_VAR")
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
diff --git a/pkg/services/provisioning/notifiers/testdata/test-configs/correct-properties/correct-properties.yaml b/pkg/services/provisioning/notifiers/testdata/test-configs/correct-properties/correct-properties.yaml
index af0736f35a4a6..1d846f64473ba 100644
--- a/pkg/services/provisioning/notifiers/testdata/test-configs/correct-properties/correct-properties.yaml
+++ b/pkg/services/provisioning/notifiers/testdata/test-configs/correct-properties/correct-properties.yaml
@@ -1,5 +1,5 @@
notifiers:
- - name: default-slack-notification
+ - name: $TEST_VAR-slack-notification
type: slack
uid: notifier1
org_id: 2
@@ -39,4 +39,4 @@ delete_notifiers:
org_id: 0
uid: "notifier3"
- name: Deleted notification with whitespaces in name
- uid: "notifier4"
\ No newline at end of file
+ uid: "notifier4"
diff --git a/pkg/services/provisioning/notifiers/types.go b/pkg/services/provisioning/notifiers/types.go
index f788da79c79af..48ff9a6ce1d95 100644
--- a/pkg/services/provisioning/notifiers/types.go
+++ b/pkg/services/provisioning/notifiers/types.go
@@ -1,30 +1,61 @@
package notifiers
-import "github.com/grafana/grafana/pkg/components/simplejson"
+import (
+ "github.com/grafana/grafana/pkg/components/simplejson"
+ "github.com/grafana/grafana/pkg/services/provisioning/values"
+)
+// notificationsAsConfig is normalized data object for notifications config data. Any config version should be mappable
+// to this type.
type notificationsAsConfig struct {
- Notifications []*notificationFromConfig `json:"notifiers" yaml:"notifiers"`
- DeleteNotifications []*deleteNotificationConfig `json:"delete_notifiers" yaml:"delete_notifiers"`
+ Notifications []*notificationFromConfig
+ DeleteNotifications []*deleteNotificationConfig
}
type deleteNotificationConfig struct {
- Uid string `json:"uid" yaml:"uid"`
- Name string `json:"name" yaml:"name"`
- OrgId int64 `json:"org_id" yaml:"org_id"`
- OrgName string `json:"org_name" yaml:"org_name"`
+ Uid string
+ Name string
+ OrgId int64
+ OrgName string
}
type notificationFromConfig struct {
- Uid string `json:"uid" yaml:"uid"`
- OrgId int64 `json:"org_id" yaml:"org_id"`
- OrgName string `json:"org_name" yaml:"org_name"`
- Name string `json:"name" yaml:"name"`
- Type string `json:"type" yaml:"type"`
- SendReminder bool `json:"send_reminder" yaml:"send_reminder"`
- DisableResolveMessage bool `json:"disable_resolve_message" yaml:"disable_resolve_message"`
- Frequency string `json:"frequency" yaml:"frequency"`
- IsDefault bool `json:"is_default" yaml:"is_default"`
- Settings map[string]interface{} `json:"settings" yaml:"settings"`
+ Uid string
+ OrgId int64
+ OrgName string
+ Name string
+ Type string
+ SendReminder bool
+ DisableResolveMessage bool
+ Frequency string
+ IsDefault bool
+ Settings map[string]interface{}
+}
+
+// notificationsAsConfigV0 is mapping for zero version configs. This is mapped to its normalised version.
+type notificationsAsConfigV0 struct {
+ Notifications []*notificationFromConfigV0 `json:"notifiers" yaml:"notifiers"`
+ DeleteNotifications []*deleteNotificationConfigV0 `json:"delete_notifiers" yaml:"delete_notifiers"`
+}
+
+type deleteNotificationConfigV0 struct {
+ Uid values.StringValue `json:"uid" yaml:"uid"`
+ Name values.StringValue `json:"name" yaml:"name"`
+ OrgId values.Int64Value `json:"org_id" yaml:"org_id"`
+ OrgName values.StringValue `json:"org_name" yaml:"org_name"`
+}
+
+type notificationFromConfigV0 struct {
+ Uid values.StringValue `json:"uid" yaml:"uid"`
+ OrgId values.Int64Value `json:"org_id" yaml:"org_id"`
+ OrgName values.StringValue `json:"org_name" yaml:"org_name"`
+ Name values.StringValue `json:"name" yaml:"name"`
+ Type values.StringValue `json:"type" yaml:"type"`
+ SendReminder values.BoolValue `json:"send_reminder" yaml:"send_reminder"`
+ DisableResolveMessage values.BoolValue `json:"disable_resolve_message" yaml:"disable_resolve_message"`
+ Frequency values.StringValue `json:"frequency" yaml:"frequency"`
+ IsDefault values.BoolValue `json:"is_default" yaml:"is_default"`
+ Settings values.JSONValue `json:"settings" yaml:"settings"`
}
func (notification notificationFromConfig) SettingsToJson() *simplejson.Json {
@@ -36,3 +67,38 @@ func (notification notificationFromConfig) SettingsToJson() *simplejson.Json {
}
return settings
}
+
+// mapToNotificationFromConfig maps config syntax to normalized notificationsAsConfig object. Every version
+// of the config syntax should have this function.
+func (cfg *notificationsAsConfigV0) mapToNotificationFromConfig() *notificationsAsConfig {
+ r := ¬ificationsAsConfig{}
+ if cfg == nil {
+ return r
+ }
+
+ for _, notification := range cfg.Notifications {
+ r.Notifications = append(r.Notifications, ¬ificationFromConfig{
+ Uid: notification.Uid.Value(),
+ OrgId: notification.OrgId.Value(),
+ OrgName: notification.OrgName.Value(),
+ Name: notification.Name.Value(),
+ Type: notification.Type.Value(),
+ IsDefault: notification.IsDefault.Value(),
+ Settings: notification.Settings.Value(),
+ DisableResolveMessage: notification.DisableResolveMessage.Value(),
+ Frequency: notification.Frequency.Value(),
+ SendReminder: notification.SendReminder.Value(),
+ })
+ }
+
+ for _, notification := range cfg.DeleteNotifications {
+ r.DeleteNotifications = append(r.DeleteNotifications, &deleteNotificationConfig{
+ Uid: notification.Uid.Value(),
+ OrgId: notification.OrgId.Value(),
+ OrgName: notification.OrgName.Value(),
+ Name: notification.Name.Value(),
+ })
+ }
+
+ return r
+}
diff --git a/pkg/services/provisioning/values/values.go b/pkg/services/provisioning/values/values.go
new file mode 100644
index 0000000000000..48c7cd6444e63
--- /dev/null
+++ b/pkg/services/provisioning/values/values.go
@@ -0,0 +1,206 @@
+// A set of value types to use in provisioning. They add custom unmarshaling logic that puts the string values
+// through os.ExpandEnv.
+// Usage:
+// type Data struct {
+// Field StringValue `yaml:"field"` // Instead of string
+// }
+// d := &Data{}
+// // unmarshal into d
+// d.Field.Value() // returns the final interpolated value from the yaml file
+//
+package values
+
+import (
+ "github.com/pkg/errors"
+ "os"
+ "reflect"
+ "strconv"
+)
+
+type IntValue struct {
+ value int
+ Raw string
+}
+
+func (val *IntValue) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ interpolated, err := getInterpolated(unmarshal)
+ if err != nil {
+ return err
+ }
+ if len(interpolated.value) == 0 {
+ // To keep the same behaviour as the yaml lib which just does not set the value if it is empty.
+ return nil
+ }
+ val.Raw = interpolated.raw
+ val.value, err = strconv.Atoi(interpolated.value)
+ return errors.Wrap(err, "cannot convert value int")
+}
+
+func (val *IntValue) Value() int {
+ return val.value
+}
+
+type Int64Value struct {
+ value int64
+ Raw string
+}
+
+func (val *Int64Value) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ interpolated, err := getInterpolated(unmarshal)
+ if err != nil {
+ return err
+ }
+ if len(interpolated.value) == 0 {
+ // To keep the same behaviour as the yaml lib which just does not set the value if it is empty.
+ return nil
+ }
+ val.Raw = interpolated.raw
+ val.value, err = strconv.ParseInt(interpolated.value, 10, 64)
+ return err
+}
+
+func (val *Int64Value) Value() int64 {
+ return val.value
+}
+
+type StringValue struct {
+ value string
+ Raw string
+}
+
+func (val *StringValue) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ interpolated, err := getInterpolated(unmarshal)
+ if err != nil {
+ return err
+ }
+ val.Raw = interpolated.raw
+ val.value = interpolated.value
+ return err
+}
+
+func (val *StringValue) Value() string {
+ return val.value
+}
+
+type BoolValue struct {
+ value bool
+ Raw string
+}
+
+func (val *BoolValue) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ interpolated, err := getInterpolated(unmarshal)
+ if err != nil {
+ return err
+ }
+ val.Raw = interpolated.raw
+ val.value, err = strconv.ParseBool(interpolated.value)
+ return err
+}
+
+func (val *BoolValue) Value() bool {
+ return val.value
+}
+
+type JSONValue struct {
+ value map[string]interface{}
+ Raw map[string]interface{}
+}
+
+func (val *JSONValue) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ unmarshaled := make(map[string]interface{})
+ err := unmarshal(unmarshaled)
+ if err != nil {
+ return err
+ }
+ val.Raw = unmarshaled
+ interpolated := make(map[string]interface{})
+ for key, val := range unmarshaled {
+ interpolated[key] = tranformInterface(val)
+ }
+ val.value = interpolated
+ return err
+}
+
+func (val *JSONValue) Value() map[string]interface{} {
+ return val.value
+}
+
+type StringMapValue struct {
+ value map[string]string
+ Raw map[string]string
+}
+
+func (val *StringMapValue) UnmarshalYAML(unmarshal func(interface{}) error) error {
+ unmarshaled := make(map[string]string)
+ err := unmarshal(unmarshaled)
+ if err != nil {
+ return err
+ }
+ val.Raw = unmarshaled
+ interpolated := make(map[string]string)
+ for key, val := range unmarshaled {
+ interpolated[key] = interpolateValue(val)
+ }
+ val.value = interpolated
+ return err
+}
+
+func (val *StringMapValue) Value() map[string]string {
+ return val.value
+}
+
+// tranformInterface tries to transform any interface type into proper value with env expansion. It travers maps and
+// slices and the actual interpolation is done on all simple string values in the structure. It returns a copy of any
+// map or slice value instead of modifying them in place.
+func tranformInterface(i interface{}) interface{} {
+ switch reflect.TypeOf(i).Kind() {
+ case reflect.Slice:
+ return transformSlice(i.([]interface{}))
+ case reflect.Map:
+ return transformMap(i.(map[interface{}]interface{}))
+ case reflect.String:
+ return interpolateValue(i.(string))
+ default:
+ // Was int, float or some other value that we do not need to do any transform on.
+ return i
+ }
+}
+
+func transformSlice(i []interface{}) interface{} {
+ var transformed []interface{}
+ for _, val := range i {
+ transformed = append(transformed, tranformInterface(val))
+ }
+ return transformed
+}
+
+func transformMap(i map[interface{}]interface{}) interface{} {
+ transformed := make(map[interface{}]interface{})
+ for key, val := range i {
+ transformed[key] = tranformInterface(val)
+ }
+ return transformed
+}
+
+// interpolateValue returns final value after interpolation. At the moment only env var interpolation is done
+// here but in the future something like interpolation from file could be also done here.
+func interpolateValue(val string) string {
+ return os.ExpandEnv(val)
+}
+
+type interpolated struct {
+ value string
+ raw string
+}
+
+// getInterpolated unmarshals the value as string and runs interpolation on it. It is the responsibility of each
+// value type to convert this string value to appropriate type.
+func getInterpolated(unmarshal func(interface{}) error) (*interpolated, error) {
+ var raw string
+ err := unmarshal(&raw)
+ if err != nil {
+ return &interpolated{}, err
+ }
+ value := interpolateValue(raw)
+ return &interpolated{raw: raw, value: value}, nil
+}
diff --git a/pkg/services/provisioning/values/values_test.go b/pkg/services/provisioning/values/values_test.go
new file mode 100644
index 0000000000000..284069be39584
--- /dev/null
+++ b/pkg/services/provisioning/values/values_test.go
@@ -0,0 +1,210 @@
+package values
+
+import (
+ . "github.com/smartystreets/goconvey/convey"
+ "gopkg.in/yaml.v2"
+ "os"
+ "testing"
+)
+
+func TestValues(t *testing.T) {
+ Convey("Values", t, func() {
+ os.Setenv("INT", "1")
+ os.Setenv("STRING", "test")
+ os.Setenv("BOOL", "true")
+
+ Convey("IntValue", func() {
+ type Data struct {
+ Val IntValue `yaml:"val"`
+ }
+ d := &Data{}
+
+ Convey("Should unmarshal simple number", func() {
+ unmarshalingTest(`val: 1`, d)
+ So(d.Val.Value(), ShouldEqual, 1)
+ So(d.Val.Raw, ShouldEqual, "1")
+ })
+
+ Convey("Should unmarshal env var", func() {
+ unmarshalingTest(`val: $INT`, d)
+ So(d.Val.Value(), ShouldEqual, 1)
+ So(d.Val.Raw, ShouldEqual, "$INT")
+ })
+
+ Convey("Should ignore empty value", func() {
+ unmarshalingTest(`val: `, d)
+ So(d.Val.Value(), ShouldEqual, 0)
+ So(d.Val.Raw, ShouldEqual, "")
+ })
+ })
+
+ Convey("StringValue", func() {
+ type Data struct {
+ Val StringValue `yaml:"val"`
+ }
+ d := &Data{}
+
+ Convey("Should unmarshal simple string", func() {
+ unmarshalingTest(`val: test`, d)
+ So(d.Val.Value(), ShouldEqual, "test")
+ So(d.Val.Raw, ShouldEqual, "test")
+ })
+
+ Convey("Should unmarshal env var", func() {
+ unmarshalingTest(`val: $STRING`, d)
+ So(d.Val.Value(), ShouldEqual, "test")
+ So(d.Val.Raw, ShouldEqual, "$STRING")
+ })
+
+ Convey("Should ignore empty value", func() {
+ unmarshalingTest(`val: `, d)
+ So(d.Val.Value(), ShouldEqual, "")
+ So(d.Val.Raw, ShouldEqual, "")
+ })
+ })
+
+ Convey("BoolValue", func() {
+ type Data struct {
+ Val BoolValue `yaml:"val"`
+ }
+ d := &Data{}
+
+ Convey("Should unmarshal bool value", func() {
+ unmarshalingTest(`val: true`, d)
+ So(d.Val.Value(), ShouldBeTrue)
+ So(d.Val.Raw, ShouldEqual, "true")
+ })
+
+ Convey("Should unmarshal explicit string", func() {
+ unmarshalingTest(`val: "true"`, d)
+ So(d.Val.Value(), ShouldBeTrue)
+ So(d.Val.Raw, ShouldEqual, "true")
+ })
+
+ Convey("Should unmarshal env var", func() {
+ unmarshalingTest(`val: $BOOL`, d)
+ So(d.Val.Value(), ShouldBeTrue)
+ So(d.Val.Raw, ShouldEqual, "$BOOL")
+ })
+
+ Convey("Should ignore empty value", func() {
+ unmarshalingTest(`val: `, d)
+ So(d.Val.Value(), ShouldBeFalse)
+ So(d.Val.Raw, ShouldEqual, "")
+ })
+ })
+
+ Convey("JSONValue", func() {
+
+ type Data struct {
+ Val JSONValue `yaml:"val"`
+ }
+ d := &Data{}
+
+ Convey("Should unmarshal variable nesting", func() {
+ doc := `
+ val:
+ one: 1
+ two: $STRING
+ three:
+ - 1
+ - two
+ - three:
+ inside: $STRING
+ four:
+ nested:
+ onemore: $INT
+ multiline: >
+ Some text with $STRING
+ anchor: &label $INT
+ anchored: *label
+ `
+ unmarshalingTest(doc, d)
+
+ type anyMap = map[interface{}]interface{}
+ So(d.Val.Value(), ShouldResemble, map[string]interface{}{
+ "one": 1,
+ "two": "test",
+ "three": []interface{}{
+ 1, "two", anyMap{
+ "three": anyMap{
+ "inside": "test",
+ },
+ },
+ },
+ "four": anyMap{
+ "nested": anyMap{
+ "onemore": "1",
+ },
+ },
+ "multiline": "Some text with test\n",
+ "anchor": "1",
+ "anchored": "1",
+ })
+
+ So(d.Val.Raw, ShouldResemble, map[string]interface{}{
+ "one": 1,
+ "two": "$STRING",
+ "three": []interface{}{
+ 1, "two", anyMap{
+ "three": anyMap{
+ "inside": "$STRING",
+ },
+ },
+ },
+ "four": anyMap{
+ "nested": anyMap{
+ "onemore": "$INT",
+ },
+ },
+ "multiline": "Some text with $STRING\n",
+ "anchor": "$INT",
+ "anchored": "$INT",
+ })
+ })
+ })
+
+ Convey("StringMapValue", func() {
+ type Data struct {
+ Val StringMapValue `yaml:"val"`
+ }
+ d := &Data{}
+
+ Convey("Should unmarshal mapping", func() {
+ doc := `
+ val:
+ one: 1
+ two: "test string"
+ three: $STRING
+ four: true
+ `
+ unmarshalingTest(doc, d)
+ So(d.Val.Value(), ShouldResemble, map[string]string{
+ "one": "1",
+ "two": "test string",
+ "three": "test",
+ "four": "true",
+ })
+
+ So(d.Val.Raw, ShouldResemble, map[string]string{
+ "one": "1",
+ "two": "test string",
+ "three": "$STRING",
+ "four": "true",
+ })
+
+ })
+ })
+
+ Reset(func() {
+ os.Unsetenv("INT")
+ os.Unsetenv("STRING")
+ os.Unsetenv("BOOL")
+ })
+ })
+}
+
+func unmarshalingTest(document string, out interface{}) {
+ err := yaml.Unmarshal([]byte(document), out)
+ So(err, ShouldBeNil)
+}
diff --git a/pkg/services/sqlstore/dashboard_acl.go b/pkg/services/sqlstore/dashboard_acl.go
index 0b195c4562b8a..31015ff932f13 100644
--- a/pkg/services/sqlstore/dashboard_acl.go
+++ b/pkg/services/sqlstore/dashboard_acl.go
@@ -112,7 +112,7 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error {
LEFT JOIN ` + dialect.Quote("user") + ` AS u ON u.id = da.user_id
LEFT JOIN team ug on ug.id = da.team_id
WHERE d.org_id = ? AND d.id = ? AND da.id IS NOT NULL
- ORDER BY 1 ASC
+ ORDER BY da.id ASC
`
query.Result = make([]*m.DashboardAclInfoDTO, 0)
diff --git a/pkg/services/sqlstore/stars_test.go b/pkg/services/sqlstore/stars_test.go
index 4e48dfdbcb35c..43a612c1a5b8a 100644
--- a/pkg/services/sqlstore/stars_test.go
+++ b/pkg/services/sqlstore/stars_test.go
@@ -36,7 +36,6 @@ func TestUserStarsDataAccess(t *testing.T) {
So(query.Result, ShouldBeFalse)
})
-
})
})
}
diff --git a/pkg/services/sqlstore/stats.go b/pkg/services/sqlstore/stats.go
index 2b7c35a4b4ad2..a1191cb21c8ee 100644
--- a/pkg/services/sqlstore/stats.go
+++ b/pkg/services/sqlstore/stats.go
@@ -89,52 +89,84 @@ func GetSystemStats(query *m.GetSystemStatsQuery) error {
}
func GetAdminStats(query *m.GetAdminStatsQuery) error {
+ activeEndDate := time.Now().Add(-activeUserTimeLimit)
+ roleCounter := func(role, alias string) string {
+ sql :=
+ `
+ (
+ SELECT COUNT(*)
+ FROM ` + dialect.Quote("user") + ` as u
+ WHERE
+ (SELECT COUNT(*)
+ FROM org_user
+ WHERE org_user.user_id=u.id
+ AND org_user.role='` + role + `')>0
+ ) as ` + alias + `,
+ (
+ SELECT COUNT(*)
+ FROM ` + dialect.Quote("user") + ` as u
+ WHERE
+ (SELECT COUNT(*)
+ FROM org_user
+ WHERE org_user.user_id=u.id
+ AND org_user.role='` + role + `')>0
+ AND u.last_seen_at>?
+ ) as active_` + alias
+
+ return sql
+ }
+
var rawSql = `SELECT
- (
- SELECT COUNT(*)
- FROM ` + dialect.Quote("user") + `
- ) AS users,
- (
+ (
SELECT COUNT(*)
FROM ` + dialect.Quote("org") + `
- ) AS orgs,
- (
+ ) AS orgs,
+ (
SELECT COUNT(*)
FROM ` + dialect.Quote("dashboard") + `
- ) AS dashboards,
- (
+ ) AS dashboards,
+ (
SELECT COUNT(*)
FROM ` + dialect.Quote("dashboard_snapshot") + `
- ) AS snapshots,
- (
+ ) AS snapshots,
+ (
SELECT COUNT( DISTINCT ( ` + dialect.Quote("term") + ` ))
FROM ` + dialect.Quote("dashboard_tag") + `
- ) AS tags,
- (
+ ) AS tags,
+ (
SELECT COUNT(*)
FROM ` + dialect.Quote("data_source") + `
- ) AS datasources,
- (
+ ) AS datasources,
+ (
SELECT COUNT(*)
FROM ` + dialect.Quote("playlist") + `
- ) AS playlists,
- (
+ ) AS playlists,
+ (
SELECT COUNT(*) FROM ` + dialect.Quote("star") + `
- ) AS stars,
- (
+ ) AS stars,
+ (
SELECT COUNT(*)
FROM ` + dialect.Quote("alert") + `
- ) AS alerts,
- (
- SELECT COUNT(*)
- from ` + dialect.Quote("user") + ` where last_seen_at > ?
- ) as active_users
+ ) AS alerts,
+ (
+ SELECT COUNT(*)
+ FROM ` + dialect.Quote("user") + `
+ ) AS users,
+ (
+ SELECT COUNT(*)
+ FROM ` + dialect.Quote("user") + ` where last_seen_at > ?
+ ) as active_users,
+ ` + roleCounter("Admin", "admins") + `,
+ ` + roleCounter("Editor", "editors") + `,
+ ` + roleCounter("Viewer", "viewers") + `,
+ (
+ SELECT COUNT(*)
+ FROM ` + dialect.Quote("user_auth_token") + ` where rotated_at > ?
+ ) as active_sessions
`
- activeUserDeadlineDate := time.Now().Add(-activeUserTimeLimit)
-
var stats m.AdminStats
- _, err := x.SQL(rawSql, activeUserDeadlineDate).Get(&stats)
+ _, err := x.SQL(rawSql, activeEndDate, activeEndDate, activeEndDate, activeEndDate, activeEndDate.Unix()).Get(&stats)
if err != nil {
return err
}
diff --git a/pkg/services/sqlstore/stats_test.go b/pkg/services/sqlstore/stats_test.go
index 6949a0dbda2d9..38396aef5b058 100644
--- a/pkg/services/sqlstore/stats_test.go
+++ b/pkg/services/sqlstore/stats_test.go
@@ -4,43 +4,48 @@ import (
"context"
"testing"
- m "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
)
func TestStatsDataAccess(t *testing.T) {
-
Convey("Testing Stats Data Access", t, func() {
InitTestDB(t)
Convey("Get system stats should not results in error", func() {
- query := m.GetSystemStatsQuery{}
+ query := models.GetSystemStatsQuery{}
err := GetSystemStats(&query)
So(err, ShouldBeNil)
})
Convey("Get system user count stats should not results in error", func() {
- query := m.GetSystemUserCountStatsQuery{}
+ query := models.GetSystemUserCountStatsQuery{}
err := GetSystemUserCountStats(context.Background(), &query)
So(err, ShouldBeNil)
})
Convey("Get datasource stats should not results in error", func() {
- query := m.GetDataSourceStatsQuery{}
+ query := models.GetDataSourceStatsQuery{}
err := GetDataSourceStats(&query)
So(err, ShouldBeNil)
})
Convey("Get datasource access stats should not results in error", func() {
- query := m.GetDataSourceAccessStatsQuery{}
+ query := models.GetDataSourceAccessStatsQuery{}
err := GetDataSourceAccessStats(&query)
So(err, ShouldBeNil)
})
Convey("Get alert notifier stats should not results in error", func() {
- query := m.GetAlertNotifierUsageStatsQuery{}
+ query := models.GetAlertNotifierUsageStatsQuery{}
err := GetAlertNotifiersUsageStats(context.Background(), &query)
So(err, ShouldBeNil)
})
+
+ Convey("Get admin stats should not result in error", func() {
+ query := models.GetAdminStatsQuery{}
+ err := GetAdminStats(&query)
+ So(err, ShouldBeNil)
+ })
})
}
diff --git a/pkg/tsdb/cloudwatch/cloudwatch.go b/pkg/tsdb/cloudwatch/cloudwatch.go
index ab9c5ce8335fb..56e9bd30e98b0 100644
--- a/pkg/tsdb/cloudwatch/cloudwatch.go
+++ b/pkg/tsdb/cloudwatch/cloudwatch.go
@@ -228,5 +228,9 @@ func formatAlias(query *CloudWatchQuery, stat string, dimensions map[string]stri
return in
})
+ if string(result) == "" {
+ return metricName + "_" + stat
+ }
+
return string(result)
}
diff --git a/public/app/features/admin/__snapshots__/ServerStats.test.tsx.snap b/public/app/features/admin/__snapshots__/ServerStats.test.tsx.snap
index da9a80aeb674c..23d4d714559d3 100644
--- a/public/app/features/admin/__snapshots__/ServerStats.test.tsx.snap
+++ b/public/app/features/admin/__snapshots__/ServerStats.test.tsx.snap
@@ -212,7 +212,7 @@ exports[`ServerStats Should render table with stats 1`] = `
=> {
const res = await getBackendSrv().get('api/admin/stats');
return [
{ name: 'Total users', value: res.users },
- { name: 'Total dashboards', value: res.dashboards },
+ { name: 'Total admins', value: res.admins },
+ { name: 'Total editors', value: res.editors },
+ { name: 'Total viewers', value: res.viewers },
{ name: 'Active users (seen last 30 days)', value: res.activeUsers },
+ { name: 'Active admins (seen last 30 days)', value: res.activeAdmins },
+ { name: 'Active editors (seen last 30 days)', value: res.activeEditors },
+ { name: 'Active viewers (seen last 30 days)', value: res.activeViewers },
+ { name: 'Active sessions', value: res.activeSessions },
+ { name: 'Total dashboards', value: res.dashboards },
{ name: 'Total orgs', value: res.orgs },
{ name: 'Total playlists', value: res.playlists },
{ name: 'Total snapshots', value: res.snapshots },
diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.tsx
index d4f6c62294860..c69e7be0c4e63 100644
--- a/public/app/features/dashboard/dashgrid/PanelChrome.tsx
+++ b/public/app/features/dashboard/dashgrid/PanelChrome.tsx
@@ -22,7 +22,7 @@ import { ScopedVars } from '@grafana/ui';
import templateSrv from 'app/features/templating/template_srv';
-import { getProcessedSeriesData } from '../state/PanelQueryRunner';
+import { getProcessedSeriesData } from '../state/PanelQueryState';
import { Unsubscribable } from 'rxjs';
const DEFAULT_PLUGIN_ERROR = 'Error in plugin';
@@ -48,6 +48,7 @@ export interface State {
export class PanelChrome extends PureComponent
{
timeSrv: TimeSrv = getTimeSrv();
querySubscription: Unsubscribable;
+ delayedStateUpdate: Partial;
constructor(props: Props) {
super(props);
@@ -118,7 +119,15 @@ export class PanelChrome extends PureComponent {
}
}
- this.setState({ isFirstLoad, errorMessage, data });
+ const stateUpdate = { isFirstLoad, errorMessage, data };
+
+ if (this.isVisible) {
+ this.setState(stateUpdate);
+ } else {
+ // if we are getting data while another panel is in fullscreen / edit mode
+ // we need to store the data but not update state yet
+ this.delayedStateUpdate = stateUpdate;
+ }
},
};
@@ -162,9 +171,19 @@ export class PanelChrome extends PureComponent {
};
onRender = () => {
- this.setState({
- renderCounter: this.state.renderCounter + 1,
- });
+ const stateUpdate = { renderCounter: this.state.renderCounter + 1 };
+
+ // If we have received a data update while hidden copy over that state as well
+ if (this.delayedStateUpdate) {
+ Object.assign(stateUpdate, this.delayedStateUpdate);
+ this.delayedStateUpdate = null;
+ }
+
+ this.setState(stateUpdate);
+ };
+
+ onOptionsChange = (options: any) => {
+ this.props.panel.updateOptions(options);
};
replaceVariables = (value: string, extraVars?: ScopedVars, format?: string) => {
@@ -223,6 +242,7 @@ export class PanelChrome extends PureComponent {
height={height - PANEL_HEADER_HEIGHT - config.theme.panelPadding.vertical}
renderCounter={renderCounter}
replaceVariables={this.replaceVariables}
+ onOptionsChange={this.onOptionsChange}
/>
>
diff --git a/public/app/features/dashboard/state/PanelQueryRunner.test.ts b/public/app/features/dashboard/state/PanelQueryRunner.test.ts
index 33db473b1d014..9286d7d73468d 100644
--- a/public/app/features/dashboard/state/PanelQueryRunner.test.ts
+++ b/public/app/features/dashboard/state/PanelQueryRunner.test.ts
@@ -1,43 +1,7 @@
-import { getProcessedSeriesData, PanelQueryRunner } from './PanelQueryRunner';
+import { PanelQueryRunner } from './PanelQueryRunner';
import { PanelData, DataQueryRequest } from '@grafana/ui/src/types';
import moment from 'moment';
-describe('PanelQueryRunner', () => {
- it('converts timeseries to table skipping nulls', () => {
- const input1 = {
- target: 'Field Name',
- datapoints: [[100, 1], [200, 2]],
- };
- const input2 = {
- // without target
- target: '',
- datapoints: [[100, 1], [200, 2]],
- };
- const data = getProcessedSeriesData([null, input1, input2, null, null]);
- expect(data.length).toBe(2);
- expect(data[0].fields[0].name).toBe(input1.target);
- expect(data[0].rows).toBe(input1.datapoints);
-
- // Default name
- expect(data[1].fields[0].name).toEqual('Value');
-
- // Every colun should have a name and a type
- for (const table of data) {
- for (const column of table.fields) {
- expect(column.name).toBeDefined();
- expect(column.type).toBeDefined();
- }
- }
- });
-
- it('supports null values from query OK', () => {
- expect(getProcessedSeriesData([null, null, null, null])).toEqual([]);
- expect(getProcessedSeriesData(undefined)).toEqual([]);
- expect(getProcessedSeriesData((null as unknown) as any[])).toEqual([]);
- expect(getProcessedSeriesData([])).toEqual([]);
- });
-});
-
interface ScenarioContext {
setup: (fn: () => void) => void;
maxDataPoints?: number | null;
diff --git a/public/app/features/dashboard/state/PanelQueryRunner.ts b/public/app/features/dashboard/state/PanelQueryRunner.ts
index 496ece9a84073..848ccfc2204f5 100644
--- a/public/app/features/dashboard/state/PanelQueryRunner.ts
+++ b/public/app/features/dashboard/state/PanelQueryRunner.ts
@@ -7,21 +7,11 @@ import { Subject, Unsubscribable, PartialObserver } from 'rxjs';
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
import kbn from 'app/core/utils/kbn';
import templateSrv from 'app/features/templating/template_srv';
-
-// Components & Types
-import {
- guessFieldTypes,
- toSeriesData,
- PanelData,
- DataQuery,
- TimeRange,
- ScopedVars,
- DataQueryRequest,
- SeriesData,
- DataSourceApi,
-} from '@grafana/ui';
import { PanelQueryState } from './PanelQueryState';
+// Types
+import { PanelData, DataQuery, TimeRange, ScopedVars, DataQueryRequest, DataSourceApi } from '@grafana/ui';
+
export interface QueryRunnerOptions {
datasource: string | DataSourceApi;
queries: TQuery[];
@@ -107,6 +97,9 @@ export class PanelQueryRunner {
delayStateNotification,
} = options;
+ // filter out hidden queries & deep clone them
+ const clonedAndFilteredQueries = cloneDeep(queries.filter(q => !q.hide));
+
const request: DataQueryRequest = {
requestId: getNextRequestId(),
timezone,
@@ -116,26 +109,20 @@ export class PanelQueryRunner {
timeInfo,
interval: '',
intervalMs: 0,
- targets: cloneDeep(
- queries.filter(q => {
- return !q.hide; // Skip any hidden queries
- })
- ),
+ targets: clonedAndFilteredQueries,
maxDataPoints: maxDataPoints || widthPixels,
scopedVars: scopedVars || {},
cacheTimeout,
startTime: Date.now(),
};
- // Deprecated
+
+ // Add deprecated property
(request as any).rangeRaw = timeRange.raw;
let loadingStateTimeoutId = 0;
try {
- const ds =
- datasource && (datasource as any).query
- ? (datasource as DataSourceApi)
- : await getDatasourceSrv().get(datasource as string, request.scopedVars);
+ const ds = await getDataSource(datasource, request.scopedVars);
// Attach the datasource name to each query
request.targets = request.targets.map(query => {
@@ -218,22 +205,12 @@ export class PanelQueryRunner {
}
}
-/**
- * All panels will be passed tables that have our best guess at colum type set
- *
- * This is also used by PanelChrome for snapshot support
- */
-export function getProcessedSeriesData(results?: any[]): SeriesData[] {
- if (!results) {
- return [];
+async function getDataSource(
+ datasource: string | DataSourceApi | null,
+ scopedVars: ScopedVars
+): Promise {
+ if (datasource && (datasource as any).query) {
+ return datasource as DataSourceApi;
}
-
- const series: SeriesData[] = [];
- for (const r of results) {
- if (r) {
- series.push(guessFieldTypes(toSeriesData(r)));
- }
- }
-
- return series;
+ return await getDatasourceSrv().get(datasource as string, scopedVars);
}
diff --git a/public/app/features/dashboard/state/PanelQueryState.test.ts b/public/app/features/dashboard/state/PanelQueryState.test.ts
index 6d7004a931042..894a770201109 100644
--- a/public/app/features/dashboard/state/PanelQueryState.test.ts
+++ b/public/app/features/dashboard/state/PanelQueryState.test.ts
@@ -1,4 +1,4 @@
-import { toDataQueryError, PanelQueryState } from './PanelQueryState';
+import { toDataQueryError, PanelQueryState, getProcessedSeriesData } from './PanelQueryState';
import { MockDataSourceApi } from 'test/mocks/datasource_srv';
import { DataQueryResponse } from '@grafana/ui';
import { getQueryOptions } from 'test/helpers/getQueryOptions';
@@ -44,3 +44,39 @@ describe('PanelQueryState', () => {
expect(hasRun).toBeFalsy();
});
});
+
+describe('getProcessedSeriesData', () => {
+ it('converts timeseries to table skipping nulls', () => {
+ const input1 = {
+ target: 'Field Name',
+ datapoints: [[100, 1], [200, 2]],
+ };
+ const input2 = {
+ // without target
+ target: '',
+ datapoints: [[100, 1], [200, 2]],
+ };
+ const data = getProcessedSeriesData([null, input1, input2, null, null]);
+ expect(data.length).toBe(2);
+ expect(data[0].fields[0].name).toBe(input1.target);
+ expect(data[0].rows).toBe(input1.datapoints);
+
+ // Default name
+ expect(data[1].fields[0].name).toEqual('Value');
+
+ // Every colun should have a name and a type
+ for (const table of data) {
+ for (const column of table.fields) {
+ expect(column.name).toBeDefined();
+ expect(column.type).toBeDefined();
+ }
+ }
+ });
+
+ it('supports null values from query OK', () => {
+ expect(getProcessedSeriesData([null, null, null, null])).toEqual([]);
+ expect(getProcessedSeriesData(undefined)).toEqual([]);
+ expect(getProcessedSeriesData((null as unknown) as any[])).toEqual([]);
+ expect(getProcessedSeriesData([])).toEqual([]);
+ });
+});
diff --git a/public/app/features/dashboard/state/PanelQueryState.ts b/public/app/features/dashboard/state/PanelQueryState.ts
index 2e52835ec7a82..e5ae946e612ac 100644
--- a/public/app/features/dashboard/state/PanelQueryState.ts
+++ b/public/app/features/dashboard/state/PanelQueryState.ts
@@ -1,21 +1,25 @@
+// Libraries
import isString from 'lodash/isString';
+import isEqual from 'lodash/isEqual';
+
+// Utils & Services
+import { getBackendSrv } from 'app/core/services/backend_srv';
+import * as dateMath from 'app/core/utils/datemath';
+import { guessFieldTypes, toSeriesData, isSeriesData } from '@grafana/ui/src/utils';
+
+// Types
import {
DataSourceApi,
DataQueryRequest,
PanelData,
LoadingState,
toLegacyResponseData,
- isSeriesData,
- toSeriesData,
DataQueryError,
DataStreamObserver,
DataStreamState,
SeriesData,
+ DataQueryResponseData,
} from '@grafana/ui';
-import { getProcessedSeriesData } from './PanelQueryRunner';
-import { getBackendSrv } from 'app/core/services/backend_srv';
-import isEqual from 'lodash/isEqual';
-import * as dateMath from 'app/core/utils/datemath';
export class PanelQueryState {
// The current/last running request
@@ -70,9 +74,10 @@ export class PanelQueryState {
cancel(reason: string) {
const { request } = this;
try {
+ // If no endTime the call to datasource.query did not complete
+ // call rejector to reject the executor promise
if (!request.endTime) {
request.endTime = Date.now();
-
this.rejector('Canceled:' + reason);
}
@@ -107,7 +112,7 @@ export class PanelQueryState {
// Set the loading state immediatly
this.response.state = LoadingState.Loading;
- return (this.executor = new Promise((resolve, reject) => {
+ this.executor = new Promise((resolve, reject) => {
this.rejector = reject;
return ds
@@ -125,21 +130,16 @@ export class PanelQueryState {
state: LoadingState.Done,
request: this.request,
series: this.sendSeries ? getProcessedSeriesData(resp.data) : [],
- legacy: this.sendLegacy
- ? resp.data.map(v => {
- if (isSeriesData(v)) {
- return toLegacyResponseData(v);
- }
- return v;
- })
- : undefined,
+ legacy: this.sendLegacy ? translateToLegacyData(resp.data) : undefined,
};
resolve(this.getPanelData());
})
.catch(err => {
resolve(this.setError(err));
});
- }));
+ });
+
+ return this.executor;
}
// Send a notice when the stream has updated the current model
@@ -168,35 +168,43 @@ export class PanelQueryState {
}
active.push(stream);
}
+
this.streams = active;
this.streamCallback();
};
closeStreams(keepSeries = false) {
- if (this.streams.length) {
- const series: SeriesData[] = [];
- for (const stream of this.streams) {
- if (stream.series) {
- series.push.apply(series, stream.series);
- }
- try {
- stream.unsubscribe();
- } catch {}
+ if (!this.streams.length) {
+ return;
+ }
+
+ const series: SeriesData[] = [];
+
+ for (const stream of this.streams) {
+ if (stream.series) {
+ series.push.apply(series, stream.series);
}
- this.streams = [];
-
- // Move the series from streams to the resposne
- if (keepSeries) {
- const { response } = this;
- this.response = {
- ...response,
- series: [
- ...response.series,
- ...series, // Append the streamed series
- ],
- };
+
+ try {
+ stream.unsubscribe();
+ } catch {
+ console.log('Failed to unsubscribe to stream');
}
}
+
+ this.streams = [];
+
+ // Move the series from streams to the resposne
+ if (keepSeries) {
+ const { response } = this;
+ this.response = {
+ ...response,
+ series: [
+ ...response.series,
+ ...series, // Append the streamed series
+ ],
+ };
+ }
}
getPanelData(): PanelData {
@@ -213,6 +221,7 @@ export class PanelQueryState {
let done = this.isFinished(response.state);
const series = [...response.series];
const active: DataStreamState[] = [];
+
for (const stream of this.streams) {
if (shouldDisconnect(request, stream)) {
stream.unsubscribe();
@@ -221,10 +230,12 @@ export class PanelQueryState {
active.push(stream);
series.push.apply(series, stream.series);
+
if (!this.isFinished(stream.state)) {
done = false;
}
}
+
this.streams = active;
// Update the time range
@@ -240,7 +251,7 @@ export class PanelQueryState {
return {
state: done ? LoadingState.Done : LoadingState.Streaming,
series, // Union of series from response and all streams
- legacy: this.sendLegacy ? series.map(s => toLegacyResponseData(s)) : undefined,
+ legacy: this.sendLegacy ? translateToLegacyData(series) : undefined,
request: {
...this.request,
range: timeRange, // update the time range
@@ -309,3 +320,32 @@ export function toDataQueryError(err: any): DataQueryError {
}
return error;
}
+
+function translateToLegacyData(data: DataQueryResponseData) {
+ return data.map(v => {
+ if (isSeriesData(v)) {
+ return toLegacyResponseData(v);
+ }
+ return v;
+ });
+}
+
+/**
+ * All panels will be passed tables that have our best guess at colum type set
+ *
+ * This is also used by PanelChrome for snapshot support
+ */
+export function getProcessedSeriesData(results?: any[]): SeriesData[] {
+ if (!results) {
+ return [];
+ }
+
+ const series: SeriesData[] = [];
+ for (const r of results) {
+ if (r) {
+ series.push(guessFieldTypes(toSeriesData(r)));
+ }
+ }
+
+ return series;
+}
diff --git a/public/app/plugins/datasource/testdata/StreamHandler.ts b/public/app/plugins/datasource/testdata/StreamHandler.ts
index 825b11d8cd8fd..9b97cc3ef5d34 100644
--- a/public/app/plugins/datasource/testdata/StreamHandler.ts
+++ b/public/app/plugins/datasource/testdata/StreamHandler.ts
@@ -27,33 +27,40 @@ export class StreamHandler {
process(req: DataQueryRequest, observer: DataStreamObserver): DataQueryResponse | undefined {
let resp: DataQueryResponse;
+
for (const query of req.targets) {
- if ('streaming_client' === query.scenarioId) {
- if (!resp) {
- resp = { data: [] };
- }
- query.stream = defaults(query.stream, defaultQuery);
-
- const key = req.dashboardId + '/' + req.panelId + '/' + query.refId;
- if (this.workers[key]) {
- const existing = this.workers[key];
- if (existing.update(query, req)) {
- continue;
- }
- existing.unsubscribe();
- delete this.workers[key];
- }
- const type = query.stream.type;
- if (type === 'signal') {
- this.workers[key] = new SignalWorker(key, query, req, observer);
- } else if (type === 'logs') {
- this.workers[key] = new LogsWorker(key, query, req, observer);
- } else {
- throw {
- message: 'Unknown Stream type: ' + type,
- refId: query.refId,
- } as DataQueryError;
+ if ('streaming_client' !== query.scenarioId) {
+ continue;
+ }
+
+ if (!resp) {
+ resp = { data: [] };
+ }
+
+ // set stream option defaults
+ query.stream = defaults(query.stream, defaultQuery);
+ // create stream key
+ const key = req.dashboardId + '/' + req.panelId + '/' + query.refId;
+
+ if (this.workers[key]) {
+ const existing = this.workers[key];
+ if (existing.update(query, req)) {
+ continue;
}
+ existing.unsubscribe();
+ delete this.workers[key];
+ }
+
+ const type = query.stream.type;
+ if (type === 'signal') {
+ this.workers[key] = new SignalWorker(key, query, req, observer);
+ } else if (type === 'logs') {
+ this.workers[key] = new LogsWorker(key, query, req, observer);
+ } else {
+ throw {
+ message: 'Unknown Stream type: ' + type,
+ refId: query.refId,
+ } as DataQueryError;
}
}
return resp;
@@ -92,7 +99,8 @@ export class StreamWorker {
};
update(query: TestDataQuery, request: DataQueryRequest): boolean {
- if (this.query.type !== query.stream.type) {
+ // Check if stream has been unsubscribed or query changed type
+ if (this.observer === null || this.query.type !== query.stream.type) {
return false;
}
this.query = query.stream;
@@ -121,7 +129,10 @@ export class StreamWorker {
// Broadcast the changes
if (this.observer) {
this.observer(stream);
+ } else {
+ console.log('StreamWorker working without any observer');
}
+
this.last = Date.now();
}
}
@@ -131,7 +142,7 @@ export class SignalWorker extends StreamWorker {
constructor(key: string, query: TestDataQuery, request: DataQueryRequest, observer: DataStreamObserver) {
super(key, query, request, observer);
- window.setTimeout(() => {
+ setTimeout(() => {
this.stream.series = [this.initBuffer(query.refId)];
this.looper();
}, 10);
diff --git a/public/app/plugins/panel/graph/Legend/Legend.tsx b/public/app/plugins/panel/graph/Legend/Legend.tsx
index 8702bdac85934..c20623f8c0ed0 100644
--- a/public/app/plugins/panel/graph/Legend/Legend.tsx
+++ b/public/app/plugins/panel/graph/Legend/Legend.tsx
@@ -311,7 +311,7 @@ class LegendTableHeaderItem extends PureComponent {
render() {
return (
-
}>
+
);
diff --git a/public/app/plugins/panel/graph2/GraphLegendEditor.tsx b/public/app/plugins/panel/graph2/GraphLegendEditor.tsx
new file mode 100644
index 0000000000000..7d5d914fb9242
--- /dev/null
+++ b/public/app/plugins/panel/graph2/GraphLegendEditor.tsx
@@ -0,0 +1,103 @@
+import React from 'react';
+import capitalize from 'lodash/capitalize';
+import without from 'lodash/without';
+import { LegendOptions, PanelOptionsGroup, Switch, Input } from '@grafana/ui';
+
+export interface GraphLegendEditorLegendOptions extends LegendOptions {
+ stats?: string[];
+ decimals?: number;
+ sortBy?: string;
+ sortDesc?: boolean;
+}
+
+interface GraphLegendEditorProps {
+ stats: string[];
+ options: GraphLegendEditorLegendOptions;
+ onChange: (options: GraphLegendEditorLegendOptions) => void;
+}
+
+export const GraphLegendEditor: React.FunctionComponent = props => {
+ const { stats, options, onChange } = props;
+
+ const onStatToggle = (stat: string) => (event?: React.SyntheticEvent) => {
+ let newStats;
+ if (!event) {
+ return;
+ }
+
+ // @ts-ignore
+ if (event.target.checked) {
+ newStats = (options.stats || []).concat([stat]);
+ } else {
+ newStats = without(options.stats, stat);
+ }
+ onChange({
+ ...options,
+ stats: newStats,
+ });
+ };
+
+ const onOptionToggle = (option: keyof LegendOptions) => (event?: React.SyntheticEvent) => {
+ const newOption = {};
+ if (!event) {
+ return;
+ }
+ // TODO: fix the ignores
+ // @ts-ignore
+ newOption[option] = event.target.checked;
+ if (option === 'placement') {
+ // @ts-ignore
+ newOption[option] = event.target.checked ? 'right' : 'under';
+ }
+
+ onChange({
+ ...options,
+ ...newOption,
+ });
+ };
+
+ return (
+
+
+
Options
+
+
+
+
+
+
Values
+ {stats.map(stat => {
+ return (
+
-1}
+ onChange={onStatToggle(stat)}
+ key={stat}
+ />
+ );
+ })}
+
+
Decimals
+
{
+ onChange({
+ ...options,
+ decimals: parseInt(event.target.value, 10),
+ });
+ }}
+ />
+
+
+
+
+
Hidden series
+ {/* */}
+
+
+
+ );
+};
diff --git a/public/app/plugins/panel/graph2/GraphPanel.tsx b/public/app/plugins/panel/graph2/GraphPanel.tsx
index a6821323b272e..7b544d7e67464 100644
--- a/public/app/plugins/panel/graph2/GraphPanel.tsx
+++ b/public/app/plugins/panel/graph2/GraphPanel.tsx
@@ -1,67 +1,57 @@
-// Libraries
-import _ from 'lodash';
-import React, { PureComponent } from 'react';
-
-import { Graph, PanelProps, NullValueMode, colors, GraphSeriesXY, FieldType, getFirstTimeField } from '@grafana/ui';
+import React from 'react';
+import { PanelProps, GraphWithLegend /*, GraphSeriesXY*/ } from '@grafana/ui';
import { Options } from './types';
-import { getFlotPairs } from '@grafana/ui/src/utils/flotPairs';
-
-interface Props extends PanelProps {}
-
-export class GraphPanel extends PureComponent {
- render() {
- const { data, timeRange, width, height } = this.props;
- const { showLines, showBars, showPoints } = this.props.options;
-
- const graphs: GraphSeriesXY[] = [];
- for (const series of data.series) {
- const timeColumn = getFirstTimeField(series);
- if (timeColumn < 0) {
- continue;
- }
-
- for (let i = 0; i < series.fields.length; i++) {
- const field = series.fields[i];
-
- // Show all numeric columns
- if (field.type === FieldType.number) {
- // Use external calculator just to make sure it works :)
- const points = getFlotPairs({
- series,
- xIndex: timeColumn,
- yIndex: i,
- nullValueMode: NullValueMode.Null,
- });
-
- if (points.length > 0) {
- graphs.push({
- label: field.name,
- data: points,
- color: colors[graphs.length % colors.length],
- });
- }
- }
- }
- }
-
- if (graphs.length < 1) {
- return (
-
-
No data found in response
-
- );
- }
-
+import { GraphPanelController } from './GraphPanelController';
+import { LegendDisplayMode } from '@grafana/ui/src/components/Legend/Legend';
+
+interface GraphPanelProps extends PanelProps {}
+
+export const GraphPanel: React.FunctionComponent = ({
+ data,
+ timeRange,
+ width,
+ height,
+ options,
+ onOptionsChange,
+}) => {
+ if (!data) {
return (
-
+
+
No data found in response
+
);
}
-}
+
+ const {
+ graph: { showLines, showBars, showPoints },
+ legend: legendOptions,
+ } = options;
+
+ const graphProps = {
+ showBars,
+ showLines,
+ showPoints,
+ };
+ const { asTable, isVisible, ...legendProps } = legendOptions;
+ return (
+
+ {({ onSeriesToggle, ...controllerApi }) => {
+ return (
+
+ );
+ }}
+
+ );
+};
diff --git a/public/app/plugins/panel/graph2/GraphPanelController.tsx b/public/app/plugins/panel/graph2/GraphPanelController.tsx
new file mode 100644
index 0000000000000..5ac4811586c08
--- /dev/null
+++ b/public/app/plugins/panel/graph2/GraphPanelController.tsx
@@ -0,0 +1,156 @@
+import React from 'react';
+import { GraphSeriesXY, PanelData } from '@grafana/ui';
+import difference from 'lodash/difference';
+import { getGraphSeriesModel } from './getGraphSeriesModel';
+import { Options, SeriesOptions } from './types';
+import { SeriesColorChangeHandler, SeriesAxisToggleHandler } from '@grafana/ui/src/components/Graph/GraphWithLegend';
+
+interface GraphPanelControllerAPI {
+ series: GraphSeriesXY[];
+ onSeriesAxisToggle: SeriesAxisToggleHandler;
+ onSeriesColorChange: SeriesColorChangeHandler;
+ onSeriesToggle: (label: string, event: React.MouseEvent) => void;
+ onToggleSort: (sortBy: string) => void;
+}
+
+interface GraphPanelControllerProps {
+ children: (api: GraphPanelControllerAPI) => JSX.Element;
+ options: Options;
+ data: PanelData;
+ onOptionsChange: (options: Options) => void;
+}
+
+interface GraphPanelControllerState {
+ graphSeriesModel: GraphSeriesXY[];
+ hiddenSeries: string[];
+}
+
+export class GraphPanelController extends React.Component {
+ constructor(props: GraphPanelControllerProps) {
+ super(props);
+
+ this.onSeriesToggle = this.onSeriesToggle.bind(this);
+ this.onSeriesColorChange = this.onSeriesColorChange.bind(this);
+ this.onSeriesAxisToggle = this.onSeriesAxisToggle.bind(this);
+ this.onToggleSort = this.onToggleSort.bind(this);
+
+ this.state = {
+ graphSeriesModel: getGraphSeriesModel(
+ props.data,
+ props.options.series,
+ props.options.graph,
+ props.options.legend
+ ),
+ hiddenSeries: [],
+ };
+ }
+
+ static getDerivedStateFromProps(props: GraphPanelControllerProps, state: GraphPanelControllerState) {
+ return {
+ ...state,
+ graphSeriesModel: getGraphSeriesModel(
+ props.data,
+ props.options.series,
+ props.options.graph,
+ props.options.legend
+ ),
+ };
+ }
+
+ onSeriesOptionsUpdate(label: string, optionsUpdate: SeriesOptions) {
+ const { onOptionsChange, options } = this.props;
+ const updatedSeriesOptions: { [label: string]: SeriesOptions } = { ...options.series };
+ updatedSeriesOptions[label] = optionsUpdate;
+ onOptionsChange({
+ ...options,
+ series: updatedSeriesOptions,
+ });
+ }
+
+ onSeriesAxisToggle(label: string, yAxis: number) {
+ const {
+ options: { series },
+ } = this.props;
+ const seriesOptionsUpdate: SeriesOptions = series[label]
+ ? {
+ ...series[label],
+ yAxis,
+ }
+ : {
+ yAxis,
+ };
+ this.onSeriesOptionsUpdate(label, seriesOptionsUpdate);
+ }
+
+ onSeriesColorChange(label: string, color: string) {
+ const {
+ options: { series },
+ } = this.props;
+ const seriesOptionsUpdate: SeriesOptions = series[label]
+ ? {
+ ...series[label],
+ color,
+ }
+ : {
+ color,
+ };
+
+ this.onSeriesOptionsUpdate(label, seriesOptionsUpdate);
+ }
+
+ onToggleSort(sortBy: string) {
+ const { onOptionsChange, options } = this.props;
+ onOptionsChange({
+ ...options,
+ legend: {
+ ...options.legend,
+ sortBy,
+ sortDesc: sortBy === options.legend.sortBy ? !options.legend.sortDesc : false,
+ },
+ });
+ }
+
+ onSeriesToggle(label: string, event: React.MouseEvent) {
+ const { hiddenSeries, graphSeriesModel } = this.state;
+
+ if (event.ctrlKey || event.metaKey || event.shiftKey) {
+ // Toggling series with key makes the series itself to toggle
+ if (hiddenSeries.indexOf(label) > -1) {
+ this.setState({
+ hiddenSeries: hiddenSeries.filter(series => series !== label),
+ });
+ } else {
+ this.setState({
+ hiddenSeries: hiddenSeries.concat([label]),
+ });
+ }
+ } else {
+ // Toggling series with out key toggles all the series but the clicked one
+ const allSeriesLabels = graphSeriesModel.map(series => series.label);
+
+ if (hiddenSeries.length + 1 === allSeriesLabels.length) {
+ this.setState({ hiddenSeries: [] });
+ } else {
+ this.setState({
+ hiddenSeries: difference(allSeriesLabels, [label]),
+ });
+ }
+ }
+ }
+
+ render() {
+ const { children } = this.props;
+ const { graphSeriesModel, hiddenSeries } = this.state;
+
+ return children({
+ series: graphSeriesModel.map(series => ({
+ ...series,
+ isVisible: hiddenSeries.indexOf(series.label) === -1,
+ })),
+ onSeriesToggle: this.onSeriesToggle,
+ onSeriesColorChange: this.onSeriesColorChange,
+ onSeriesAxisToggle: this.onSeriesAxisToggle,
+ onToggleSort: this.onToggleSort,
+ });
+ }
+}
diff --git a/public/app/plugins/panel/graph2/GraphPanelEditor.tsx b/public/app/plugins/panel/graph2/GraphPanelEditor.tsx
index 1a64290759cab..afcbb68d2c159 100644
--- a/public/app/plugins/panel/graph2/GraphPanelEditor.tsx
+++ b/public/app/plugins/panel/graph2/GraphPanelEditor.tsx
@@ -3,40 +3,56 @@ import _ from 'lodash';
import React, { PureComponent } from 'react';
// Types
-import { PanelEditorProps, Switch } from '@grafana/ui';
-import { Options } from './types';
+import { PanelEditorProps, Switch, LegendOptions, StatID } from '@grafana/ui';
+import { Options, GraphOptions } from './types';
+import { GraphLegendEditor } from './GraphLegendEditor';
export class GraphPanelEditor extends PureComponent> {
+ onGraphOptionsChange = (options: Partial) => {
+ this.props.onOptionsChange({
+ ...this.props.options,
+ graph: {
+ ...this.props.options.graph,
+ ...options,
+ },
+ });
+ };
+
+ onLegendOptionsChange = (options: LegendOptions) => {
+ this.props.onOptionsChange({ ...this.props.options, legend: options });
+ };
+
onToggleLines = () => {
- this.props.onOptionsChange({ ...this.props.options, showLines: !this.props.options.showLines });
+ this.onGraphOptionsChange({ showLines: !this.props.options.graph.showLines });
};
onToggleBars = () => {
- this.props.onOptionsChange({ ...this.props.options, showBars: !this.props.options.showBars });
+ this.onGraphOptionsChange({ showBars: !this.props.options.graph.showBars });
};
onTogglePoints = () => {
- this.props.onOptionsChange({ ...this.props.options, showPoints: !this.props.options.showPoints });
+ this.onGraphOptionsChange({ showPoints: !this.props.options.graph.showPoints });
};
render() {
- const { showBars, showPoints, showLines } = this.props.options;
+ const {
+ graph: { showBars, showPoints, showLines },
+ } = this.props.options;
return (
-
+ <>
Draw Modes
-
-
Test Options
-
-
-
-
-
+
+ >
);
}
}
diff --git a/public/app/plugins/panel/graph2/getGraphSeriesModel.ts b/public/app/plugins/panel/graph2/getGraphSeriesModel.ts
new file mode 100644
index 0000000000000..c39a1627c1a1d
--- /dev/null
+++ b/public/app/plugins/panel/graph2/getGraphSeriesModel.ts
@@ -0,0 +1,83 @@
+import {
+ GraphSeriesXY,
+ getFirstTimeField,
+ FieldType,
+ NullValueMode,
+ calculateStats,
+ colors,
+ getFlotPairs,
+ getColorFromHexRgbOrName,
+ getDisplayProcessor,
+ DisplayValue,
+ PanelData,
+} from '@grafana/ui';
+import { SeriesOptions, GraphOptions } from './types';
+import { GraphLegendEditorLegendOptions } from './GraphLegendEditor';
+
+export const getGraphSeriesModel = (
+ data: PanelData,
+ seriesOptions: SeriesOptions,
+ graphOptions: GraphOptions,
+ legendOptions: GraphLegendEditorLegendOptions
+) => {
+ const graphs: GraphSeriesXY[] = [];
+
+ const displayProcessor = getDisplayProcessor({
+ decimals: legendOptions.decimals,
+ });
+
+ for (const series of data.series) {
+ const timeColumn = getFirstTimeField(series);
+ if (timeColumn < 0) {
+ continue;
+ }
+
+ for (let i = 0; i < series.fields.length; i++) {
+ const field = series.fields[i];
+
+ // Show all numeric columns
+ if (field.type === FieldType.number) {
+ // Use external calculator just to make sure it works :)
+ const points = getFlotPairs({
+ series,
+ xIndex: timeColumn,
+ yIndex: i,
+ nullValueMode: NullValueMode.Null,
+ });
+
+ if (points.length > 0) {
+ const seriesStats = calculateStats({ series, stats: legendOptions.stats, fieldIndex: i });
+ let statsDisplayValues;
+
+ if (legendOptions.stats) {
+ statsDisplayValues = legendOptions.stats.map(stat => {
+ const statDisplayValue = displayProcessor(seriesStats[stat]);
+
+ return {
+ ...statDisplayValue,
+ text: statDisplayValue.text,
+ title: stat,
+ };
+ });
+ }
+
+ const seriesColor =
+ seriesOptions[field.name] && seriesOptions[field.name].color
+ ? getColorFromHexRgbOrName(seriesOptions[field.name].color)
+ : colors[graphs.length % colors.length];
+
+ graphs.push({
+ label: field.name,
+ data: points,
+ color: seriesColor,
+ info: statsDisplayValues,
+ isVisible: true,
+ yAxis: (seriesOptions[field.name] && seriesOptions[field.name].yAxis) || 1,
+ });
+ }
+ }
+ }
+ }
+
+ return graphs;
+};
diff --git a/public/app/plugins/panel/graph2/types.ts b/public/app/plugins/panel/graph2/types.ts
index 1f6e9c093dd7b..18885c5025406 100644
--- a/public/app/plugins/panel/graph2/types.ts
+++ b/public/app/plugins/panel/graph2/types.ts
@@ -1,11 +1,34 @@
-export interface Options {
+import { LegendOptions } from '@grafana/ui';
+import { GraphLegendEditorLegendOptions } from './GraphLegendEditor';
+
+export interface SeriesOptions {
+ color?: string;
+ yAxis?: number;
+}
+export interface GraphOptions {
showBars: boolean;
showLines: boolean;
showPoints: boolean;
}
+export interface Options {
+ graph: GraphOptions;
+ legend: LegendOptions & GraphLegendEditorLegendOptions;
+ series: {
+ [alias: string]: SeriesOptions;
+ };
+}
+
export const defaults: Options = {
- showBars: false,
- showLines: true,
- showPoints: false,
+ graph: {
+ showBars: false,
+ showLines: true,
+ showPoints: false,
+ },
+ legend: {
+ asTable: false,
+ isVisible: true,
+ placement: 'under',
+ },
+ series: {},
};
diff --git a/scripts/circle-test-postgres.sh b/scripts/circle-test-postgres.sh
index 7ddfe6887d933..df4897484ad4f 100755
--- a/scripts/circle-test-postgres.sh
+++ b/scripts/circle-test-postgres.sh
@@ -12,6 +12,7 @@ function exit_if_fail {
export GRAFANA_TEST_DB=postgres
-time for d in $(go list ./pkg/...); do
- exit_if_fail go test -tags=integration $d
-done
\ No newline at end of file
+exit_if_fail go test -v -run="StatsDataAccess" -tags=integration ./pkg/services/sqlstore/...
+#time for d in $(go list ./pkg/...); do
+# exit_if_fail go test -tags=integration $d
+#done
\ No newline at end of file