mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Chore: reduce strict errors for variables (#31241)
* Chore: reduces a lot of variable errors * Chore: reduces variable Editor errors * Chore: reduces variable Picker errors * Chore: reduce error count * Chore: reduces errors for ChangeEvent instead of FormEvent * Chore: reduces errors with CombinedState * Chore: reduces ComponentType errors * Chore: reduce errors in reducers * Chore: reduces misc errors * Chore: reduce AdhocPicker errors * Chore: reduce error limit * Update public/app/features/variables/adhoc/picker/AdHocFilterValue.tsx Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com> * Chore: updates after PR comments * Chore: small refactor Co-authored-by: Alex Khomenko <Clarity-89@users.noreply.github.com>
This commit is contained in:
parent
6c4be29655
commit
3c1f27b0e6
@ -2,17 +2,7 @@ import { ComponentType } from 'react';
|
||||
import { Reducer } from 'redux';
|
||||
import { Registry, UrlQueryValue, VariableType } from '@grafana/data';
|
||||
|
||||
import {
|
||||
AdHocVariableModel,
|
||||
ConstantVariableModel,
|
||||
CustomVariableModel,
|
||||
DataSourceVariableModel,
|
||||
IntervalVariableModel,
|
||||
QueryVariableModel,
|
||||
TextBoxVariableModel,
|
||||
VariableModel,
|
||||
VariableOption,
|
||||
} from './types';
|
||||
import { VariableModel, VariableOption } from './types';
|
||||
import { VariableEditorProps } from './editor/types';
|
||||
import { VariablesState } from './state/variablesReducer';
|
||||
import { VariablePickerProps } from './pickers/types';
|
||||
@ -36,22 +26,12 @@ export interface VariableAdapter<Model extends VariableModel> {
|
||||
updateOptions: (variable: Model, searchFilter?: string) => Promise<void>;
|
||||
getSaveModel: (variable: Model, saveCurrentAsDefault?: boolean) => Partial<Model>;
|
||||
getValueForUrl: (variable: Model) => string | string[];
|
||||
picker: ComponentType<VariablePickerProps>;
|
||||
editor: ComponentType<VariableEditorProps>;
|
||||
picker: ComponentType<VariablePickerProps<Model>>;
|
||||
editor: ComponentType<VariableEditorProps<Model>>;
|
||||
reducer: Reducer<VariablesState>;
|
||||
beforeAdding?: (model: any) => any;
|
||||
}
|
||||
|
||||
export type VariableModels =
|
||||
| QueryVariableModel
|
||||
| CustomVariableModel
|
||||
| TextBoxVariableModel
|
||||
| ConstantVariableModel
|
||||
| DataSourceVariableModel
|
||||
| IntervalVariableModel
|
||||
| AdHocVariableModel;
|
||||
export type VariableTypeRegistry<Model extends VariableModel = VariableModel> = Registry<VariableAdapter<Model>>;
|
||||
|
||||
export const getDefaultVariableAdapters = () => [
|
||||
createQueryVariableAdapter(),
|
||||
createCustomVariableAdapter(),
|
||||
@ -63,4 +43,4 @@ export const getDefaultVariableAdapters = () => [
|
||||
createSystemVariableAdapter(),
|
||||
];
|
||||
|
||||
export const variableAdapters: VariableTypeRegistry = new Registry<VariableAdapter<VariableModels>>();
|
||||
export const variableAdapters = new Registry<VariableAdapter<any>>();
|
||||
|
@ -3,8 +3,7 @@ import { DataSourcePluginMeta, DataSourceSelectItem } from '@grafana/data';
|
||||
import { variableAdapters } from '../adapters';
|
||||
import { createAdHocVariableAdapter } from './adapter';
|
||||
import { reduxTester } from '../../../../test/core/redux/reduxTester';
|
||||
import { TemplatingState } from 'app/features/variables/state/reducers';
|
||||
import { getRootReducer } from '../state/helpers';
|
||||
import { getRootReducer, RootReducerType } from '../state/helpers';
|
||||
import { toVariableIdentifier, toVariablePayload } from '../state/types';
|
||||
import {
|
||||
addFilter,
|
||||
@ -19,7 +18,6 @@ import {
|
||||
import { filterAdded, filterRemoved, filtersRestored, filterUpdated } from './reducer';
|
||||
import { addVariable, changeVariableProp } from '../state/sharedReducer';
|
||||
import { updateLocation } from 'app/core/actions';
|
||||
import { DashboardState, LocationState } from 'app/types';
|
||||
import { VariableModel } from 'app/features/variables/types';
|
||||
import { changeVariableEditorExtended, setIdInEditor } from '../editor/reducer';
|
||||
import { adHocBuilder } from '../shared/testing/builders';
|
||||
@ -34,12 +32,6 @@ jest.mock('app/features/plugins/datasource_srv', () => ({
|
||||
})),
|
||||
}));
|
||||
|
||||
type ReducersUsedInContext = {
|
||||
templating: TemplatingState;
|
||||
dashboard: DashboardState;
|
||||
location: LocationState;
|
||||
};
|
||||
|
||||
variableAdapters.setInit(() => [createAdHocVariableAdapter()]);
|
||||
|
||||
describe('adhoc actions', () => {
|
||||
@ -66,7 +58,7 @@ describe('adhoc actions', () => {
|
||||
.withDatasource(options.datasource)
|
||||
.build();
|
||||
|
||||
const tester = await reduxTester<ReducersUsedInContext>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(createAddVariableAction(variable))
|
||||
.whenAsyncActionIsDispatched(applyFilterFromTable(options), true);
|
||||
@ -90,7 +82,7 @@ describe('adhoc actions', () => {
|
||||
operator: '=',
|
||||
};
|
||||
|
||||
const tester = await reduxTester<ReducersUsedInContext>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenAsyncActionIsDispatched(applyFilterFromTable(options), true);
|
||||
|
||||
@ -123,7 +115,7 @@ describe('adhoc actions', () => {
|
||||
.withDatasource(options.datasource)
|
||||
.build();
|
||||
|
||||
const tester = await reduxTester<ReducersUsedInContext>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(createAddVariableAction(variable))
|
||||
.whenAsyncActionIsDispatched(applyFilterFromTable(options), true);
|
||||
@ -155,7 +147,7 @@ describe('adhoc actions', () => {
|
||||
|
||||
const variable = adHocBuilder().withId('Filters').withName('Filters').withDatasource(options.datasource).build();
|
||||
|
||||
const tester = await reduxTester<ReducersUsedInContext>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(createAddVariableAction(existing))
|
||||
.whenAsyncActionIsDispatched(applyFilterFromTable(options), true);
|
||||
@ -194,7 +186,7 @@ describe('adhoc actions', () => {
|
||||
|
||||
const update = { index: 0, filter: updated };
|
||||
|
||||
const tester = await reduxTester<ReducersUsedInContext>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(createAddVariableAction(variable))
|
||||
.whenAsyncActionIsDispatched(changeFilter('elastic-filter', update), true);
|
||||
@ -230,7 +222,7 @@ describe('adhoc actions', () => {
|
||||
.withDatasource('elasticsearch')
|
||||
.build();
|
||||
|
||||
const tester = await reduxTester<ReducersUsedInContext>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(createAddVariableAction(variable))
|
||||
.whenAsyncActionIsDispatched(addFilter('elastic-filter', adding), true);
|
||||
@ -261,7 +253,7 @@ describe('adhoc actions', () => {
|
||||
.withDatasource('elasticsearch')
|
||||
.build();
|
||||
|
||||
const tester = await reduxTester<ReducersUsedInContext>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(createAddVariableAction(variable))
|
||||
.whenAsyncActionIsDispatched(addFilter('elastic-filter', adding), true);
|
||||
@ -284,7 +276,7 @@ describe('adhoc actions', () => {
|
||||
.withDatasource('elasticsearch')
|
||||
.build();
|
||||
|
||||
const tester = await reduxTester<ReducersUsedInContext>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(createAddVariableAction(variable))
|
||||
.whenAsyncActionIsDispatched(removeFilter('elastic-filter', 0), true);
|
||||
@ -314,7 +306,7 @@ describe('adhoc actions', () => {
|
||||
.withDatasource('elasticsearch')
|
||||
.build();
|
||||
|
||||
const tester = await reduxTester<ReducersUsedInContext>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(createAddVariableAction(variable))
|
||||
.whenAsyncActionIsDispatched(removeFilter('elastic-filter', 0), true);
|
||||
@ -349,7 +341,7 @@ describe('adhoc actions', () => {
|
||||
{ ...existing, name: 'value-2' },
|
||||
];
|
||||
|
||||
const tester = await reduxTester<ReducersUsedInContext>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(createAddVariableAction(variable))
|
||||
.whenAsyncActionIsDispatched(setFiltersFromUrl('elastic-filter', fromUrl), true);
|
||||
@ -380,7 +372,7 @@ describe('adhoc actions', () => {
|
||||
getMetricSources.mockRestore();
|
||||
getMetricSources.mockReturnValue(datasources);
|
||||
|
||||
const tester = reduxTester<ReducersUsedInContext>()
|
||||
const tester = reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(initAdHocVariableEditor());
|
||||
|
||||
@ -406,7 +398,7 @@ describe('adhoc actions', () => {
|
||||
getDatasource.mockRestore();
|
||||
getDatasource.mockResolvedValue(null);
|
||||
|
||||
const tester = await reduxTester<ReducersUsedInContext>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(createAddVariableAction(variable))
|
||||
.whenActionIsDispatched(setIdInEditor({ id: variable.id }))
|
||||
@ -434,7 +426,7 @@ describe('adhoc actions', () => {
|
||||
getTagKeys: () => {},
|
||||
});
|
||||
|
||||
const tester = await reduxTester<ReducersUsedInContext>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(createAddVariableAction(variable))
|
||||
.whenActionIsDispatched(setIdInEditor({ id: variable.id }))
|
||||
|
@ -6,7 +6,7 @@ import { MetricFindValue, SelectableValue } from '@grafana/data';
|
||||
interface Props {
|
||||
datasource: string;
|
||||
filterKey: string;
|
||||
filterValue: string | null;
|
||||
filterValue?: string;
|
||||
onChange: (item: SelectableValue<string>) => void;
|
||||
placeHolder?: string;
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import React, { PureComponent, ReactNode } from 'react';
|
||||
import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux';
|
||||
import { StoreState } from 'app/types';
|
||||
import { connect, ConnectedProps } from 'react-redux';
|
||||
import { AdHocVariableFilter, AdHocVariableModel } from 'app/features/variables/types';
|
||||
import { VariablePickerProps } from '../../pickers/types';
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
@ -10,20 +9,20 @@ import { addFilter, changeFilter, removeFilter } from '../actions';
|
||||
import { REMOVE_FILTER_KEY } from './AdHocFilterKey';
|
||||
import { AdHocFilterRenderer } from './AdHocFilterRenderer';
|
||||
|
||||
const mapDispatchToProps = {
|
||||
addFilter,
|
||||
removeFilter,
|
||||
changeFilter,
|
||||
};
|
||||
|
||||
const connector = connect(null, mapDispatchToProps);
|
||||
|
||||
interface OwnProps extends VariablePickerProps<AdHocVariableModel> {}
|
||||
|
||||
interface ConnectedProps {}
|
||||
|
||||
interface DispatchProps {
|
||||
addFilter: typeof addFilter;
|
||||
removeFilter: typeof removeFilter;
|
||||
changeFilter: typeof changeFilter;
|
||||
}
|
||||
|
||||
type Props = OwnProps & ConnectedProps & DispatchProps;
|
||||
type Props = OwnProps & ConnectedProps<typeof connector>;
|
||||
|
||||
export class AdHocPickerUnconnected extends PureComponent<Props> {
|
||||
onChange = (index: number, prop: string) => (key: SelectableValue<string>) => {
|
||||
onChange = (index: number, prop: string) => (key: SelectableValue<string | null>) => {
|
||||
const { id, filters } = this.props.variable;
|
||||
const { value } = key;
|
||||
|
||||
@ -85,13 +84,5 @@ export class AdHocPickerUnconnected extends PureComponent<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps: MapDispatchToProps<DispatchProps, OwnProps> = {
|
||||
addFilter,
|
||||
removeFilter,
|
||||
changeFilter,
|
||||
};
|
||||
|
||||
const mapStateToProps: MapStateToProps<ConnectedProps, OwnProps, StoreState> = (state) => ({});
|
||||
|
||||
export const AdHocPicker = connect(mapStateToProps, mapDispatchToProps)(AdHocPickerUnconnected);
|
||||
export const AdHocPicker = connector(AdHocPickerUnconnected);
|
||||
AdHocPicker.displayName = 'AdHocPicker';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { ChangeEvent, FocusEvent, PureComponent } from 'react';
|
||||
import React, { FormEvent, PureComponent } from 'react';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { VerticalGroup } from '@grafana/ui';
|
||||
|
||||
@ -10,17 +10,17 @@ import { VariableTextField } from '../editor/VariableTextField';
|
||||
export interface Props extends VariableEditorProps<ConstantVariableModel> {}
|
||||
|
||||
export class ConstantVariableEditor extends PureComponent<Props> {
|
||||
onChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
onChange = (event: FormEvent<HTMLInputElement>) => {
|
||||
this.props.onPropChange({
|
||||
propName: 'query',
|
||||
propValue: event.target.value,
|
||||
propValue: event.currentTarget.value,
|
||||
});
|
||||
};
|
||||
|
||||
onBlur = (event: FocusEvent<HTMLInputElement>) => {
|
||||
onBlur = (event: FormEvent<HTMLInputElement>) => {
|
||||
this.props.onPropChange({
|
||||
propName: 'query',
|
||||
propValue: event.target.value,
|
||||
propValue: event.currentTarget.value,
|
||||
updateOptions: true,
|
||||
});
|
||||
};
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { variableAdapters } from '../adapters';
|
||||
import { createConstantVariableAdapter } from './adapter';
|
||||
import { reduxTester } from '../../../../test/core/redux/reduxTester';
|
||||
import { TemplatingState } from 'app/features/variables/state/reducers';
|
||||
import { updateConstantVariableOptions } from './actions';
|
||||
import { getRootReducer } from '../state/helpers';
|
||||
import { getRootReducer, RootReducerType } from '../state/helpers';
|
||||
import { ConstantVariableModel, initialVariableModelState, VariableOption } from '../types';
|
||||
import { toVariablePayload } from '../state/types';
|
||||
import { createConstantOptionsFromQuery } from './reducer';
|
||||
@ -35,19 +34,15 @@ describe('constant actions', () => {
|
||||
query: 'A',
|
||||
};
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(updateConstantVariableOptions(toVariablePayload(variable)), true);
|
||||
|
||||
tester.thenDispatchedActionsPredicateShouldEqual((actions) => {
|
||||
const [createAction, setCurrentAction] = actions;
|
||||
const expectedNumberOfActions = 2;
|
||||
|
||||
expect(createAction).toEqual(createConstantOptionsFromQuery(toVariablePayload(variable)));
|
||||
expect(setCurrentAction).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option })));
|
||||
return actions.length === expectedNumberOfActions;
|
||||
});
|
||||
tester.thenDispatchedActionsShouldEqual(
|
||||
createConstantOptionsFromQuery(toVariablePayload(variable)),
|
||||
setCurrentVariableValue(toVariablePayload(variable, { option }))
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -4,10 +4,10 @@ import { dispatch } from '../../../store/store';
|
||||
import { setOptionAsCurrent, setOptionFromUrl } from '../state/actions';
|
||||
import { VariableAdapter } from '../adapters';
|
||||
import { constantVariableReducer, initialConstantVariableModelState } from './reducer';
|
||||
import { OptionsPicker } from '../pickers';
|
||||
import { ConstantVariableEditor } from './ConstantVariableEditor';
|
||||
import { updateConstantVariableOptions } from './actions';
|
||||
import { toVariableIdentifier } from '../state/types';
|
||||
import { optionPickerFactory } from '../pickers';
|
||||
|
||||
export const createConstantVariableAdapter = (): VariableAdapter<ConstantVariableModel> => {
|
||||
return {
|
||||
@ -16,7 +16,7 @@ export const createConstantVariableAdapter = (): VariableAdapter<ConstantVariabl
|
||||
name: 'Constant',
|
||||
initialState: initialConstantVariableModelState,
|
||||
reducer: constantVariableReducer,
|
||||
picker: OptionsPicker,
|
||||
picker: optionPickerFactory<ConstantVariableModel>(),
|
||||
editor: ConstantVariableEditor,
|
||||
dependsOn: () => {
|
||||
return false;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { ChangeEvent, FocusEvent, PureComponent } from 'react';
|
||||
import React, { FormEvent, PureComponent } from 'react';
|
||||
import { CustomVariableModel, VariableWithMultiSupport } from '../types';
|
||||
import { SelectionOptionsEditor } from '../editor/SelectionOptionsEditor';
|
||||
import { OnPropChangeArguments, VariableEditorProps } from '../editor/types';
|
||||
@ -21,10 +21,10 @@ interface DispatchProps {
|
||||
export type Props = OwnProps & ConnectedProps & DispatchProps;
|
||||
|
||||
class CustomVariableEditorUnconnected extends PureComponent<Props> {
|
||||
onChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
|
||||
onChange = (event: FormEvent<HTMLTextAreaElement>) => {
|
||||
this.props.onPropChange({
|
||||
propName: 'query',
|
||||
propValue: event.target.value,
|
||||
propValue: event.currentTarget.value,
|
||||
});
|
||||
};
|
||||
|
||||
@ -32,10 +32,10 @@ class CustomVariableEditorUnconnected extends PureComponent<Props> {
|
||||
this.props.onPropChange({ propName, propValue, updateOptions: true });
|
||||
};
|
||||
|
||||
onBlur = (event: FocusEvent<HTMLTextAreaElement>) => {
|
||||
onBlur = (event: FormEvent<HTMLTextAreaElement>) => {
|
||||
this.props.onPropChange({
|
||||
propName: 'query',
|
||||
propValue: event.target.value,
|
||||
propValue: event.currentTarget.value,
|
||||
updateOptions: true,
|
||||
});
|
||||
};
|
||||
|
@ -2,11 +2,10 @@ import { variableAdapters } from '../adapters';
|
||||
import { updateCustomVariableOptions } from './actions';
|
||||
import { createCustomVariableAdapter } from './adapter';
|
||||
import { reduxTester } from '../../../../test/core/redux/reduxTester';
|
||||
import { getRootReducer } from '../state/helpers';
|
||||
import { getRootReducer, RootReducerType } from '../state/helpers';
|
||||
import { CustomVariableModel, initialVariableModelState, VariableOption } from '../types';
|
||||
import { toVariablePayload } from '../state/types';
|
||||
import { addVariable, setCurrentVariableValue } from '../state/sharedReducer';
|
||||
import { TemplatingState } from '../state/reducers';
|
||||
import { createCustomOptionsFromQuery } from './reducer';
|
||||
|
||||
describe('custom actions', () => {
|
||||
@ -48,19 +47,15 @@ describe('custom actions', () => {
|
||||
includeAll: false,
|
||||
};
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(updateCustomVariableOptions(toVariablePayload(variable)), true);
|
||||
|
||||
tester.thenDispatchedActionsPredicateShouldEqual((actions) => {
|
||||
const [createAction, setCurrentAction] = actions;
|
||||
const expectedNumberOfActions = 2;
|
||||
|
||||
expect(createAction).toEqual(createCustomOptionsFromQuery(toVariablePayload(variable)));
|
||||
expect(setCurrentAction).toEqual(setCurrentVariableValue(toVariablePayload(variable, { option })));
|
||||
return actions.length === expectedNumberOfActions;
|
||||
});
|
||||
tester.thenDispatchedActionsShouldEqual(
|
||||
createCustomOptionsFromQuery(toVariablePayload(variable)),
|
||||
setCurrentVariableValue(toVariablePayload(variable, { option }))
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -4,11 +4,11 @@ import { dispatch } from '../../../store/store';
|
||||
import { setOptionAsCurrent, setOptionFromUrl } from '../state/actions';
|
||||
import { VariableAdapter } from '../adapters';
|
||||
import { customVariableReducer, initialCustomVariableModelState } from './reducer';
|
||||
import { OptionsPicker } from '../pickers';
|
||||
import { CustomVariableEditor } from './CustomVariableEditor';
|
||||
import { updateCustomVariableOptions } from './actions';
|
||||
import { ALL_VARIABLE_TEXT, toVariableIdentifier } from '../state/types';
|
||||
import { isAllVariable } from '../utils';
|
||||
import { optionPickerFactory } from '../pickers';
|
||||
|
||||
export const createCustomVariableAdapter = (): VariableAdapter<CustomVariableModel> => {
|
||||
return {
|
||||
@ -17,7 +17,7 @@ export const createCustomVariableAdapter = (): VariableAdapter<CustomVariableMod
|
||||
name: 'Custom',
|
||||
initialState: initialCustomVariableModelState,
|
||||
reducer: customVariableReducer,
|
||||
picker: OptionsPicker,
|
||||
picker: optionPickerFactory<CustomVariableModel>(),
|
||||
editor: CustomVariableEditor,
|
||||
dependsOn: () => {
|
||||
return false;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { ChangeEvent, FocusEvent, PureComponent } from 'react';
|
||||
import React, { FormEvent, PureComponent } from 'react';
|
||||
import { MapDispatchToProps, MapStateToProps } from 'react-redux';
|
||||
import { InlineFieldRow, VerticalGroup } from '@grafana/ui';
|
||||
|
||||
@ -34,17 +34,17 @@ export class DataSourceVariableEditorUnConnected extends PureComponent<Props> {
|
||||
this.props.initDataSourceVariableEditor();
|
||||
}
|
||||
|
||||
onRegExChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
onRegExChange = (event: FormEvent<HTMLInputElement>) => {
|
||||
this.props.onPropChange({
|
||||
propName: 'regex',
|
||||
propValue: event.target.value,
|
||||
propValue: event.currentTarget.value,
|
||||
});
|
||||
};
|
||||
|
||||
onRegExBlur = (event: FocusEvent<HTMLInputElement>) => {
|
||||
onRegExBlur = (event: FormEvent<HTMLInputElement>) => {
|
||||
this.props.onPropChange({
|
||||
propName: 'regex',
|
||||
propValue: event.target.value,
|
||||
propValue: event.currentTarget.value,
|
||||
updateOptions: true,
|
||||
});
|
||||
};
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { DataSourceInstanceSettings } from '@grafana/data';
|
||||
|
||||
import { reduxTester } from '../../../../test/core/redux/reduxTester';
|
||||
import { TemplatingState } from '../state/reducers';
|
||||
import { getRootReducer } from '../state/helpers';
|
||||
import { getRootReducer, RootReducerType } from '../state/helpers';
|
||||
import { toVariableIdentifier, toVariablePayload } from '../state/types';
|
||||
import { variableAdapters } from '../adapters';
|
||||
import { createDataSourceVariableAdapter } from './adapter';
|
||||
@ -49,7 +48,7 @@ describe('data source actions', () => {
|
||||
query: 'mock-data-id',
|
||||
});
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(
|
||||
addVariable(toVariablePayload(datasource, { global: false, index: 0, model: datasource }))
|
||||
@ -97,7 +96,7 @@ describe('data source actions', () => {
|
||||
regex: '/.*(second-name).*/',
|
||||
});
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(
|
||||
addVariable(toVariablePayload(datasource, { global: false, index: 0, model: datasource }))
|
||||
@ -142,7 +141,7 @@ describe('data source actions', () => {
|
||||
|
||||
const { dependencies, getListMock, getDatasourceSrvMock } = getTestContext({ sources });
|
||||
|
||||
await reduxTester<{ templating: TemplatingState }>()
|
||||
await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(initDataSourceVariableEditor(dependencies))
|
||||
.thenDispatchedActionsShouldEqual(
|
||||
|
@ -4,11 +4,11 @@ import { dispatch } from '../../../store/store';
|
||||
import { setOptionAsCurrent, setOptionFromUrl } from '../state/actions';
|
||||
import { VariableAdapter } from '../adapters';
|
||||
import { dataSourceVariableReducer, initialDataSourceVariableModelState } from './reducer';
|
||||
import { OptionsPicker } from '../pickers';
|
||||
import { ALL_VARIABLE_TEXT, toVariableIdentifier } from '../state/types';
|
||||
import { DataSourceVariableEditor } from './DataSourceVariableEditor';
|
||||
import { updateDataSourceVariableOptions } from './actions';
|
||||
import { containsVariable, isAllVariable } from '../utils';
|
||||
import { optionPickerFactory } from '../pickers';
|
||||
|
||||
export const createDataSourceVariableAdapter = (): VariableAdapter<DataSourceVariableModel> => {
|
||||
return {
|
||||
@ -17,7 +17,7 @@ export const createDataSourceVariableAdapter = (): VariableAdapter<DataSourceVar
|
||||
name: 'Datasource',
|
||||
initialState: initialDataSourceVariableModelState,
|
||||
reducer: dataSourceVariableReducer,
|
||||
picker: OptionsPicker,
|
||||
picker: optionPickerFactory<DataSourceVariableModel>(),
|
||||
editor: DataSourceVariableEditor,
|
||||
dependsOn: (variable, variableToTest) => {
|
||||
if (variable.regex) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { FunctionComponent, useCallback } from 'react';
|
||||
import React, { ChangeEvent, FormEvent, FunctionComponent, useCallback } from 'react';
|
||||
import { InlineFieldRow, VerticalGroup } from '@grafana/ui';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
|
||||
@ -16,22 +16,22 @@ export interface SelectionOptionsEditorProps<Model extends VariableWithMultiSupp
|
||||
|
||||
export const SelectionOptionsEditor: FunctionComponent<SelectionOptionsEditorProps> = (props) => {
|
||||
const onMultiChanged = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
(event: ChangeEvent<HTMLInputElement>) => {
|
||||
props.onMultiChanged(toVariableIdentifier(props.variable), event.target.checked);
|
||||
},
|
||||
[props.onMultiChanged, props.variable]
|
||||
);
|
||||
|
||||
const onIncludeAllChanged = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
(event: ChangeEvent<HTMLInputElement>) => {
|
||||
props.onPropChange({ propName: 'includeAll', propValue: event.target.checked });
|
||||
},
|
||||
[props.onPropChange]
|
||||
);
|
||||
|
||||
const onAllValueChanged = useCallback(
|
||||
(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
props.onPropChange({ propName: 'allValue', propValue: event.target.value });
|
||||
(event: FormEvent<HTMLInputElement>) => {
|
||||
props.onPropChange({ propName: 'allValue', propValue: event.currentTarget.value });
|
||||
},
|
||||
[props.onPropChange]
|
||||
);
|
||||
|
@ -5,34 +5,34 @@ import { selectors } from '@grafana/e2e-selectors';
|
||||
import { toVariableIdentifier, toVariablePayload, VariableIdentifier } from '../state/types';
|
||||
import { StoreState } from '../../../types';
|
||||
import { VariableEditorEditor } from './VariableEditorEditor';
|
||||
import { connect, MapStateToProps, MapDispatchToProps } from 'react-redux';
|
||||
import { connect, ConnectedProps } from 'react-redux';
|
||||
import { getEditorVariables } from '../state/selectors';
|
||||
import { VariableModel } from '../types';
|
||||
import { switchToEditMode, switchToListMode, switchToNewMode } from './actions';
|
||||
import { changeVariableOrder, duplicateVariable, removeVariable } from '../state/sharedReducer';
|
||||
import { VariableEditorList } from './VariableEditorList';
|
||||
import { DashboardModel } from '../../dashboard/state';
|
||||
import { VariablesUnknownTable } from '../inspect/VariablesUnknownTable';
|
||||
import { VariablesDependenciesButton } from '../inspect/VariablesDependenciesButton';
|
||||
|
||||
const mapStateToProps = (state: StoreState) => ({
|
||||
variables: getEditorVariables(state),
|
||||
idInEditor: state.templating.editor.id,
|
||||
dashboard: state.dashboard.getModel(),
|
||||
});
|
||||
|
||||
const mapDispatchToProps = {
|
||||
changeVariableOrder,
|
||||
duplicateVariable,
|
||||
removeVariable,
|
||||
switchToNewMode,
|
||||
switchToEditMode,
|
||||
switchToListMode,
|
||||
};
|
||||
|
||||
interface OwnProps {}
|
||||
|
||||
interface ConnectedProps {
|
||||
idInEditor: string | null;
|
||||
variables: VariableModel[];
|
||||
dashboard: DashboardModel | null;
|
||||
}
|
||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
||||
interface DispatchProps {
|
||||
changeVariableOrder: typeof changeVariableOrder;
|
||||
duplicateVariable: typeof duplicateVariable;
|
||||
removeVariable: typeof removeVariable;
|
||||
switchToNewMode: typeof switchToNewMode;
|
||||
switchToEditMode: typeof switchToEditMode;
|
||||
switchToListMode: typeof switchToListMode;
|
||||
}
|
||||
|
||||
type Props = OwnProps & ConnectedProps & DispatchProps;
|
||||
type Props = OwnProps & ConnectedProps<typeof connector>;
|
||||
|
||||
class VariableEditorContainerUnconnected extends PureComponent<Props> {
|
||||
componentDidMount(): void {
|
||||
@ -48,7 +48,7 @@ class VariableEditorContainerUnconnected extends PureComponent<Props> {
|
||||
this.props.switchToEditMode(identifier);
|
||||
};
|
||||
|
||||
onNewVariable = (event: MouseEvent<HTMLAnchorElement>) => {
|
||||
onNewVariable = (event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
this.props.switchToNewMode();
|
||||
};
|
||||
@ -124,19 +124,4 @@ class VariableEditorContainerUnconnected extends PureComponent<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps: MapStateToProps<ConnectedProps, OwnProps, StoreState> = (state) => ({
|
||||
variables: getEditorVariables(state),
|
||||
idInEditor: state.templating.editor.id,
|
||||
dashboard: state.dashboard.getModel(),
|
||||
});
|
||||
|
||||
const mapDispatchToProps: MapDispatchToProps<DispatchProps, OwnProps> = {
|
||||
changeVariableOrder,
|
||||
duplicateVariable,
|
||||
removeVariable,
|
||||
switchToNewMode,
|
||||
switchToEditMode,
|
||||
switchToListMode,
|
||||
};
|
||||
|
||||
export const VariableEditorContainer = connect(mapStateToProps, mapDispatchToProps)(VariableEditorContainerUnconnected);
|
||||
export const VariableEditorContainer = connector(VariableEditorContainerUnconnected);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { ChangeEvent, FormEvent, PureComponent } from 'react';
|
||||
import React, { FormEvent, PureComponent } from 'react';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import { AppEvents, LoadingState, SelectableValue, VariableType } from '@grafana/data';
|
||||
import { Button, Icon, InlineFieldRow, VerticalGroup } from '@grafana/ui';
|
||||
@ -62,9 +62,9 @@ export class VariableEditorEditorUnConnected extends PureComponent<Props> {
|
||||
this.props.variableEditorUnMount(this.props.identifier);
|
||||
}
|
||||
|
||||
onNameChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
onNameChange = (event: FormEvent<HTMLInputElement>) => {
|
||||
event.preventDefault();
|
||||
this.props.changeVariableName(this.props.identifier, event.target.value);
|
||||
this.props.changeVariableName(this.props.identifier, event.currentTarget.value);
|
||||
};
|
||||
|
||||
onTypeChange = (option: SelectableValue<VariableType>) => {
|
||||
@ -74,16 +74,16 @@ export class VariableEditorEditorUnConnected extends PureComponent<Props> {
|
||||
this.props.changeVariableType(toVariablePayload(this.props.identifier, { newType: option.value }));
|
||||
};
|
||||
|
||||
onLabelChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
onLabelChange = (event: FormEvent<HTMLInputElement>) => {
|
||||
event.preventDefault();
|
||||
this.props.changeVariableProp(
|
||||
toVariablePayload(this.props.identifier, { propName: 'label', propValue: event.target.value })
|
||||
toVariablePayload(this.props.identifier, { propName: 'label', propValue: event.currentTarget.value })
|
||||
);
|
||||
};
|
||||
|
||||
onDescriptionChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
onDescriptionChange = (event: FormEvent<HTMLInputElement>) => {
|
||||
this.props.changeVariableProp(
|
||||
toVariablePayload(this.props.identifier, { propName: 'description', propValue: event.target.value })
|
||||
toVariablePayload(this.props.identifier, { propName: 'description', propValue: event.currentTarget.value })
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -15,7 +15,7 @@ import { VariableUsagesButton } from '../inspect/VariableUsagesButton';
|
||||
export interface Props {
|
||||
variables: VariableModel[];
|
||||
dashboard: DashboardModel | null;
|
||||
onAddClick: (event: MouseEvent<HTMLAnchorElement>) => void;
|
||||
onAddClick: (event: MouseEvent) => void;
|
||||
onEditClick: (identifier: VariableIdentifier) => void;
|
||||
onChangeVariableOrder: (identifier: VariableIdentifier, fromIndex: number, toIndex: number) => void;
|
||||
onDuplicateVariable: (identifier: VariableIdentifier) => void;
|
||||
|
@ -176,7 +176,7 @@ export function isQueryEditor<
|
||||
>(
|
||||
component: VariableQueryEditorType,
|
||||
datasource: DataSourceApi<TQuery, TOptions>
|
||||
): component is ComponentType<QueryEditorProps<any>> {
|
||||
): component is ComponentType<QueryEditorProps<DataSourceApi<TQuery, TOptions>, TQuery, TOptions, any>> {
|
||||
if (!component) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { ChangeEvent, FocusEvent, PureComponent } from 'react';
|
||||
import React, { ChangeEvent, FormEvent, PureComponent } from 'react';
|
||||
import { InlineFieldRow, VerticalGroup } from '@grafana/ui';
|
||||
|
||||
import { IntervalVariableModel } from '../types';
|
||||
@ -20,17 +20,17 @@ export class IntervalVariableEditor extends PureComponent<Props> {
|
||||
});
|
||||
};
|
||||
|
||||
onQueryChanged = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
onQueryChanged = (event: FormEvent<HTMLInputElement>) => {
|
||||
this.props.onPropChange({
|
||||
propName: 'query',
|
||||
propValue: event.target.value,
|
||||
propValue: event.currentTarget.value,
|
||||
});
|
||||
};
|
||||
|
||||
onQueryBlur = (event: FocusEvent<HTMLInputElement>) => {
|
||||
onQueryBlur = (event: FormEvent<HTMLInputElement>) => {
|
||||
this.props.onPropChange({
|
||||
propName: 'query',
|
||||
propValue: event.target.value,
|
||||
propValue: event.currentTarget.value,
|
||||
updateOptions: true,
|
||||
});
|
||||
};
|
||||
@ -43,10 +43,10 @@ export class IntervalVariableEditor extends PureComponent<Props> {
|
||||
});
|
||||
};
|
||||
|
||||
onAutoMinChanged = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
onAutoMinChanged = (event: FormEvent<HTMLInputElement>) => {
|
||||
this.props.onPropChange({
|
||||
propName: 'auto_min',
|
||||
propValue: event.target.value,
|
||||
propValue: event.currentTarget.value,
|
||||
updateOptions: true,
|
||||
});
|
||||
};
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { getRootReducer } from '../state/helpers';
|
||||
import { getRootReducer, RootReducerType } from '../state/helpers';
|
||||
import { reduxTester } from '../../../../test/core/redux/reduxTester';
|
||||
import { TemplatingState } from '../state/reducers';
|
||||
import { toVariableIdentifier, toVariablePayload } from '../state/types';
|
||||
import { updateAutoValue, UpdateAutoValueDependencies, updateIntervalVariableOptions } from './actions';
|
||||
import { createIntervalOptions } from './reducer';
|
||||
@ -26,7 +25,7 @@ describe('interval actions', () => {
|
||||
it('then correct actions are dispatched', async () => {
|
||||
const interval = intervalBuilder().withId('0').withQuery('1s,1m,1h,1d').withAuto(false).build();
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(interval, { global: false, index: 0, model: interval })))
|
||||
.whenAsyncActionIsDispatched(updateIntervalVariableOptions(toVariableIdentifier(interval)), true);
|
||||
@ -64,7 +63,7 @@ describe('interval actions', () => {
|
||||
.withAutoMin('1xyz') // illegal interval string
|
||||
.build();
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(interval, { global: false, index: 0, model: interval })))
|
||||
.whenAsyncActionIsDispatched(updateOptions(toVariableIdentifier(interval)), true);
|
||||
@ -121,7 +120,7 @@ describe('interval actions', () => {
|
||||
} as unknown) as TemplateSrv,
|
||||
};
|
||||
|
||||
await reduxTester<{ templating: TemplatingState }>()
|
||||
await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(
|
||||
addVariable(toVariablePayload(interval, { global: false, index: 0, model: interval }))
|
||||
@ -165,7 +164,7 @@ describe('interval actions', () => {
|
||||
} as unknown) as TemplateSrv,
|
||||
};
|
||||
|
||||
await reduxTester<{ templating: TemplatingState }>()
|
||||
await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(
|
||||
addVariable(toVariablePayload(interval, { global: false, index: 0, model: interval }))
|
||||
|
@ -4,10 +4,10 @@ import { dispatch } from '../../../store/store';
|
||||
import { setOptionAsCurrent, setOptionFromUrl } from '../state/actions';
|
||||
import { VariableAdapter } from '../adapters';
|
||||
import { initialIntervalVariableModelState, intervalVariableReducer } from './reducer';
|
||||
import { OptionsPicker } from '../pickers';
|
||||
import { toVariableIdentifier } from '../state/types';
|
||||
import { IntervalVariableEditor } from './IntervalVariableEditor';
|
||||
import { updateAutoValue, updateIntervalVariableOptions } from './actions';
|
||||
import { optionPickerFactory } from '../pickers';
|
||||
|
||||
export const createIntervalVariableAdapter = (): VariableAdapter<IntervalVariableModel> => {
|
||||
return {
|
||||
@ -16,7 +16,7 @@ export const createIntervalVariableAdapter = (): VariableAdapter<IntervalVariabl
|
||||
name: 'Interval',
|
||||
initialState: initialIntervalVariableModelState,
|
||||
reducer: intervalVariableReducer,
|
||||
picker: OptionsPicker,
|
||||
picker: optionPickerFactory<IntervalVariableModel>(),
|
||||
editor: IntervalVariableEditor,
|
||||
dependsOn: () => {
|
||||
return false;
|
||||
|
@ -1,119 +1,124 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { connect, MapDispatchToProps, MapStateToProps } from 'react-redux';
|
||||
import React, { ComponentType, PureComponent } from 'react';
|
||||
import { connect, ConnectedProps } from 'react-redux';
|
||||
import { ClickOutsideWrapper } from '@grafana/ui';
|
||||
import { LoadingState } from '@grafana/data';
|
||||
|
||||
import { StoreState } from 'app/types';
|
||||
import { VariableLink } from '../shared/VariableLink';
|
||||
import { VariableInput } from '../shared/VariableInput';
|
||||
import { commitChangesToVariable, filterOrSearchOptions, navigateOptions, toggleAndFetchTag } from './actions';
|
||||
import { OptionsPickerState, showOptions, toggleAllOptions, toggleOption } from './reducer';
|
||||
import { VariableOption, VariableTag, VariableWithMultiSupport, VariableWithOptions } from '../../types';
|
||||
import { VariableOptions } from '../shared/VariableOptions';
|
||||
import { isQuery } from '../../guard';
|
||||
import { isMulti, isQuery } from '../../guard';
|
||||
import { VariablePickerProps } from '../types';
|
||||
import { formatVariableLabel } from '../../shared/formatVariable';
|
||||
import { toVariableIdentifier } from '../../state/types';
|
||||
import { getVariableQueryRunner } from '../../query/VariableQueryRunner';
|
||||
import { VariableLink } from '../shared/VariableLink';
|
||||
|
||||
interface OwnProps extends VariablePickerProps<VariableWithMultiSupport> {}
|
||||
|
||||
interface ConnectedProps {
|
||||
picker: OptionsPickerState;
|
||||
}
|
||||
|
||||
interface DispatchProps {
|
||||
showOptions: typeof showOptions;
|
||||
commitChangesToVariable: typeof commitChangesToVariable;
|
||||
toggleAllOptions: typeof toggleAllOptions;
|
||||
toggleOption: typeof toggleOption;
|
||||
toggleAndFetchTag: typeof toggleAndFetchTag;
|
||||
filterOrSearchOptions: typeof filterOrSearchOptions;
|
||||
navigateOptions: typeof navigateOptions;
|
||||
}
|
||||
|
||||
type Props = OwnProps & ConnectedProps & DispatchProps;
|
||||
|
||||
export class OptionsPickerUnconnected extends PureComponent<Props> {
|
||||
onShowOptions = () => this.props.showOptions(this.props.variable);
|
||||
onHideOptions = () => this.props.commitChangesToVariable(this.props.onVariableChange);
|
||||
|
||||
onToggleOption = (option: VariableOption, clearOthers: boolean) => {
|
||||
const toggleFunc = this.props.variable.multi ? this.onToggleMultiValueVariable : this.onToggleSingleValueVariable;
|
||||
toggleFunc(option, clearOthers);
|
||||
export const optionPickerFactory = <Model extends VariableWithOptions | VariableWithMultiSupport>(): ComponentType<
|
||||
VariablePickerProps<Model>
|
||||
> => {
|
||||
const mapDispatchToProps = {
|
||||
showOptions,
|
||||
commitChangesToVariable,
|
||||
filterOrSearchOptions,
|
||||
toggleAllOptions,
|
||||
toggleOption,
|
||||
toggleAndFetchTag,
|
||||
navigateOptions,
|
||||
};
|
||||
|
||||
onToggleSingleValueVariable = (option: VariableOption, clearOthers: boolean) => {
|
||||
this.props.toggleOption({ option, clearOthers, forceSelect: false });
|
||||
this.onHideOptions();
|
||||
};
|
||||
const mapStateToProps = (state: StoreState) => ({
|
||||
picker: state.templating.optionsPicker,
|
||||
});
|
||||
|
||||
onToggleMultiValueVariable = (option: VariableOption, clearOthers: boolean) => {
|
||||
this.props.toggleOption({ option, clearOthers, forceSelect: false });
|
||||
};
|
||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
||||
render() {
|
||||
const { variable, picker } = this.props;
|
||||
const showOptions = picker.id === variable.id;
|
||||
interface OwnProps extends VariablePickerProps<Model> {}
|
||||
|
||||
return (
|
||||
<div className="variable-link-wrapper">
|
||||
{this.renderLink(showOptions, variable)}
|
||||
{this.renderOptions(showOptions, picker)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
type Props = OwnProps & ConnectedProps<typeof connector>;
|
||||
|
||||
renderLink(showOptions: boolean, variable: VariableWithMultiSupport) {
|
||||
if (showOptions) {
|
||||
return null;
|
||||
class OptionsPickerUnconnected extends PureComponent<Props> {
|
||||
onShowOptions = () => this.props.showOptions(this.props.variable);
|
||||
onHideOptions = () => this.props.commitChangesToVariable(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({ option, clearOthers, forceSelect: false });
|
||||
this.onHideOptions();
|
||||
};
|
||||
|
||||
onToggleMultiValueVariable = (option: VariableOption, clearOthers: boolean) => {
|
||||
this.props.toggleOption({ option, clearOthers, forceSelect: false });
|
||||
};
|
||||
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
const linkText = formatVariableLabel(variable);
|
||||
const tags = getSelectedTags(variable);
|
||||
const loading = variable.state === LoadingState.Loading;
|
||||
renderLink(variable: VariableWithOptions) {
|
||||
const linkText = formatVariableLabel(variable);
|
||||
const tags = getSelectedTags(variable);
|
||||
const loading = variable.state === LoadingState.Loading;
|
||||
|
||||
return (
|
||||
<VariableLink
|
||||
text={linkText}
|
||||
tags={tags}
|
||||
onClick={this.onShowOptions}
|
||||
loading={loading}
|
||||
onCancel={this.onCancel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
onCancel = () => {
|
||||
getVariableQueryRunner().cancelRequest(toVariableIdentifier(this.props.variable));
|
||||
};
|
||||
|
||||
renderOptions(showOptions: boolean, picker: OptionsPickerState) {
|
||||
if (!showOptions) {
|
||||
return null;
|
||||
return (
|
||||
<VariableLink
|
||||
text={linkText}
|
||||
tags={tags}
|
||||
onClick={this.onShowOptions}
|
||||
loading={loading}
|
||||
onCancel={this.onCancel}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<ClickOutsideWrapper onClick={this.onHideOptions}>
|
||||
<VariableInput
|
||||
value={picker.queryValue}
|
||||
onChange={this.props.filterOrSearchOptions}
|
||||
onNavigate={this.props.navigateOptions}
|
||||
/>
|
||||
<VariableOptions
|
||||
values={picker.options}
|
||||
onToggle={this.onToggleOption}
|
||||
onToggleAll={this.props.toggleAllOptions}
|
||||
onToggleTag={this.props.toggleAndFetchTag}
|
||||
highlightIndex={picker.highlightIndex}
|
||||
multi={picker.multi}
|
||||
tags={picker.tags}
|
||||
selectedValues={picker.selectedValues}
|
||||
/>
|
||||
</ClickOutsideWrapper>
|
||||
);
|
||||
onCancel = () => {
|
||||
getVariableQueryRunner().cancelRequest(toVariableIdentifier(this.props.variable));
|
||||
};
|
||||
|
||||
renderOptions(picker: OptionsPickerState) {
|
||||
return (
|
||||
<ClickOutsideWrapper onClick={this.onHideOptions}>
|
||||
<VariableInput
|
||||
value={picker.queryValue}
|
||||
onChange={this.props.filterOrSearchOptions}
|
||||
onNavigate={this.props.navigateOptions}
|
||||
/>
|
||||
<VariableOptions
|
||||
values={picker.options}
|
||||
onToggle={this.onToggleOption}
|
||||
onToggleAll={this.props.toggleAllOptions}
|
||||
onToggleTag={this.props.toggleAndFetchTag}
|
||||
highlightIndex={picker.highlightIndex}
|
||||
multi={picker.multi}
|
||||
tags={picker.tags}
|
||||
selectedValues={picker.selectedValues}
|
||||
/>
|
||||
</ClickOutsideWrapper>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const OptionsPicker = connector(OptionsPickerUnconnected);
|
||||
OptionsPicker.displayName = 'OptionsPicker';
|
||||
|
||||
return OptionsPicker;
|
||||
};
|
||||
|
||||
const getSelectedTags = (variable: VariableWithOptions): VariableTag[] => {
|
||||
if (!isQuery(variable) || !Array.isArray(variable.tags)) {
|
||||
@ -121,20 +126,3 @@ const getSelectedTags = (variable: VariableWithOptions): VariableTag[] => {
|
||||
}
|
||||
return variable.tags.filter((t) => t.selected);
|
||||
};
|
||||
|
||||
const mapDispatchToProps: MapDispatchToProps<DispatchProps, OwnProps> = {
|
||||
showOptions,
|
||||
commitChangesToVariable,
|
||||
filterOrSearchOptions,
|
||||
toggleAllOptions,
|
||||
toggleOption,
|
||||
toggleAndFetchTag,
|
||||
navigateOptions,
|
||||
};
|
||||
|
||||
const mapStateToProps: MapStateToProps<ConnectedProps, OwnProps, StoreState> = (state) => ({
|
||||
picker: state.templating.optionsPicker,
|
||||
});
|
||||
|
||||
export const OptionsPicker = connect(mapStateToProps, mapDispatchToProps)(OptionsPickerUnconnected);
|
||||
OptionsPicker.displayName = 'OptionsPicker';
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { reduxTester } from '../../../../../test/core/redux/reduxTester';
|
||||
import { getRootReducer } from '../../state/helpers';
|
||||
import { TemplatingState } from '../../state/reducers';
|
||||
import { getRootReducer, RootReducerType } from '../../state/helpers';
|
||||
import { initialVariableModelState, QueryVariableModel, VariableRefresh, VariableSort } from '../../types';
|
||||
import {
|
||||
hideOptions,
|
||||
@ -53,7 +52,7 @@ describe('options picker actions', () => {
|
||||
const clearOthers = false;
|
||||
const key = NavigationKey.cancel;
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(showOptions(variable))
|
||||
@ -86,7 +85,7 @@ describe('options picker actions', () => {
|
||||
const clearOthers = false;
|
||||
const key = NavigationKey.select;
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(showOptions(variable))
|
||||
@ -109,7 +108,7 @@ describe('options picker actions', () => {
|
||||
const clearOthers = true;
|
||||
const key = NavigationKey.select;
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(showOptions(variable))
|
||||
@ -128,7 +127,7 @@ describe('options picker actions', () => {
|
||||
const clearOthers = true;
|
||||
const key = NavigationKey.select;
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(showOptions(variable))
|
||||
@ -149,7 +148,7 @@ describe('options picker actions', () => {
|
||||
const clearOthers = true;
|
||||
const key = NavigationKey.select;
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(showOptions(variable))
|
||||
@ -171,7 +170,7 @@ describe('options picker actions', () => {
|
||||
const clearOthers = false;
|
||||
const key = NavigationKey.selectAndClose;
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(showOptions(variable))
|
||||
@ -205,7 +204,7 @@ describe('options picker actions', () => {
|
||||
const variable = createMultiVariable({ options, current: createOption(['A'], ['A'], true), includeAll: false });
|
||||
const filter = 'A';
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(showOptions(variable))
|
||||
@ -220,7 +219,7 @@ describe('options picker actions', () => {
|
||||
const options = [createOption('A', 'A', true), createOption('B'), createOption('C')];
|
||||
const variable = createMultiVariable({ options, current: createOption(['A'], ['A'], true), includeAll: false });
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(showOptions(variable))
|
||||
@ -247,7 +246,7 @@ describe('options picker actions', () => {
|
||||
const variable = createMultiVariable({ options, current: createOption(['A'], ['A'], true), includeAll: false });
|
||||
const clearOthers = false;
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(showOptions(variable))
|
||||
@ -278,7 +277,7 @@ describe('options picker actions', () => {
|
||||
const variable = createMultiVariable({ options, current: createOption(['A'], ['A'], true), includeAll: false });
|
||||
const clearOthers = false;
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(showOptions(variable))
|
||||
@ -310,7 +309,7 @@ describe('options picker actions', () => {
|
||||
const variable = createMultiVariable({ options, current: createOption(['A'], ['A'], true), includeAll: false });
|
||||
const clearOthers = false;
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(showOptions(variable))
|
||||
@ -329,7 +328,7 @@ describe('options picker actions', () => {
|
||||
const variable = createMultiVariable({ options, current: createOption(['A'], ['A'], true), includeAll: false });
|
||||
const clearOthers = false;
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(showOptions(variable))
|
||||
@ -365,7 +364,7 @@ describe('options picker actions', () => {
|
||||
tags: [tag],
|
||||
});
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(showOptions(variable))
|
||||
@ -391,7 +390,7 @@ describe('options picker actions', () => {
|
||||
// @ts-ignore strict null error TS2345: Argument of type '() => Promise<{ value: string; text: string; }[]>' is not assignable to parameter of type '() => Promise<never[]>'
|
||||
datasource.metricFindQuery.mockImplementation(() => Promise.resolve(values));
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(showOptions(variable))
|
||||
|
@ -78,7 +78,7 @@ const setVariable = async (updated: VariableWithMultiSupport) => {
|
||||
return;
|
||||
};
|
||||
|
||||
export const commitChangesToVariable = (callback?: (updated: VariableWithMultiSupport) => void): ThunkResult<void> => {
|
||||
export const commitChangesToVariable = (callback?: (updated: any) => void): ThunkResult<void> => {
|
||||
return async (dispatch, getState) => {
|
||||
const picker = getState().templating.optionsPicker;
|
||||
const existing = getVariable<VariableWithMultiSupport>(picker.id, getState());
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||
import { cloneDeep, isString, trim } from 'lodash';
|
||||
import { VariableOption, VariableTag, VariableWithMultiSupport } from '../../types';
|
||||
import { VariableOption, VariableTag, VariableWithMultiSupport, VariableWithOptions } from '../../types';
|
||||
import { ALL_VARIABLE_VALUE } from '../../state/types';
|
||||
import { isQuery } from '../../guard';
|
||||
import { isMulti, isQuery } from '../../guard';
|
||||
import { applyStateChanges } from '../../../../core/utils/applyStateChanges';
|
||||
import { containsSearchFilter } from '../../utils';
|
||||
|
||||
@ -119,15 +119,19 @@ const optionsPickerSlice = createSlice({
|
||||
name: 'templating/optionsPicker',
|
||||
initialState,
|
||||
reducers: {
|
||||
showOptions: (state, action: PayloadAction<VariableWithMultiSupport>): OptionsPickerState => {
|
||||
const { query, options, multi } = action.payload;
|
||||
showOptions: (state, action: PayloadAction<VariableWithOptions>): OptionsPickerState => {
|
||||
const { query, options } = action.payload;
|
||||
|
||||
state.highlightIndex = -1;
|
||||
state.options = cloneDeep(options);
|
||||
state.tags = getTags(action.payload);
|
||||
state.multi = multi ?? false;
|
||||
state.id = action.payload.id;
|
||||
state.queryValue = '';
|
||||
state.multi = false;
|
||||
|
||||
if (isMulti(action.payload)) {
|
||||
state.tags = getTags(action.payload);
|
||||
state.multi = action.payload.multi ?? false;
|
||||
}
|
||||
|
||||
if (isQuery(action.payload)) {
|
||||
const { queryValue } = action.payload;
|
||||
|
@ -1 +1 @@
|
||||
export { OptionsPicker } from './OptionsPicker/OptionsPicker';
|
||||
export { optionPickerFactory } from './OptionsPicker/OptionsPicker';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { ChangeEvent, PureComponent } from 'react';
|
||||
import React, { ChangeEvent, FormEvent, PureComponent } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import { MapDispatchToProps, MapStateToProps } from 'react-redux';
|
||||
import { InlineField, InlineFieldRow, VerticalGroup } from '@grafana/ui';
|
||||
@ -92,34 +92,34 @@ export class QueryVariableEditorUnConnected extends PureComponent<Props, State>
|
||||
}
|
||||
};
|
||||
|
||||
onRegExChange = (event: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({ regex: event.target.value });
|
||||
onRegExChange = (event: FormEvent<HTMLInputElement>) => {
|
||||
this.setState({ regex: event.currentTarget.value });
|
||||
};
|
||||
|
||||
onRegExBlur = async (event: ChangeEvent<HTMLInputElement>) => {
|
||||
const regex = event.target.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 });
|
||||
}
|
||||
};
|
||||
|
||||
onTagsQueryChange = async (event: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({ tagsQuery: event.target.value });
|
||||
onTagsQueryChange = async (event: FormEvent<HTMLInputElement>) => {
|
||||
this.setState({ tagsQuery: event.currentTarget.value });
|
||||
};
|
||||
|
||||
onTagsQueryBlur = async (event: ChangeEvent<HTMLInputElement>) => {
|
||||
const tagsQuery = event.target.value;
|
||||
onTagsQueryBlur = async (event: FormEvent<HTMLInputElement>) => {
|
||||
const tagsQuery = event.currentTarget.value;
|
||||
if (this.props.variable.tagsQuery !== tagsQuery) {
|
||||
this.props.onPropChange({ propName: 'tagsQuery', propValue: tagsQuery, updateOptions: true });
|
||||
}
|
||||
};
|
||||
|
||||
onTagValuesQueryChange = async (event: ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({ tagValuesQuery: event.target.value });
|
||||
onTagValuesQueryChange = async (event: FormEvent<HTMLInputElement>) => {
|
||||
this.setState({ tagValuesQuery: event.currentTarget.value });
|
||||
};
|
||||
|
||||
onTagValuesQueryBlur = async (event: ChangeEvent<HTMLInputElement>) => {
|
||||
const tagValuesQuery = event.target.value;
|
||||
onTagValuesQueryBlur = async (event: FormEvent<HTMLInputElement>) => {
|
||||
const tagValuesQuery = event.currentTarget.value;
|
||||
if (this.props.variable.tagValuesQuery !== tagValuesQuery) {
|
||||
this.props.onPropChange({ propName: 'tagValuesQuery', propValue: tagValuesQuery, updateOptions: true });
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { getDefaultTimeRange, LoadingState } from '@grafana/data';
|
||||
import { variableAdapters } from '../adapters';
|
||||
import { createQueryVariableAdapter } from './adapter';
|
||||
import { reduxTester } from '../../../../test/core/redux/reduxTester';
|
||||
import { getRootReducer } from '../state/helpers';
|
||||
import { getRootReducer, RootReducerType } from '../state/helpers';
|
||||
import { QueryVariableModel, VariableHide, VariableRefresh, VariableSort } from '../types';
|
||||
import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE, toVariablePayload } from '../state/types';
|
||||
import {
|
||||
@ -14,7 +14,6 @@ import {
|
||||
variableStateFailed,
|
||||
variableStateFetching,
|
||||
} from '../state/sharedReducer';
|
||||
import { TemplatingState } from '../state/reducers';
|
||||
import {
|
||||
changeQueryVariableDataSource,
|
||||
changeQueryVariableQuery,
|
||||
@ -87,7 +86,7 @@ describe('query actions', () => {
|
||||
|
||||
mockDatasourceMetrics(variable, optionsMetrics, tagsMetrics);
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true);
|
||||
@ -111,7 +110,7 @@ describe('query actions', () => {
|
||||
|
||||
mockDatasourceMetrics(variable, optionsMetrics, tagsMetrics);
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true);
|
||||
@ -138,7 +137,7 @@ describe('query actions', () => {
|
||||
|
||||
mockDatasourceMetrics(variable, optionsMetrics, []);
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true);
|
||||
@ -160,7 +159,7 @@ describe('query actions', () => {
|
||||
|
||||
mockDatasourceMetrics(variable, optionsMetrics, []);
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(updateQueryVariableOptions(toVariablePayload(variable)), true);
|
||||
@ -186,7 +185,7 @@ describe('query actions', () => {
|
||||
|
||||
mockDatasourceMetrics(variable, optionsMetrics, []);
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(setIdInEditor({ id: variable.id }))
|
||||
@ -214,7 +213,7 @@ describe('query actions', () => {
|
||||
|
||||
mockDatasourceMetrics(variable, optionsMetrics, []);
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(setIdInEditor({ id: variable.id }))
|
||||
@ -241,7 +240,7 @@ describe('query actions', () => {
|
||||
|
||||
mocks[variable.datasource!].metricFindQuery = jest.fn(() => Promise.reject(error));
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenActionIsDispatched(setIdInEditor({ id: variable.id }))
|
||||
@ -277,7 +276,7 @@ describe('query actions', () => {
|
||||
components: { VariableQueryEditor: editor },
|
||||
});
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(initQueryVariableEditor(toVariablePayload(variable)), true);
|
||||
@ -306,7 +305,7 @@ describe('query actions', () => {
|
||||
components: { VariableQueryEditor: editor },
|
||||
});
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(initQueryVariableEditor(toVariablePayload(variable)), true);
|
||||
@ -334,7 +333,7 @@ describe('query actions', () => {
|
||||
components: { VariableQueryEditor: editor },
|
||||
});
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(initQueryVariableEditor(toVariablePayload(variable)), true);
|
||||
@ -356,7 +355,7 @@ describe('query actions', () => {
|
||||
it('then correct actions are dispatched', async () => {
|
||||
const variable = createVariable({ datasource: undefined });
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(initQueryVariableEditor(toVariablePayload(variable)), true);
|
||||
@ -380,7 +379,7 @@ describe('query actions', () => {
|
||||
components: { VariableQueryEditor: editor },
|
||||
});
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(changeQueryVariableDataSource(toVariablePayload(variable), 'datasource'), true);
|
||||
@ -410,7 +409,7 @@ describe('query actions', () => {
|
||||
components: {},
|
||||
});
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(changeQueryVariableDataSource(toVariablePayload(variable), 'datasource'), true);
|
||||
@ -442,7 +441,7 @@ describe('query actions', () => {
|
||||
|
||||
mockDatasourceMetrics({ ...variable, query }, optionsMetrics, tagsMetrics);
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(changeQueryVariableQuery(toVariablePayload(variable), query, definition), true);
|
||||
@ -473,7 +472,7 @@ describe('query actions', () => {
|
||||
|
||||
mockDatasourceMetrics({ ...variable, query }, optionsMetrics, []);
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(changeQueryVariableQuery(toVariablePayload(variable), query, definition), true);
|
||||
@ -502,7 +501,7 @@ describe('query actions', () => {
|
||||
|
||||
mockDatasourceMetrics({ ...variable, query }, optionsMetrics, []);
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(changeQueryVariableQuery(toVariablePayload(variable), query, definition), true);
|
||||
@ -528,7 +527,7 @@ describe('query actions', () => {
|
||||
const query = `$${variable.name}`;
|
||||
const definition = 'depends on datasource variable';
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(changeQueryVariableQuery(toVariablePayload(variable), query, definition), true);
|
||||
|
@ -5,11 +5,11 @@ import { initialQueryVariableModelState, queryVariableReducer } from './reducer'
|
||||
import { dispatch } from '../../../store/store';
|
||||
import { setOptionAsCurrent, setOptionFromUrl } from '../state/actions';
|
||||
import { VariableAdapter } from '../adapters';
|
||||
import { OptionsPicker } from '../pickers';
|
||||
import { QueryVariableEditor } from './QueryVariableEditor';
|
||||
import { updateQueryVariableOptions } from './actions';
|
||||
import { ALL_VARIABLE_TEXT, toVariableIdentifier } from '../state/types';
|
||||
import { containsVariable, isAllVariable } from '../utils';
|
||||
import { optionPickerFactory } from '../pickers';
|
||||
|
||||
export const createQueryVariableAdapter = (): VariableAdapter<QueryVariableModel> => {
|
||||
return {
|
||||
@ -18,7 +18,7 @@ export const createQueryVariableAdapter = (): VariableAdapter<QueryVariableModel
|
||||
name: 'Query',
|
||||
initialState: initialQueryVariableModelState,
|
||||
reducer: queryVariableReducer,
|
||||
picker: OptionsPicker,
|
||||
picker: optionPickerFactory<QueryVariableModel>(),
|
||||
editor: QueryVariableEditor,
|
||||
dependsOn: (variable, variableToTest) => {
|
||||
return containsVariable(variable.query, variable.datasource, variable.regex, variableToTest.name);
|
||||
|
@ -1,7 +1,12 @@
|
||||
import { AnyAction } from 'redux';
|
||||
import { UrlQueryMap } from '@grafana/data';
|
||||
|
||||
import { getRootReducer, getTemplatingAndLocationRootReducer, getTemplatingRootReducer } from './helpers';
|
||||
import {
|
||||
getRootReducer,
|
||||
getTemplatingAndLocationRootReducer,
|
||||
getTemplatingRootReducer,
|
||||
RootReducerType,
|
||||
TemplatingAndLocationReducerType,
|
||||
} from './helpers';
|
||||
import { variableAdapters } from '../adapters';
|
||||
import { createQueryVariableAdapter } from '../query/adapter';
|
||||
import { createCustomVariableAdapter } from '../custom/adapter';
|
||||
@ -49,7 +54,6 @@ import {
|
||||
initialVariableEditorState,
|
||||
setIdInEditor,
|
||||
} from '../editor/reducer';
|
||||
import { DashboardState, LocationState } from '../../../types';
|
||||
import {
|
||||
TransactionStatus,
|
||||
variablesClearTransaction,
|
||||
@ -63,6 +67,7 @@ import { ConstantVariableModel, VariableRefresh } from '../types';
|
||||
import { updateVariableOptions } from '../query/reducer';
|
||||
import { setVariableQueryRunner, VariableQueryRunner } from '../query/VariableQueryRunner';
|
||||
import { setDataSourceSrv } from '@grafana/runtime';
|
||||
import { LocationState } from 'app/types';
|
||||
|
||||
variableAdapters.setInit(() => [
|
||||
createQueryVariableAdapter(),
|
||||
@ -145,10 +150,12 @@ describe('shared actions', () => {
|
||||
const custom = customBuilder().build();
|
||||
const textbox = textboxBuilder().build();
|
||||
const list = [query, constant, datasource, custom, textbox];
|
||||
const preloadedState = {
|
||||
templating: ({} as unknown) as TemplatingState,
|
||||
location: ({ query: {} } as unknown) as LocationState,
|
||||
};
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState; location: { query: UrlQueryMap } }>({
|
||||
preloadedState: { templating: ({} as unknown) as TemplatingState, location: { query: {} } },
|
||||
})
|
||||
const tester = await reduxTester<TemplatingAndLocationReducerType>({ preloadedState })
|
||||
.givenRootReducer(getTemplatingAndLocationRootReducer())
|
||||
.whenActionIsDispatched(variablesInitTransaction({ uid: '' }))
|
||||
.whenActionIsDispatched(initDashboardTemplating(list))
|
||||
@ -202,9 +209,12 @@ describe('shared actions', () => {
|
||||
|
||||
const list = [stats, substats];
|
||||
const query = { orgId: '1', 'var-stats': 'response', 'var-substats': ALL_VARIABLE_TEXT };
|
||||
const tester = await reduxTester<{ templating: TemplatingState; location: { query: UrlQueryMap } }>({
|
||||
preloadedState: { templating: ({} as unknown) as TemplatingState, location: { query } },
|
||||
})
|
||||
const preloadedState = {
|
||||
templating: ({} as unknown) as TemplatingState,
|
||||
location: ({ query } as unknown) as LocationState,
|
||||
};
|
||||
|
||||
const tester = await reduxTester<TemplatingAndLocationReducerType>({ preloadedState })
|
||||
.givenRootReducer(getTemplatingAndLocationRootReducer())
|
||||
.whenActionIsDispatched(variablesInitTransaction({ uid: '' }))
|
||||
.whenActionIsDispatched(initDashboardTemplating(list))
|
||||
@ -558,11 +568,6 @@ describe('shared actions', () => {
|
||||
});
|
||||
|
||||
describe('initVariablesTransaction', () => {
|
||||
type ReducersUsedInContext = {
|
||||
templating: TemplatingState;
|
||||
dashboard: DashboardState;
|
||||
location: LocationState;
|
||||
};
|
||||
const constant = constantBuilder().withId('constant').withName('constant').build();
|
||||
const templating: any = { list: [constant] };
|
||||
const uid = 'uid';
|
||||
@ -570,7 +575,7 @@ describe('shared actions', () => {
|
||||
|
||||
describe('when called and the previous dashboard has completed', () => {
|
||||
it('then correct actions are dispatched', async () => {
|
||||
const tester = await reduxTester<ReducersUsedInContext>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenAsyncActionIsDispatched(initVariablesTransaction(uid, dashboard));
|
||||
|
||||
@ -598,7 +603,7 @@ describe('shared actions', () => {
|
||||
it('then correct actions are dispatched', async () => {
|
||||
const transactionState = { uid: 'previous-uid', status: TransactionStatus.Fetching };
|
||||
|
||||
const tester = await reduxTester<ReducersUsedInContext>({
|
||||
const tester = await reduxTester<RootReducerType>({
|
||||
preloadedState: ({
|
||||
templating: {
|
||||
transaction: transactionState,
|
||||
@ -606,7 +611,7 @@ describe('shared actions', () => {
|
||||
optionsPicker: { ...initialState },
|
||||
editor: { ...initialVariableEditorState },
|
||||
},
|
||||
} as unknown) as ReducersUsedInContext,
|
||||
} as unknown) as RootReducerType,
|
||||
})
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenAsyncActionIsDispatched(initVariablesTransaction(uid, dashboard));
|
||||
|
@ -516,7 +516,7 @@ export const onTimeRangeUpdated = (
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}) as VariableWithOptions[];
|
||||
|
||||
const promises = variablesThatNeedRefresh.map((variable: VariableWithOptions) =>
|
||||
dispatch(timeRangeUpdated(toVariableIdentifier(variable)))
|
||||
|
@ -7,7 +7,8 @@ import { VariablesState } from './variablesReducer';
|
||||
import { locationReducer } from '../../../core/reducers/location';
|
||||
import { VariableAdapter } from '../adapters';
|
||||
import { dashboardReducer } from 'app/features/dashboard/state/reducers';
|
||||
import { templatingReducers } from './reducers';
|
||||
import { templatingReducers, TemplatingState } from './reducers';
|
||||
import { DashboardState, LocationState } from '../../../types';
|
||||
|
||||
export const getVariableState = (
|
||||
noOfVariables: number,
|
||||
@ -76,6 +77,8 @@ export const getRootReducer = () =>
|
||||
templating: templatingReducers,
|
||||
});
|
||||
|
||||
export type RootReducerType = { location: LocationState; dashboard: DashboardState; templating: TemplatingState };
|
||||
|
||||
export const getTemplatingRootReducer = () =>
|
||||
combineReducers({
|
||||
templating: templatingReducers,
|
||||
@ -86,3 +89,5 @@ export const getTemplatingAndLocationRootReducer = () =>
|
||||
templating: templatingReducers,
|
||||
location: locationReducer,
|
||||
});
|
||||
|
||||
export type TemplatingAndLocationReducerType = { location: LocationState; templating: TemplatingState };
|
||||
|
@ -10,8 +10,7 @@ import { createConstantVariableAdapter } from '../constant/adapter';
|
||||
import { VariableRefresh } from '../types';
|
||||
import { constantBuilder, intervalBuilder } from '../shared/testing/builders';
|
||||
import { reduxTester } from '../../../../test/core/redux/reduxTester';
|
||||
import { TemplatingState } from './reducers';
|
||||
import { getRootReducer } from './helpers';
|
||||
import { getRootReducer, RootReducerType } from './helpers';
|
||||
import { toVariableIdentifier, toVariablePayload } from './types';
|
||||
import {
|
||||
setCurrentVariableValue,
|
||||
@ -23,6 +22,7 @@ import { createIntervalOptions } from '../interval/reducer';
|
||||
import { silenceConsoleOutput } from '../../../../test/core/utils/silenceConsoleOutput';
|
||||
import { notifyApp } from '../../../core/reducers/appNotification';
|
||||
import { expect } from '../../../../test/lib/common';
|
||||
import { TemplatingState } from './reducers';
|
||||
|
||||
variableAdapters.setInit(() => [createIntervalVariableAdapter(), createConstantVariableAdapter()]);
|
||||
|
||||
@ -63,7 +63,7 @@ const getTestContext = () => {
|
||||
} as unknown) as DashboardState;
|
||||
const startRefreshMock = jest.fn();
|
||||
const adapter = variableAdapters.get('interval');
|
||||
const preloadedState = {
|
||||
const preloadedState = ({
|
||||
dashboard,
|
||||
location: { query: '' },
|
||||
templating: ({
|
||||
@ -72,7 +72,7 @@ const getTestContext = () => {
|
||||
'constant-1': { ...constant },
|
||||
},
|
||||
} as unknown) as TemplatingState,
|
||||
};
|
||||
} as unknown) as RootReducerType;
|
||||
|
||||
return {
|
||||
interval,
|
||||
@ -98,7 +98,7 @@ describe('when onTimeRangeUpdated is dispatched', () => {
|
||||
startRefreshMock,
|
||||
} = getTestContext();
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>({ preloadedState })
|
||||
const tester = await reduxTester<RootReducerType>({ preloadedState })
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenAsyncActionIsDispatched(onTimeRangeUpdated(range, dependencies));
|
||||
|
||||
@ -133,7 +133,7 @@ describe('when onTimeRangeUpdated is dispatched', () => {
|
||||
startRefreshMock,
|
||||
} = getTestContext();
|
||||
|
||||
const base = await reduxTester<{ templating: TemplatingState }>({ preloadedState })
|
||||
const base = await reduxTester<RootReducerType>({ preloadedState })
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenAsyncActionIsDispatched(setOptionAsCurrent(toVariableIdentifier(interval), interval.options[0], false));
|
||||
|
||||
@ -173,7 +173,7 @@ describe('when onTimeRangeUpdated is dispatched', () => {
|
||||
|
||||
adapter.updateOptions = jest.fn().mockRejectedValue(new Error('Something broke'));
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>({ preloadedState, debug: true })
|
||||
const tester = await reduxTester<RootReducerType>({ preloadedState, debug: true })
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenAsyncActionIsDispatched(onTimeRangeUpdated(range, dependencies), true);
|
||||
|
||||
|
@ -2,6 +2,7 @@ import { reducerTester } from '../../../../test/core/redux/reducerTester';
|
||||
import {
|
||||
initialTransactionState,
|
||||
transactionReducer,
|
||||
TransactionState,
|
||||
TransactionStatus,
|
||||
variablesClearTransaction,
|
||||
variablesCompleteTransaction,
|
||||
@ -11,7 +12,7 @@ import {
|
||||
describe('transactionReducer', () => {
|
||||
describe('when variablesInitTransaction is dispatched', () => {
|
||||
it('then state should be correct', () => {
|
||||
reducerTester()
|
||||
reducerTester<TransactionState>()
|
||||
.givenReducer(transactionReducer, { ...initialTransactionState })
|
||||
.whenActionIsDispatched(variablesInitTransaction({ uid: 'a uid' }))
|
||||
.thenStateShouldEqual({ ...initialTransactionState, uid: 'a uid', status: TransactionStatus.Fetching });
|
||||
@ -21,7 +22,7 @@ describe('transactionReducer', () => {
|
||||
describe('when variablesCompleteTransaction is dispatched', () => {
|
||||
describe('and transaction uid is the same', () => {
|
||||
it('then state should be correct', () => {
|
||||
reducerTester()
|
||||
reducerTester<TransactionState>()
|
||||
.givenReducer(transactionReducer, {
|
||||
...initialTransactionState,
|
||||
uid: 'before',
|
||||
@ -34,7 +35,7 @@ describe('transactionReducer', () => {
|
||||
|
||||
describe('and transaction uid is not the same', () => {
|
||||
it('then state should be correct', () => {
|
||||
reducerTester()
|
||||
reducerTester<TransactionState>()
|
||||
.givenReducer(transactionReducer, {
|
||||
...initialTransactionState,
|
||||
uid: 'before',
|
||||
@ -48,7 +49,7 @@ describe('transactionReducer', () => {
|
||||
|
||||
describe('when variablesClearTransaction is dispatched', () => {
|
||||
it('then state should be correct', () => {
|
||||
reducerTester()
|
||||
reducerTester<TransactionState>()
|
||||
.givenReducer(transactionReducer, {
|
||||
...initialTransactionState,
|
||||
uid: 'before',
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { createAction, PayloadAction } from '@reduxjs/toolkit';
|
||||
import { createAction } from '@reduxjs/toolkit';
|
||||
import { variableAdapters } from '../adapters';
|
||||
import { sharedReducer } from './sharedReducer';
|
||||
import { VariableModel } from '../types';
|
||||
import { VariablePayload } from './types';
|
||||
import { AnyAction } from 'redux';
|
||||
|
||||
export interface VariablesState extends Record<string, VariableModel> {}
|
||||
|
||||
@ -10,10 +10,7 @@ export const initialVariablesState: VariablesState = {};
|
||||
|
||||
export const cleanVariables = createAction<undefined>('templating/cleanVariables');
|
||||
|
||||
export const variablesReducer = (
|
||||
state: VariablesState = initialVariablesState,
|
||||
action: PayloadAction<VariablePayload>
|
||||
): VariablesState => {
|
||||
export const variablesReducer = (state: VariablesState = initialVariablesState, action: AnyAction): VariablesState => {
|
||||
if (cleanVariables.match(action)) {
|
||||
const globalVariables = Object.values(state).filter((v) => v.global);
|
||||
if (!globalVariables) {
|
||||
|
@ -20,8 +20,8 @@ export const createSystemVariableAdapter = (): VariableAdapter<SystemVariable<an
|
||||
state: LoadingState.Done,
|
||||
},
|
||||
reducer: (state: any, action: any) => state,
|
||||
picker: (null as unknown) as ComponentType<VariablePickerProps>,
|
||||
editor: (null as unknown) as ComponentType<VariableEditorProps>,
|
||||
picker: (null as unknown) as ComponentType<VariablePickerProps<SystemVariable<any>>>,
|
||||
editor: (null as unknown) as ComponentType<VariableEditorProps<SystemVariable<any>>>,
|
||||
dependsOn: () => {
|
||||
return false;
|
||||
},
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { ChangeEvent, ReactElement, useCallback } from 'react';
|
||||
import React, { FormEvent, ReactElement, useCallback } from 'react';
|
||||
import { VerticalGroup } from '@grafana/ui';
|
||||
|
||||
import { TextBoxVariableModel } from '../types';
|
||||
@ -11,16 +11,16 @@ export interface Props extends VariableEditorProps<TextBoxVariableModel> {}
|
||||
|
||||
export function TextBoxVariableEditor({ onPropChange, variable: { query } }: Props): ReactElement {
|
||||
const updateVariable = useCallback(
|
||||
(event: ChangeEvent<HTMLInputElement>, updateOptions: boolean) => {
|
||||
(event: FormEvent<HTMLInputElement>, updateOptions: boolean) => {
|
||||
event.preventDefault();
|
||||
onPropChange({ propName: 'originalQuery', propValue: event.target.value, updateOptions: false });
|
||||
onPropChange({ propName: 'query', propValue: event.target.value, updateOptions });
|
||||
onPropChange({ propName: 'originalQuery', propValue: event.currentTarget.value, updateOptions: false });
|
||||
onPropChange({ propName: 'query', propValue: event.currentTarget.value, updateOptions });
|
||||
},
|
||||
[onPropChange]
|
||||
);
|
||||
|
||||
const onChange = useCallback((e: ChangeEvent<HTMLInputElement>) => updateVariable(e, false), [updateVariable]);
|
||||
const onBlur = useCallback((e: ChangeEvent<HTMLInputElement>) => updateVariable(e, true), [updateVariable]);
|
||||
const onChange = useCallback((e: FormEvent<HTMLInputElement>) => updateVariable(e, false), [updateVariable]);
|
||||
const onBlur = useCallback((e: FormEvent<HTMLInputElement>) => updateVariable(e, true), [updateVariable]);
|
||||
|
||||
return (
|
||||
<VerticalGroup spacing="xs">
|
||||
|
@ -1,9 +1,8 @@
|
||||
import { variableAdapters } from '../adapters';
|
||||
import { createTextBoxVariableAdapter } from './adapter';
|
||||
import { reduxTester } from '../../../../test/core/redux/reduxTester';
|
||||
import { TemplatingState } from 'app/features/variables/state/reducers';
|
||||
import { setTextBoxVariableOptionsFromUrl, updateTextBoxVariableOptions } from './actions';
|
||||
import { getRootReducer } from '../state/helpers';
|
||||
import { getRootReducer, RootReducerType } from '../state/helpers';
|
||||
import { VariableOption } from '../types';
|
||||
import { toVariablePayload } from '../state/types';
|
||||
import { createTextBoxOptions } from './reducer';
|
||||
@ -24,7 +23,7 @@ describe('textbox actions', () => {
|
||||
|
||||
const variable = textboxBuilder().withId('textbox').withName('textbox').withCurrent('A').withQuery('A').build();
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(updateTextBoxVariableOptions(toVariablePayload(variable)), true);
|
||||
@ -42,7 +41,7 @@ describe('textbox actions', () => {
|
||||
const urlValue = 'bB';
|
||||
const variable = textboxBuilder().withId('textbox').withName('textbox').withCurrent('A').withQuery('A').build();
|
||||
|
||||
const tester = await reduxTester<{ templating: TemplatingState }>()
|
||||
const tester = await reduxTester<RootReducerType>()
|
||||
.givenRootReducer(getRootReducer())
|
||||
.whenActionIsDispatched(addVariable(toVariablePayload(variable, { global: false, index: 0, model: variable })))
|
||||
.whenAsyncActionIsDispatched(setTextBoxVariableOptionsFromUrl(toVariablePayload(variable), urlValue), true);
|
||||
|
@ -3,7 +3,7 @@ set -e
|
||||
|
||||
echo -e "Collecting code stats (typescript errors & more)"
|
||||
|
||||
ERROR_COUNT_LIMIT=584
|
||||
ERROR_COUNT_LIMIT=452
|
||||
ERROR_COUNT="$(./node_modules/.bin/tsc --project tsconfig.json --noEmit --strict true | grep -oP 'Found \K(\d+)')"
|
||||
|
||||
if [ "$ERROR_COUNT" -gt $ERROR_COUNT_LIMIT ]; then
|
||||
|
Loading…
Reference in New Issue
Block a user