123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 |
- import { cloneDeep } from 'lodash';
- import { DataSourceRef, getDataSourceRef } from '@grafana/data';
- import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
- import { AdHocVariableFilter, AdHocVariableModel } from 'app/features/variables/types';
- import { StoreState, ThunkResult } from 'app/types';
- import { changeVariableEditorExtended } from '../editor/reducer';
- import { getAdhocVariableEditorState } from '../editor/selectors';
- import { isAdHoc } from '../guard';
- import { variableUpdated } from '../state/actions';
- import { toKeyedAction } from '../state/keyedVariablesReducer';
- import { getLastKey, getNewVariableIndex, getVariable, getVariablesState } from '../state/selectors';
- import { addVariable, changeVariableProp } from '../state/sharedReducer';
- import { AddVariable, KeyedVariableIdentifier } from '../state/types';
- import { toKeyedVariableIdentifier, toVariablePayload } from '../utils';
- import {
- AdHocVariabelFilterUpdate,
- filterAdded,
- filterRemoved,
- filtersRestored,
- filterUpdated,
- initialAdHocVariableModelState,
- } from './reducer';
- export interface AdHocTableOptions {
- datasource: DataSourceRef;
- key: string;
- value: string;
- operator: string;
- }
- const filterTableName = 'Filters';
- export const applyFilterFromTable = (options: AdHocTableOptions): ThunkResult<void> => {
- return async (dispatch, getState) => {
- let variable = getVariableByOptions(options, getState());
- if (!variable) {
- dispatch(createAdHocVariable(options));
- variable = getVariableByOptions(options, getState());
- if (!variable) {
- return;
- }
- }
- const index = variable.filters.findIndex((f) => f.key === options.key && f.value === options.value);
- if (index === -1) {
- const { value, key, operator } = options;
- const filter = { value, key, operator, condition: '' };
- return await dispatch(addFilter(toKeyedVariableIdentifier(variable), filter));
- }
- const filter = { ...variable.filters[index], operator: options.operator };
- return await dispatch(changeFilter(toKeyedVariableIdentifier(variable), { index, filter }));
- };
- };
- export const changeFilter = (
- identifier: KeyedVariableIdentifier,
- update: AdHocVariabelFilterUpdate
- ): ThunkResult<void> => {
- return async (dispatch, getState) => {
- const variable = getVariable(identifier, getState());
- dispatch(toKeyedAction(identifier.rootStateKey, filterUpdated(toVariablePayload(variable, update))));
- await dispatch(variableUpdated(toKeyedVariableIdentifier(variable), true));
- };
- };
- export const removeFilter = (identifier: KeyedVariableIdentifier, index: number): ThunkResult<void> => {
- return async (dispatch, getState) => {
- const variable = getVariable(identifier, getState());
- dispatch(toKeyedAction(identifier.rootStateKey, filterRemoved(toVariablePayload(variable, index))));
- await dispatch(variableUpdated(toKeyedVariableIdentifier(variable), true));
- };
- };
- export const addFilter = (identifier: KeyedVariableIdentifier, filter: AdHocVariableFilter): ThunkResult<void> => {
- return async (dispatch, getState) => {
- const variable = getVariable(identifier, getState());
- dispatch(toKeyedAction(identifier.rootStateKey, filterAdded(toVariablePayload(variable, filter))));
- await dispatch(variableUpdated(toKeyedVariableIdentifier(variable), true));
- };
- };
- export const setFiltersFromUrl = (
- identifier: KeyedVariableIdentifier,
- filters: AdHocVariableFilter[]
- ): ThunkResult<void> => {
- return async (dispatch, getState) => {
- const variable = getVariable(identifier, getState());
- dispatch(toKeyedAction(identifier.rootStateKey, filtersRestored(toVariablePayload(variable, filters))));
- await dispatch(variableUpdated(toKeyedVariableIdentifier(variable), true));
- };
- };
- export const changeVariableDatasource = (
- identifier: KeyedVariableIdentifier,
- datasource?: DataSourceRef
- ): ThunkResult<void> => {
- return async (dispatch, getState) => {
- const { editor } = getVariablesState(identifier.rootStateKey, getState());
- const extended = getAdhocVariableEditorState(editor);
- const variable = getVariable(identifier, getState());
- dispatch(
- toKeyedAction(
- identifier.rootStateKey,
- changeVariableProp(toVariablePayload(variable, { propName: 'datasource', propValue: datasource }))
- )
- );
- const ds = await getDatasourceSrv().get(datasource);
- // TS TODO: ds is not typed to be optional - is this check unnecessary or is the type incorrect?
- const message = ds?.getTagKeys
- ? 'Ad hoc filters are applied automatically to all queries that target this data source'
- : 'This data source does not support ad hoc filters yet.';
- dispatch(
- toKeyedAction(
- identifier.rootStateKey,
- changeVariableEditorExtended({
- infoText: message,
- dataSources: extended?.dataSources ?? [],
- })
- )
- );
- };
- };
- export const initAdHocVariableEditor =
- (key: string): ThunkResult<void> =>
- (dispatch) => {
- const dataSources = getDatasourceSrv().getList({ metrics: true, variables: true });
- const selectable = dataSources.reduce(
- (all: Array<{ text: string; value: DataSourceRef | null }>, ds) => {
- if (ds.meta.mixed) {
- return all;
- }
- const text = ds.isDefault ? `${ds.name} (default)` : ds.name;
- const value = getDataSourceRef(ds);
- all.push({ text, value });
- return all;
- },
- [{ text: '', value: {} }]
- );
- dispatch(
- toKeyedAction(
- key,
- changeVariableEditorExtended({
- dataSources: selectable,
- })
- )
- );
- };
- const createAdHocVariable = (options: AdHocTableOptions): ThunkResult<void> => {
- return (dispatch, getState) => {
- const key = getLastKey(getState());
- const model: AdHocVariableModel = {
- ...cloneDeep(initialAdHocVariableModelState),
- datasource: options.datasource,
- name: filterTableName,
- id: filterTableName,
- rootStateKey: key,
- };
- const global = false;
- const index = getNewVariableIndex(key, getState());
- const identifier: KeyedVariableIdentifier = { type: 'adhoc', id: model.id, rootStateKey: key };
- dispatch(toKeyedAction(key, addVariable(toVariablePayload<AddVariable>(identifier, { global, model, index }))));
- };
- };
- const getVariableByOptions = (options: AdHocTableOptions, state: StoreState): AdHocVariableModel | undefined => {
- const key = getLastKey(state);
- const templatingState = getVariablesState(key, state);
- return Object.values(templatingState.variables).find(
- (v) => isAdHoc(v) && v.datasource?.uid === options.datasource.uid
- ) as AdHocVariableModel;
- };
|