grafana/public/app/features/variables/editor/actions.ts
Torkel Ödegaard 264645eecd
TopNav: Dashboard settings (#52682)
* Scenes: Support new top nav

* Page: Make Page component support new and old dashboard page layouts

* Pass scrollbar props

* Fixing flex layout for dashboard

* Progress on dashboard settings working with topnav

* Updated

* Annotations working

* Starting to work fully

* Fix merge issue

* Fixed tests

* Added buttons to annotations editor

* Updating tests

* Move Page component to each page

* fixed general settings page

* Fixed versions

* Fixed annotation item page

* Variables section working

* Fixed tests

* Minor fixes to versions

* Update

* Fixing unit tests

* Adding add variable button

* Restore annotations edit form so it's the same as before

* Fixed semicolon in dashboard permissions

* Fixing unit tests

* Fixing tests

* Minor test update

* Fixing unit test

* Fixing e2e tests

* fix for e2e test

* fix a11y issues

* Changing places Settings -> General

* Trying to fix a11y

* I hope this fixes the e2e test

* Fixing merge issue

* tweak
2022-08-24 18:05:12 +02:00

131 lines
5.0 KiB
TypeScript

import { cloneDeep } from 'lodash';
import { VariableType } from '@grafana/data';
import { locationService } from '@grafana/runtime';
import { ThunkResult } from '../../../types';
import { variableAdapters } from '../adapters';
import { initInspect } from '../inspect/reducer';
import { createUsagesNetwork, transformUsagesToNetwork } from '../inspect/utils';
import { toKeyedAction } from '../state/keyedVariablesReducer';
import { getEditorVariables, getNewVariableIndex, getVariable, getVariablesByKey } from '../state/selectors';
import { addVariable, removeVariable } from '../state/sharedReducer';
import { AddVariable, KeyedVariableIdentifier, VariableIdentifier } from '../state/types';
import { VariableModel } from '../types';
import { toKeyedVariableIdentifier, toStateKey, toVariablePayload } from '../utils';
import {
changeVariableNameFailed,
changeVariableNameSucceeded,
variableEditorMounted,
variableEditorUnMounted,
} from './reducer';
export const variableEditorMount = (identifier: KeyedVariableIdentifier): ThunkResult<void> => {
return async (dispatch) => {
const { rootStateKey } = identifier;
dispatch(
toKeyedAction(rootStateKey, variableEditorMounted({ name: getVariable(identifier).name, id: identifier.id }))
);
};
};
export const variableEditorUnMount = (identifier: KeyedVariableIdentifier): ThunkResult<void> => {
return async (dispatch, getState) => {
const { rootStateKey } = identifier;
dispatch(toKeyedAction(rootStateKey, variableEditorUnMounted(toVariablePayload(identifier))));
};
};
export const changeVariableName = (identifier: KeyedVariableIdentifier, newName: string): ThunkResult<void> => {
return (dispatch, getState) => {
const { id, rootStateKey: uid } = identifier;
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 = getVariablesByKey(uid, getState());
const foundVariables = variables.filter((v) => v.name === newName && v.id !== id);
if (foundVariables.length) {
errorText = 'Variable with the same name already exists';
}
if (errorText) {
dispatch(toKeyedAction(uid, changeVariableNameFailed({ newName, errorText })));
return;
}
dispatch(completeChangeVariableName(identifier, newName));
};
};
export const completeChangeVariableName =
(identifier: KeyedVariableIdentifier, newName: string): ThunkResult<void> =>
(dispatch, getState) => {
const { rootStateKey } = identifier;
const originalVariable = getVariable(identifier, getState());
if (originalVariable.name === newName) {
dispatch(toKeyedAction(rootStateKey, changeVariableNameSucceeded(toVariablePayload(identifier, { newName }))));
return;
}
const model = { ...cloneDeep(originalVariable), name: newName, id: newName };
const global = originalVariable.global;
const index = originalVariable.index;
const renamedIdentifier = toKeyedVariableIdentifier(model);
dispatch(toKeyedAction(rootStateKey, addVariable(toVariablePayload(renamedIdentifier, { global, index, model }))));
dispatch(
toKeyedAction(rootStateKey, changeVariableNameSucceeded(toVariablePayload(renamedIdentifier, { newName })))
);
dispatch(toKeyedAction(rootStateKey, removeVariable(toVariablePayload(identifier, { reIndex: false }))));
};
export const createNewVariable =
(key: string | null | undefined, type: VariableType = 'query'): ThunkResult<void> =>
(dispatch, getState) => {
const rootStateKey = toStateKey(key);
const id = getNextAvailableId(type, getVariablesByKey(rootStateKey, getState()));
const identifier: VariableIdentifier = { type, id };
const global = false;
const index = getNewVariableIndex(rootStateKey, getState());
const model: VariableModel = cloneDeep(variableAdapters.get(type).initialState);
model.id = id;
model.name = id;
model.rootStateKey = rootStateKey;
dispatch(
toKeyedAction(rootStateKey, addVariable(toVariablePayload<AddVariable>(identifier, { global, model, index })))
);
locationService.partial({ editIndex: index });
};
export const initListMode =
(key: string | null | undefined): ThunkResult<void> =>
(dispatch, getState) => {
const rootStateKey = toStateKey(key);
const state = getState();
const variables = getEditorVariables(rootStateKey, state);
const dashboard = state.dashboard.getModel();
const { usages } = createUsagesNetwork(variables, dashboard);
const usagesNetwork = transformUsagesToNetwork(usages);
dispatch(toKeyedAction(rootStateKey, initInspect({ usages, usagesNetwork })));
};
export function getNextAvailableId(type: VariableType, variables: VariableModel[]): string {
let counter = 0;
let nextId = `${type}${counter}`;
while (variables.find((variable) => variable.id === nextId)) {
nextId = `${type}${++counter}`;
}
return nextId;
}