Typed variables pt3: Type VariableState with TypedVariableModel (#53015)

* 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

* undo whatever changes i did to swagger spec
This commit is contained in:
Josh Hunt
2022-08-03 12:38:59 +01:00
committed by GitHub
parent 8f81c4d2ce
commit c7d3fec515
5 changed files with 24 additions and 21 deletions
-3
View File
@@ -6229,9 +6229,6 @@ exports[`better eslint`] = {
[0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"] [0, 0, 0, "Unexpected any. Specify a different type.", "1"]
], ],
"public/app/features/variables/state/variablesReducer.ts:5381": [
[0, 0, 0, "Do not use any type assertions.", "0"]
],
"public/app/features/variables/system/adapter.ts:5381": [ "public/app/features/variables/system/adapter.ts:5381": [
[0, 0, 0, "Unexpected any. Specify a different type.", "0"], [0, 0, 0, "Unexpected any. Specify a different type.", "0"],
[0, 0, 0, "Unexpected any. Specify a different type.", "1"], [0, 0, 0, "Unexpected any. Specify a different type.", "1"],
@@ -63,9 +63,7 @@ export class TemplateSrv implements BaseTemplateSrv {
} }
getVariables(): TypedVariableModel[] { getVariables(): TypedVariableModel[] {
// TODO: we remove this type assertion in a later PR return this.dependencies.getVariables();
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
return this.dependencies.getVariables() as TypedVariableModel[];
} }
updateIndex() { updateIndex() {
@@ -1,14 +1,19 @@
import memoizeOne from 'memoize-one'; import memoizeOne from 'memoize-one';
import { TypedVariableModel, VariableWithMultiSupport, VariableWithOptions } from '@grafana/data';
import { getState } from '../../../store/store'; import { getState } from '../../../store/store';
import { StoreState } from '../../../types'; import { StoreState } from '../../../types';
import { VariableModel } from '../types';
import { toStateKey } from '../utils'; import { toStateKey } from '../utils';
import { getInitialTemplatingState, TemplatingState } from './reducers'; import { getInitialTemplatingState, TemplatingState } from './reducers';
import { KeyedVariableIdentifier, VariablesState } from './types'; import { KeyedVariableIdentifier, VariablesState } from './types';
export const getVariable = <T extends VariableModel = VariableModel>( // TODO: this is just a temporary type until we remove generics from getVariable and 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 const getVariable = <T extends GenericVariableModel = GenericVariableModel>(
identifier: KeyedVariableIdentifier, identifier: KeyedVariableIdentifier,
state: StoreState = getState(), state: StoreState = getState(),
throwWhenMissing = true throwWhenMissing = true
@@ -26,7 +31,7 @@ export const getVariable = <T extends VariableModel = VariableModel>(
}; };
function getFilteredVariablesByKey( function getFilteredVariablesByKey(
filter: (model: VariableModel) => boolean, filter: (model: TypedVariableModel) => boolean,
key: string, key: string,
state: StoreState = getState() state: StoreState = getState()
) { ) {
@@ -39,21 +44,21 @@ export function getVariablesState(key: string, state: StoreState = getState()):
return state.templating.keys[toStateKey(key)] ?? getInitialTemplatingState(); return state.templating.keys[toStateKey(key)] ?? getInitialTemplatingState();
} }
export function getVariablesByKey(key: string, state: StoreState = getState()): VariableModel[] { export function getVariablesByKey(key: string, state: StoreState = getState()): TypedVariableModel[] {
return getFilteredVariablesByKey(defaultVariablesFilter, key, state); return getFilteredVariablesByKey(defaultVariablesFilter, key, state);
} }
function defaultVariablesFilter(variable: VariableModel): boolean { function defaultVariablesFilter(variable: TypedVariableModel): boolean {
return variable.type !== 'system'; return variable.type !== 'system';
} }
export const getSubMenuVariables = memoizeOne( export const getSubMenuVariables = memoizeOne(
(key: string, variables: Record<string, VariableModel>): VariableModel[] => { (key: string, variables: Record<string, TypedVariableModel>): TypedVariableModel[] => {
return getVariablesByKey(key, getState()); return getVariablesByKey(key, getState());
} }
); );
export const getEditorVariables = (key: string, state: StoreState): VariableModel[] => { export const getEditorVariables = (key: string, state: StoreState): TypedVariableModel[] => {
return getVariablesByKey(key, state); return getVariablesByKey(key, state);
}; };
@@ -63,7 +68,7 @@ export function getNewVariableIndex(key: string, state: StoreState = getState())
return getNextVariableIndex(Object.values(getVariablesState(key, state).variables)); return getNextVariableIndex(Object.values(getVariablesState(key, state).variables));
} }
export function getNextVariableIndex(variables: VariableModel[]): number { export function getNextVariableIndex(variables: TypedVariableModel[]): number {
const sorted = variables.filter(defaultVariablesFilter).sort((v1, v2) => v1.index - v2.index); const sorted = variables.filter(defaultVariablesFilter).sort((v1, v2) => v1.index - v2.index);
return sorted.length > 0 ? sorted[sorted.length - 1].index + 1 : 0; return sorted.length > 0 ? sorted[sorted.length - 1].index + 1 : 0;
} }
@@ -85,7 +90,7 @@ export function getLastKey(state: StoreState = getState()): string {
} }
// selectors used by template srv, assumes that lastKey is in state. Needs to change when/if dashboard redux state becomes keyed too. // selectors used by template srv, assumes that lastKey is in state. Needs to change when/if dashboard redux state becomes keyed too.
export function getFilteredVariables(filter: (model: VariableModel) => boolean, state: StoreState = getState()) { export function getFilteredVariables(filter: (model: TypedVariableModel) => boolean, state: StoreState = getState()) {
const lastKey = getIfExistsLastKey(state); const lastKey = getIfExistsLastKey(state);
if (!lastKey) { if (!lastKey) {
return []; return [];
@@ -109,6 +114,10 @@ export function getVariableWithName(name: string, state: StoreState = getState()
return getVariable({ id: name, rootStateKey: lastKey, type: 'query' }, state, false); return getVariable({ id: name, rootStateKey: lastKey, type: 'query' }, state, false);
} }
export function getInstanceState<Model extends VariableModel = VariableModel>(state: VariablesState, id: string) { // TODO: remove the generic and type assertion in a later PR
export function getInstanceState<Model extends GenericVariableModel = GenericVariableModel>(
state: VariablesState,
id: string
) {
return state[id] as Model; return state[id] as Model;
} }
+2 -2
View File
@@ -1,8 +1,8 @@
import { VariableType } from '@grafana/data'; import { VariableType, TypedVariableModel } from '@grafana/data';
import { VariableModel } from '../types'; import { VariableModel } from '../types';
export interface VariablesState extends Record<string, VariableModel> {} export type VariablesState = Record<string, TypedVariableModel>;
export const initialVariablesState: VariablesState = {}; export const initialVariablesState: VariablesState = {};
@@ -2,7 +2,6 @@ import { createAction } from '@reduxjs/toolkit';
import { AnyAction } from 'redux'; import { AnyAction } from 'redux';
import { variableAdapters } from '../adapters'; import { variableAdapters } from '../adapters';
import { VariableModel } from '../types';
import { sharedReducer } from './sharedReducer'; import { sharedReducer } from './sharedReducer';
import { initialVariablesState, VariablesState } from './types'; import { initialVariablesState, VariablesState } from './types';
@@ -16,10 +15,10 @@ export const variablesReducer = (state: VariablesState = initialVariablesState,
return initialVariablesState; return initialVariablesState;
} }
const variables = globalVariables.reduce((allVariables, state) => { const variables = globalVariables.reduce<typeof state>((allVariables, state) => {
allVariables[state.id] = state; allVariables[state.id] = state;
return allVariables; return allVariables;
}, {} as Record<string, VariableModel>); }, {});
return variables; return variables;
} }