Templating: fixes filtering options with more than 1000 entries (#24614)

* Templating: fixes filtering options with more then 1000 entries

* Chore: reduces strict null errors by 2
pull/24636/head
Hugo Häggmark 5 years ago committed by GitHub
parent 622246d56d
commit 083a2ce220
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      public/app/features/variables/editor/actions.ts
  2. 27
      public/app/features/variables/pickers/OptionsPicker/reducer.test.ts
  3. 11
      public/app/features/variables/pickers/OptionsPicker/reducer.ts
  4. 2
      public/app/features/variables/state/selectors.ts
  5. 2
      public/app/plugins/datasource/testdata/metricTree.ts

@ -101,8 +101,8 @@ export const completeChangeVariableName = (identifier: VariableIdentifier, newNa
) => { ) => {
const originalVariable = getVariable(identifier.id, getState()); const originalVariable = getVariable(identifier.id, getState());
const model = { ...cloneDeep(originalVariable), name: newName, id: newName }; const model = { ...cloneDeep(originalVariable), name: newName, id: newName };
const global = originalVariable.global; const global = originalVariable.global!; // global is undefined because of old variable system
const index = originalVariable.index; const index = originalVariable.index!; // index is undefined because of old variable system
const renamedIdentifier = toVariableIdentifier(model); const renamedIdentifier = toVariableIdentifier(model);
dispatch(addVariable(toVariablePayload(renamedIdentifier, { global, index, model }))); dispatch(addVariable(toVariablePayload(renamedIdentifier, { global, index, model })));

@ -3,6 +3,7 @@ import {
hideOptions, hideOptions,
initialState as optionsPickerInitialState, initialState as optionsPickerInitialState,
moveOptionsHighlight, moveOptionsHighlight,
OPTIONS_LIMIT,
optionsPickerReducer, optionsPickerReducer,
OptionsPickerState, OptionsPickerState,
showOptions, showOptions,
@ -607,6 +608,32 @@ describe('optionsPickerReducer', () => {
highlightIndex: 0, highlightIndex: 0,
}); });
}); });
describe('and option count is are greater then OPTIONS_LIMIT', () => {
it('then state should be correct', () => {
const searchQuery = 'option:1337';
const options = [];
for (let index = 0; index <= OPTIONS_LIMIT + 337; index++) {
options.push({ text: `option:${index}`, value: `option:${index}`, selected: false });
}
const { initialState } = getVariableTestContext({
queryValue: searchQuery,
});
reducerTester<OptionsPickerState>()
.givenReducer(optionsPickerReducer, cloneDeep(initialState))
.whenActionIsDispatched(updateOptionsAndFilter(options))
.thenStateShouldEqual({
...cloneDeep(initialState),
options: [{ text: 'option:1337', value: 'option:1337', selected: false }],
selectedValues: [],
queryValue: 'option:1337',
highlightIndex: 0,
});
});
});
}); });
describe('when updateOptionsFromSearch is dispatched and variable has searchFilter', () => { describe('when updateOptionsFromSearch is dispatched and variable has searchFilter', () => {

@ -34,6 +34,8 @@ export const initialState: OptionsPickerState = {
multi: false, multi: false,
}; };
export const OPTIONS_LIMIT = 1000;
const getTags = (model: VariableWithMultiSupport) => { const getTags = (model: VariableWithMultiSupport) => {
if (isQuery(model) && Array.isArray(model.tags)) { if (isQuery(model) && Array.isArray(model.tags)) {
return cloneDeep(model.tags); return cloneDeep(model.tags);
@ -50,7 +52,7 @@ const applyLimit = (options: VariableOption[]): VariableOption[] => {
if (!Array.isArray(options)) { if (!Array.isArray(options)) {
return []; return [];
} }
return options.slice(0, Math.min(options.length, 1000)); return options.slice(0, Math.min(options.length, OPTIONS_LIMIT));
}; };
const updateDefaultSelection = (state: OptionsPickerState): OptionsPickerState => { const updateDefaultSelection = (state: OptionsPickerState): OptionsPickerState => {
@ -176,13 +178,14 @@ const optionsPickerSlice = createSlice({
updateOptionsAndFilter: (state, action: PayloadAction<VariableOption[]>): OptionsPickerState => { updateOptionsAndFilter: (state, action: PayloadAction<VariableOption[]>): OptionsPickerState => {
const searchQuery = (state.queryValue ?? '').toLowerCase(); const searchQuery = (state.queryValue ?? '').toLowerCase();
state.options = applyLimit(action.payload); const filteredOptions = action.payload.filter(option => {
state.highlightIndex = 0;
state.options = state.options.filter(option => {
const text = Array.isArray(option.text) ? option.text.toString() : option.text; const text = Array.isArray(option.text) ? option.text.toString() : option.text;
return text.toLowerCase().indexOf(searchQuery) !== -1; return text.toLowerCase().indexOf(searchQuery) !== -1;
}); });
state.options = applyLimit(filteredOptions);
state.highlightIndex = 0;
return applyStateChanges(state, updateSelectedValues); return applyStateChanges(state, updateSelectedValues);
}, },
updateOptionsFromSearch: (state, action: PayloadAction<VariableOption[]>): OptionsPickerState => { updateOptionsFromSearch: (state, action: PayloadAction<VariableOption[]>): OptionsPickerState => {

@ -12,7 +12,7 @@ export const getVariable = <T extends VariableModel = VariableModel>(
if (throwWhenMissing) { if (throwWhenMissing) {
throw new Error(`Couldn't find variable with id:${id}`); throw new Error(`Couldn't find variable with id:${id}`);
} }
return undefined; return (undefined as unknown) as T;
} }
return state.templating.variables[id] as T; return state.templating.variables[id] as T;

@ -19,7 +19,7 @@ function buildMetricTree(parent: string, depth: number): TreeNode[] {
const chars = ['A', 'B', 'C']; const chars = ['A', 'B', 'C'];
const children: TreeNode[] = []; const children: TreeNode[] = [];
if (depth > 3) { if (depth > 5) {
return []; return [];
} }

Loading…
Cancel
Save