123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- import React, { ComponentType, PureComponent } from 'react';
- import { connect, ConnectedProps } from 'react-redux';
- import { bindActionCreators } from 'redux';
- import { LoadingState } from '@grafana/data';
- import { ClickOutsideWrapper } from '@grafana/ui';
- import { StoreState, ThunkDispatch } from 'app/types';
- import { isMulti } from '../../guard';
- import { getVariableQueryRunner } from '../../query/VariableQueryRunner';
- import { formatVariableLabel } from '../../shared/formatVariable';
- import { toKeyedAction } from '../../state/keyedVariablesReducer';
- import { getVariablesState } from '../../state/selectors';
- import { KeyedVariableIdentifier } from '../../state/types';
- import { VariableOption, VariableWithMultiSupport, VariableWithOptions } from '../../types';
- import { toKeyedVariableIdentifier } from '../../utils';
- import { VariableInput } from '../shared/VariableInput';
- import { VariableLink } from '../shared/VariableLink';
- import { VariableOptions } from '../shared/VariableOptions';
- import { NavigationKey, VariablePickerProps } from '../types';
- import { commitChangesToVariable, filterOrSearchOptions, navigateOptions, openOptions } from './actions';
- import { initialOptionPickerState, OptionsPickerState, toggleAllOptions, toggleOption } from './reducer';
- export const optionPickerFactory = <Model extends VariableWithOptions | VariableWithMultiSupport>(): ComponentType<
- VariablePickerProps<Model>
- > => {
- const mapDispatchToProps = (dispatch: ThunkDispatch) => {
- return {
- ...bindActionCreators({ openOptions, commitChangesToVariable, navigateOptions }, dispatch),
- filterOrSearchOptions: (identifier: KeyedVariableIdentifier, filter = '') => {
- dispatch(filterOrSearchOptions(identifier, filter));
- },
- toggleAllOptions: (identifier: KeyedVariableIdentifier) =>
- dispatch(toKeyedAction(identifier.rootStateKey, toggleAllOptions())),
- toggleOption: (
- identifier: KeyedVariableIdentifier,
- option: VariableOption,
- clearOthers: boolean,
- forceSelect: boolean
- ) => dispatch(toKeyedAction(identifier.rootStateKey, toggleOption({ option, clearOthers, forceSelect }))),
- };
- };
- const mapStateToProps = (state: StoreState, ownProps: OwnProps) => {
- const { rootStateKey } = ownProps.variable;
- if (!rootStateKey) {
- console.error('OptionPickerFactory: variable has no rootStateKey');
- return {
- picker: initialOptionPickerState,
- };
- }
- return {
- picker: getVariablesState(rootStateKey, state).optionsPicker,
- };
- };
- const connector = connect(mapStateToProps, mapDispatchToProps);
- interface OwnProps extends VariablePickerProps<Model> {}
- type Props = OwnProps & ConnectedProps<typeof connector>;
- class OptionsPickerUnconnected extends PureComponent<Props> {
- onShowOptions = () =>
- this.props.openOptions(toKeyedVariableIdentifier(this.props.variable), this.props.onVariableChange);
- onHideOptions = () => {
- if (!this.props.variable.rootStateKey) {
- console.error('Variable has no rootStateKey');
- return;
- }
- this.props.commitChangesToVariable(this.props.variable.rootStateKey, this.props.onVariableChange);
- };
- onToggleOption = (option: VariableOption, clearOthers: boolean) => {
- const toggleFunc =
- isMulti(this.props.variable) && this.props.variable.multi
- ? this.onToggleMultiValueVariable
- : this.onToggleSingleValueVariable;
- toggleFunc(option, clearOthers);
- };
- onToggleSingleValueVariable = (option: VariableOption, clearOthers: boolean) => {
- this.props.toggleOption(toKeyedVariableIdentifier(this.props.variable), option, clearOthers, false);
- this.onHideOptions();
- };
- onToggleMultiValueVariable = (option: VariableOption, clearOthers: boolean) => {
- this.props.toggleOption(toKeyedVariableIdentifier(this.props.variable), option, clearOthers, false);
- };
- onToggleAllOptions = () => {
- this.props.toggleAllOptions(toKeyedVariableIdentifier(this.props.variable));
- };
- onFilterOrSearchOptions = (filter: string) => {
- this.props.filterOrSearchOptions(toKeyedVariableIdentifier(this.props.variable), filter);
- };
- onNavigate = (key: NavigationKey, clearOthers: boolean) => {
- if (!this.props.variable.rootStateKey) {
- console.error('Variable has no rootStateKey');
- return;
- }
- this.props.navigateOptions(this.props.variable.rootStateKey, key, clearOthers);
- };
- render() {
- const { variable, picker } = this.props;
- const showOptions = picker.id === variable.id;
- return (
- <div className="variable-link-wrapper">
- {showOptions ? this.renderOptions(picker) : this.renderLink(variable)}
- </div>
- );
- }
- renderLink(variable: VariableWithOptions) {
- const linkText = formatVariableLabel(variable);
- const loading = variable.state === LoadingState.Loading;
- return (
- <VariableLink
- id={`var-${variable.id}`}
- text={linkText}
- onClick={this.onShowOptions}
- loading={loading}
- onCancel={this.onCancel}
- />
- );
- }
- onCancel = () => {
- getVariableQueryRunner().cancelRequest(toKeyedVariableIdentifier(this.props.variable));
- };
- renderOptions(picker: OptionsPickerState) {
- const { id } = this.props.variable;
- return (
- <ClickOutsideWrapper onClick={this.onHideOptions}>
- <VariableInput
- id={`var-${id}`}
- value={picker.queryValue}
- onChange={this.onFilterOrSearchOptions}
- onNavigate={this.onNavigate}
- aria-expanded={true}
- aria-controls={`options-${id}`}
- />
- <VariableOptions
- values={picker.options}
- onToggle={this.onToggleOption}
- onToggleAll={this.onToggleAllOptions}
- highlightIndex={picker.highlightIndex}
- multi={picker.multi}
- selectedValues={picker.selectedValues}
- id={`options-${id}`}
- />
- </ClickOutsideWrapper>
- );
- }
- }
- const OptionsPicker = connector(OptionsPickerUnconnected);
- OptionsPicker.displayName = 'OptionsPicker';
- return OptionsPicker;
- };
|