mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
43
public/app/core/components/Picker/Unit/UnitGroup.tsx
Normal file
43
public/app/core/components/Picker/Unit/UnitGroup.tsx
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import React, { PureComponent } from 'react';
|
||||||
|
import { GroupProps } from 'react-select/lib/components/Group';
|
||||||
|
|
||||||
|
interface ExtendedGroupProps extends GroupProps<any> {
|
||||||
|
data: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface State {
|
||||||
|
expanded: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class UnitGroup extends PureComponent<ExtendedGroupProps, State> {
|
||||||
|
state = {
|
||||||
|
expanded: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidUpdate(nextProps) {
|
||||||
|
if (nextProps.selectProps.inputValue !== '') {
|
||||||
|
this.setState({ expanded: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onToggleChildren = () => {
|
||||||
|
this.setState(prevState => ({
|
||||||
|
expanded: !prevState.expanded,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { children, label } = this.props;
|
||||||
|
const { expanded } = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="width-21 unit-picker-group" style={{ marginBottom: '5px' }}>
|
||||||
|
<div className="unit-picker-group-item" onClick={this.onToggleChildren}>
|
||||||
|
<span style={{ textTransform: 'capitalize' }}>{label}</span>
|
||||||
|
<i className={`fa ${expanded ? 'fa-minus' : 'fa-plus'}`} />{' '}
|
||||||
|
</div>
|
||||||
|
{expanded && children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
22
public/app/core/components/Picker/Unit/UnitOption.tsx
Normal file
22
public/app/core/components/Picker/Unit/UnitOption.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import React, { SFC } from 'react';
|
||||||
|
import { components } from 'react-select';
|
||||||
|
import { OptionProps } from 'react-select/lib/components/Option';
|
||||||
|
|
||||||
|
interface ExtendedOptionProps extends OptionProps<any> {
|
||||||
|
data: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UnitOption: SFC<ExtendedOptionProps> = props => {
|
||||||
|
const { children, isSelected, className } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<components.Option {...props}>
|
||||||
|
<div className={`unit-picker-option__button btn btn-link ${className}`}>
|
||||||
|
{isSelected && <i className="fa fa-check pull-right" aria-hidden="true" />}
|
||||||
|
<div className="gf-form">{children}</div>
|
||||||
|
</div>
|
||||||
|
</components.Option>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UnitOption;
|
||||||
69
public/app/core/components/Picker/Unit/UnitPicker.tsx
Normal file
69
public/app/core/components/Picker/Unit/UnitPicker.tsx
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import React, { PureComponent } from 'react';
|
||||||
|
import Select from 'react-select';
|
||||||
|
import UnitGroup from './UnitGroup';
|
||||||
|
import UnitOption from './UnitOption';
|
||||||
|
import ResetStyles from '../ResetStyles';
|
||||||
|
import kbn from '../../../utils/kbn';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onSelected: (item: any) => {} | void;
|
||||||
|
defaultValue?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class UnitPicker extends PureComponent<Props> {
|
||||||
|
render() {
|
||||||
|
const { defaultValue, onSelected } = this.props;
|
||||||
|
|
||||||
|
const unitGroups = kbn.getUnitFormats();
|
||||||
|
|
||||||
|
// Need to transform the data structure to work well with Select
|
||||||
|
const groupOptions = unitGroups.map(group => {
|
||||||
|
const options = group.submenu.map(unit => {
|
||||||
|
return {
|
||||||
|
label: unit.text,
|
||||||
|
value: unit.value,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
label: group.text,
|
||||||
|
options,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
...ResetStyles,
|
||||||
|
menu: () => ({
|
||||||
|
maxHeight: '75%',
|
||||||
|
overflow: 'scroll',
|
||||||
|
}),
|
||||||
|
menuList: () =>
|
||||||
|
({
|
||||||
|
overflowY: 'auto',
|
||||||
|
position: 'relative',
|
||||||
|
} as React.CSSProperties),
|
||||||
|
};
|
||||||
|
|
||||||
|
const value = groupOptions.map(group => {
|
||||||
|
return group.options.find(option => option.value === defaultValue);
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
classNamePrefix="gf-form-select-box"
|
||||||
|
className="width-20 gf-form-input--form-dropdown"
|
||||||
|
defaultValue={value}
|
||||||
|
isSearchable={true}
|
||||||
|
menuShouldScrollIntoView={false}
|
||||||
|
options={groupOptions}
|
||||||
|
placeholder="Choose"
|
||||||
|
onChange={onSelected}
|
||||||
|
components={{
|
||||||
|
Group: UnitGroup,
|
||||||
|
Option: UnitOption,
|
||||||
|
}}
|
||||||
|
styles={styles}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -405,7 +405,8 @@ kbn.valueFormats.percentunit = (size, decimals) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Formats the value to hex. Uses float if specified decimals are not 0.
|
/* Formats the value to hex. Uses float if specified decimals are not 0.
|
||||||
* There are two options, one with 0x, and one without */
|
* There are two submenu
|
||||||
|
* , one with 0x, and one without */
|
||||||
|
|
||||||
kbn.valueFormats.hex = (value, decimals) => {
|
kbn.valueFormats.hex = (value, decimals) => {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ export class DataPanel extends Component<Props, State> {
|
|||||||
render() {
|
render() {
|
||||||
const { queries } = this.props;
|
const { queries } = this.props;
|
||||||
const { response, loading, isFirstLoad } = this.state;
|
const { response, loading, isFirstLoad } = this.state;
|
||||||
|
|
||||||
const timeSeries = response.data;
|
const timeSeries = response.data;
|
||||||
|
|
||||||
if (isFirstLoad && loading === LoadingState.Loading) {
|
if (isFirstLoad && loading === LoadingState.Loading) {
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ export class PanelChrome extends PureComponent<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onRender = () => {
|
onRender = () => {
|
||||||
console.log('onRender');
|
|
||||||
this.setState({
|
this.setState({
|
||||||
renderCounter: this.state.renderCounter + 1,
|
renderCounter: this.state.renderCounter + 1,
|
||||||
});
|
});
|
||||||
@@ -87,7 +86,6 @@ export class PanelChrome extends PureComponent<Props, State> {
|
|||||||
const { datasource, targets } = panel;
|
const { datasource, targets } = panel;
|
||||||
const PanelComponent = this.props.component;
|
const PanelComponent = this.props.component;
|
||||||
|
|
||||||
console.log('panelChrome render');
|
|
||||||
return (
|
return (
|
||||||
<AutoSizer>
|
<AutoSizer>
|
||||||
{({ width, height }) => {
|
{({ width, height }) => {
|
||||||
|
|||||||
@@ -28,13 +28,15 @@ export class ElasticConfigCtrl {
|
|||||||
];
|
];
|
||||||
|
|
||||||
indexPatternTypeChanged() {
|
indexPatternTypeChanged() {
|
||||||
if (!this.current.database ||
|
if (
|
||||||
this.current.database.length === 0 ||
|
!this.current.database ||
|
||||||
this.current.database.startsWith('[logstash-]')) {
|
this.current.database.length === 0 ||
|
||||||
const def = _.find(this.indexPatternTypes, {
|
this.current.database.startsWith('[logstash-]')
|
||||||
value: this.current.jsonData.interval,
|
) {
|
||||||
});
|
const def = _.find(this.indexPatternTypes, {
|
||||||
this.current.database = def.example || 'es-index-name';
|
value: this.current.jsonData.interval,
|
||||||
|
});
|
||||||
|
this.current.database = def.example || 'es-index-name';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,20 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import Gauge from 'app/viz/Gauge';
|
import Gauge from 'app/viz/Gauge';
|
||||||
import { NullValueMode, PanelProps } from 'app/types';
|
import { Label } from 'app/core/components/Label/Label';
|
||||||
|
import UnitPicker from 'app/core/components/Picker/Unit/UnitPicker';
|
||||||
|
import { NullValueMode, PanelOptionsProps, PanelProps } from 'app/types';
|
||||||
import { getTimeSeriesVMs } from 'app/viz/state/timeSeries';
|
import { getTimeSeriesVMs } from 'app/viz/state/timeSeries';
|
||||||
import { GaugeOptions } from './GaugeOptions';
|
|
||||||
|
|
||||||
export interface Options {}
|
export interface Options {
|
||||||
|
unit: { label: string; value: string };
|
||||||
|
}
|
||||||
|
|
||||||
interface Props extends PanelProps<Options> {}
|
interface Props extends PanelProps<Options> {}
|
||||||
|
|
||||||
export class GaugePanel extends PureComponent<Props> {
|
export class GaugePanel extends PureComponent<Props> {
|
||||||
render() {
|
render() {
|
||||||
const { timeSeries, width, height } = this.props;
|
const { timeSeries, width, height } = this.props;
|
||||||
|
const { unit } = this.props.options;
|
||||||
|
|
||||||
const vmSeries = getTimeSeriesVMs({
|
const vmSeries = getTimeSeriesVMs({
|
||||||
timeSeries: timeSeries,
|
timeSeries: timeSeries,
|
||||||
@@ -18,7 +22,35 @@ export class GaugePanel extends PureComponent<Props> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Gauge maxValue={100} minValue={0} timeSeries={vmSeries} thresholds={[0, 100]} height={height} width={width} />
|
<Gauge
|
||||||
|
maxValue={100}
|
||||||
|
minValue={0}
|
||||||
|
timeSeries={vmSeries}
|
||||||
|
thresholds={[0, 100]}
|
||||||
|
height={height}
|
||||||
|
width={width}
|
||||||
|
unit={unit}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GaugeOptions extends PureComponent<PanelOptionsProps<Options>> {
|
||||||
|
onUnitChange = value => {
|
||||||
|
this.props.onChange({ ...this.props.options, unit: value });
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="section gf-form-group">
|
||||||
|
<h5 className="page-heading">Value</h5>
|
||||||
|
<div className="gf-form-inline">
|
||||||
|
<Label width={5}>Unit</Label>
|
||||||
|
<UnitPicker defaultValue={this.props.options.unit.value} onSelected={value => this.onUnitChange(value)} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React, { PureComponent } from 'react';
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import { TimeSeriesVMs } from 'app/types';
|
import { TimeSeriesVMs } from 'app/types';
|
||||||
import config from '../core/config';
|
import config from '../core/config';
|
||||||
|
import kbn from '../core/utils/kbn';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
timeSeries: TimeSeriesVMs;
|
timeSeries: TimeSeriesVMs;
|
||||||
@@ -10,6 +11,7 @@ interface Props {
|
|||||||
showThresholdMarkers?: boolean;
|
showThresholdMarkers?: boolean;
|
||||||
thresholds?: number[];
|
thresholds?: number[];
|
||||||
showThresholdLables?: boolean;
|
showThresholdLables?: boolean;
|
||||||
|
unit: { label: string; value: string };
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
}
|
}
|
||||||
@@ -36,6 +38,13 @@ export class Gauge extends PureComponent<Props> {
|
|||||||
this.draw();
|
this.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
formatValue(value) {
|
||||||
|
const { unit } = this.props;
|
||||||
|
|
||||||
|
const formatFunc = kbn.valueFormats[unit.value];
|
||||||
|
return formatFunc(value);
|
||||||
|
}
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
const {
|
const {
|
||||||
maxValue,
|
maxValue,
|
||||||
@@ -94,7 +103,7 @@ export class Gauge extends PureComponent<Props> {
|
|||||||
value: {
|
value: {
|
||||||
color: fontColor,
|
color: fontColor,
|
||||||
formatter: () => {
|
formatter: () => {
|
||||||
return Math.round(timeSeries[0].stats.avg);
|
return this.formatValue(timeSeries[0].stats.avg);
|
||||||
},
|
},
|
||||||
font: {
|
font: {
|
||||||
size: fontSize,
|
size: fontSize,
|
||||||
|
|||||||
@@ -102,6 +102,7 @@
|
|||||||
@import 'components/delete_button';
|
@import 'components/delete_button';
|
||||||
@import 'components/add_data_source.scss';
|
@import 'components/add_data_source.scss';
|
||||||
@import 'components/page_loader';
|
@import 'components/page_loader';
|
||||||
|
@import 'components/unit-picker';
|
||||||
|
|
||||||
// PAGES
|
// PAGES
|
||||||
@import 'pages/login';
|
@import 'pages/login';
|
||||||
|
|||||||
24
public/sass/components/_unit-picker.scss
Normal file
24
public/sass/components/_unit-picker.scss
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
.unit-picker-option {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
border-radius: 0;
|
||||||
|
white-space: normal;
|
||||||
|
|
||||||
|
i.fa-check {
|
||||||
|
padding-left: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit-picker-group {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit-picker-group-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
border-bottom: 1px solid #555;
|
||||||
|
}
|
||||||
10
yarn.lock
10
yarn.lock
@@ -397,15 +397,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/react" "*"
|
"@types/react" "*"
|
||||||
|
|
||||||
"@types/react@*":
|
"@types/react@*", "@types/react@16.7.6", "@types/react@^16.1.0", "@types/react@^16.7.6":
|
||||||
version "16.4.16"
|
|
||||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.4.16.tgz#99f91b1200ae8c2062030402006d3b3c3a177043"
|
|
||||||
integrity sha512-lxyoipLWweAnLnSsV4Ho2NAZTKKmxeYgkTQ6PaDiPDU9JJBUY2zJVVGiK1smzYv8+ZgbqEmcm5xM74GCpunSEA==
|
|
||||||
dependencies:
|
|
||||||
"@types/prop-types" "*"
|
|
||||||
csstype "^2.2.0"
|
|
||||||
|
|
||||||
"@types/react@^16.1.0", "@types/react@^16.7.6":
|
|
||||||
version "16.7.6"
|
version "16.7.6"
|
||||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.7.6.tgz#80e4bab0d0731ad3ae51f320c4b08bdca5f03040"
|
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.7.6.tgz#80e4bab0d0731ad3ae51f320c4b08bdca5f03040"
|
||||||
integrity sha512-QBUfzftr/8eg/q3ZRgf/GaDP6rTYc7ZNem+g4oZM38C9vXyV8AWRWaTQuW5yCoZTsfHrN7b3DeEiUnqH9SrnpA==
|
integrity sha512-QBUfzftr/8eg/q3ZRgf/GaDP6rTYc7ZNem+g4oZM38C9vXyV8AWRWaTQuW5yCoZTsfHrN7b3DeEiUnqH9SrnpA==
|
||||||
|
|||||||
Reference in New Issue
Block a user