actions.ts 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. import { cloneDeep } from 'lodash';
  2. import { VariableType } from '@grafana/data';
  3. import { ThunkResult } from '../../../types';
  4. import { variableAdapters } from '../adapters';
  5. import { initInspect } from '../inspect/reducer';
  6. import { createUsagesNetwork, transformUsagesToNetwork } from '../inspect/utils';
  7. import { updateOptions } from '../state/actions';
  8. import { toKeyedAction } from '../state/keyedVariablesReducer';
  9. import { getEditorVariables, getNewVariableIndex, getVariable, getVariablesByKey } from '../state/selectors';
  10. import { addVariable, removeVariable } from '../state/sharedReducer';
  11. import { AddVariable, KeyedVariableIdentifier, VariableIdentifier } from '../state/types';
  12. import { VariableModel } from '../types';
  13. import { toKeyedVariableIdentifier, toStateKey, toVariablePayload } from '../utils';
  14. import {
  15. changeVariableNameFailed,
  16. changeVariableNameSucceeded,
  17. clearIdInEditor,
  18. setIdInEditor,
  19. variableEditorMounted,
  20. variableEditorUnMounted,
  21. } from './reducer';
  22. export const variableEditorMount = (identifier: KeyedVariableIdentifier): ThunkResult<void> => {
  23. return async (dispatch) => {
  24. const { rootStateKey } = identifier;
  25. dispatch(toKeyedAction(rootStateKey, variableEditorMounted({ name: getVariable(identifier).name })));
  26. };
  27. };
  28. export const variableEditorUnMount = (identifier: KeyedVariableIdentifier): ThunkResult<void> => {
  29. return async (dispatch, getState) => {
  30. const { rootStateKey } = identifier;
  31. dispatch(toKeyedAction(rootStateKey, variableEditorUnMounted(toVariablePayload(identifier))));
  32. };
  33. };
  34. export const onEditorUpdate = (identifier: KeyedVariableIdentifier): ThunkResult<void> => {
  35. return async (dispatch) => {
  36. await dispatch(updateOptions(identifier));
  37. dispatch(switchToListMode(identifier.rootStateKey));
  38. };
  39. };
  40. export const changeVariableName = (identifier: KeyedVariableIdentifier, newName: string): ThunkResult<void> => {
  41. return (dispatch, getState) => {
  42. const { id, rootStateKey: uid } = identifier;
  43. let errorText = null;
  44. if (!newName.match(/^(?!__).*$/)) {
  45. errorText = "Template names cannot begin with '__', that's reserved for Grafana's global variables";
  46. }
  47. if (!newName.match(/^\w+$/)) {
  48. errorText = 'Only word and digit characters are allowed in variable names';
  49. }
  50. const variables = getVariablesByKey(uid, getState());
  51. const foundVariables = variables.filter((v) => v.name === newName && v.id !== id);
  52. if (foundVariables.length) {
  53. errorText = 'Variable with the same name already exists';
  54. }
  55. if (errorText) {
  56. dispatch(toKeyedAction(uid, changeVariableNameFailed({ newName, errorText })));
  57. return;
  58. }
  59. dispatch(completeChangeVariableName(identifier, newName));
  60. };
  61. };
  62. export const completeChangeVariableName =
  63. (identifier: KeyedVariableIdentifier, newName: string): ThunkResult<void> =>
  64. (dispatch, getState) => {
  65. const { rootStateKey } = identifier;
  66. const originalVariable = getVariable(identifier, getState());
  67. if (originalVariable.name === newName) {
  68. dispatch(toKeyedAction(rootStateKey, changeVariableNameSucceeded(toVariablePayload(identifier, { newName }))));
  69. return;
  70. }
  71. const model = { ...cloneDeep(originalVariable), name: newName, id: newName };
  72. const global = originalVariable.global;
  73. const index = originalVariable.index;
  74. const renamedIdentifier = toKeyedVariableIdentifier(model);
  75. dispatch(toKeyedAction(rootStateKey, addVariable(toVariablePayload(renamedIdentifier, { global, index, model }))));
  76. dispatch(
  77. toKeyedAction(rootStateKey, changeVariableNameSucceeded(toVariablePayload(renamedIdentifier, { newName })))
  78. );
  79. dispatch(switchToEditMode(renamedIdentifier));
  80. dispatch(toKeyedAction(rootStateKey, removeVariable(toVariablePayload(identifier, { reIndex: false }))));
  81. };
  82. export const switchToNewMode =
  83. (key: string | null | undefined, type: VariableType = 'query'): ThunkResult<void> =>
  84. (dispatch, getState) => {
  85. const rootStateKey = toStateKey(key);
  86. const id = getNextAvailableId(type, getVariablesByKey(rootStateKey, getState()));
  87. const identifier: VariableIdentifier = { type, id };
  88. const global = false;
  89. const index = getNewVariableIndex(rootStateKey, getState());
  90. const model: VariableModel = cloneDeep(variableAdapters.get(type).initialState);
  91. model.id = id;
  92. model.name = id;
  93. model.rootStateKey = rootStateKey;
  94. dispatch(
  95. toKeyedAction(rootStateKey, addVariable(toVariablePayload<AddVariable>(identifier, { global, model, index })))
  96. );
  97. dispatch(toKeyedAction(rootStateKey, setIdInEditor({ id: identifier.id })));
  98. };
  99. export const switchToEditMode =
  100. (identifier: KeyedVariableIdentifier): ThunkResult<void> =>
  101. (dispatch) => {
  102. const { rootStateKey } = identifier;
  103. dispatch(toKeyedAction(rootStateKey, setIdInEditor({ id: identifier.id })));
  104. };
  105. export const switchToListMode =
  106. (key: string | null | undefined): ThunkResult<void> =>
  107. (dispatch, getState) => {
  108. const rootStateKey = toStateKey(key);
  109. dispatch(toKeyedAction(rootStateKey, clearIdInEditor()));
  110. const state = getState();
  111. const variables = getEditorVariables(rootStateKey, state);
  112. const dashboard = state.dashboard.getModel();
  113. const { usages } = createUsagesNetwork(variables, dashboard);
  114. const usagesNetwork = transformUsagesToNetwork(usages);
  115. dispatch(toKeyedAction(rootStateKey, initInspect({ usages, usagesNetwork })));
  116. };
  117. export function getNextAvailableId(type: VariableType, variables: VariableModel[]): string {
  118. let counter = 0;
  119. let nextId = `${type}${counter}`;
  120. while (variables.find((variable) => variable.id === nextId)) {
  121. nextId = `${type}${++counter}`;
  122. }
  123. return nextId;
  124. }