mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
wip: add option group component
This commit is contained in:
parent
b18f064817
commit
ab5e5de814
@ -0,0 +1,53 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import Select from 'react-select';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
import GroupHeading from 'app/core/components/Picker/GroupHeading';
|
||||||
|
import DescriptionOption from 'app/core/components/Picker/DescriptionOption';
|
||||||
|
import IndicatorsContainer from 'app/core/components/Picker/IndicatorsContainer';
|
||||||
|
import ResetStyles from 'app/core/components/Picker/ResetStyles';
|
||||||
|
import NoOptionsMessage from 'app/core/components/Picker/NoOptionsMessage';
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
groups: any[];
|
||||||
|
searchable: boolean;
|
||||||
|
selected: string;
|
||||||
|
placeholder?: string;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class OptionGroupPicker extends React.Component<Props, any> {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { onChange, groups, selected, placeholder, className, searchable } = this.props;
|
||||||
|
const options = _.flatten(groups.map(o => o.options));
|
||||||
|
const selectedOption = options.find(option => option.value === selected);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Select
|
||||||
|
placeholder={placeholder}
|
||||||
|
classNamePrefix={`gf-form-select-box`}
|
||||||
|
className={className}
|
||||||
|
options={groups}
|
||||||
|
components={{
|
||||||
|
GroupHeading,
|
||||||
|
Option: DescriptionOption,
|
||||||
|
IndicatorsContainer,
|
||||||
|
NoOptionsMessage,
|
||||||
|
}}
|
||||||
|
styles={ResetStyles}
|
||||||
|
isSearchable={searchable}
|
||||||
|
maxMenuHeight={50}
|
||||||
|
onChange={option => onChange(option.value)}
|
||||||
|
getOptionValue={i => i.value}
|
||||||
|
getOptionLabel={i => i.label}
|
||||||
|
value={selectedOption}
|
||||||
|
noOptionsMessage={() => 'No metrics found'}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +1,20 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
// import SimplePicker from 'app/core/components/Picker/SimplePicker';
|
|
||||||
import Select from 'react-select';
|
import Select from 'react-select';
|
||||||
// import DescriptionPicker from 'app/core/components/Picker/DescriptionPicker';
|
import _ from 'lodash';
|
||||||
|
|
||||||
import DescriptionOption from 'app/core/components/Picker/DescriptionOption';
|
import DescriptionOption from 'app/core/components/Picker/DescriptionOption';
|
||||||
import IndicatorsContainer from 'app/core/components/Picker/IndicatorsContainer';
|
import IndicatorsContainer from 'app/core/components/Picker/IndicatorsContainer';
|
||||||
import ResetStyles from 'app/core/components/Picker/ResetStyles';
|
import ResetStyles from 'app/core/components/Picker/ResetStyles';
|
||||||
import NoOptionsMessage from 'app/core/components/Picker/NoOptionsMessage';
|
import NoOptionsMessage from 'app/core/components/Picker/NoOptionsMessage';
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
onChange: (value: string) => void;
|
onChange: (value: string) => void;
|
||||||
options: any[];
|
options: any[];
|
||||||
|
searchable: boolean;
|
||||||
selected: string;
|
selected: string;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
groups?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OptionPicker extends React.Component<Props, any> {
|
export class OptionPicker extends React.Component<Props, any> {
|
||||||
@ -22,8 +23,9 @@ export class OptionPicker extends React.Component<Props, any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { onChange, options, selected, placeholder, className } = this.props;
|
const { onChange, options, selected, placeholder, className, searchable } = this.props;
|
||||||
const selectedOption = options.find(metric => metric.value === selected);
|
const selectedOption = options.find(option => option.value === selected);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
@ -36,7 +38,8 @@ export class OptionPicker extends React.Component<Props, any> {
|
|||||||
NoOptionsMessage,
|
NoOptionsMessage,
|
||||||
}}
|
}}
|
||||||
styles={ResetStyles}
|
styles={ResetStyles}
|
||||||
isDisabled={false}
|
isSearchable={searchable}
|
||||||
|
maxMenuHeight={50}
|
||||||
onChange={option => onChange(option.value)}
|
onChange={option => onChange(option.value)}
|
||||||
getOptionValue={i => i.value}
|
getOptionValue={i => i.value}
|
||||||
getOptionLabel={i => i.label}
|
getOptionLabel={i => i.label}
|
||||||
|
@ -5,8 +5,9 @@
|
|||||||
onChange="ctrl.handleServiceChange"
|
onChange="ctrl.handleServiceChange"
|
||||||
selected="ctrl.service"
|
selected="ctrl.service"
|
||||||
options="ctrl.services"
|
options="ctrl.services"
|
||||||
placeholder="ctrl.defaultDropdownValue"
|
searchable="false"
|
||||||
className="width-12"
|
placeholder="ctrl.defaultServiceValue"
|
||||||
|
className=""width-15""
|
||||||
></option-picker>
|
></option-picker>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form gf-form--grow"><div class="gf-form-label gf-form-label--grow"></div></div>
|
<div class="gf-form gf-form--grow"><div class="gf-form-label gf-form-label--grow"></div></div>
|
||||||
@ -14,13 +15,14 @@
|
|||||||
<div class="gf-form-inline">
|
<div class="gf-form-inline">
|
||||||
<div class="gf-form">
|
<div class="gf-form">
|
||||||
<span class="gf-form-label width-9 query-keyword">Metric</span>
|
<span class="gf-form-label width-9 query-keyword">Metric</span>
|
||||||
<option-picker
|
<option-group-picker
|
||||||
onChange="ctrl.handleMetricTypeChange"
|
onChange="ctrl.handleMetricTypeChange"
|
||||||
selected="ctrl.metricType"
|
selected="ctrl.metricType"
|
||||||
options="ctrl.metrics"
|
groups="ctrl.insertTemplateVariables(ctrl.defaultServiceValue !== ctrl.service ? ctrl.metrics : ctrl.metricGroups)"
|
||||||
|
searchable="true"
|
||||||
placeholder="ctrl.defaultDropdownValue"
|
placeholder="ctrl.defaultDropdownValue"
|
||||||
className="width-12"
|
className=""width-15""
|
||||||
></option-picker>
|
></option-group-picker>
|
||||||
</div>
|
</div>
|
||||||
<div class="gf-form gf-form--grow"><div class="gf-form-label gf-form-label--grow"></div></div>
|
<div class="gf-form gf-form--grow"><div class="gf-form-label gf-form-label--grow"></div></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,6 +3,7 @@ import { QueryCtrl } from 'app/plugins/sdk';
|
|||||||
import './query_aggregation_ctrl';
|
import './query_aggregation_ctrl';
|
||||||
import './query_filter_ctrl';
|
import './query_filter_ctrl';
|
||||||
import { OptionPicker } from './components/OptionPicker';
|
import { OptionPicker } from './components/OptionPicker';
|
||||||
|
import { OptionGroupPicker } from './components/OptionGroupPicker';
|
||||||
import { react2AngularDirective } from 'app/core/utils/react2angular';
|
import { react2AngularDirective } from 'app/core/utils/react2angular';
|
||||||
|
|
||||||
export interface QueryMeta {
|
export interface QueryMeta {
|
||||||
@ -70,6 +71,15 @@ export class StackdriverQueryCtrl extends QueryCtrl {
|
|||||||
'options',
|
'options',
|
||||||
'onChange',
|
'onChange',
|
||||||
'selected',
|
'selected',
|
||||||
|
'searchable',
|
||||||
|
'className',
|
||||||
|
'placeholder',
|
||||||
|
]);
|
||||||
|
react2AngularDirective('optionGroupPicker', OptionGroupPicker, [
|
||||||
|
'groups',
|
||||||
|
'onChange',
|
||||||
|
'selected',
|
||||||
|
'searchable',
|
||||||
'className',
|
'className',
|
||||||
'placeholder',
|
'placeholder',
|
||||||
]);
|
]);
|
||||||
|
@ -36,6 +36,7 @@ export class StackdriverFilterCtrl {
|
|||||||
metricType: string;
|
metricType: string;
|
||||||
metricDescriptors: any[];
|
metricDescriptors: any[];
|
||||||
metrics: any[];
|
metrics: any[];
|
||||||
|
metricGroups: any[];
|
||||||
services: any[];
|
services: any[];
|
||||||
groupBySegments: any[];
|
groupBySegments: any[];
|
||||||
filterSegments: FilterSegments;
|
filterSegments: FilterSegments;
|
||||||
@ -52,6 +53,7 @@ export class StackdriverFilterCtrl {
|
|||||||
|
|
||||||
this.metricDescriptors = [];
|
this.metricDescriptors = [];
|
||||||
this.metrics = [];
|
this.metrics = [];
|
||||||
|
this.metricGroups = [];
|
||||||
this.services = [];
|
this.services = [];
|
||||||
|
|
||||||
this.getCurrentProject()
|
this.getCurrentProject()
|
||||||
@ -106,6 +108,7 @@ export class StackdriverFilterCtrl {
|
|||||||
this.metricDescriptors = await this.datasource.getMetricTypes(this.target.defaultProject);
|
this.metricDescriptors = await this.datasource.getMetricTypes(this.target.defaultProject);
|
||||||
this.services = this.getServicesList();
|
this.services = this.getServicesList();
|
||||||
this.metrics = this.getMetricsList();
|
this.metrics = this.getMetricsList();
|
||||||
|
this.metricGroups = this.getMetricGroups();
|
||||||
return this.metricDescriptors;
|
return this.metricDescriptors;
|
||||||
} else {
|
} else {
|
||||||
return [];
|
return [];
|
||||||
@ -113,11 +116,11 @@ export class StackdriverFilterCtrl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getServicesList() {
|
getServicesList() {
|
||||||
const defaultValue = { value: this.$scope.defaultServiceValue, text: this.$scope.defaultServiceValue };
|
const defaultValue = { value: this.$scope.defaultServiceValue, label: this.$scope.defaultServiceValue };
|
||||||
const services = this.metricDescriptors.map(m => {
|
const services = this.metricDescriptors.map(m => {
|
||||||
return {
|
return {
|
||||||
value: m.service,
|
value: m.service,
|
||||||
label: m.serviceShortName,
|
label: _.startCase(m.serviceShortName),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -128,6 +131,37 @@ export class StackdriverFilterCtrl {
|
|||||||
return services.length > 0 ? [defaultValue, ..._.uniqBy(services, 'value')] : [];
|
return services.length > 0 ? [defaultValue, ..._.uniqBy(services, 'value')] : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getMetricGroups() {
|
||||||
|
return this.metrics.reduce((acc, curr) => {
|
||||||
|
const group = acc.find(group => group.service === curr.service);
|
||||||
|
if (group) {
|
||||||
|
group.options = [...group.options, { value: curr.value, label: curr.label }];
|
||||||
|
} else {
|
||||||
|
acc = [
|
||||||
|
...acc,
|
||||||
|
{
|
||||||
|
label: _.startCase(curr.serviceShortName),
|
||||||
|
service: curr.service,
|
||||||
|
options: [{ value: curr.value, label: curr.label }],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
insertTemplateVariables(options) {
|
||||||
|
const templateVariables = {
|
||||||
|
label: 'Template Variables',
|
||||||
|
options: this.templateSrv.variables.map(v => ({
|
||||||
|
label: `$${v.name}`,
|
||||||
|
value: `$${v.name}`,
|
||||||
|
description: `$${v.definition}`,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
return [templateVariables, { label: 'Metrics', options }];
|
||||||
|
}
|
||||||
|
|
||||||
getMetricsList() {
|
getMetricsList() {
|
||||||
const metrics = this.metricDescriptors.map(m => {
|
const metrics = this.metricDescriptors.map(m => {
|
||||||
return {
|
return {
|
||||||
@ -178,6 +212,7 @@ export class StackdriverFilterCtrl {
|
|||||||
handleServiceChange(service) {
|
handleServiceChange(service) {
|
||||||
this.target.service = this.service = service;
|
this.target.service = this.service = service;
|
||||||
this.metrics = this.getMetricsList();
|
this.metrics = this.getMetricsList();
|
||||||
|
this.metricGroups = this.getMetricGroups();
|
||||||
this.setMetricType();
|
this.setMetricType();
|
||||||
this.getLabels();
|
this.getLabels();
|
||||||
if (!this.metrics.find(m => m.value === this.target.metricType)) {
|
if (!this.metrics.find(m => m.value === this.target.metricType)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user