grafana/public/app/features/variables/editor/actions.ts
Lucas Raschek 6b1b52b704
Templating: Fixes renaming a variable using special characters or same name (#26866)
* Fix variable editor name-input bug

You couldn't delete an invalid character after typing it into the name-input field.
While investigating the issue turned out to be bigger, as there was a problem with
valid characters too. (See test scenarios below)

The fix seems to be, to remove an unnecessary check in the `changeVariableName`
action. There is theoretically now the possibility, that the `changeVariableName`
action is called with the same name, as the variable is already, but practically
there seems no possibility, that this could happen. A test, which checks that, had
to be removed too.

Test scenarios:
* 1st Scenario
    1. Type "@"
    2. Try deleting it
* 2nd Scenario
    1. Type "w"
    2. delete "w"
    3. Try typing "w" again

Fixes #26562

* Fix bug when updating existing variable
2020-08-13 06:52:32 +02:00

135 lines
5.0 KiB
TypeScript

import { ThunkResult } from '../../../types';
import { getNewVariabelIndex, getVariable, getVariables } from '../state/selectors';
import {
changeVariableNameFailed,
changeVariableNameSucceeded,
clearIdInEditor,
setIdInEditor,
variableEditorMounted,
variableEditorUnMounted,
} from './reducer';
import { variableAdapters } from '../adapters';
import {
AddVariable,
NEW_VARIABLE_ID,
toVariableIdentifier,
toVariablePayload,
VariableIdentifier,
} from '../state/types';
import cloneDeep from 'lodash/cloneDeep';
import { VariableType } from '@grafana/data';
import { addVariable, removeVariable, storeNewVariable } from '../state/sharedReducer';
export const variableEditorMount = (identifier: VariableIdentifier): ThunkResult<void> => {
return async dispatch => {
dispatch(variableEditorMounted({ name: getVariable(identifier.id).name }));
};
};
export const variableEditorUnMount = (identifier: VariableIdentifier): ThunkResult<void> => {
return async (dispatch, getState) => {
dispatch(variableEditorUnMounted(toVariablePayload(identifier)));
if (getState().templating.variables[NEW_VARIABLE_ID]) {
dispatch(removeVariable(toVariablePayload({ type: identifier.type, id: NEW_VARIABLE_ID }, { reIndex: false })));
}
};
};
export const onEditorUpdate = (identifier: VariableIdentifier): ThunkResult<void> => {
return async (dispatch, getState) => {
const variableInState = getVariable(identifier.id, getState());
await variableAdapters.get(variableInState.type).updateOptions(variableInState);
dispatch(switchToListMode());
};
};
export const onEditorAdd = (identifier: VariableIdentifier): ThunkResult<void> => {
return async (dispatch, getState) => {
const newVariableInState = getVariable(NEW_VARIABLE_ID, getState());
const id = newVariableInState.name;
dispatch(storeNewVariable(toVariablePayload({ type: identifier.type, id })));
const variableInState = getVariable(id, getState());
await variableAdapters.get(variableInState.type).updateOptions(variableInState);
dispatch(switchToListMode());
dispatch(removeVariable(toVariablePayload({ type: identifier.type, id: NEW_VARIABLE_ID }, { reIndex: false })));
};
};
export const changeVariableName = (identifier: VariableIdentifier, newName: string): ThunkResult<void> => {
return (dispatch, getState) => {
let errorText = null;
if (!newName.match(/^(?!__).*$/)) {
errorText = "Template names cannot begin with '__', that's reserved for Grafana's global variables";
}
if (!newName.match(/^\w+$/)) {
errorText = 'Only word and digit characters are allowed in variable names';
}
const variables = getVariables(getState());
const foundVariables = variables.filter(v => v.name === newName && v.id !== identifier.id);
if (foundVariables.length) {
errorText = 'Variable with the same name already exists';
}
if (errorText) {
dispatch(changeVariableNameFailed({ newName, errorText }));
return;
}
const thunkToCall = identifier.id === NEW_VARIABLE_ID ? completeChangeNewVariableName : completeChangeVariableName;
dispatch(thunkToCall(identifier, newName));
};
};
export const completeChangeNewVariableName = (
identifier: VariableIdentifier,
newName: string
): ThunkResult<void> => dispatch => {
dispatch(changeVariableNameSucceeded(toVariablePayload(identifier, { newName })));
};
export const completeChangeVariableName = (identifier: VariableIdentifier, newName: string): ThunkResult<void> => (
dispatch,
getState
) => {
const originalVariable = getVariable(identifier.id, getState());
if (originalVariable.name === newName) {
dispatch(changeVariableNameSucceeded(toVariablePayload(identifier, { newName })));
return;
}
const model = { ...cloneDeep(originalVariable), name: newName, id: newName };
const global = originalVariable.global;
const index = originalVariable.index;
const renamedIdentifier = toVariableIdentifier(model);
dispatch(addVariable(toVariablePayload(renamedIdentifier, { global, index, model })));
dispatch(changeVariableNameSucceeded(toVariablePayload(renamedIdentifier, { newName })));
dispatch(switchToEditMode(renamedIdentifier));
dispatch(removeVariable(toVariablePayload(identifier, { reIndex: false })));
};
export const switchToNewMode = (): ThunkResult<void> => (dispatch, getState) => {
const type: VariableType = 'query';
const id = NEW_VARIABLE_ID;
const global = false;
const model = cloneDeep(variableAdapters.get(type).initialState);
const index = getNewVariabelIndex(getState());
const identifier = { type, id };
dispatch(
addVariable(
toVariablePayload<AddVariable>(identifier, { global, model, index })
)
);
dispatch(setIdInEditor({ id: identifier.id }));
};
export const switchToEditMode = (identifier: VariableIdentifier): ThunkResult<void> => dispatch => {
dispatch(setIdInEditor({ id: identifier.id }));
};
export const switchToListMode = (): ThunkResult<void> => dispatch => {
dispatch(clearIdInEditor());
};