123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- import { css } from '@emotion/css';
- import React, { FormEvent, PureComponent } from 'react';
- import { connect, ConnectedProps } from 'react-redux';
- import { DataSourceInstanceSettings, getDataSourceRef, LoadingState, SelectableValue } from '@grafana/data';
- import { selectors } from '@grafana/e2e-selectors';
- import { DataSourcePicker, getTemplateSrv } from '@grafana/runtime';
- import { InlineField, InlineFieldRow, VerticalGroup } from '@grafana/ui';
- import { StoreState } from '../../../types';
- import { getTimeSrv } from '../../dashboard/services/TimeSrv';
- import { SelectionOptionsEditor } from '../editor/SelectionOptionsEditor';
- import { VariableSectionHeader } from '../editor/VariableSectionHeader';
- import { VariableTextField } from '../editor/VariableTextField';
- import { initialVariableEditorState } from '../editor/reducer';
- import { getQueryVariableEditorState } from '../editor/selectors';
- import { OnPropChangeArguments, VariableEditorProps } from '../editor/types';
- import { isLegacyQueryEditor, isQueryEditor } from '../guard';
- import { changeVariableMultiValue } from '../state/actions';
- import { getVariablesState } from '../state/selectors';
- import { QueryVariableModel, VariableRefresh, VariableSort, VariableWithMultiSupport } from '../types';
- import { toKeyedVariableIdentifier } from '../utils';
- import { QueryVariableRefreshSelect } from './QueryVariableRefreshSelect';
- import { QueryVariableSortSelect } from './QueryVariableSortSelect';
- import { changeQueryVariableDataSource, changeQueryVariableQuery, initQueryVariableEditor } from './actions';
- const mapStateToProps = (state: StoreState, ownProps: OwnProps) => {
- const { rootStateKey } = ownProps.variable;
- if (!rootStateKey) {
- console.error('QueryVariableEditor: variable has no rootStateKey');
- return {
- extended: getQueryVariableEditorState(initialVariableEditorState),
- };
- }
- const { editor } = getVariablesState(rootStateKey, state);
- return {
- extended: getQueryVariableEditorState(editor),
- };
- };
- const mapDispatchToProps = {
- initQueryVariableEditor,
- changeQueryVariableDataSource,
- changeQueryVariableQuery,
- changeVariableMultiValue,
- };
- const connector = connect(mapStateToProps, mapDispatchToProps);
- export interface OwnProps extends VariableEditorProps<QueryVariableModel> {}
- export type Props = OwnProps & ConnectedProps<typeof connector>;
- export interface State {
- regex: string | null;
- tagsQuery: string | null;
- tagValuesQuery: string | null;
- }
- export class QueryVariableEditorUnConnected extends PureComponent<Props, State> {
- state: State = {
- regex: null,
- tagsQuery: null,
- tagValuesQuery: null,
- };
- async componentDidMount() {
- await this.props.initQueryVariableEditor(toKeyedVariableIdentifier(this.props.variable));
- }
- componentDidUpdate(prevProps: Readonly<Props>): void {
- if (prevProps.variable.datasource !== this.props.variable.datasource) {
- this.props.changeQueryVariableDataSource(
- toKeyedVariableIdentifier(this.props.variable),
- this.props.variable.datasource
- );
- }
- }
- onDataSourceChange = (dsSettings: DataSourceInstanceSettings) => {
- this.props.onPropChange({
- propName: 'datasource',
- propValue: dsSettings.isDefault ? null : getDataSourceRef(dsSettings),
- });
- };
- onLegacyQueryChange = async (query: any, definition: string) => {
- if (this.props.variable.query !== query) {
- this.props.changeQueryVariableQuery(toKeyedVariableIdentifier(this.props.variable), query, definition);
- }
- };
- onQueryChange = async (query: any) => {
- if (this.props.variable.query !== query) {
- let definition = '';
- if (query && query.hasOwnProperty('query') && typeof query.query === 'string') {
- definition = query.query;
- }
- this.props.changeQueryVariableQuery(toKeyedVariableIdentifier(this.props.variable), query, definition);
- }
- };
- onRegExChange = (event: FormEvent<HTMLInputElement>) => {
- this.setState({ regex: event.currentTarget.value });
- };
- onRegExBlur = async (event: FormEvent<HTMLInputElement>) => {
- const regex = event.currentTarget.value;
- if (this.props.variable.regex !== regex) {
- this.props.onPropChange({ propName: 'regex', propValue: regex, updateOptions: true });
- }
- };
- onRefreshChange = (option: SelectableValue<VariableRefresh>) => {
- this.props.onPropChange({ propName: 'refresh', propValue: option.value });
- };
- onSortChange = async (option: SelectableValue<VariableSort>) => {
- this.props.onPropChange({ propName: 'sort', propValue: option.value, updateOptions: true });
- };
- onSelectionOptionsChange = async ({ propValue, propName }: OnPropChangeArguments<VariableWithMultiSupport>) => {
- this.props.onPropChange({ propName, propValue, updateOptions: true });
- };
- renderQueryEditor = () => {
- const { extended, variable } = this.props;
- if (!extended || !extended.dataSource || !extended.VariableQueryEditor) {
- return null;
- }
- const query = variable.query;
- const datasource = extended.dataSource;
- const VariableQueryEditor = extended.VariableQueryEditor;
- if (isLegacyQueryEditor(VariableQueryEditor, datasource)) {
- return (
- <VariableQueryEditor
- datasource={datasource}
- query={query}
- templateSrv={getTemplateSrv()}
- onChange={this.onLegacyQueryChange}
- />
- );
- }
- const range = getTimeSrv().timeRange();
- if (isQueryEditor(VariableQueryEditor, datasource)) {
- return (
- <VariableQueryEditor
- datasource={datasource}
- query={query}
- onChange={this.onQueryChange}
- onRunQuery={() => {}}
- data={{ series: [], state: LoadingState.Done, timeRange: range }}
- range={range}
- onBlur={() => {}}
- history={[]}
- />
- );
- }
- return null;
- };
- render() {
- return (
- <VerticalGroup spacing="xs">
- <VariableSectionHeader name="Query Options" />
- <VerticalGroup spacing="lg">
- <VerticalGroup spacing="none">
- <InlineFieldRow>
- <InlineField label="Data source" labelWidth={20} htmlFor="data-source-picker">
- <DataSourcePicker
- current={this.props.variable.datasource}
- onChange={this.onDataSourceChange}
- variables={true}
- />
- </InlineField>
- <QueryVariableRefreshSelect onChange={this.onRefreshChange} refresh={this.props.variable.refresh} />
- </InlineFieldRow>
- <div
- className={css`
- flex-direction: column;
- width: 100%;
- `}
- >
- {this.renderQueryEditor()}
- </div>
- <VariableTextField
- value={this.state.regex ?? this.props.variable.regex}
- name="Regex"
- placeholder="/.*-(?<text>.*)-(?<value>.*)-.*/"
- onChange={this.onRegExChange}
- onBlur={this.onRegExBlur}
- labelWidth={20}
- interactive={true}
- tooltip={
- <div>
- Optional, if you want to extract part of a series name or metric node segment. Named capture groups
- can be used to separate the display text and value (
- <a
- className="external-link"
- href="https://grafana.com/docs/grafana/latest/variables/filter-variables-with-regex#filter-and-modify-using-named-text-and-value-capture-groups"
- target="__blank"
- >
- see examples
- </a>
- ).
- </div>
- }
- testId={selectors.pages.Dashboard.Settings.Variables.Edit.QueryVariable.queryOptionsRegExInputV2}
- grow
- />
- <QueryVariableSortSelect onChange={this.onSortChange} sort={this.props.variable.sort} />
- </VerticalGroup>
- <SelectionOptionsEditor
- variable={this.props.variable}
- onPropChange={this.onSelectionOptionsChange}
- onMultiChanged={this.props.changeVariableMultiValue}
- />
- </VerticalGroup>
- </VerticalGroup>
- );
- }
- }
- export const QueryVariableEditor = connector(QueryVariableEditorUnConnected);
|