mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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 ...
This commit is contained in:
@@ -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 = {
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
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 = [];
|
||||
const data: TestData[] = [];
|
||||
|
||||
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;
|
||||
// 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;
|
||||
}
|
||||
|
||||
data.push(model);
|
||||
}
|
||||
}
|
||||
for (const series of queryRes.series) {
|
||||
data.push({
|
||||
target: series.name,
|
||||
datapoints: series.points,
|
||||
});
|
||||
}
|
||||
});
|
||||
for (const table of results.tables || []) {
|
||||
data.push(table as TableData);
|
||||
}
|
||||
|
||||
for (const series of results.series || []) {
|
||||
data.push({ target: series.name, datapoints: series.points });
|
||||
}
|
||||
}
|
||||
|
||||
return { data: data };
|
||||
|
||||
47
public/app/plugins/panel/piechart/PieChartOptionsBox.tsx
Normal file
47
public/app/plugins/panel/piechart/PieChartOptionsBox.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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>
|
||||
);
|
||||
}
|
||||
}
|
||||
57
public/app/plugins/panel/piechart/PieChartPanel.tsx
Normal file
57
public/app/plugins/panel/piechart/PieChartPanel.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
// 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>
|
||||
);
|
||||
}
|
||||
}
|
||||
27
public/app/plugins/panel/piechart/PieChartPanelEditor.tsx
Normal file
27
public/app/plugins/panel/piechart/PieChartPanelEditor.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
54
public/app/plugins/panel/piechart/PieChartValueEditor.tsx
Normal file
54
public/app/plugins/panel/piechart/PieChartValueEditor.tsx
Normal file
@@ -0,0 +1,54 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
}
|
||||
29
public/app/plugins/panel/piechart/img/icon_piechart.svg
Normal file
29
public/app/plugins/panel/piechart/img/icon_piechart.svg
Normal file
@@ -0,0 +1,29 @@
|
||||
<?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>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
10
public/app/plugins/panel/piechart/module.tsx
Normal file
10
public/app/plugins/panel/piechart/module.tsx
Normal file
@@ -0,0 +1,10 @@
|
||||
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);
|
||||
19
public/app/plugins/panel/piechart/plugin.json
Normal file
19
public/app/plugins/panel/piechart/plugin.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
21
public/app/plugins/panel/piechart/types.ts
Normal file
21
public/app/plugins/panel/piechart/types.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
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;
|
||||
|
||||
40
public/sass/components/_panel_piechart.scss
Normal file
40
public/sass/components/_panel_piechart.scss
Normal file
@@ -0,0 +1,40 @@
|
||||
.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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user