diff --git a/public/app/features/variables/adhoc/picker/AdHocFilterBuilder.tsx b/public/app/features/variables/adhoc/picker/AdHocFilterBuilder.tsx index ae1e3a51b50..22fb121f4cb 100644 --- a/public/app/features/variables/adhoc/picker/AdHocFilterBuilder.tsx +++ b/public/app/features/variables/adhoc/picker/AdHocFilterBuilder.tsx @@ -1,77 +1,63 @@ -import React, { FC, ReactElement, useState } from 'react'; -import { Icon, SegmentAsync } from '@grafana/ui'; -import { OperatorSegment } from './OperatorSegment'; +import React, { FC, useCallback, useState } from 'react'; import { AdHocVariableFilter } from 'app/features/variables/types'; import { SelectableValue } from '@grafana/data'; +import { AdHocFilterKey, REMOVE_FILTER_KEY } from './AdHocFilterKey'; +import { AdHocFilterRenderer } from './AdHocFilterRenderer'; interface Props { - onLoadKeys: () => Promise>>; - onLoadValues: (key: string) => Promise>>; + datasource: string; onCompleted: (filter: AdHocVariableFilter) => void; appendBefore?: React.ReactNode; } -export const AdHocFilterBuilder: FC = ({ appendBefore, onCompleted, onLoadKeys, onLoadValues }) => { +export const AdHocFilterBuilder: FC = ({ datasource, appendBefore, onCompleted }) => { const [key, setKey] = useState(null); const [operator, setOperator] = useState('='); + const onKeyChanged = useCallback( + (item: SelectableValue) => { + if (item.value !== REMOVE_FILTER_KEY) { + setKey(item.value ?? ''); + return; + } + setKey(null); + }, + [setKey] + ); + + const onOperatorChanged = useCallback((item: SelectableValue) => setOperator(item.value ?? ''), [ + setOperator, + ]); + + const onValueChanged = useCallback( + (item: SelectableValue) => { + onCompleted({ + value: item.value ?? '', + operator: operator, + condition: '', + key: key!, + }); + setKey(null); + setOperator('='); + }, + [onCompleted, key, setKey, setOperator] + ); + if (key === null) { - return ( -
- setKey(value ?? '')} - loadOptions={onLoadKeys} - /> -
- ); + return ; } return ( {appendBefore} -
- setKey(value ?? '')} - loadOptions={onLoadKeys} - /> -
-
- setOperator(value ?? '')} /> -
-
- { - onCompleted({ - value: value ?? '', - operator: operator, - condition: '', - key: key, - }); - setKey(null); - setOperator('='); - }} - loadOptions={() => onLoadValues(key)} - /> -
+
); }; - -function filterAddButton(key: string | null): ReactElement | undefined { - if (key !== null) { - return undefined; - } - - return ( - - - - ); -} diff --git a/public/app/features/variables/adhoc/picker/AdHocFilterKey.tsx b/public/app/features/variables/adhoc/picker/AdHocFilterKey.tsx new file mode 100644 index 00000000000..ee994e945ca --- /dev/null +++ b/public/app/features/variables/adhoc/picker/AdHocFilterKey.tsx @@ -0,0 +1,65 @@ +import React, { FC, ReactElement } from 'react'; +import { Icon, SegmentAsync } from '@grafana/ui'; +import { getDatasourceSrv } from '../../../plugins/datasource_srv'; +import { SelectableValue } from '@grafana/data'; + +interface Props { + datasource: string; + filterKey: string | null; + onChange: (item: SelectableValue) => void; +} + +export const AdHocFilterKey: FC = ({ datasource, onChange, filterKey }) => { + const loadKeys = () => fetchFilterKeys(datasource); + const loadKeysWithRemove = () => fetchFilterKeysWithRemove(datasource); + + if (filterKey === null) { + return ( +
+ +
+ ); + } + + return ( +
+ +
+ ); +}; + +export const REMOVE_FILTER_KEY = '-- remove filter --'; +const REMOVE_VALUE = { label: REMOVE_FILTER_KEY, value: REMOVE_FILTER_KEY }; + +const plusSegment: ReactElement = ( + + + +); + +const fetchFilterKeys = async (datasource: string): Promise>> => { + const ds = await getDatasourceSrv().get(datasource); + + if (!ds || !ds.getTagKeys) { + return []; + } + + const metrics = await ds.getTagKeys(); + return metrics.map(m => ({ label: m.text, value: m.text })); +}; + +const fetchFilterKeysWithRemove = async (datasource: string): Promise>> => { + const keys = await fetchFilterKeys(datasource); + return [REMOVE_VALUE, ...keys]; +}; diff --git a/public/app/features/variables/adhoc/picker/AdHocFilterRenderer.tsx b/public/app/features/variables/adhoc/picker/AdHocFilterRenderer.tsx new file mode 100644 index 00000000000..126c15b4219 --- /dev/null +++ b/public/app/features/variables/adhoc/picker/AdHocFilterRenderer.tsx @@ -0,0 +1,40 @@ +import React, { FC } from 'react'; +import { OperatorSegment } from './OperatorSegment'; +import { AdHocVariableFilter } from 'app/features/variables/types'; +import { SelectableValue } from '@grafana/data'; +import { AdHocFilterKey } from './AdHocFilterKey'; +import { AdHocFilterValue } from './AdHocFilterValue'; + +interface Props { + datasource: string; + filter: AdHocVariableFilter; + onKeyChange: (item: SelectableValue) => void; + onOperatorChange: (item: SelectableValue) => void; + onValueChange: (item: SelectableValue) => void; + placeHolder?: string; +} + +export const AdHocFilterRenderer: FC = ({ + datasource, + filter: { key, operator, value }, + onKeyChange, + onOperatorChange, + onValueChange, + placeHolder, +}) => { + return ( + <> + +
+ +
+ + + ); +}; diff --git a/public/app/features/variables/adhoc/picker/AdHocFilterValue.tsx b/public/app/features/variables/adhoc/picker/AdHocFilterValue.tsx new file mode 100644 index 00000000000..9a3eb340974 --- /dev/null +++ b/public/app/features/variables/adhoc/picker/AdHocFilterValue.tsx @@ -0,0 +1,39 @@ +import React, { FC } from 'react'; +import { SegmentAsync } from '@grafana/ui'; +import { getDatasourceSrv } from '../../../plugins/datasource_srv'; +import { MetricFindValue, SelectableValue } from '@grafana/data'; + +interface Props { + datasource: string; + filterKey: string; + filterValue: string | null; + onChange: (item: SelectableValue) => void; + placeHolder?: string; +} + +export const AdHocFilterValue: FC = ({ datasource, onChange, filterKey, filterValue, placeHolder }) => { + const loadValues = () => fetchFilterValues(datasource, filterKey); + + return ( +
+ +
+ ); +}; + +const fetchFilterValues = async (datasource: string, key: string): Promise>> => { + const ds = await getDatasourceSrv().get(datasource); + + if (!ds || !ds.getTagValues) { + return []; + } + + const metrics = await ds.getTagValues({ key }); + return metrics.map((m: MetricFindValue) => ({ label: m.text, value: m.text })); +}; diff --git a/public/app/features/variables/adhoc/picker/AdHocPicker.tsx b/public/app/features/variables/adhoc/picker/AdHocPicker.tsx index a8beba48dab..80fc69cd270 100644 --- a/public/app/features/variables/adhoc/picker/AdHocPicker.tsx +++ b/public/app/features/variables/adhoc/picker/AdHocPicker.tsx @@ -2,14 +2,13 @@ import React, { PureComponent, ReactNode } from 'react'; import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux'; import { StoreState } from 'app/types'; import { AdHocVariableFilter, AdHocVariableModel } from 'app/features/variables/types'; -import { SegmentAsync } from '@grafana/ui'; import { VariablePickerProps } from '../../pickers/types'; -import { OperatorSegment } from './OperatorSegment'; -import { MetricFindValue, SelectableValue } from '@grafana/data'; +import { SelectableValue } from '@grafana/data'; import { AdHocFilterBuilder } from './AdHocFilterBuilder'; -import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; import { ConditionSegment } from './ConditionSegment'; import { addFilter, changeFilter, removeFilter } from '../actions'; +import { REMOVE_FILTER_KEY } from './AdHocFilterKey'; +import { AdHocFilterRenderer } from './AdHocFilterRenderer'; interface OwnProps extends VariablePickerProps {} @@ -23,8 +22,6 @@ interface DispatchProps { type Props = OwnProps & ConnectedProps & DispatchProps; -const REMOVE_FILTER_KEY = '-- remove filter --'; -const REMOVE_VALUE = { label: REMOVE_FILTER_KEY, value: REMOVE_FILTER_KEY }; export class AdHocPickerUnconnected extends PureComponent { onChange = (index: number, prop: string) => (key: SelectableValue) => { const { id, filters } = this.props.variable; @@ -48,35 +45,6 @@ export class AdHocPickerUnconnected extends PureComponent { this.props.addFilter(id, filter); }; - fetchFilterKeys = async () => { - const { variable } = this.props; - const ds = await getDatasourceSrv().get(variable.datasource!); - - if (!ds || !ds.getTagKeys) { - return []; - } - - const metrics = await ds.getTagKeys(); - return metrics.map(m => ({ label: m.text, value: m.text })); - }; - - fetchFilterKeysWithRemove = async () => { - const keys = await this.fetchFilterKeys(); - return [REMOVE_VALUE, ...keys]; - }; - - fetchFilterValues = async (key: string) => { - const { variable } = this.props; - const ds = await getDatasourceSrv().get(variable.datasource!); - - if (!ds || !ds.getTagValues) { - return []; - } - - const metrics = await ds.getTagValues({ key }); - return metrics.map((m: MetricFindValue) => ({ label: m.text, value: m.text })); - }; - render() { const { filters } = this.props.variable; @@ -84,9 +52,8 @@ export class AdHocPickerUnconnected extends PureComponent {
{this.renderFilters(filters)} 0 ? : null} - onLoadKeys={this.fetchFilterKeys} - onLoadValues={this.fetchFilterValues} onCompleted={this.appendFilterToVariable} />
@@ -96,7 +63,7 @@ export class AdHocPickerUnconnected extends PureComponent { renderFilters(filters: AdHocVariableFilter[]) { return filters.reduce((segments: ReactNode[], filter, index) => { if (segments.length > 0) { - segments.push(); + segments.push(); } segments.push(this.renderFilterSegments(filter, index)); return segments; @@ -106,25 +73,13 @@ export class AdHocPickerUnconnected extends PureComponent { renderFilterSegments(filter: AdHocVariableFilter, index: number) { return ( -
- -
-
- -
-
- this.fetchFilterValues(filter.key)} - /> -
+
); }