Commit 50ebc768 by ryan

Merge remote-tracking branch 'grafana/master' into show-all-columns

* grafana/master: (56 commits)
  another change that didn't come with earlier commit
  change that didn't come with in last commit
  reversed dashboard-padding
  Update CloudWatch metrics/dimension list (#16102)
  brought back dashboard-padding and panel-padding variables, made dashboard-padding more specific
  fix(prometheus): Change aligment of range queries (#16110)
  Minor refactoring of testdata query order PR #16122
  cleaner version
  maintain query order
  Update PLUGIN_DEV.md
  Merge with master, and updated logo and name
  more fixes to snapshot
  more fixes to snapshot
  removed empty space in snapshot
  fixed snapshot for test
  removed dashboard variables, removed headings-font-family variable, created theme variables for links and z-index, removed unused class in _panel_editor and _dashboard
  Tooltip: show percent instead of value
  Right tooltip position
  Add "No data points" message
  Improve tooltip look
  ...
parents 0558b17b f2e1bfcd
......@@ -27,3 +27,8 @@ If you think we missed exposing a crucial lib or Grafana component let us know b
The angular directive `<spectrum-picker>` is now deprecated (will still work for a version more) but we recommend plugin authors
to upgrade to new `<color-picker color="ctrl.color" onChange="ctrl.onSparklineColorChange"></color-picker>`
## Changes in v6.0
### DashboardSrv.ts
If you utilize [DashboardSrv](https://github.com/grafana/grafana/commit/8574dca081002f36e482b572517d8f05fd44453f#diff-1ab99561f9f6a10e1fafcddc39bc1d65) in your plugin code, `dash` was renamed to `dashboard`
......@@ -21,6 +21,7 @@
"@torkelo/react-select": "2.1.1",
"@types/react-color": "^2.14.0",
"classnames": "^2.2.5",
"d3": "^5.7.0",
"jquery": "^3.2.1",
"lodash": "^4.17.10",
"moment": "^2.22.2",
......@@ -43,6 +44,7 @@
"@storybook/addon-knobs": "^4.1.7",
"@storybook/react": "^4.1.4",
"@types/classnames": "^2.2.6",
"@types/d3": "^5.7.0",
"@types/jest": "^23.3.2",
"@types/jquery": "^1.10.35",
"@types/lodash": "^4.14.119",
......
import { storiesOf } from '@storybook/react';
import { number, text, object } from '@storybook/addon-knobs';
import { PieChart, PieChartType } from './PieChart';
import { withCenteredStory } from '../../utils/storybook/withCenteredStory';
import { renderComponentWithTheme } from '../../utils/storybook/withTheme';
const getKnobs = () => {
return {
datapoints: object('datapoints', [
{
value: 100,
name: '100',
color: '#7EB26D',
},
{
value: 200,
name: '200',
color: '#6ED0E0',
},
]),
pieType: text('pieType', PieChartType.PIE),
strokeWidth: number('strokeWidth', 1),
unit: text('unit', 'ms'),
};
};
const PieChartStories = storiesOf('UI/PieChart/PieChart', module);
PieChartStories.addDecorator(withCenteredStory);
PieChartStories.add('Pie type: pie', () => {
const { datapoints, pieType, strokeWidth, unit } = getKnobs();
return renderComponentWithTheme(PieChart, {
width: 200,
height: 400,
datapoints,
pieType,
strokeWidth,
unit,
});
});
import React, { PureComponent } from 'react';
import { select, pie, arc, event } from 'd3';
import { sum } from 'lodash';
import { GrafanaThemeType } from '../../types';
import { Themeable } from '../../index';
export enum PieChartType {
PIE = 'pie',
DONUT = 'donut',
}
export interface PieChartDataPoint {
value: number;
name: string;
color: string;
}
export interface Props extends Themeable {
height: number;
width: number;
datapoints: PieChartDataPoint[];
unit: string;
pieType: PieChartType;
strokeWidth: number;
}
export class PieChart extends PureComponent<Props> {
containerElement: any;
svgElement: any;
tooltipElement: any;
tooltipValueElement: any;
static defaultProps = {
pieType: 'pie',
format: 'short',
stat: 'current',
strokeWidth: 1,
theme: GrafanaThemeType.Dark,
};
componentDidMount() {
this.draw();
}
componentDidUpdate() {
this.draw();
}
draw() {
const { datapoints, pieType, strokeWidth } = this.props;
if (datapoints.length === 0) {
return;
}
const data = datapoints.map(datapoint => datapoint.value);
const names = datapoints.map(datapoint => datapoint.name);
const colors = datapoints.map(datapoint => datapoint.color);
const total = sum(data) || 1;
const percents = data.map((item: number) => (item / total) * 100);
const width = this.containerElement.offsetWidth;
const height = this.containerElement.offsetHeight;
const radius = Math.min(width, height) / 2;
const outerRadius = radius - radius / 10;
const innerRadius = pieType === PieChartType.PIE ? 0 : radius - radius / 3;
const svg = select(this.svgElement)
.html('')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', `translate(${width / 2},${height / 2})`);
const pieChart = pie();
const customArc = arc()
.outerRadius(outerRadius)
.innerRadius(innerRadius)
.padAngle(0);
svg
.selectAll('path')
.data(pieChart(data))
.enter()
.append('path')
.attr('d', customArc as any)
.attr('fill', (d: any, idx: number) => colors[idx])
.style('fill-opacity', 0.15)
.style('stroke', (d: any, idx: number) => colors[idx])
.style('stroke-width', `${strokeWidth}px`)
.on('mouseover', (d: any, idx: any) => {
select(this.tooltipElement).style('opacity', 1);
select(this.tooltipValueElement).text(`${names[idx]} (${percents[idx].toFixed(2)}%)`);
})
.on('mousemove', () => {
select(this.tooltipElement)
.style('top', `${event.pageY - height / 2}px`)
.style('left', `${event.pageX}px`);
})
.on('mouseout', () => {
select(this.tooltipElement).style('opacity', 0);
});
}
render() {
const { height, width, datapoints } = this.props;
if (datapoints.length > 0) {
return (
<div className="piechart-panel">
<div
ref={element => (this.containerElement = element)}
className="piechart-container"
style={{
height: `${height * 0.9}px`,
width: `${Math.min(width, height * 1.3)}px`,
}}
>
<svg ref={element => (this.svgElement = element)} />
</div>
<div className="piechart-tooltip" ref={element => (this.tooltipElement = element)}>
<div className="piechart-tooltip-time">
<div
id="tooltip-value"
className="piechart-tooltip-value"
ref={element => (this.tooltipValueElement = element)}
/>
</div>
</div>
</div>
);
} else {
return (
<div className="piechart-panel">
<div className="datapoints-warning">
<span className="small">No data points</span>
</div>
</div>
);
}
}
}
......@@ -195,7 +195,7 @@ exports[`Render should render with base threshold 1`] = `
"typography": Object {
"fontFamily": Object {
"monospace": "Menlo, Monaco, Consolas, 'Courier New', monospace",
"sansSerif": "'Roboto', Helvetica, Arial, sans-serif",
"sansSerif": "'Roboto', 'Helvetica Neue', Arial, sans-serif",
},
"heading": Object {
"h1": "28px",
......@@ -211,6 +211,10 @@ exports[`Render should render with base threshold 1`] = `
"sm": 1.1,
"xs": 1,
},
"link": Object {
"decoration": "none",
"hoverDecoration": "none",
},
"size": Object {
"base": "13px",
"lg": "18px",
......@@ -225,6 +229,15 @@ exports[`Render should render with base threshold 1`] = `
"semibold": 500,
},
},
"zIndex": Object {
"dropdown": "1000",
"modal": "1050",
"modalBackdrop": "1040",
"navbarFixed": "1020",
"sidemenu": "1025",
"tooltip": "1030",
"typeahead": "1060",
},
}
}
>
......@@ -339,7 +352,7 @@ exports[`Render should render with base threshold 1`] = `
"typography": Object {
"fontFamily": Object {
"monospace": "Menlo, Monaco, Consolas, 'Courier New', monospace",
"sansSerif": "'Roboto', Helvetica, Arial, sans-serif",
"sansSerif": "'Roboto', 'Helvetica Neue', Arial, sans-serif",
},
"heading": Object {
"h1": "28px",
......@@ -355,6 +368,10 @@ exports[`Render should render with base threshold 1`] = `
"sm": 1.1,
"xs": 1,
},
"link": Object {
"decoration": "none",
"hoverDecoration": "none",
},
"size": Object {
"base": "13px",
"lg": "18px",
......@@ -369,6 +386,15 @@ exports[`Render should render with base threshold 1`] = `
"semibold": 500,
},
},
"zIndex": Object {
"dropdown": "1000",
"modal": "1050",
"modalBackdrop": "1040",
"navbarFixed": "1020",
"sidemenu": "1025",
"tooltip": "1030",
"typeahead": "1060",
},
}
}
/>
......
......@@ -25,6 +25,7 @@ export { PanelOptionsGrid } from './PanelOptionsGrid/PanelOptionsGrid';
export { ValueMappingsEditor } from './ValueMappingsEditor/ValueMappingsEditor';
export { Switch } from './Switch/Switch';
export { EmptySearchResult } from './EmptySearchResult/EmptySearchResult';
export { PieChart, PieChartDataPoint, PieChartType } from './PieChart/PieChart';
export { UnitPicker } from './UnitPicker/UnitPicker';
export { Input, InputStatus } from './Input/Input';
......
......@@ -110,7 +110,6 @@ $font-size-h4: ${theme.typography.heading.h4} !default;
$font-size-h5: ${theme.typography.heading.h5} !default;
$font-size-h6: ${theme.typography.heading.h6} !default;
$headings-font-family: 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif;
$headings-line-height: ${theme.typography.lineHeight.sm} !default;
// Components
......@@ -130,8 +129,8 @@ $page-sidebar-margin: 56px;
// Links
// -------------------------
$link-decoration: none !default;
$link-hover-decoration: none !default;
$link-decoration: ${theme.typography.link.decoration} !default;
$link-hover-decoration: ${theme.typography.link.hoverDecoration} !default;
// Tables
//
......@@ -166,13 +165,13 @@ $form-icon-danger: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www
// -------------------------
// Used for a bird's eye view of components dependent on the z-axis
// Try to avoid customizing these :)
$zindex-dropdown: 1000;
$zindex-navbar-fixed: 1020;
$zindex-sidemenu: 1025;
$zindex-tooltip: 1030;
$zindex-modal-backdrop: 1040;
$zindex-modal: 1050;
$zindex-typeahead: 1060;
$zindex-dropdown: ${theme.zIndex.dropdown};
$zindex-navbar-fixed: ${theme.zIndex.navbarFixed};
$zindex-sidemenu: ${theme.zIndex.sidemenu};
$zindex-tooltip: ${theme.zIndex.tooltip};
$zindex-modal-backdrop: ${theme.zIndex.modalBackdrop};
$zindex-modal: ${theme.zIndex.modal};
$zindex-typeahead: ${theme.zIndex.typeahead};
// Buttons
//
......@@ -197,10 +196,8 @@ $btn-semi-transparent: rgba(0, 0, 0, 0.2) !default;
$side-menu-width: 60px;
// dashboard
$dashboard-padding: 10px * 2;
$panel-horizontal-padding: 10;
$panel-vertical-padding: 5;
$panel-padding: 0px $panel-horizontal-padding + 0px $panel-vertical-padding + 0px $panel-horizontal-padding + 0px;
$dashboard-padding: $space-md;
$panel-padding: 0 $space-md $space-sm $space-md;
// tabs
$tabs-padding: 10px 15px 9px;
......
......@@ -4,7 +4,7 @@ const theme: GrafanaThemeCommons = {
name: 'Grafana Default',
typography: {
fontFamily: {
sansSerif: "'Roboto', Helvetica, Arial, sans-serif",
sansSerif: "'Roboto', 'Helvetica Neue', Arial, sans-serif",
monospace: "Menlo, Monaco, Consolas, 'Courier New', monospace",
},
size: {
......@@ -34,6 +34,10 @@ const theme: GrafanaThemeCommons = {
md: 4 / 3,
lg: 1.5,
},
link: {
decoration: 'none',
hoverDecoration: 'none',
},
},
breakpoints: {
xs: '0',
......@@ -66,6 +70,15 @@ const theme: GrafanaThemeCommons = {
horizontal: 10,
vertical: 5,
},
zIndex: {
dropdown: '1000',
navbarFixed: '1020',
sidemenu: '1025',
tooltip: '1030',
modalBackdrop: '1040',
modal: '1050',
typeahead: '1060',
},
};
export default theme;
......@@ -46,6 +46,10 @@ export interface GrafanaThemeCommons {
h5: string;
h6: string;
};
link: {
decoration: string;
hoverDecoration: string;
};
};
spacing: {
d: string;
......@@ -71,6 +75,15 @@ export interface GrafanaThemeCommons {
horizontal: number;
vertical: number;
};
zIndex: {
dropdown: string;
navbarFixed: string;
sidemenu: string;
tooltip: string;
modalBackdrop: string;
modal: string;
typeahead: string;
};
}
export interface GrafanaTheme extends GrafanaThemeCommons {
......
......@@ -28,6 +28,7 @@ import * as singlestatPanel from 'app/plugins/panel/singlestat/module';
import * as singlestatPanel2 from 'app/plugins/panel/singlestat2/module';
import * as gettingStartedPanel from 'app/plugins/panel/gettingstarted/module';
import * as gaugePanel from 'app/plugins/panel/gauge/module';
import * as pieChartPanel from 'app/plugins/panel/piechart/module';
import * as barGaugePanel from 'app/plugins/panel/bargauge/module';
const builtInPlugins = {
......@@ -61,6 +62,7 @@ const builtInPlugins = {
'app/plugins/panel/singlestat2/module': singlestatPanel2,
'app/plugins/panel/gettingstarted/module': gettingStartedPanel,
'app/plugins/panel/gauge/module': gaugePanel,
'app/plugins/panel/piechart/module': pieChartPanel,
'app/plugins/panel/bargauge/module': barGaugePanel,
};
......
......@@ -224,7 +224,8 @@ export class PrometheusDatasource implements DataSourceApi<PromQuery> {
query.expr = this.templateSrv.replace(expr, scopedVars, this.interpolateQueryExpr);
query.requestId = options.panelId + target.refId;
// Align query interval with step
// Align query interval with step to allow query caching and to ensure
// that about-same-time query results look the same.
const adjusted = alignRange(start, end, query.step);
query.start = adjusted.start;
query.end = adjusted.end;
......@@ -497,8 +498,15 @@ export class PrometheusDatasource implements DataSourceApi<PromQuery> {
}
}
export function alignRange(start, end, step) {
const alignedEnd = Math.ceil(end / step) * step;
/**
* Align query range to step.
* Rounds start and end down to a multiple of step.
* @param start Timestamp marking the beginning of the range.
* @param end Timestamp marking the end of the range.
* @param step Interval to align start and end with.
*/
export function alignRange(start: number, end: number, step: number): { end: number; start: number } {
const alignedEnd = Math.floor(end / step) * step;
const alignedStart = Math.floor(start / step) * step;
return {
end: alignedEnd,
......
......@@ -206,12 +206,12 @@ describe('PrometheusDatasource', () => {
it('does align intervals that are a multiple of steps', () => {
const range = alignRange(1, 4, 3);
expect(range.start).toEqual(0);
expect(range.end).toEqual(6);
expect(range.end).toEqual(3);
});
it('does align intervals that are not a multiple of steps', () => {
const range = alignRange(1, 5, 3);
expect(range.start).toEqual(0);
expect(range.end).toEqual(6);
expect(range.end).toEqual(3);
});
});
......@@ -360,7 +360,7 @@ describe('PrometheusDatasource', () => {
};
// Interval alignment with step
const urlExpected =
'proxied/api/v1/query_range?query=' + encodeURIComponent('test{job="testjob"}') + '&start=60&end=240&step=60';
'proxied/api/v1/query_range?query=' + encodeURIComponent('test{job="testjob"}') + '&start=60&end=180&step=60';
beforeEach(async () => {
const response = {
......@@ -788,7 +788,7 @@ describe('PrometheusDatasource', () => {
interval: '5s',
};
// times get rounded up to interval
const urlExpected = 'proxied/api/v1/query_range?query=test&start=50&end=450&step=50';
const urlExpected = 'proxied/api/v1/query_range?query=test&start=50&end=400&step=50';
backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response));
ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv as any, templateSrv, timeSrv);
await ctx.ds.query(query);
......@@ -831,7 +831,7 @@ describe('PrometheusDatasource', () => {
interval: '10s',
};
// times get aligned to interval
const urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=0&end=500&step=100';
const urlExpected = 'proxied/api/v1/query_range?query=test' + '&start=0&end=400&step=100';
backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response));
ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv as any, templateSrv, timeSrv);
await ctx.ds.query(query);
......@@ -996,7 +996,7 @@ describe('PrometheusDatasource', () => {
const urlExpected =
'proxied/api/v1/query_range?query=' +
encodeURIComponent('rate(test[$__interval])') +
'&start=0&end=500&step=100';
'&start=0&end=400&step=100';
backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response));
templateSrv.replace = jest.fn(str => str);
ctx.ds = new PrometheusDatasource(instanceSettings, q, backendSrv as any, templateSrv, timeSrv);
......@@ -1041,7 +1041,7 @@ describe('PrometheusDatasource', () => {
const urlExpected =
'proxied/api/v1/query_range?query=' +
encodeURIComponent('rate(test[$__interval])') +
'&start=50&end=450&step=50';
'&start=50&end=400&step=50';
templateSrv.replace = jest.fn(str => str);
backendSrv.datasourceRequest = jest.fn(() => Promise.resolve(response));
......@@ -1166,7 +1166,7 @@ describe('PrometheusDatasource for POST', () => {
const dataExpected = {
query: 'test{job="testjob"}',
start: 1 * 60,
end: 3 * 60,
end: 2 * 60,
step: 60,
};
const query = {
......
import _ from 'lodash';
import TableModel from 'app/core/table_model';
import { DataSourceApi, DataQueryOptions } from '@grafana/ui';
import { DataSourceApi, DataQueryOptions, TableData, TimeSeries } from '@grafana/ui';
import { TestDataQuery, Scenario } from './types';
type TestData = TimeSeries | TableData;
export interface TestDataRegistry {
[key: string]: TestData[];
}
export class TestDataDatasource implements DataSourceApi<TestDataQuery> {
id: number;
......@@ -42,26 +47,24 @@ export class TestDataDatasource implements DataSourceApi<TestDataQuery> {
},
})
.then(res => {
const data = [];
if (res.data.results) {
_.forEach(res.data.results, queryRes => {
if (queryRes.tables) {
for (const table of queryRes.tables) {
const model = new TableModel();
model.rows = table.rows;
model.columns = table.columns;
const data: TestData[] = [];
data.push(model);
// Returns data in the order it was asked for.
// if the response has data with different refId, it is ignored
for (const query of queries) {
const results = res.data.results[query.refId];
if (!results) {
console.warn('No Results for:', query);
continue;
}
for (const table of results.tables || []) {
data.push(table as TableData);
}
for (const series of queryRes.series) {
data.push({
target: series.name,
datapoints: series.points,
});
for (const series of results.series || []) {
data.push({ target: series.name, datapoints: series.points });
}
});
}
return { data: data };
......
// Libraries
import React, { PureComponent } from 'react';
// Components
import { Select, FormLabel, PanelOptionsGroup } from '@grafana/ui';
// Types
import { FormField, PanelEditorProps } from '@grafana/ui';
import { PieChartType } from '@grafana/ui';
import { PieChartOptions } from './types';
const labelWidth = 8;
const pieChartOptions = [{ value: PieChartType.PIE, label: 'Pie' }, { value: PieChartType.DONUT, label: 'Donut' }];
export class PieChartOptionsBox extends PureComponent<PanelEditorProps<PieChartOptions>> {
onPieTypeChange = pieType => this.props.onOptionsChange({ ...this.props.options, pieType: pieType.value });
onStrokeWidthChange = ({ target }) =>
this.props.onOptionsChange({ ...this.props.options, strokeWidth: target.value });
render() {
const { options } = this.props;
const { pieType, strokeWidth } = options;
return (
<PanelOptionsGroup title="PieChart">
<div className="gf-form">
<FormLabel width={labelWidth}>Type</FormLabel>
<Select
width={12}
options={pieChartOptions}
onChange={this.onPieTypeChange}
value={pieChartOptions.find(option => option.value === pieType)}
/>
</div>
<div className="gf-form">
<FormField
label="Divider width"
labelWidth={labelWidth}
onChange={this.onStrokeWidthChange}
value={strokeWidth}
/>
</div>
</PanelOptionsGroup>
);
}
}
// Libraries
import React, { PureComponent } from 'react';
// Services & Utils
import { processTimeSeries, ThemeContext } from '@grafana/ui';
// Components
import { PieChart, PieChartDataPoint } from '@grafana/ui';
// Types
import { PieChartOptions } from './types';
import { PanelProps, NullValueMode } from '@grafana/ui/src/types';
interface Props extends PanelProps<PieChartOptions> {}
export class PieChartPanel extends PureComponent<Props> {
render() {
const { data, width, height, options } = this.props;
const { valueOptions } = options;
const datapoints: PieChartDataPoint[] = [];
if (data) {
const vmSeries = processTimeSeries({
data,
nullValueMode: NullValueMode.Null,
});
for (let i = 0; i < vmSeries.length; i++) {
const serie = vmSeries[i];
if (serie) {
datapoints.push({
value: serie.stats[valueOptions.stat],
name: serie.label,
color: serie.color,
});
}
}
}
// TODO: support table data
return (
<ThemeContext.Consumer>
{theme => (
<PieChart
width={width}
height={height}
datapoints={datapoints}
pieType={options.pieType}
strokeWidth={options.strokeWidth}
unit={valueOptions.unit}
theme={theme}
/>
)}
</ThemeContext.Consumer>
);
}
}
import React, { PureComponent } from 'react';
import { PanelEditorProps, PanelOptionsGrid } from '@grafana/ui';
import PieChartValueEditor from './PieChartValueEditor';
import { PieChartOptionsBox } from './PieChartOptionsBox';
import { PieChartOptions, PieChartValueOptions } from './types';
export default class PieChartPanelEditor extends PureComponent<PanelEditorProps<PieChartOptions>> {
onValueOptionsChanged = (valueOptions: PieChartValueOptions) =>
this.props.onOptionsChange({
...this.props.options,
valueOptions,
});
render() {
const { onOptionsChange, options } = this.props;
return (
<>
<PanelOptionsGrid>
<PieChartValueEditor onChange={this.onValueOptionsChanged} options={options.valueOptions} />
<PieChartOptionsBox onOptionsChange={onOptionsChange} options={options} />
</PanelOptionsGrid>
</>
);
}
}
import React, { PureComponent } from 'react';
import { FormLabel, PanelOptionsGroup, Select, UnitPicker } from '@grafana/ui';
import { PieChartValueOptions } from './types';
const statOptions = [
{ value: 'min', label: 'Min' },
{ value: 'max', label: 'Max' },
{ value: 'avg', label: 'Average' },
{ value: 'current', label: 'Current' },
{ value: 'total', label: 'Total' },
];
const labelWidth = 6;
export interface Props {
options: PieChartValueOptions;
onChange: (valueOptions: PieChartValueOptions) => void;
}
export default class PieChartValueEditor extends PureComponent<Props> {
onUnitChange = unit =>
this.props.onChange({
...this.props.options,
unit: unit.value,
});
onStatChange = stat =>
this.props.onChange({
...this.props.options,
stat: stat.value,
});
render() {
const { stat, unit } = this.props.options;
return (
<PanelOptionsGroup title="Value">
<div className="gf-form">
<FormLabel width={labelWidth}>Unit</FormLabel>
<UnitPicker defaultValue={unit} onChange={this.onUnitChange} />
</div>
<div className="gf-form">
<FormLabel width={labelWidth}>Value</FormLabel>
<Select
width={12}
options={statOptions}
onChange={this.onStatChange}
value={statOptions.find(option => option.value === stat)}
/>
</div>
</PanelOptionsGroup>
);
}
}
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 23.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="100px" height="100px" viewBox="0 0 100 100" style="enable-background:new 0 0 100 100;" xml:space="preserve">
<style type="text/css">
.st0{fill:url(#SVGID_1_);}
.st1{fill:#C9202F;}
.st2{fill:url(#SVGID_2_);}
</style>
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="34.3609" y1="59.9311" x2="106.9924" y2="-19.0856">
<stop offset="0" style="stop-color:#FFF33B"/>
<stop offset="5.948725e-02" style="stop-color:#FFE029"/>
<stop offset="0.1303" style="stop-color:#FFD218"/>
<stop offset="0.2032" style="stop-color:#FEC90F"/>
<stop offset="0.2809" style="stop-color:#FDC70C"/>
<stop offset="0.6685" style="stop-color:#F3903F"/>
<stop offset="0.8876" style="stop-color:#ED683C"/>
<stop offset="1" style="stop-color:#E93E3A"/>
</linearGradient>
<path class="st0" d="M51.8,0.1v47.4l45.1-14.7C89.8,13.4,72.4,0.8,51.8,0.1z"/>
<path class="st1" d="M98,36.3L52.9,50.9l17.7,24.3l10.2,14C97.1,76.6,103.7,56.1,98,36.3z"/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="1.519853e-02" y1="50.001" x2="77.8424" y2="50.001">
<stop offset="0" style="stop-color:#04A64D"/>
<stop offset="1" style="stop-color:#007E39"/>
</linearGradient>
<path class="st2" d="M48.2,50.6V0.1C21.4,1,0,23,0,50C0,77.5,22.4,99.9,50,99.9c10.5,0,19.4-2.7,27.9-8.5L48.2,50.6z"/>
</g>
</svg>
import { ReactPanelPlugin } from '@grafana/ui';
import PieChartPanelEditor from './PieChartPanelEditor';
import { PieChartPanel } from './PieChartPanel';
import { PieChartOptions, defaults } from './types';
export const reactPanel = new ReactPanelPlugin<PieChartOptions>(PieChartPanel);
reactPanel.setEditor(PieChartPanelEditor);
reactPanel.setDefaults(defaults);
{
"type": "panel",
"name": "PieChart v2",
"id": "piechart",
"state": "alpha",
"dataFormats": ["time_series"],
"info": {
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
},
"logos": {
"small": "img/icon_piechart.svg",
"large": "img/icon_piechart.svg"
}
}
}
import { PieChartType } from '@grafana/ui';
export interface PieChartOptions {
pieType: PieChartType;
strokeWidth: number;
valueOptions: PieChartValueOptions;
}
export interface PieChartValueOptions {
unit: string;
stat: string;
}
export const defaults: PieChartOptions = {
pieType: PieChartType.PIE,
strokeWidth: 1,
valueOptions: {
unit: 'short',
stat: 'current',
},
};
......@@ -54,6 +54,7 @@
@import 'components/panel_alertlist';
@import 'components/panel_dashlist';
@import 'components/panel_gettingstarted';
@import 'components/panel_piechart';
@import 'components/panel_pluginlist';
@import 'components/panel_singlestat';
@import 'components/panel_table';
......
......@@ -90,7 +90,7 @@ $grid-gutter-width: 30px !default;
// Typography
// -------------------------
$font-family-sans-serif: 'Roboto', Helvetica, Arial, sans-serif;
$font-family-sans-serif: 'Roboto', 'Helvetica Neue', Arial, sans-serif;
$font-family-monospace: Menlo, Monaco, Consolas, 'Courier New', monospace;
$font-size-root: 14px !default;
......@@ -113,7 +113,6 @@ $font-size-h4: 18px !default;
$font-size-h5: 16px !default;
$font-size-h6: 14px !default;
$headings-font-family: 'Roboto', 'Helvetica Neue', Helvetica, Arial, sans-serif;
$headings-line-height: 1.1 !default;
// Components
......@@ -200,10 +199,8 @@ $btn-semi-transparent: rgba(0, 0, 0, 0.2) !default;
$side-menu-width: 60px;
// dashboard
$dashboard-padding: 10px * 2;
$panel-horizontal-padding: 10;
$panel-vertical-padding: 5;
$panel-padding: 0px $panel-horizontal-padding + 0px $panel-vertical-padding + 0px $panel-horizontal-padding + 0px;
$dashboard-padding: $space-md;
$panel-padding: 0 $space-md $space-sm $space-md;
// tabs
$tabs-padding: 10px 15px 9px;
......
......@@ -110,7 +110,6 @@ h6,
.h5,
.h6 {
margin-bottom: $space-sm;
font-family: $headings-font-family;
font-weight: $font-weight-regular;
line-height: $headings-line-height;
color: $headings-color;
......
......@@ -83,10 +83,6 @@
padding: 0 $dashboard-padding $space-sm $dashboard-padding;
}
.panel-editor-container__panel {
margin: 0 $dashboard-padding;
}
.search-container {
left: 0 !important;
}
......
......@@ -3,8 +3,7 @@ $column-horizontal-spacing: 10px;
.logs-panel-options {
display: flex;
background-color: $page-bg;
padding: $panel-padding;
padding-top: 10px;
padding: $space-sm $space-md $space-sm $space-md;
border-radius: $border-radius;
margin: $space-md 0 $space-sm;
border: $panel-border;
......
.piechart-panel {
position: relative;
display: table;
width: 100%;
height: 100%;
.piechart-container {
top: 10px;
margin: auto;
svg {
width: 100%;
height: 100%;
}
}
.piechart-tooltip {
white-space: nowrap;
font-size: 12px;
background-color: #141414;
color: #d8d9da;
opacity: 0;
position: absolute;
.piechart-tooltip-time {
text-align: center;
position: relative;
padding: 0.2rem;
font-weight: bold;
color: #d8d9da;
.piechart-tooltip-value {
display: table-cell;
font-weight: bold;
padding: 15px;
text-align: right;
}
}
}
}
......@@ -13,7 +13,7 @@
.tabbed-view-header {
box-shadow: $page-header-shadow;
border-bottom: 1px solid $page-header-border-color;
padding: 0 $dashboard-padding;
padding: 0 $space-md;
@include clearfix();
}
......
......@@ -260,7 +260,6 @@ div.flot-text {
}
.dashboard-header {
font-family: $headings-font-family;
font-size: $font-size-h3;
text-align: center;
overflow: hidden;
......@@ -273,10 +272,6 @@ div.flot-text {
}
}
.panel-full-edit {
padding-top: $dashboard-padding;
}
.dashboard-loading {
height: 60vh;
display: flex;
......
......@@ -176,12 +176,10 @@
}
.explore-panel__header {
padding: $panel-padding;
padding-top: 5px;
padding-bottom: 0;
padding: $space-sm $space-md 0 $space-md;
display: flex;
cursor: pointer;
margin-bottom: 5px;
margin-bottom: $space-sm;
transition: all 0.1s linear;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment