mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'unit-picker' into gauge-value-options
This commit is contained in:
commit
5722773467
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;
|
68
public/app/core/components/Picker/Unit/UnitPicker.tsx
Normal file
68
public/app/core/components/Picker/Unit/UnitPicker.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
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: '500px',
|
||||
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}
|
||||
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.
|
||||
* 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) => {
|
||||
if (value == null) {
|
||||
|
@ -134,6 +134,7 @@ export class DataPanel extends Component<Props, State> {
|
||||
render() {
|
||||
const { queries } = this.props;
|
||||
const { response, loading, isFirstLoad } = this.state;
|
||||
|
||||
const timeSeries = response.data;
|
||||
|
||||
if (isFirstLoad && loading === LoadingState.Loading) {
|
||||
|
@ -70,7 +70,6 @@ export class PanelChrome extends PureComponent<Props, State> {
|
||||
};
|
||||
|
||||
onRender = () => {
|
||||
console.log('onRender');
|
||||
this.setState({
|
||||
renderCounter: this.state.renderCounter + 1,
|
||||
});
|
||||
@ -87,7 +86,6 @@ export class PanelChrome extends PureComponent<Props, State> {
|
||||
const { datasource, targets } = panel;
|
||||
const PanelComponent = this.props.component;
|
||||
|
||||
console.log('panelChrome render');
|
||||
return (
|
||||
<AutoSizer>
|
||||
{({ width, height }) => {
|
||||
|
@ -28,13 +28,15 @@ export class ElasticConfigCtrl {
|
||||
];
|
||||
|
||||
indexPatternTypeChanged() {
|
||||
if (!this.current.database ||
|
||||
this.current.database.length === 0 ||
|
||||
this.current.database.startsWith('[logstash-]')) {
|
||||
const def = _.find(this.indexPatternTypes, {
|
||||
value: this.current.jsonData.interval,
|
||||
});
|
||||
this.current.database = def.example || 'es-index-name';
|
||||
if (
|
||||
!this.current.database ||
|
||||
this.current.database.length === 0 ||
|
||||
this.current.database.startsWith('[logstash-]')
|
||||
) {
|
||||
const def = _.find(this.indexPatternTypes, {
|
||||
value: this.current.jsonData.interval,
|
||||
});
|
||||
this.current.database = def.example || 'es-index-name';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,14 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { Label } from 'app/core/components/Label/Label';
|
||||
import SimplePicker from 'app/core/components/Picker/SimplePicker';
|
||||
import UnitPicker from 'app/core/components/Picker/Unit/UnitPicker';
|
||||
import Gauge from 'app/viz/Gauge';
|
||||
import { NullValueMode, PanelOptionsProps, PanelProps } from 'app/types';
|
||||
import { getTimeSeriesVMs } from 'app/viz/state/timeSeries';
|
||||
import { Label } from '../../../core/components/Label/Label';
|
||||
import SimplePicker from '../../../core/components/Picker/SimplePicker';
|
||||
|
||||
export interface Options {
|
||||
stat: { value: string; text: string };
|
||||
unit: { label: string; value: string };
|
||||
}
|
||||
|
||||
interface Props extends PanelProps<Options> {}
|
||||
@ -25,7 +27,7 @@ const statOptions = [
|
||||
{ value: 'last_time', text: 'Time of last point' },
|
||||
];
|
||||
|
||||
export class GaugePanel extends PureComponent<Props> {
|
||||
class GaugePanel extends PureComponent<Props> {
|
||||
render() {
|
||||
const { timeSeries, width, height } = this.props;
|
||||
|
||||
@ -39,13 +41,15 @@ export class GaugePanel extends PureComponent<Props> {
|
||||
}
|
||||
|
||||
class GaugeOptions extends PureComponent<PanelOptionsProps<Options>> {
|
||||
onUnitChange = value => {
|
||||
this.props.onChange({ ...this.props.options, unit: value });
|
||||
};
|
||||
|
||||
onStatChange = value => {
|
||||
this.props.onChange({ ...this.props.options, stat: value });
|
||||
};
|
||||
|
||||
render() {
|
||||
const { stat } = this.props.options;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="section gf-form-group">
|
||||
@ -53,15 +57,19 @@ class GaugeOptions extends PureComponent<PanelOptionsProps<Options>> {
|
||||
<div className="gf-form-inline">
|
||||
<Label width={5}>Stat</Label>
|
||||
<SimplePicker
|
||||
defaultValue={statOptions.find(option => option.value === stat.value)}
|
||||
defaultValue={statOptions.find(option => option.value === this.props.options.stat.value)}
|
||||
width={11}
|
||||
options={statOptions}
|
||||
getOptionLabel={i => i.text}
|
||||
getOptionValue={i => i.value}
|
||||
onSelected={this.onStatChange}
|
||||
value={stat}
|
||||
value={this.props.options.stat}
|
||||
/>
|
||||
</div>
|
||||
<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 { TimeSeriesVMs } from 'app/types';
|
||||
import config from '../core/config';
|
||||
import kbn from '../core/utils/kbn';
|
||||
|
||||
interface Props {
|
||||
timeSeries: TimeSeriesVMs;
|
||||
@ -10,6 +11,7 @@ interface Props {
|
||||
showThresholdMarkers?: boolean;
|
||||
thresholds?: number[];
|
||||
showThresholdLables?: boolean;
|
||||
unit: { label: string; value: string };
|
||||
width: number;
|
||||
height: number;
|
||||
stat?: { value: string; text: string };
|
||||
@ -37,6 +39,13 @@ export class Gauge extends PureComponent<Props> {
|
||||
this.draw();
|
||||
}
|
||||
|
||||
formatValue(value) {
|
||||
const { unit } = this.props;
|
||||
|
||||
const formatFunc = kbn.valueFormats[unit.value];
|
||||
return formatFunc(value);
|
||||
}
|
||||
|
||||
draw() {
|
||||
const {
|
||||
timeSeries,
|
||||
@ -96,7 +105,7 @@ export class Gauge extends PureComponent<Props> {
|
||||
value: {
|
||||
color: fontColor,
|
||||
formatter: () => {
|
||||
return Math.round(timeSeries[0].stats[stat.value]);
|
||||
return this.formatValue(timeSeries[0].stats[stat.value]);
|
||||
},
|
||||
font: {
|
||||
size: fontSize,
|
||||
|
@ -102,6 +102,7 @@
|
||||
@import 'components/delete_button';
|
||||
@import 'components/add_data_source.scss';
|
||||
@import 'components/page_loader';
|
||||
@import 'components/unit-picker';
|
||||
|
||||
// PAGES
|
||||
@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:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react@*":
|
||||
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":
|
||||
"@types/react@*", "@types/react@16.7.6", "@types/react@^16.1.0", "@types/react@^16.7.6":
|
||||
version "16.7.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.7.6.tgz#80e4bab0d0731ad3ae51f320c4b08bdca5f03040"
|
||||
integrity sha512-QBUfzftr/8eg/q3ZRgf/GaDP6rTYc7ZNem+g4oZM38C9vXyV8AWRWaTQuW5yCoZTsfHrN7b3DeEiUnqH9SrnpA==
|
||||
|
Loading…
Reference in New Issue
Block a user