|
|
|
|
@ -10,6 +10,14 @@ import { |
|
|
|
|
TypedVariableModel, |
|
|
|
|
UrlQueryMap, |
|
|
|
|
UrlQueryValue, |
|
|
|
|
OrgVariableModel, |
|
|
|
|
QueryVariableModel, |
|
|
|
|
DashboardVariableModel, |
|
|
|
|
UserVariableModel, |
|
|
|
|
VariableHide, |
|
|
|
|
VariableOption, |
|
|
|
|
VariableRefresh, |
|
|
|
|
VariableWithOptions, |
|
|
|
|
} from '@grafana/data'; |
|
|
|
|
import { config, locationService } from '@grafana/runtime'; |
|
|
|
|
import { notifyApp } from 'app/core/actions'; |
|
|
|
|
@ -28,35 +36,17 @@ import { getTemplateSrv, TemplateSrv } from '../../templating/template_srv'; |
|
|
|
|
import { variableAdapters } from '../adapters'; |
|
|
|
|
import { ALL_VARIABLE_TEXT, ALL_VARIABLE_VALUE, VARIABLE_PREFIX } from '../constants'; |
|
|
|
|
import { cleanEditorState } from '../editor/reducer'; |
|
|
|
|
import { |
|
|
|
|
hasCurrent, |
|
|
|
|
hasLegacyVariableSupport, |
|
|
|
|
hasOptions, |
|
|
|
|
hasStandardVariableSupport, |
|
|
|
|
isAdHoc, |
|
|
|
|
isConstant, |
|
|
|
|
isMulti, |
|
|
|
|
isQuery, |
|
|
|
|
} from '../guard'; |
|
|
|
|
import { hasCurrent, hasLegacyVariableSupport, hasOptions, hasStandardVariableSupport, isMulti } from '../guard'; |
|
|
|
|
import { getAllAffectedPanelIdsForVariableChange, getPanelVars } from '../inspect/utils'; |
|
|
|
|
import { cleanPickerState } from '../pickers/OptionsPicker/reducer'; |
|
|
|
|
import { alignCurrentWithMulti } from '../shared/multiOptions'; |
|
|
|
|
import { |
|
|
|
|
DashboardVariableModel, |
|
|
|
|
initialVariableModelState, |
|
|
|
|
OrgVariableModel, |
|
|
|
|
QueryVariableModel, |
|
|
|
|
TransactionStatus, |
|
|
|
|
UserVariableModel, |
|
|
|
|
VariableHide, |
|
|
|
|
VariableModel, |
|
|
|
|
VariableOption, |
|
|
|
|
VariableRefresh, |
|
|
|
|
VariablesChanged, |
|
|
|
|
VariablesChangedEvent, |
|
|
|
|
VariablesChangedInUrl, |
|
|
|
|
VariablesTimeRangeProcessDone, |
|
|
|
|
VariableWithOptions, |
|
|
|
|
} from '../types'; |
|
|
|
|
import { |
|
|
|
|
ensureStringValues, |
|
|
|
|
@ -145,7 +135,7 @@ export const initDashboardTemplating = (key: string, dashboard: DashboardModel): |
|
|
|
|
}; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
export function fixSelectedInconsistency(model: VariableModel): VariableModel | VariableWithOptions { |
|
|
|
|
export function fixSelectedInconsistency(model: TypedVariableModel): TypedVariableModel | VariableWithOptions { |
|
|
|
|
if (!hasOptions(model)) { |
|
|
|
|
return model; |
|
|
|
|
} |
|
|
|
|
@ -275,7 +265,7 @@ export const changeVariableMultiValue = (identifier: KeyedVariableIdentifier, mu |
|
|
|
|
}; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
export const processVariableDependencies = async (variable: VariableModel, state: StoreState) => { |
|
|
|
|
export const processVariableDependencies = async (variable: TypedVariableModel, state: StoreState) => { |
|
|
|
|
if (!variable.rootStateKey) { |
|
|
|
|
throw new Error(`rootStateKey not found for variable with id:${variable.id}`); |
|
|
|
|
} |
|
|
|
|
@ -305,7 +295,7 @@ export const processVariableDependencies = async (variable: VariableModel, state |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const isDependencyGraphCircular = ( |
|
|
|
|
variable: VariableModel, |
|
|
|
|
variable: TypedVariableModel, |
|
|
|
|
state: StoreState, |
|
|
|
|
encounteredDependencyIds: Set<string> = new Set() |
|
|
|
|
): boolean => { |
|
|
|
|
@ -320,12 +310,12 @@ const isDependencyGraphCircular = ( |
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const getDirectDependencies = (variable: VariableModel, state: StoreState) => { |
|
|
|
|
const getDirectDependencies = (variable: TypedVariableModel, state: StoreState) => { |
|
|
|
|
if (!variable.rootStateKey) { |
|
|
|
|
return []; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const directDependencies: VariableModel[] = []; |
|
|
|
|
const directDependencies: TypedVariableModel[] = []; |
|
|
|
|
|
|
|
|
|
for (const otherVariable of getVariablesByKey(variable.rootStateKey, state)) { |
|
|
|
|
if (variable === otherVariable) { |
|
|
|
|
@ -342,7 +332,7 @@ const getDirectDependencies = (variable: VariableModel, state: StoreState) => { |
|
|
|
|
return directDependencies; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const isWaitingForDependencies = (key: string, dependencies: VariableModel[], state: StoreState): boolean => { |
|
|
|
|
const isWaitingForDependencies = (key: string, dependencies: TypedVariableModel[], state: StoreState): boolean => { |
|
|
|
|
if (dependencies.length === 0) { |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
@ -395,8 +385,7 @@ export const processVariables = (key: string): ThunkResult<Promise<void>> => { |
|
|
|
|
return async (dispatch, getState) => { |
|
|
|
|
const queryParams = locationService.getSearchObject(); |
|
|
|
|
const promises = getVariablesByKey(key, getState()).map( |
|
|
|
|
async (variable: VariableModel) => |
|
|
|
|
await dispatch(processVariable(toKeyedVariableIdentifier(variable), queryParams)) |
|
|
|
|
async (variable) => await dispatch(processVariable(toKeyedVariableIdentifier(variable), queryParams)) |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
await Promise.all(promises); |
|
|
|
|
@ -571,7 +560,7 @@ export const setOptionAsCurrent = ( |
|
|
|
|
}; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
export const createGraph = (variables: VariableModel[]) => { |
|
|
|
|
export const createGraph = (variables: TypedVariableModel[]) => { |
|
|
|
|
const g = new Graph(); |
|
|
|
|
|
|
|
|
|
variables.forEach((v) => { |
|
|
|
|
@ -618,13 +607,14 @@ export const variableUpdated = ( |
|
|
|
|
const panels = state.dashboard?.getModel()?.panels ?? []; |
|
|
|
|
const panelVars = getPanelVars(panels); |
|
|
|
|
|
|
|
|
|
const event: VariablesChangedEvent = isAdHoc(variableInState) |
|
|
|
|
? { refreshAll: true, panelIds: [] } // for adhoc variables we don't know which panels that will be impacted
|
|
|
|
|
: { |
|
|
|
|
refreshAll: false, |
|
|
|
|
panelIds: Array.from(getAllAffectedPanelIdsForVariableChange([variableInState.id], g, panelVars)), |
|
|
|
|
variable: getVariable(identifier, state), |
|
|
|
|
}; |
|
|
|
|
const event: VariablesChangedEvent = |
|
|
|
|
variableInState.type === 'adhoc' |
|
|
|
|
? { refreshAll: true, panelIds: [] } // for adhoc variables we don't know which panels that will be impacted
|
|
|
|
|
: { |
|
|
|
|
refreshAll: false, |
|
|
|
|
panelIds: Array.from(getAllAffectedPanelIdsForVariableChange([variableInState.id], g, panelVars)), |
|
|
|
|
variable: getVariable(identifier, state), |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const node = g.getNode(variableInState.name); |
|
|
|
|
let promises: Array<Promise<any>> = []; |
|
|
|
|
@ -653,7 +643,12 @@ export interface OnTimeRangeUpdatedDependencies { |
|
|
|
|
events: typeof appEvents; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const dfs = (node: Node, visited: string[], variables: VariableModel[], variablesRefreshTimeRange: VariableModel[]) => { |
|
|
|
|
const dfs = ( |
|
|
|
|
node: Node, |
|
|
|
|
visited: string[], |
|
|
|
|
variables: TypedVariableModel[], |
|
|
|
|
variablesRefreshTimeRange: TypedVariableModel[] |
|
|
|
|
) => { |
|
|
|
|
if (!visited.includes(node.name)) { |
|
|
|
|
visited.push(node.name); |
|
|
|
|
} |
|
|
|
|
@ -858,7 +853,7 @@ export const templateVarsChangedInUrl = |
|
|
|
|
value = variableInModel.current.value; // revert value to the value stored in dashboard json
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (variableInModel && isConstant(variableInModel)) { |
|
|
|
|
if (variableInModel && variableInModel.type === 'constant') { |
|
|
|
|
value = variableInModel.query; // revert value to the value stored in dashboard json, constants don't store current values in dashboard json
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -869,7 +864,9 @@ export const templateVarsChangedInUrl = |
|
|
|
|
|
|
|
|
|
const filteredVars = variables.filter((v) => { |
|
|
|
|
const key = VARIABLE_PREFIX + v.name; |
|
|
|
|
return vars.hasOwnProperty(key) && isVariableUrlValueDifferentFromCurrent(v, vars[key].value) && !isAdHoc(v); |
|
|
|
|
return ( |
|
|
|
|
vars.hasOwnProperty(key) && isVariableUrlValueDifferentFromCurrent(v, vars[key].value) && v.type !== 'adhoc' |
|
|
|
|
); |
|
|
|
|
}); |
|
|
|
|
const varGraph = createGraph(variables); |
|
|
|
|
const panelVars = getPanelVars(dashboard?.panels ?? []); |
|
|
|
|
@ -891,7 +888,7 @@ export const templateVarsChangedInUrl = |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
export function isVariableUrlValueDifferentFromCurrent(variable: VariableModel, urlValue: any): boolean { |
|
|
|
|
export function isVariableUrlValueDifferentFromCurrent(variable: TypedVariableModel, urlValue: any): boolean { |
|
|
|
|
const variableValue = variableAdapters.get(variable.type).getValueForUrl(variable); |
|
|
|
|
let stringUrlValue = ensureStringValues(urlValue); |
|
|
|
|
if (Array.isArray(variableValue) && !Array.isArray(stringUrlValue)) { |
|
|
|
|
@ -963,7 +960,7 @@ export function migrateVariablesDatasourceNameToRef( |
|
|
|
|
return (dispatch, getState) => { |
|
|
|
|
const variables = getVariablesByKey(key, getState()); |
|
|
|
|
for (const variable of variables) { |
|
|
|
|
if (!isAdHoc(variable) && !isQuery(variable)) { |
|
|
|
|
if (variable.type !== 'adhoc' && variable.type !== 'query') { |
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|