From 081d6e9d3e788fd7475879b61f6b0ec63376d0e4 Mon Sep 17 00:00:00 2001 From: Josh Hunt Date: Wed, 10 Aug 2022 16:06:49 +0100 Subject: [PATCH] Typed variables pt5: Remove generics from getInstanceState (#53018) * wip * make diff easier to read * Update template_srv getVariables to return new TypedVariableModel * update VariableType to use the type from TypedVariableModel * tidy things up * Chore: Use type-accurate mock variables in tests * Chore: Type VariableState to use TypedVariableModel * fix typo * remove type assertion from template_srv.getVariables * use typescript/no-redeclare for compatibility with ts overloads * remove generics from getVariable() and overload it to only return undefined based on arguments * update usages of getVariable() * Remove generic from getInstanceState * update usages of getInstanceState * fix lint --- .betterer.results | 3 --- .../app/features/variables/adhoc/reducer.ts | 26 ++++++++++++++----- .../features/variables/constant/reducer.ts | 6 ++++- .../app/features/variables/custom/reducer.ts | 6 ++++- .../features/variables/datasource/reducer.ts | 6 ++++- .../features/variables/interval/reducer.ts | 5 +++- .../app/features/variables/query/reducer.ts | 6 ++++- .../app/features/variables/state/selectors.ts | 14 +++------- .../features/variables/state/sharedReducer.ts | 9 +++++-- .../app/features/variables/textbox/reducer.ts | 6 ++++- 10 files changed, 59 insertions(+), 28 deletions(-) diff --git a/.betterer.results b/.betterer.results index 2f28d797da1..46315613a4a 100644 --- a/.betterer.results +++ b/.betterer.results @@ -6176,9 +6176,6 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] ], - "public/app/features/variables/state/selectors.ts:5381": [ - [0, 0, 0, "Do not use any type assertions.", "0"] - ], "public/app/features/variables/state/sharedReducer.test.ts:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"] diff --git a/public/app/features/variables/adhoc/reducer.ts b/public/app/features/variables/adhoc/reducer.ts index 267257ad2b0..cb6af23d137 100644 --- a/public/app/features/variables/adhoc/reducer.ts +++ b/public/app/features/variables/adhoc/reducer.ts @@ -22,23 +22,37 @@ export const adHocVariableSlice = createSlice({ initialState: initialVariablesState, reducers: { filterAdded: (state: VariablesState, action: PayloadAction>) => { - const instanceState = getInstanceState(state, action.payload.id); + const instanceState = getInstanceState(state, action.payload.id); + if (instanceState.type !== 'adhoc') { + return; + } + instanceState.filters.push(action.payload.data); }, filterRemoved: (state: VariablesState, action: PayloadAction>) => { - const instanceState = getInstanceState(state, action.payload.id); - const index = action.payload.data; + const instanceState = getInstanceState(state, action.payload.id); + if (instanceState.type !== 'adhoc') { + return; + } + const index = action.payload.data; instanceState.filters.splice(index, 1); }, filterUpdated: (state: VariablesState, action: PayloadAction>) => { - const instanceState = getInstanceState(state, action.payload.id); - const { filter, index } = action.payload.data; + const instanceState = getInstanceState(state, action.payload.id); + if (instanceState.type !== 'adhoc') { + return; + } + const { filter, index } = action.payload.data; instanceState.filters[index] = filter; }, filtersRestored: (state: VariablesState, action: PayloadAction>) => { - const instanceState = getInstanceState(state, action.payload.id); + const instanceState = getInstanceState(state, action.payload.id); + if (instanceState.type !== 'adhoc') { + return; + } + instanceState.filters = action.payload.data; }, }, diff --git a/public/app/features/variables/constant/reducer.ts b/public/app/features/variables/constant/reducer.ts index c6b4eac74f8..78e0ed2695e 100644 --- a/public/app/features/variables/constant/reducer.ts +++ b/public/app/features/variables/constant/reducer.ts @@ -18,7 +18,11 @@ export const constantVariableSlice = createSlice({ initialState: initialVariablesState, reducers: { createConstantOptionsFromQuery: (state: VariablesState, action: PayloadAction) => { - const instanceState = getInstanceState(state, action.payload.id); + const instanceState = getInstanceState(state, action.payload.id); + if (instanceState.type !== 'constant') { + return; + } + instanceState.options = [ { text: instanceState.query.trim(), value: instanceState.query.trim(), selected: false }, ]; diff --git a/public/app/features/variables/custom/reducer.ts b/public/app/features/variables/custom/reducer.ts index 4c5c744d657..c021decc8dd 100644 --- a/public/app/features/variables/custom/reducer.ts +++ b/public/app/features/variables/custom/reducer.ts @@ -21,7 +21,11 @@ export const customVariableSlice = createSlice({ initialState: initialVariablesState, reducers: { createCustomOptionsFromQuery: (state: VariablesState, action: PayloadAction) => { - const instanceState = getInstanceState(state, action.payload.id); + const instanceState = getInstanceState(state, action.payload.id); + if (instanceState.type !== 'custom') { + return; + } + const { includeAll, query } = instanceState; const match = query.match(/(?:\\,|[^,])+/g) ?? []; diff --git a/public/app/features/variables/datasource/reducer.ts b/public/app/features/variables/datasource/reducer.ts index eda07cac254..9e422dae7b5 100644 --- a/public/app/features/variables/datasource/reducer.ts +++ b/public/app/features/variables/datasource/reducer.ts @@ -29,7 +29,11 @@ export const dataSourceVariableSlice = createSlice({ ) => { const { sources, regex } = action.payload.data; const options: VariableOption[] = []; - const instanceState = getInstanceState(state, action.payload.id); + const instanceState = getInstanceState(state, action.payload.id); + if (instanceState.type !== 'datasource') { + return; + } + for (let i = 0; i < sources.length; i++) { const source = sources[i]; // must match on type diff --git a/public/app/features/variables/interval/reducer.ts b/public/app/features/variables/interval/reducer.ts index d1e910bd7f2..a0d7d2de27b 100644 --- a/public/app/features/variables/interval/reducer.ts +++ b/public/app/features/variables/interval/reducer.ts @@ -22,7 +22,10 @@ export const intervalVariableSlice = createSlice({ initialState: initialVariablesState, reducers: { createIntervalOptions: (state: VariablesState, action: PayloadAction) => { - const instanceState = getInstanceState(state, action.payload.id); + const instanceState = getInstanceState(state, action.payload.id); + if (instanceState.type !== 'interval') { + return; + } const options: VariableOption[] = map(instanceState.query.match(/(["'])(.*?)\1|\w+/g), (text) => { text = text.replace(/["']+/g, ''); return { text: text.trim(), value: text.trim(), selected: false }; diff --git a/public/app/features/variables/query/reducer.ts b/public/app/features/variables/query/reducer.ts index 91b895bf8c4..fb4c4fe0374 100644 --- a/public/app/features/variables/query/reducer.ts +++ b/public/app/features/variables/query/reducer.ts @@ -141,7 +141,11 @@ export const queryVariableSlice = createSlice({ reducers: { updateVariableOptions: (state: VariablesState, action: PayloadAction>) => { const { results, templatedRegex } = action.payload.data; - const instanceState = getInstanceState(state, action.payload.id); + const instanceState = getInstanceState(state, action.payload.id); + if (instanceState.type !== 'query') { + return; + } + const { includeAll, sort } = instanceState; const options = metricNamesToVariableValues(templatedRegex, sort, results); diff --git a/public/app/features/variables/state/selectors.ts b/public/app/features/variables/state/selectors.ts index f6eb904abb6..d9334fd17c0 100644 --- a/public/app/features/variables/state/selectors.ts +++ b/public/app/features/variables/state/selectors.ts @@ -1,6 +1,6 @@ import memoizeOne from 'memoize-one'; -import { TypedVariableModel, VariableWithMultiSupport, VariableWithOptions } from '@grafana/data'; +import { TypedVariableModel } from '@grafana/data'; import { getState } from '../../../store/store'; import { StoreState } from '../../../types'; @@ -9,10 +9,6 @@ import { toStateKey } from '../utils'; import { getInitialTemplatingState, TemplatingState } from './reducers'; import { KeyedVariableIdentifier, VariablesState } from './types'; -// TODO: this is just a temporary type until we remove generics from getInstanceState in a later PR -// we need to it satisfy the constraint of callers who specify VariableWithOptions or VariableWithMultiSupport -type GenericVariableModel = TypedVariableModel | VariableWithOptions | VariableWithMultiSupport; - export function getVariable( identifier: KeyedVariableIdentifier, state: StoreState, @@ -123,10 +119,6 @@ export function getVariableWithName(name: string, state: StoreState = getState() return getVariable({ id: name, rootStateKey: lastKey, type: 'query' }, state, false); } -// TODO: remove the generic and type assertion in a later PR -export function getInstanceState( - state: VariablesState, - id: string -) { - return state[id] as Model; +export function getInstanceState(state: VariablesState, id: string) { + return state[id]; } diff --git a/public/app/features/variables/state/sharedReducer.ts b/public/app/features/variables/state/sharedReducer.ts index 572f8f1485f..0d75e937031 100644 --- a/public/app/features/variables/state/sharedReducer.ts +++ b/public/app/features/variables/state/sharedReducer.ts @@ -5,7 +5,8 @@ import { LoadingState, VariableType } from '@grafana/data'; import { variableAdapters } from '../adapters'; import { changeVariableNameSucceeded } from '../editor/reducer'; -import { VariableModel, VariableOption, VariableWithOptions } from '../types'; +import { hasOptions } from '../guard'; +import { VariableModel, VariableOption } from '../types'; import { ensureStringValues } from '../utils'; import { getInstanceState, getNextVariableIndex } from './selectors'; @@ -123,7 +124,11 @@ const sharedReducerSlice = createSlice({ return; } - const instanceState = getInstanceState(state, action.payload.id); + const instanceState = getInstanceState(state, action.payload.id); + if (!hasOptions(instanceState)) { + return; + } + const { option } = action.payload.data; const current = { ...option, text: ensureStringValues(option?.text), value: ensureStringValues(option?.value) }; diff --git a/public/app/features/variables/textbox/reducer.ts b/public/app/features/variables/textbox/reducer.ts index 9195c3ea456..76fa81274cd 100644 --- a/public/app/features/variables/textbox/reducer.ts +++ b/public/app/features/variables/textbox/reducer.ts @@ -18,7 +18,11 @@ export const textBoxVariableSlice = createSlice({ initialState: initialVariablesState, reducers: { createTextBoxOptions: (state: VariablesState, action: PayloadAction) => { - const instanceState = getInstanceState(state, action.payload.id); + const instanceState = getInstanceState(state, action.payload.id); + if (instanceState.type !== 'textbox') { + return; + } + const option = { text: instanceState.query.trim(), value: instanceState.query.trim(), selected: false }; instanceState.options = [option]; instanceState.current = option;