Panels: Progress on new singlestat / BigValue (#19374)

* POC: friday hack

* exploring new singlestat styles

* minor changes

* Testing bizcharts

* style tweaks

* Updated

* minor progress

* updated

* Updated layout handling

* Updated editor

* added editor options

* adding mode

* progress on new display mode

* tweaks

* Added classic style

* Added final mode

* Minor tweak

* tweaks

* minor tweak

* Singlestat: Adjust colors for light theme

* fixed build issues with bizcharts

* fixed typescript issue

* updated snapshot

* Added demo dashboard
This commit is contained in:
Torkel Ödegaard 2019-10-04 12:01:42 +02:00 committed by GitHub
parent 45e0ebcc57
commit 81dd57524d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 1377 additions and 356 deletions

View File

@ -0,0 +1,647 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"links": [],
"panels": [
{
"datasource": null,
"gridPos": {
"h": 7,
"w": 20,
"x": 0,
"y": 0
},
"id": 2,
"interval": "10m",
"options": {
"colorMode": 0,
"displayMode": 2,
"fieldOptions": {
"calcs": ["mean"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "blue",
"value": null
},
{
"color": "green",
"value": 10
},
{
"color": "purple",
"value": 20
},
{
"color": "orange",
"value": 40
},
{
"color": "red",
"value": 80
}
],
"unit": "percent"
},
"override": {},
"values": false
},
"orientation": "auto",
"sparkline": {
"show": true
}
},
"pluginVersion": "6.5.0-pre",
"targets": [
{
"refId": "A",
"scenarioId": "random_walk"
},
{
"refId": "B",
"scenarioId": "random_walk"
},
{
"refId": "C",
"scenarioId": "random_walk"
},
{
"refId": "D",
"scenarioId": "random_walk"
},
{
"refId": "E",
"scenarioId": "random_walk"
},
{
"refId": "F",
"scenarioId": "random_walk"
},
{
"refId": "G",
"scenarioId": "random_walk"
}
],
"timeFrom": null,
"timeShift": null,
"title": "Panel Title",
"type": "singlestat2"
},
{
"datasource": null,
"gridPos": {
"h": 20,
"w": 4,
"x": 20,
"y": 0
},
"id": 8,
"interval": "10m",
"options": {
"colorMode": 0,
"displayMode": 2,
"fieldOptions": {
"calcs": ["mean"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "blue",
"value": null
},
{
"color": "green",
"value": 10
},
{
"color": "purple",
"value": 20
},
{
"color": "orange",
"value": 40
},
{
"color": "red",
"value": 80
}
],
"unit": "percent"
},
"override": {},
"values": false
},
"orientation": "auto",
"sparkline": {
"show": true
}
},
"pluginVersion": "6.5.0-pre",
"targets": [
{
"refId": "A",
"scenarioId": "random_walk"
},
{
"refId": "B",
"scenarioId": "random_walk"
},
{
"refId": "C",
"scenarioId": "random_walk"
},
{
"refId": "D",
"scenarioId": "random_walk"
},
{
"refId": "E",
"scenarioId": "random_walk"
},
{
"refId": "F",
"scenarioId": "random_walk"
},
{
"refId": "G",
"scenarioId": "random_walk"
}
],
"timeFrom": null,
"timeShift": null,
"title": "Panel Title",
"type": "singlestat2"
},
{
"datasource": null,
"gridPos": {
"h": 3,
"w": 20,
"x": 0,
"y": 7
},
"id": 6,
"interval": "10m",
"options": {
"colorMode": 0,
"displayMode": 2,
"fieldOptions": {
"calcs": ["mean"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "blue",
"value": null
},
{
"color": "green",
"value": 10
},
{
"color": "purple",
"value": 20
},
{
"color": "orange",
"value": 40
},
{
"color": "red",
"value": 80
}
],
"unit": "percent"
},
"override": {},
"values": false
},
"orientation": "auto",
"sparkline": {
"show": true
}
},
"pluginVersion": "6.5.0-pre",
"targets": [
{
"refId": "A",
"scenarioId": "random_walk"
},
{
"refId": "B",
"scenarioId": "random_walk"
},
{
"refId": "C",
"scenarioId": "random_walk"
},
{
"refId": "D",
"scenarioId": "random_walk"
},
{
"refId": "E",
"scenarioId": "random_walk"
},
{
"refId": "F",
"scenarioId": "random_walk"
},
{
"refId": "G",
"scenarioId": "random_walk"
}
],
"timeFrom": null,
"timeShift": null,
"title": "Panel Title",
"type": "singlestat2"
},
{
"datasource": null,
"gridPos": {
"h": 6,
"w": 20,
"x": 0,
"y": 10
},
"id": 3,
"interval": "10m",
"options": {
"colorMode": 0,
"displayMode": 3,
"fieldOptions": {
"calcs": ["mean"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "blue",
"value": null
},
{
"color": "green",
"value": 10
},
{
"color": "purple",
"value": 20
},
{
"color": "orange",
"value": 40
},
{
"color": "red",
"value": 80
}
],
"unit": "percent"
},
"override": {},
"values": false
},
"orientation": "auto",
"sparkline": {
"show": true
}
},
"pluginVersion": "6.5.0-pre",
"targets": [
{
"refId": "A",
"scenarioId": "random_walk"
},
{
"refId": "B",
"scenarioId": "random_walk"
},
{
"refId": "C",
"scenarioId": "random_walk"
},
{
"refId": "D",
"scenarioId": "random_walk"
},
{
"refId": "E",
"scenarioId": "random_walk"
},
{
"refId": "F",
"scenarioId": "random_walk"
},
{
"refId": "G",
"scenarioId": "random_walk"
}
],
"timeFrom": null,
"timeShift": null,
"title": "Panel Title",
"type": "singlestat2"
},
{
"datasource": null,
"gridPos": {
"h": 6,
"w": 20,
"x": 0,
"y": 16
},
"id": 4,
"interval": "10m",
"options": {
"colorMode": 0,
"displayMode": 0,
"fieldOptions": {
"calcs": ["mean"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "blue",
"value": null
},
{
"color": "green",
"value": 10
},
{
"color": "purple",
"value": 20
},
{
"color": "orange",
"value": 40
},
{
"color": "red",
"value": 80
}
],
"unit": "percent"
},
"override": {},
"values": false
},
"orientation": "auto",
"sparkline": {
"show": true
}
},
"pluginVersion": "6.5.0-pre",
"targets": [
{
"refId": "A",
"scenarioId": "random_walk"
},
{
"refId": "B",
"scenarioId": "random_walk"
},
{
"refId": "C",
"scenarioId": "random_walk"
},
{
"refId": "D",
"scenarioId": "random_walk"
},
{
"refId": "E",
"scenarioId": "random_walk"
},
{
"refId": "F",
"scenarioId": "random_walk"
},
{
"refId": "G",
"scenarioId": "random_walk"
}
],
"timeFrom": null,
"timeShift": null,
"title": "Panel Title",
"type": "singlestat2"
},
{
"datasource": null,
"gridPos": {
"h": 21,
"w": 4,
"x": 20,
"y": 20
},
"id": 9,
"interval": "10m",
"options": {
"colorMode": 0,
"displayMode": 0,
"fieldOptions": {
"calcs": ["mean"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "blue",
"value": null
},
{
"color": "green",
"value": 10
},
{
"color": "purple",
"value": 20
},
{
"color": "orange",
"value": 40
},
{
"color": "red",
"value": 80
}
],
"unit": "percent"
},
"override": {},
"values": false
},
"orientation": "auto",
"sparkline": {
"show": true
}
},
"pluginVersion": "6.5.0-pre",
"targets": [
{
"refId": "A",
"scenarioId": "random_walk"
},
{
"refId": "B",
"scenarioId": "random_walk"
},
{
"refId": "C",
"scenarioId": "random_walk"
},
{
"refId": "D",
"scenarioId": "random_walk"
},
{
"refId": "E",
"scenarioId": "random_walk"
},
{
"refId": "F",
"scenarioId": "random_walk"
},
{
"refId": "G",
"scenarioId": "random_walk"
}
],
"timeFrom": null,
"timeShift": null,
"title": "Panel Title",
"type": "singlestat2"
},
{
"datasource": null,
"gridPos": {
"h": 6,
"w": 20,
"x": 0,
"y": 22
},
"id": 5,
"interval": "10m",
"options": {
"colorMode": 0,
"displayMode": 1,
"fieldOptions": {
"calcs": ["mean"],
"defaults": {
"mappings": [],
"max": 100,
"min": 0,
"thresholds": [
{
"color": "blue",
"value": null
},
{
"color": "green",
"value": 10
},
{
"color": "purple",
"value": 20
},
{
"color": "orange",
"value": 40
},
{
"color": "red",
"value": 80
}
],
"unit": "percent"
},
"override": {},
"values": false
},
"orientation": "auto",
"sparkline": {
"show": true
}
},
"pluginVersion": "6.5.0-pre",
"targets": [
{
"refId": "A",
"scenarioId": "random_walk"
},
{
"refId": "B",
"scenarioId": "random_walk"
},
{
"refId": "C",
"scenarioId": "random_walk"
},
{
"refId": "D",
"scenarioId": "random_walk"
},
{
"refId": "E",
"scenarioId": "random_walk"
},
{
"refId": "F",
"scenarioId": "random_walk"
},
{
"refId": "G",
"scenarioId": "random_walk"
}
],
"timeFrom": null,
"timeShift": null,
"title": "Panel Title",
"type": "singlestat2"
}
],
"schemaVersion": 20,
"style": "dark",
"tags": ["gdev", "panel-tests"],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {
"refresh_intervals": ["5s", "10s", "30s", "1m", "5m", "15m", "30m", "1h", "2h", "1d"]
},
"timezone": "",
"title": "Panel Tests - Stat",
"uid": "jWWHNJpWz",
"version": 6
}

View File

@ -29,6 +29,7 @@
"@grafana/slate-react": "0.22.9-grafana",
"@torkelo/react-select": "2.1.1",
"@types/react-color": "2.17.0",
"bizcharts": "^3.5.5",
"@types/slate": "0.47.1",
"@types/slate-react": "0.22.5",
"classnames": "2.2.6",

View File

@ -57,6 +57,7 @@ const buildCjsPackage = ({ env }) => {
],
'node_modules/immutable/dist/immutable.js': ['Record', 'Set', 'Map', 'List', 'OrderedSet', 'is', 'Stack'],
'../../node_modules/esrever/esrever.js': ['reverse'],
'../../node_modules/bizcharts/es6/index.js': ['Chart', 'Geom', 'View', 'Tooltip', 'Legend'],
},
}),
resolve(),

View File

@ -1,14 +1,13 @@
import { storiesOf } from '@storybook/react';
import { number, text } from '@storybook/addon-knobs';
import { BigValue } from './BigValue';
import { text } from '@storybook/addon-knobs';
import { BigValue, SingleStatDisplayMode } from './BigValue';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
import { renderComponentWithTheme } from '../../utils/storybook/withTheme';
const getKnobs = () => {
return {
value: text('value', 'Hello'),
valueFontSize: number('valueFontSize', 120),
prefix: text('prefix', ''),
value: text('value', '$5022'),
title: text('title', 'Total Earnings'),
};
};
@ -16,22 +15,37 @@ const BigValueStories = storiesOf('UI/BigValue', module);
BigValueStories.addDecorator(withCenteredStory);
BigValueStories.add('Singlestat viz', () => {
const { value, prefix, valueFontSize } = getKnobs();
interface StoryOptions {
mode: SingleStatDisplayMode;
width?: number;
height?: number;
noSparkline?: boolean;
}
return renderComponentWithTheme(BigValue, {
width: 300,
height: 250,
value: {
text: value,
numeric: NaN,
fontSize: valueFontSize + '%',
},
prefix: prefix
? {
text: prefix,
numeric: NaN,
}
: null,
function addStoryForMode(options: StoryOptions) {
BigValueStories.add(`Mode: ${SingleStatDisplayMode[options.mode]}`, () => {
const { value, title } = getKnobs();
return renderComponentWithTheme(BigValue, {
width: options.width || 400,
height: options.height || 300,
displayMode: options.mode,
value: {
text: value,
numeric: 5022,
color: 'red',
title,
},
sparkline: {
minX: 0,
maxX: 5,
data: [[0, 10], [1, 20], [2, 15], [3, 25], [4, 5], [5, 10]],
},
});
});
});
}
addStoryForMode({ mode: SingleStatDisplayMode.Classic });
addStoryForMode({ mode: SingleStatDisplayMode.Classic2 });
addStoryForMode({ mode: SingleStatDisplayMode.Vibrant });
addStoryForMode({ mode: SingleStatDisplayMode.Vibrant2 });

View File

@ -1,6 +1,6 @@
import React from 'react';
import { shallow } from 'enzyme';
import { BigValue, Props } from './BigValue';
import { BigValue, Props, SingleStatDisplayMode } from './BigValue';
import { getTheme } from '../../themes/index';
jest.mock('jquery', () => ({
@ -11,6 +11,7 @@ const setup = (propOverrides?: object) => {
const props: Props = {
height: 300,
width: 300,
displayMode: SingleStatDisplayMode.Classic,
value: {
text: '25',
numeric: 25,
@ -29,7 +30,7 @@ const setup = (propOverrides?: object) => {
};
};
describe('Render BarGauge with basic options', () => {
describe('Render SingleStat with basic options', () => {
it('should render', () => {
const { wrapper } = setup();
expect(wrapper).toBeDefined();

View File

@ -1,168 +1,413 @@
// Library
import React, { PureComponent, ReactNode, CSSProperties } from 'react';
import $ from 'jquery';
import { css, cx } from 'emotion';
import React, { PureComponent, CSSProperties } from 'react';
import tinycolor from 'tinycolor2';
import { Chart, Geom } from 'bizcharts';
import { DisplayValue } from '@grafana/data';
// Utils
import { getColorFromHexRgbOrName } from '../../utils';
// Types
import { Themeable } from '../../types';
import { stylesFactory } from '../../themes/stylesFactory';
import { Themeable, GrafanaTheme } from '../../types';
export interface BigValueSparkline {
data: any[][]; // [[number,number]]
data: any[][];
minX: number;
maxX: number;
full: boolean; // full height
fillColor: string;
lineColor: string;
}
export enum SingleStatDisplayMode {
Classic,
Classic2,
Vibrant,
Vibrant2,
}
export interface Props extends Themeable {
height: number;
width: number;
value: DisplayValue;
prefix?: DisplayValue;
suffix?: DisplayValue;
sparkline?: BigValueSparkline;
backgroundColor?: string;
onClick?: React.MouseEventHandler<HTMLElement>;
className?: string;
displayMode: SingleStatDisplayMode;
}
const getStyles = stylesFactory(() => {
return {
wrapper: css`
position: 'relative';
display: 'table';
`,
title: css`
line-height: 1;
text-align: 'center';
z-index: 1;
display: 'block';
width: '100%';
position: 'absolute';
`,
value: css`
line-height: 1;
text-align: 'center';
z-index: 1;
display: 'table-cell';
vertical-align: 'middle';
position: 'relative';
font-size: '3em';
font-weight: 500;
`,
};
});
/*
* This visualization is still in POC state, needed more tests & better structure
*/
export class BigValue extends PureComponent<Props> {
canvasElement: any;
componentDidMount() {
this.draw();
}
componentDidUpdate() {
this.draw();
}
draw() {
const { sparkline, theme } = this.props;
if (sparkline && this.canvasElement) {
const { data, minX, maxX, fillColor, lineColor } = sparkline;
const options = {
legend: { show: false },
series: {
lines: {
show: true,
fill: 1,
zero: false,
lineWidth: 1,
fillColor: getColorFromHexRgbOrName(fillColor, theme.type),
},
},
yaxes: { show: false },
xaxis: {
show: false,
min: minX,
max: maxX,
},
grid: { hoverable: false, show: false },
};
const plotSeries = {
data,
color: getColorFromHexRgbOrName(lineColor, theme.type),
};
try {
$.plot(this.canvasElement, [plotSeries], options);
} catch (err) {
console.log('sparkline rendering error', err, options);
}
}
}
renderText = (value?: DisplayValue, padding?: string): ReactNode => {
if (!value || !value.text) {
return null;
}
const css: CSSProperties = {};
if (padding) {
css.padding = padding;
}
if (value.color) {
css.color = value.color;
}
if (value.fontSize) {
css.fontSize = value.fontSize;
}
return <span style={css}>{value.text}</span>;
};
renderSparkline(sparkline: BigValueSparkline) {
const { height, width } = this.props;
const plotCss: CSSProperties = {};
plotCss.position = 'absolute';
plotCss.bottom = '0px';
plotCss.left = '0px';
plotCss.width = width + 'px';
if (sparkline.full) {
const dynamicHeightMargin = height <= 100 ? 5 : Math.round(height / 100) * 15 + 5;
plotCss.height = height - dynamicHeightMargin + 'px';
} else {
plotCss.height = Math.floor(height * 0.25) + 'px';
}
return <div style={plotCss} ref={element => (this.canvasElement = element)} />;
}
render() {
const { height, width, value, prefix, suffix, sparkline, backgroundColor, onClick, className } = this.props;
const styles = getStyles();
const { value, onClick, className, sparkline } = this.props;
const layout = calculateLayout(this.props);
const panelStyles = getPanelStyles(layout);
const valueAndTitleContainerStyles = getValueAndTitleContainerStyles(layout);
const valueStyles = getValueStyles(layout);
const titleStyles = getTitleStyles(layout);
return (
<div className={cx(styles.wrapper, className)} style={{ width, height, backgroundColor }} onClick={onClick}>
{value.title && <div className={styles.title}>{value.title}</div>}
<span className={styles.value}>
{this.renderText(prefix, '0px 2px 0px 0px')}
{this.renderText(value)}
{this.renderText(suffix)}
</span>
{sparkline && this.renderSparkline(sparkline)}
<div className={className} style={panelStyles} onClick={onClick}>
<div style={valueAndTitleContainerStyles}>
{value.title && <div style={titleStyles}>{value.title}</div>}
<div style={valueStyles}>{value.text}</div>
</div>
{renderGraph(layout, sparkline)}
</div>
);
}
}
const MIN_VALUE_FONT_SIZE = 20;
const MAX_VALUE_FONT_SIZE = 50;
const MIN_TITLE_FONT_SIZE = 14;
const TITLE_VALUE_RATIO = 0.45;
const VALUE_HEIGHT_RATIO = 0.25;
const VALUE_HEIGHT_RATIO_WIDE = 0.3;
const LINE_HEIGHT = 1.2;
const PANEL_PADDING = 16;
const CHART_TOP_MARGIN = 8;
interface LayoutResult {
titleFontSize: number;
valueFontSize: number;
chartHeight: number;
chartWidth: number;
type: LayoutType;
width: number;
height: number;
displayMode: SingleStatDisplayMode;
theme: GrafanaTheme;
valueColor: string;
}
enum LayoutType {
Stacked,
StackedNoChart,
Wide,
WideNoChart,
}
export function calculateLayout(props: Props): LayoutResult {
const { width, height, sparkline, displayMode, theme, value } = props;
const useWideLayout = width / height > 2.8;
const valueColor = getColorFromHexRgbOrName(value.color || 'green', theme.type);
// handle wide layouts
if (useWideLayout) {
const valueFontSize = Math.min(
Math.max(height * VALUE_HEIGHT_RATIO_WIDE, MIN_VALUE_FONT_SIZE),
MAX_VALUE_FONT_SIZE
);
const titleFontSize = Math.max(valueFontSize * TITLE_VALUE_RATIO, MIN_TITLE_FONT_SIZE);
const chartHeight = height - PANEL_PADDING * 2;
const chartWidth = width / 2;
let type = !!sparkline ? LayoutType.Wide : LayoutType.WideNoChart;
if (height < 80 || !sparkline) {
type = LayoutType.WideNoChart;
}
return {
valueFontSize,
titleFontSize,
chartHeight,
chartWidth,
type,
width,
height,
displayMode,
theme,
valueColor,
};
}
// handle stacked layouts
const valueFontSize = Math.min(Math.max(height * VALUE_HEIGHT_RATIO, MIN_VALUE_FONT_SIZE), MAX_VALUE_FONT_SIZE);
const titleFontSize = Math.max(valueFontSize * TITLE_VALUE_RATIO, MIN_TITLE_FONT_SIZE);
const valueHeight = valueFontSize * LINE_HEIGHT;
const titleHeight = titleFontSize * LINE_HEIGHT;
let chartHeight = height - valueHeight - titleHeight - PANEL_PADDING * 2 - CHART_TOP_MARGIN;
let chartWidth = width - PANEL_PADDING * 2;
let type = LayoutType.Stacked;
if (height < 100 || !sparkline) {
type = LayoutType.StackedNoChart;
}
switch (displayMode) {
case SingleStatDisplayMode.Vibrant2:
case SingleStatDisplayMode.Classic:
case SingleStatDisplayMode.Classic2:
chartWidth = width;
chartHeight += PANEL_PADDING;
break;
}
return {
valueFontSize,
titleFontSize,
chartHeight,
chartWidth,
type,
width,
height,
displayMode,
theme,
valueColor,
};
}
export function getTitleStyles(layout: LayoutResult) {
const styles: CSSProperties = {
fontSize: `${layout.titleFontSize}px`,
textShadow: '#333 1px 1px 5px',
color: '#EEE',
};
if (layout.theme.isLight) {
styles.color = 'white';
}
return styles;
}
export function getValueStyles(layout: LayoutResult) {
const styles: CSSProperties = {
fontSize: `${layout.valueFontSize}px`,
color: '#EEE',
textShadow: '#333 1px 1px 5px',
lineHeight: LINE_HEIGHT,
};
switch (layout.displayMode) {
case SingleStatDisplayMode.Classic:
case SingleStatDisplayMode.Classic2:
styles.color = layout.valueColor;
}
return styles;
}
export function getValueAndTitleContainerStyles(layout: LayoutResult): CSSProperties {
switch (layout.type) {
case LayoutType.Wide:
return {
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
};
case LayoutType.WideNoChart:
return {
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
flexGrow: 1,
};
case LayoutType.StackedNoChart:
return {
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
};
case LayoutType.Stacked:
default:
return {
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
};
}
}
export function getPanelStyles(layout: LayoutResult) {
const panelStyles: CSSProperties = {
width: `${layout.width}px`,
height: `${layout.height}px`,
padding: `${PANEL_PADDING}px`,
borderRadius: '3px',
position: 'relative',
display: 'flex',
};
const themeFactor = layout.theme.isDark ? 1 : -0.7;
switch (layout.displayMode) {
case SingleStatDisplayMode.Vibrant:
case SingleStatDisplayMode.Vibrant2:
const bgColor2 = tinycolor(layout.valueColor)
.darken(15 * themeFactor)
.spin(8)
.toRgbString();
const bgColor3 = tinycolor(layout.valueColor)
.darken(5 * themeFactor)
.spin(-8)
.toRgbString();
panelStyles.background = `linear-gradient(120deg, ${bgColor2}, ${bgColor3})`;
break;
case SingleStatDisplayMode.Classic:
case SingleStatDisplayMode.Classic2:
panelStyles.background = `${layout.theme.colors.dark4}`;
break;
}
switch (layout.type) {
case LayoutType.Stacked:
panelStyles.flexDirection = 'column';
break;
case LayoutType.StackedNoChart:
panelStyles.alignItems = 'center';
break;
case LayoutType.Wide:
panelStyles.flexDirection = 'row';
panelStyles.alignItems = 'center';
panelStyles.justifyContent = 'space-between';
break;
case LayoutType.WideNoChart:
panelStyles.alignItems = 'center';
break;
}
return panelStyles;
}
function renderGraph(layout: LayoutResult, sparkline?: BigValueSparkline) {
if (!sparkline) {
return null;
}
const data = sparkline.data.map(values => {
return { time: values[0], value: values[1], name: 'A' };
});
const scales = {
time: {
type: 'time',
},
};
const chartStyles: CSSProperties = {
marginTop: `${CHART_TOP_MARGIN}`,
};
// default to line graph
let geomRender = renderLineGeom;
switch (layout.type) {
case LayoutType.Wide:
chartStyles.width = `${layout.chartWidth}px`;
chartStyles.height = `${layout.chartHeight}px`;
break;
case LayoutType.Stacked:
chartStyles.position = 'relative';
chartStyles.top = '8px';
break;
case LayoutType.WideNoChart:
case LayoutType.StackedNoChart:
return null;
}
if (layout.chartWidth === layout.width) {
chartStyles.position = 'absolute';
chartStyles.bottom = 0;
chartStyles.right = 0;
chartStyles.left = 0;
chartStyles.right = 0;
chartStyles.top = 'unset';
}
switch (layout.displayMode) {
case SingleStatDisplayMode.Vibrant2:
geomRender = renderVibrant2Geom;
break;
case SingleStatDisplayMode.Classic:
geomRender = renderClassicAreaGeom;
break;
case SingleStatDisplayMode.Classic2:
geomRender = renderAreaGeom;
break;
}
return (
<Chart
height={layout.chartHeight}
width={layout.chartWidth}
data={data}
animate={false}
padding={[4, 0, 0, 0]}
scale={scales}
style={chartStyles}
>
{geomRender(layout)}
</Chart>
);
}
function renderLineGeom(layout: LayoutResult) {
const lineStyle: any = {
stroke: '#CCC',
lineWidth: 2,
shadowBlur: 15,
shadowColor: '#444',
shadowOffsetY: 7,
};
return <Geom type="line" position="time*value" size={2} color="white" style={lineStyle} shape="smooth" />;
}
function renderVibrant2Geom(layout: LayoutResult) {
const lineStyle: any = {
stroke: '#CCC',
lineWidth: 2,
shadowBlur: 15,
shadowColor: '#444',
shadowOffsetY: -5,
};
return (
<>
<Geom type="area" position="time*value" size={0} color="rgba(255,255,255,0.4)" style={lineStyle} shape="smooth" />
<Geom type="line" position="time*value" size={1} color="white" style={lineStyle} shape="smooth" />
</>
);
}
function renderClassicAreaGeom(layout: LayoutResult) {
const lineStyle: any = {
opacity: 1,
fillOpacity: 1,
};
const fillColor = tinycolor(layout.valueColor)
.setAlpha(0.2)
.toRgbString();
lineStyle.stroke = layout.valueColor;
return (
<>
<Geom type="area" position="time*value" size={0} color={fillColor} style={lineStyle} shape="smooth" />
<Geom type="line" position="time*value" size={1} color={layout.valueColor} style={lineStyle} shape="smooth" />
</>
);
}
function renderAreaGeom(layout: LayoutResult) {
const lineStyle: any = {
opacity: 1,
fillOpacity: 1,
};
const color1 = tinycolor(layout.valueColor)
.darken(0)
.spin(20)
.toRgbString();
const color2 = tinycolor(layout.valueColor)
.lighten(0)
.spin(-20)
.toRgbString();
const fillColor = `l (0) 0:${color1} 1:${color2}`;
return <Geom type="area" position="time*value" size={0} color={fillColor} style={lineStyle} shape="smooth" />;
}

View File

@ -164,6 +164,8 @@ exports[`Render should render with base threshold 1`] = `
"md": "32px",
"sm": "24px",
},
"isDark": true,
"isLight": false,
"name": "Grafana Dark",
"panelHeaderHeight": 28,
"panelPadding": 8,
@ -331,6 +333,8 @@ exports[`Render should render with base threshold 1`] = `
"md": "32px",
"sm": "24px",
},
"isDark": true,
"isLight": false,
"name": "Grafana Dark",
"panelHeaderHeight": 28,
"panelPadding": 8,

View File

@ -46,7 +46,7 @@ export { Table } from './Table/Table';
export { TableInputCSV } from './Table/TableInputCSV';
// Visualizations
export { BigValue } from './BigValue/BigValue';
export { BigValue, SingleStatDisplayMode } from './BigValue/BigValue';
export { Gauge } from './Gauge/Gauge';
export { Graph } from './Graph/Graph';
export { GraphLegend } from './Graph/GraphLegend';

View File

@ -42,6 +42,8 @@ const basicColors = {
const darkTheme: GrafanaTheme = {
...defaultTheme,
type: GrafanaThemeType.Dark,
isDark: true,
isLight: false,
name: 'Grafana Dark',
colors: {
...basicColors,

View File

@ -42,6 +42,8 @@ const basicColors = {
const lightTheme: GrafanaTheme = {
...defaultTheme,
type: GrafanaThemeType.Light,
isDark: false,
isLight: true,
name: 'Grafana Light',
colors: {
...basicColors,

View File

@ -92,6 +92,8 @@ export interface GrafanaThemeCommons {
export interface GrafanaTheme extends GrafanaThemeCommons {
type: GrafanaThemeType;
isDark: boolean;
isLight: boolean;
background: {
dropdown: string;
scrollbar: string;

View File

@ -142,6 +142,7 @@ export class PanelQueryRunner {
request.interval = norm.interval;
request.intervalMs = norm.intervalMs;
console.log('to', request.range.to.valueOf());
this.pipeToSubject(runRequest(ds, request));
} catch (err) {

View File

@ -1,63 +0,0 @@
// Libraries
import React, { PureComponent } from 'react';
// Components
import { Switch, PanelOptionsGroup } from '@grafana/ui';
// Types
import { SingleStatOptions } from './types';
const labelWidth = 6;
export interface Props {
options: SingleStatOptions;
onChange: (options: SingleStatOptions) => void;
}
export class ColoringEditor extends PureComponent<Props> {
onToggleColorBackground = () =>
this.props.onChange({ ...this.props.options, colorBackground: !this.props.options.colorBackground });
onToggleColorValue = () => this.props.onChange({ ...this.props.options, colorValue: !this.props.options.colorValue });
onToggleColorPrefix = () =>
this.props.onChange({ ...this.props.options, colorPrefix: !this.props.options.colorPrefix });
onToggleColorPostfix = () =>
this.props.onChange({ ...this.props.options, colorPostfix: !this.props.options.colorPostfix });
render() {
const { colorBackground, colorValue, colorPrefix, colorPostfix } = this.props.options;
return (
<PanelOptionsGroup title="Coloring">
<Switch
label="Background"
labelClass={`width-${labelWidth}`}
checked={colorBackground!}
onChange={this.onToggleColorBackground}
/>
<Switch
label="Value"
labelClass={`width-${labelWidth}`}
checked={colorValue!}
onChange={this.onToggleColorValue}
/>
<Switch
label="Prefix"
labelClass={`width-${labelWidth}`}
checked={colorPrefix!}
onChange={this.onToggleColorPrefix}
/>
<Switch
label="Postfix"
labelClass={`width-${labelWidth}`}
checked={colorPostfix!}
onChange={this.onToggleColorPostfix}
/>
</PanelOptionsGroup>
);
}
}

View File

@ -1,70 +0,0 @@
// Libraries
import React, { PureComponent } from 'react';
// Components
import { FormLabel, Select, PanelOptionsGroup } from '@grafana/ui';
// Types
import { SingleStatOptions } from './types';
import { SelectableValue } from '@grafana/data';
const labelWidth = 6;
export interface Props {
options: SingleStatOptions;
onChange: (options: SingleStatOptions) => void;
}
const percents = ['20%', '30%', '50%', '70%', '80%', '100%', '110%', '120%', '150%', '170%', '200%'];
const fontSizeOptions = percents.map(v => {
return { value: v, label: v };
});
export class FontSizeEditor extends PureComponent<Props> {
setPrefixFontSize = (v: SelectableValue<string>) =>
this.props.onChange({ ...this.props.options, prefixFontSize: v.value });
setValueFontSize = (v: SelectableValue<string>) =>
this.props.onChange({ ...this.props.options, valueFontSize: v.value });
setPostfixFontSize = (v: SelectableValue<string>) =>
this.props.onChange({ ...this.props.options, postfixFontSize: v.value });
render() {
const { prefixFontSize, valueFontSize, postfixFontSize } = this.props.options;
return (
<PanelOptionsGroup title="Font Size">
<div className="gf-form">
<FormLabel width={labelWidth}>Prefix</FormLabel>
<Select
width={12}
options={fontSizeOptions}
onChange={this.setPrefixFontSize}
value={fontSizeOptions.find(option => option.value === prefixFontSize)}
/>
</div>
<div className="gf-form">
<FormLabel width={labelWidth}>Value</FormLabel>
<Select
width={12}
options={fontSizeOptions}
onChange={this.setValueFontSize}
value={fontSizeOptions.find(option => option.value === valueFontSize)}
/>
</div>
<div className="gf-form">
<FormLabel width={labelWidth}>Postfix</FormLabel>
<Select
width={12}
options={fontSizeOptions}
onChange={this.setPostfixFontSize}
value={fontSizeOptions.find(option => option.value === postfixFontSize)}
/>
</div>
</PanelOptionsGroup>
);
}
}

View File

@ -1,5 +1,6 @@
// Libraries
import React, { PureComponent } from 'react';
import {
PanelEditorProps,
ThresholdsEditor,
@ -10,12 +11,13 @@ import {
FieldPropertiesEditor,
PanelOptionsGroup,
DataLinksEditor,
FormLabel,
Select,
} from '@grafana/ui';
import { Threshold, ValueMapping, FieldConfig, DataLink } from '@grafana/data';
import { SingleStatOptions, SparklineOptions } from './types';
import { ColoringEditor } from './ColoringEditor';
import { FontSizeEditor } from './FontSizeEditor';
import { SingleStatOptions, SparklineOptions, displayModes, colorModes } from './types';
import { SparklineEditor } from './SparklineEditor';
import {
getDataLinksVariableSuggestions,
@ -51,6 +53,9 @@ export class SingleStatEditor extends PureComponent<PanelEditorProps<SingleStatO
sparkline,
});
onDisplayModeChange = ({ value }: any) => this.props.onOptionsChange({ ...this.props.options, displayMode: value });
onColorModeChange = ({ value }: any) => this.props.onOptionsChange({ ...this.props.options, colorMode: value });
onDefaultsChange = (field: FieldConfig) => {
this.onDisplayOptionsChanged({
...this.props.options.fieldOptions,
@ -77,17 +82,34 @@ export class SingleStatEditor extends PureComponent<PanelEditorProps<SingleStatO
<>
<PanelOptionsGrid>
<PanelOptionsGroup title="Display">
<FieldDisplayEditor onChange={this.onDisplayOptionsChanged} value={fieldOptions} />
<FieldDisplayEditor onChange={this.onDisplayOptionsChanged} value={fieldOptions} labelWidth={8} />
<div className="form-field">
<FormLabel width={8}>Display mode</FormLabel>
<Select
width={12}
options={displayModes}
defaultValue={displayModes[0]}
onChange={this.onDisplayModeChange}
value={displayModes.find(item => item.value === options.displayMode)}
/>
</div>
<div className="form-field">
<FormLabel width={8}>Color by</FormLabel>
<Select
width={12}
options={colorModes}
defaultValue={colorModes[0]}
onChange={this.onColorModeChange}
value={colorModes.find(item => item.value === options.colorMode)}
/>
</div>
<SparklineEditor options={options.sparkline} onChange={this.onSparklineChanged} />
</PanelOptionsGroup>
<PanelOptionsGroup title="Field (default)">
<FieldPropertiesEditor showMinMax={true} onChange={this.onDefaultsChange} value={defaults} />
</PanelOptionsGroup>
<FontSizeEditor options={options} onChange={this.props.onOptionsChange} />
<ColoringEditor options={options} onChange={this.props.onOptionsChange} />
<SparklineEditor options={options.sparkline} onChange={this.onSparklineChanged} />
<ThresholdsEditor onChange={this.onThresholdsChanged} thresholds={defaults.thresholds} />
</PanelOptionsGrid>

View File

@ -19,10 +19,10 @@ import { getFieldLinksSupplier } from 'app/features/panel/panellinks/linkSupplie
export class SingleStatPanel extends PureComponent<PanelProps<SingleStatOptions>> {
renderValue = (value: FieldDisplay, width: number, height: number): JSX.Element => {
let sparkline: BigValueSparkline;
if (value.sparkline) {
const { timeRange, options } = this.props;
const { timeRange, options } = this.props;
let sparkline: BigValueSparkline | undefined;
if (value.sparkline) {
sparkline = {
...options.sparkline,
data: value.sparkline,
@ -38,6 +38,7 @@ export class SingleStatPanel extends PureComponent<PanelProps<SingleStatOptions>
<BigValue
value={value.display}
sparkline={sparkline}
displayMode={options.displayMode}
width={width}
height={height}
theme={config.theme}
@ -52,6 +53,7 @@ export class SingleStatPanel extends PureComponent<PanelProps<SingleStatOptions>
getValues = (): FieldDisplay[] => {
const { data, options, replaceVariables } = this.props;
return getFieldDisplayValues({
...options,
replaceVariables,

View File

@ -2,14 +2,12 @@
import React, { PureComponent } from 'react';
// Components
import { Switch, PanelOptionsGroup } from '@grafana/ui';
import { Switch } from '@grafana/ui';
// Types
import { SparklineOptions } from './types';
const labelWidth = 6;
export interface Props {
interface Props {
options: SparklineOptions;
onChange: (options: SparklineOptions) => void;
}
@ -17,17 +15,9 @@ export interface Props {
export class SparklineEditor extends PureComponent<Props> {
onToggleShow = () => this.props.onChange({ ...this.props.options, show: !this.props.options.show });
onToggleFull = () => this.props.onChange({ ...this.props.options, full: !this.props.options.full });
render() {
const { show, full } = this.props.options;
const { show } = this.props.options;
return (
<PanelOptionsGroup title="Sparkline">
<Switch label="Show" labelClass={`width-${labelWidth}`} checked={show} onChange={this.onToggleShow} />
<Switch label="Full Height" labelClass={`width-${labelWidth}`} checked={full} onChange={this.onToggleFull} />
</PanelOptionsGroup>
);
return <Switch label="Graph" labelClass="width-8" checked={show} onChange={this.onToggleShow} />;
}
}

View File

@ -1,25 +1,35 @@
import { VizOrientation, SingleStatBaseOptions, FieldDisplayOptions } from '@grafana/ui';
import { VizOrientation, SingleStatBaseOptions, FieldDisplayOptions, SingleStatDisplayMode } from '@grafana/ui';
import { ReducerID } from '@grafana/data';
import { SelectableValue } from '@grafana/data';
export interface SparklineOptions {
show: boolean;
full: boolean; // full height
fillColor: string;
lineColor: string;
}
// Structure copied from angular
export interface SingleStatOptions extends SingleStatBaseOptions {
prefixFontSize?: string;
valueFontSize?: string;
postfixFontSize?: string;
colorBackground: boolean;
colorValue: boolean;
colorPrefix: boolean;
colorPostfix: boolean;
sparkline: SparklineOptions;
colorMode: ColorMode;
displayMode: SingleStatDisplayMode;
}
export const displayModes: Array<SelectableValue<SingleStatDisplayMode>> = [
{ value: SingleStatDisplayMode.Classic, label: 'Classic' },
{ value: SingleStatDisplayMode.Classic2, label: 'Classic 2' },
{ value: SingleStatDisplayMode.Vibrant, label: 'Vibrant' },
{ value: SingleStatDisplayMode.Vibrant2, label: 'Vibrant 2' },
];
export enum ColorMode {
Thresholds,
Series,
}
export const colorModes: Array<SelectableValue<ColorMode>> = [
{ value: ColorMode.Thresholds, label: 'Thresholds' },
{ value: ColorMode.Series, label: 'Series' },
];
export const standardFieldDisplayOptions: FieldDisplayOptions = {
values: false,
calcs: [ReducerID.mean],
@ -38,14 +48,9 @@ export const standardFieldDisplayOptions: FieldDisplayOptions = {
export const defaults: SingleStatOptions = {
sparkline: {
show: true,
full: false,
lineColor: 'rgb(31, 120, 193)',
fillColor: 'rgba(31, 118, 189, 0.18)',
},
colorMode: ColorMode.Thresholds,
displayMode: SingleStatDisplayMode.Vibrant,
fieldOptions: standardFieldDisplayOptions,
orientation: VizOrientation.Auto,
colorBackground: false,
colorValue: false,
colorPrefix: false,
colorPostfix: false,
};

View File

@ -386,3 +386,7 @@ a.external-link {
th {
font-weight: $font-weight-semi-bold;
}
canvas {
display: block;
}

View File

@ -40,7 +40,8 @@ const localStorageMock = (() => {
})();
global.localStorage = localStorageMock;
// Object.defineProperty(window, 'localStorage', { value: localStorageMock });
HTMLCanvasElement.prototype.getContext = jest.fn() as any;
const throwUnhandledRejections = () => {
process.on('unhandledRejection', err => {

240
yarn.lock
View File

@ -2,6 +2,84 @@
# yarn lockfile v1
"@antv/adjust@~0.1.0":
version "0.1.1"
resolved "https://registry.yarnpkg.com/@antv/adjust/-/adjust-0.1.1.tgz#e263ab0e1a1941a648842fc086cf65a7e3b75e98"
integrity sha512-9FaMOyBlM4AgoRL0b5o0VhEKAYkexBNUrxV8XmpHU/9NBPJONBOB/NZUlQDqxtLItrt91tCfbAuMQmF529UX2Q==
dependencies:
"@antv/util" "~1.3.1"
"@antv/attr@~0.1.2":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@antv/attr/-/attr-0.1.2.tgz#2eeb122fcaaf851a2d8749abc7c60519d3f77e37"
integrity sha512-QXjP+T2I+pJQcwZx1oCA4tipG43vgeCeKcGGKahlcxb71OBAzjJZm1QbF4frKXcnOqRkxVXtCr70X9TRair3Ew==
dependencies:
"@antv/util" "~1.3.1"
"@antv/component@~0.3.2":
version "0.3.5"
resolved "https://registry.yarnpkg.com/@antv/component/-/component-0.3.5.tgz#03f12db9206ae4e2d61c52443b7ff8bf0093e6f4"
integrity sha512-ucXFy5bDWAyEM/sRUOQJQHz3eiTP5J1t9np/y+KdmdvbqBr/B1Y6+X7lE1NzqwEuwKWfHUkVECYgqNQrhAZJWw==
dependencies:
"@antv/attr" "~0.1.2"
"@antv/g" "~3.3.5"
"@antv/util" "~1.3.1"
wolfy87-eventemitter "~5.1.0"
"@antv/coord@~0.1.0":
version "0.1.0"
resolved "https://registry.yarnpkg.com/@antv/coord/-/coord-0.1.0.tgz#48a80ae36d07552f96657e7f8095227c63f0c0a9"
integrity sha512-W1R8h3Jfb3AfMBVfCreFPMVetgEYuwHBIGn0+d3EgYXe2ckOF8XWjkpGF1fZhOMHREMr+Gt27NGiQh8yBdLUgg==
dependencies:
"@antv/util" "~1.3.1"
"@antv/g2@3.5.8-beta.1":
version "3.5.8-beta.1"
resolved "https://registry.yarnpkg.com/@antv/g2/-/g2-3.5.8-beta.1.tgz#71ba5b065ce513be916ceca258d2a02e1ea8e441"
integrity sha512-Lpq9rPDZI2mJzlaeY3qZ6R/Asb1wz6xopRmekOn3TXl8kzgQjp2m0U35gO7M2/Z+HxYOafzVjHkxCLuicsEuQw==
dependencies:
"@antv/adjust" "~0.1.0"
"@antv/attr" "~0.1.2"
"@antv/component" "~0.3.2"
"@antv/coord" "~0.1.0"
"@antv/g" "~3.3.6"
"@antv/scale" "~0.1.1"
"@antv/util" "~1.3.1"
venn.js "~0.2.20"
wolfy87-eventemitter "~5.1.0"
"@antv/g@~3.3.5", "@antv/g@~3.3.6":
version "3.3.6"
resolved "https://registry.yarnpkg.com/@antv/g/-/g-3.3.6.tgz#11fed9ddc9ed4e5a2aa244b7c8abb982a003f201"
integrity sha512-2GtyTz++s0BbN6s0ZL2/nrqGYCkd52pVoNH92YkrTdTOvpO6Z4DNoo6jGVgZdPX6Nzwli6yduC8MinVAhE8X6g==
dependencies:
"@antv/gl-matrix" "~2.7.1"
"@antv/util" "~1.3.1"
d3-ease "~1.0.3"
d3-interpolate "~1.1.5"
d3-timer "~1.0.6"
wolfy87-eventemitter "~5.1.0"
"@antv/gl-matrix@^2.7.1", "@antv/gl-matrix@~2.7.1":
version "2.7.1"
resolved "https://registry.yarnpkg.com/@antv/gl-matrix/-/gl-matrix-2.7.1.tgz#acb8e37f7ab3df01345aba4372d7942be42eba14"
integrity sha512-oOWcVNlpELIKi9x+Mm1Vwbz8pXfkbJKykoCIOJ/dNK79hSIANbpXJ5d3Rra9/wZqK6MC961B7sybFhPlLraT3Q==
"@antv/scale@~0.1.1":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@antv/scale/-/scale-0.1.3.tgz#4876e6140cb7dcda190e7fe2e780882dcac6b09d"
integrity sha512-oknlOg4OUqIh8LygrfQttx+OAnNJm2fQ81si4g8aby1WJJwj/TU1gCr+J3loIpKBtBK4VpP/OzTTqg1Ym67SOQ==
dependencies:
"@antv/util" "~1.3.1"
fecha "~2.3.3"
"@antv/util@~1.3.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@antv/util/-/util-1.3.1.tgz#30a34b201ff9126ec0d58c72c8166a9c3e644ccd"
integrity sha512-cbUta0hIJrKEaW3eKoGarz3Ita+9qUPF2YzTj8A6wds/nNiy20G26ztIWHU+5ThLc13B1n5Ik52LbaCaeg9enA==
dependencies:
"@antv/gl-matrix" "^2.7.1"
"@babel/code-frame@7.0.0", "@babel/code-frame@^7.0.0":
version "7.0.0"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8"
@ -4812,6 +4890,18 @@ binary-extensions@^1.0.0:
version "1.13.1"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
bizcharts@^3.5.5:
version "3.5.5"
resolved "https://registry.yarnpkg.com/bizcharts/-/bizcharts-3.5.5.tgz#108fb79c6dd203456361effbe3558b08ed82bf0e"
integrity sha512-2qTwWAylfPGdGX81u26a5t4IKUVHGbTK/lga873Wf+1/9mhG0TN6kLKmTpsPN9WKJmdDjFnZugFyNtB1bUWcKA==
dependencies:
"@antv/g2" "3.5.8-beta.1"
invariant "^2.2.2"
lodash.debounce "^4.0.8"
prop-types "^15.6.0"
resize-observer-polyfill "^1.5.1"
warning "^3.0.0"
bl@^1.0.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c"
@ -5879,6 +5969,11 @@ content-type@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
contour_plot@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/contour_plot/-/contour_plot-0.0.1.tgz#475870f032b8e338412aa5fc507880f0bf495c77"
integrity sha1-R1hw8DK44zhBKqX8UHiA8L9JXHc=
conventional-changelog-angular@^5.0.3:
version "5.0.3"
resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.3.tgz#299fdd43df5a1f095283ac16aeedfb0a682ecab0"
@ -6571,7 +6666,7 @@ d3-dsv@1.0.8:
iconv-lite "0.4"
rw "1"
d3-ease@1:
d3-ease@1, d3-ease@~1.0.3:
version "1.0.5"
resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.5.tgz#8ce59276d81241b1b72042d6af2d40e76d936ffb"
@ -6637,7 +6732,7 @@ d3-interpolate@1:
dependencies:
d3-color "1"
d3-interpolate@1.1.6:
d3-interpolate@1.1.6, d3-interpolate@~1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.1.6.tgz#2cf395ae2381804df08aa1bf766b7f97b5f68fb6"
dependencies:
@ -6726,7 +6821,7 @@ d3-scale@2:
d3-time "1"
d3-time-format "2"
d3-selection@1, d3-selection@^1.1.0:
d3-selection@1, d3-selection@^1.0.2, d3-selection@^1.1.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.4.0.tgz#ab9ac1e664cf967ebf1b479cc07e28ce9908c474"
@ -6766,7 +6861,7 @@ d3-time@1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.0.8.tgz#dbd2d6007bf416fe67a76d17947b784bffea1e84"
d3-timer@1:
d3-timer@1, d3-timer@~1.0.6:
version "1.0.9"
resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.9.tgz#f7bb8c0d597d792ff7131e1c24a36dd471a471ba"
@ -6774,7 +6869,7 @@ d3-timer@1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.7.tgz#df9650ca587f6c96607ff4e60cc38229e8dd8531"
d3-transition@1:
d3-transition@1, d3-transition@^1.0.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.2.0.tgz#f538c0e21b2aa1f05f3e965f8567e81284b3b2b8"
dependencies:
@ -7006,7 +7101,7 @@ deep-diff@^0.3.5:
version "0.3.8"
resolved "https://registry.yarnpkg.com/deep-diff/-/deep-diff-0.3.8.tgz#c01de63efb0eec9798801d40c7e0dae25b582c84"
deep-equal@^1.0.1:
deep-equal@^1.0.1, deep-equal@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
@ -7071,6 +7166,11 @@ define-property@^2.0.2:
is-descriptor "^1.0.2"
isobject "^3.0.1"
defined@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=
del@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5"
@ -8145,6 +8245,11 @@ fd-slicer@~1.0.1:
dependencies:
pend "~1.2.0"
fecha@~2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/fecha/-/fecha-2.3.3.tgz#948e74157df1a32fd1b12c3a3c3cdcb6ec9d96cd"
integrity sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==
figgy-pudding@^3.4.1, figgy-pudding@^3.5.1:
version "3.5.1"
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
@ -8328,6 +8433,17 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
fmin@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/fmin/-/fmin-0.0.2.tgz#59bbb40d43ffdc1c94cd00a568c41f95f1973017"
integrity sha1-Wbu0DUP/3ByUzQClaMQflfGXMBc=
dependencies:
contour_plot "^0.0.1"
json2module "^0.0.3"
rollup "^0.25.8"
tape "^4.5.1"
uglify-js "^2.6.2"
fn-name@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/fn-name/-/fn-name-2.0.1.tgz#5214d7537a4d06a4a301c0cc262feb84188002e7"
@ -8348,6 +8464,13 @@ follow-redirects@^1.0.0:
dependencies:
debug "^3.2.6"
for-each@~0.3.3:
version "0.3.3"
resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==
dependencies:
is-callable "^1.1.3"
for-in@^0.1.3:
version "0.1.8"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
@ -8533,7 +8656,7 @@ fstream@^1.0.0, fstream@^1.0.2:
mkdirp ">=0.5 0"
rimraf "2"
function-bind@^1.0.2, function-bind@^1.1.1:
function-bind@^1.0.2, function-bind@^1.1.1, function-bind@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
@ -8801,7 +8924,7 @@ glob@7.1.3, glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.1.3, glob@^7.1.4:
glob@^7.1.3, glob@^7.1.4, glob@~7.1.4:
version "7.1.4"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
@ -9221,7 +9344,7 @@ has-values@^1.0.0:
is-number "^3.0.0"
kind-of "^4.0.0"
has@^1.0.0, has@^1.0.1, has@^1.0.3:
has@^1.0.0, has@^1.0.1, has@^1.0.3, has@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
dependencies:
@ -9702,7 +9825,7 @@ inflight@^1.0.4, inflight@~1.0.6:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3, inherits@~2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@ -10908,6 +11031,13 @@ json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
json2module@^0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/json2module/-/json2module-0.0.3.tgz#00fb5f4a9b7adfc3f0647c29cb17bcd1979be9b2"
integrity sha1-APtfSpt638PwZHwpyxe80Zeb6bI=
dependencies:
rw "^1.3.2"
json3@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1"
@ -12056,7 +12186,7 @@ minimist@1.1.x:
version "1.1.3"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8"
minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0:
minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
@ -12893,7 +13023,7 @@ object-hash@^1.1.8:
version "1.3.1"
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df"
object-inspect@^1.6.0:
object-inspect@^1.6.0, object-inspect@~1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b"
@ -15908,6 +16038,13 @@ resolve@1.x, resolve@^1.1.6, resolve@^1.10.0, resolve@^1.3.2, resolve@^1.8.1:
dependencies:
path-parse "^1.0.6"
resolve@~1.11.1:
version "1.11.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e"
integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==
dependencies:
path-parse "^1.0.6"
restore-cursor@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541"
@ -15931,6 +16068,13 @@ restructured@0.0.11:
power-assert "^1.2.0"
unist-util-map "^1.0.2"
resumer@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759"
integrity sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=
dependencies:
through "~2.3.4"
ret@~0.1.10:
version "0.1.15"
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
@ -16056,6 +16200,15 @@ rollup@1.6.0:
"@types/node" "^11.9.5"
acorn "^6.1.1"
rollup@^0.25.8:
version "0.25.8"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-0.25.8.tgz#bf6ce83b87510d163446eeaa577ed6a6fc5835e0"
integrity sha1-v2zoO4dRDRY0Ru6qV37WpvxYNeA=
dependencies:
chalk "^1.1.1"
minimist "^1.2.0"
source-map-support "^0.3.2"
rst-selector-parser@^2.2.3:
version "2.2.3"
resolved "https://registry.yarnpkg.com/rst-selector-parser/-/rst-selector-parser-2.2.3.tgz#81b230ea2fcc6066c89e3472de794285d9b03d91"
@ -16101,7 +16254,7 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"
rw@1:
rw@1, rw@^1.3.2:
version "1.3.3"
resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
@ -16732,6 +16885,13 @@ source-map-resolve@^0.5.0:
source-map-url "^0.4.0"
urix "^0.1.0"
source-map-support@^0.3.2:
version "0.3.3"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.3.3.tgz#34900977d5ba3f07c7757ee72e73bb1a9b53754f"
integrity sha1-NJAJd9W6PwfHdX7nLnO7GptTdU8=
dependencies:
source-map "0.1.32"
source-map-support@^0.5.6, source-map-support@~0.5.10:
version "0.5.12"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599"
@ -16743,6 +16903,13 @@ source-map-url@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
source-map@0.1.32:
version "0.1.32"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266"
integrity sha1-yLbBZ3l7pHQKjqMyUhYv8IWRsmY=
dependencies:
amdefine ">=0.0.4"
source-map@0.4.x, source-map@^0.4.2, source-map@~0.4.1:
version "0.4.4"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
@ -17061,7 +17228,7 @@ string.prototype.padstart@^3.0.0:
es-abstract "^1.4.3"
function-bind "^1.0.2"
string.prototype.trim@^1.1.2:
string.prototype.trim@^1.1.2, string.prototype.trim@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea"
dependencies:
@ -17322,6 +17489,25 @@ tapable@^1.0.0, tapable@^1.1.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
tape@^4.5.1:
version "4.11.0"
resolved "https://registry.yarnpkg.com/tape/-/tape-4.11.0.tgz#63d41accd95e45a23a874473051c57fdbc58edc1"
integrity sha512-yixvDMX7q7JIs/omJSzSZrqulOV51EC9dK8dM0TzImTIkHWfe2/kFyL5v+d9C+SrCMaICk59ujsqFAVidDqDaA==
dependencies:
deep-equal "~1.0.1"
defined "~1.0.0"
for-each "~0.3.3"
function-bind "~1.1.1"
glob "~7.1.4"
has "~1.0.3"
inherits "~2.0.4"
minimist "~1.2.0"
object-inspect "~1.6.0"
resolve "~1.11.1"
resumer "~0.0.0"
string.prototype.trim "~1.1.2"
through "~2.3.8"
tar-fs@^1.13.0:
version "1.16.3"
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509"
@ -17503,7 +17689,7 @@ through2@^3.0.0:
dependencies:
readable-stream "2 || 3"
through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6, through@~2.3.6:
through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6, through@~2.3.4, through@~2.3.6, through@~2.3.8:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@ -17891,6 +18077,16 @@ uglify-js@3.4.x:
commander "~2.19.0"
source-map "~0.6.1"
uglify-js@^2.6.2:
version "2.8.29"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd"
integrity sha1-KcVzMUgFe7Th913zW3qcty5qWd0=
dependencies:
source-map "~0.5.1"
yargs "~3.10.0"
optionalDependencies:
uglify-to-browserify "~1.0.0"
uglify-js@^3.1.4:
version "3.5.11"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.5.11.tgz#833442c0aa29b3a7d34344c7c63adaa3f3504f6a"
@ -18231,6 +18427,15 @@ vendors@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.2.tgz#7fcb5eef9f5623b156bcea89ec37d63676f21801"
venn.js@~0.2.20:
version "0.2.20"
resolved "https://registry.yarnpkg.com/venn.js/-/venn.js-0.2.20.tgz#3f0e50cc75cba1f58692a8a32f67bd7aaf1aa6fa"
integrity sha512-bb5SYq/wamY9fvcuErb9a0FJkgIFHJjkLZWonQ+DoKKuDX3WPH2B4ouI1ce4K2iejBklQy6r1ly8nOGIyOCO6w==
dependencies:
d3-selection "^1.0.2"
d3-transition "^1.0.1"
fmin "0.0.2"
verror@1.10.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
@ -18648,6 +18853,11 @@ windows-release@^3.1.0:
dependencies:
execa "^1.0.0"
wolfy87-eventemitter@~5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/wolfy87-eventemitter/-/wolfy87-eventemitter-5.1.0.tgz#35c1ac0dd1ac0c15e35d981508fc22084a13a011"
integrity sha1-NcGsDdGsDBXjXZgVCPwiCEoToBE=
wordwrap@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"