2018-09-28 04:05:34 -05:00
|
|
|
import { ThunkAction } from 'redux-thunk';
|
2018-11-05 09:33:43 -06:00
|
|
|
import config from '../../../core/config';
|
2018-11-07 16:28:44 -06:00
|
|
|
import { getBackendSrv } from 'app/core/services/backend_srv';
|
|
|
|
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
|
|
|
import { LayoutMode } from 'app/core/components/LayoutSelector/LayoutSelector';
|
|
|
|
import { updateLocation, updateNavIndex, UpdateNavIndexAction } from 'app/core/actions';
|
|
|
|
import { UpdateLocationAction } from 'app/core/actions/location';
|
|
|
|
import { buildNavModel } from './navModel';
|
2019-01-17 11:51:07 -06:00
|
|
|
import { DataSourceSettings } from '@grafana/ui/src/types';
|
|
|
|
import { Plugin, StoreState } from 'app/types';
|
2018-11-05 09:33:43 -06:00
|
|
|
|
2018-09-28 04:05:34 -05:00
|
|
|
export enum ActionTypes {
|
|
|
|
LoadDataSources = 'LOAD_DATA_SOURCES',
|
2018-10-03 02:56:15 -05:00
|
|
|
LoadDataSourceTypes = 'LOAD_DATA_SOURCE_TYPES',
|
2019-01-28 09:25:03 -06:00
|
|
|
LoadedDataSourceTypes = 'LOADED_DATA_SOURCE_TYPES',
|
2018-10-08 07:09:02 -05:00
|
|
|
LoadDataSource = 'LOAD_DATA_SOURCE',
|
2018-10-08 09:01:17 -05:00
|
|
|
LoadDataSourceMeta = 'LOAD_DATA_SOURCE_META',
|
2018-09-28 04:05:34 -05:00
|
|
|
SetDataSourcesSearchQuery = 'SET_DATA_SOURCES_SEARCH_QUERY',
|
|
|
|
SetDataSourcesLayoutMode = 'SET_DATA_SOURCES_LAYOUT_MODE',
|
2018-10-04 04:42:17 -05:00
|
|
|
SetDataSourceTypeSearchQuery = 'SET_DATA_SOURCE_TYPE_SEARCH_QUERY',
|
2018-10-30 10:40:08 -05:00
|
|
|
SetDataSourceName = 'SET_DATA_SOURCE_NAME',
|
2018-12-05 04:47:02 -06:00
|
|
|
SetIsDefault = 'SET_IS_DEFAULT',
|
2018-09-28 04:05:34 -05:00
|
|
|
}
|
|
|
|
|
2018-10-30 10:40:08 -05:00
|
|
|
interface LoadDataSourcesAction {
|
2018-09-28 04:05:34 -05:00
|
|
|
type: ActionTypes.LoadDataSources;
|
2019-01-17 11:51:07 -06:00
|
|
|
payload: DataSourceSettings[];
|
2018-09-28 04:05:34 -05:00
|
|
|
}
|
|
|
|
|
2018-10-30 10:40:08 -05:00
|
|
|
interface SetDataSourcesSearchQueryAction {
|
2018-09-28 04:05:34 -05:00
|
|
|
type: ActionTypes.SetDataSourcesSearchQuery;
|
|
|
|
payload: string;
|
|
|
|
}
|
|
|
|
|
2018-10-30 10:40:08 -05:00
|
|
|
interface SetDataSourcesLayoutModeAction {
|
2018-09-28 04:05:34 -05:00
|
|
|
type: ActionTypes.SetDataSourcesLayoutMode;
|
|
|
|
payload: LayoutMode;
|
|
|
|
}
|
|
|
|
|
2018-10-30 10:40:08 -05:00
|
|
|
interface LoadDataSourceTypesAction {
|
2018-10-03 02:56:15 -05:00
|
|
|
type: ActionTypes.LoadDataSourceTypes;
|
2019-01-28 09:25:03 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
interface LoadedDataSourceTypesAction {
|
|
|
|
type: ActionTypes.LoadedDataSourceTypes;
|
2018-10-03 09:04:30 -05:00
|
|
|
payload: Plugin[];
|
2018-10-03 02:56:15 -05:00
|
|
|
}
|
|
|
|
|
2018-10-30 10:40:08 -05:00
|
|
|
interface SetDataSourceTypeSearchQueryAction {
|
2018-10-04 04:42:17 -05:00
|
|
|
type: ActionTypes.SetDataSourceTypeSearchQuery;
|
|
|
|
payload: string;
|
|
|
|
}
|
|
|
|
|
2018-10-30 10:40:08 -05:00
|
|
|
interface LoadDataSourceAction {
|
2018-10-08 07:09:02 -05:00
|
|
|
type: ActionTypes.LoadDataSource;
|
2019-01-17 11:51:07 -06:00
|
|
|
payload: DataSourceSettings;
|
2018-10-08 07:09:02 -05:00
|
|
|
}
|
|
|
|
|
2018-10-30 10:40:08 -05:00
|
|
|
interface LoadDataSourceMetaAction {
|
2018-10-08 09:01:17 -05:00
|
|
|
type: ActionTypes.LoadDataSourceMeta;
|
|
|
|
payload: Plugin;
|
|
|
|
}
|
|
|
|
|
2018-10-30 10:40:08 -05:00
|
|
|
interface SetDataSourceNameAction {
|
|
|
|
type: ActionTypes.SetDataSourceName;
|
|
|
|
payload: string;
|
|
|
|
}
|
|
|
|
|
2018-12-05 04:47:02 -06:00
|
|
|
interface SetIsDefaultAction {
|
|
|
|
type: ActionTypes.SetIsDefault;
|
|
|
|
payload: boolean;
|
|
|
|
}
|
|
|
|
|
2019-01-17 11:51:07 -06:00
|
|
|
const dataSourcesLoaded = (dataSources: DataSourceSettings[]): LoadDataSourcesAction => ({
|
2018-09-28 04:05:34 -05:00
|
|
|
type: ActionTypes.LoadDataSources,
|
|
|
|
payload: dataSources,
|
|
|
|
});
|
|
|
|
|
2019-01-17 11:51:07 -06:00
|
|
|
const dataSourceLoaded = (dataSource: DataSourceSettings): LoadDataSourceAction => ({
|
2018-10-08 07:09:02 -05:00
|
|
|
type: ActionTypes.LoadDataSource,
|
|
|
|
payload: dataSource,
|
|
|
|
});
|
|
|
|
|
2018-10-08 09:01:17 -05:00
|
|
|
const dataSourceMetaLoaded = (dataSourceMeta: Plugin): LoadDataSourceMetaAction => ({
|
|
|
|
type: ActionTypes.LoadDataSourceMeta,
|
|
|
|
payload: dataSourceMeta,
|
|
|
|
});
|
|
|
|
|
2019-01-28 09:25:03 -06:00
|
|
|
const dataSourceTypesLoad = (): LoadDataSourceTypesAction => ({
|
2018-10-03 02:56:15 -05:00
|
|
|
type: ActionTypes.LoadDataSourceTypes,
|
2019-01-28 09:25:03 -06:00
|
|
|
});
|
|
|
|
|
|
|
|
const dataSourceTypesLoaded = (dataSourceTypes: Plugin[]): LoadedDataSourceTypesAction => ({
|
|
|
|
type: ActionTypes.LoadedDataSourceTypes,
|
2018-10-03 02:56:15 -05:00
|
|
|
payload: dataSourceTypes,
|
|
|
|
});
|
|
|
|
|
2018-09-28 04:05:34 -05:00
|
|
|
export const setDataSourcesSearchQuery = (searchQuery: string): SetDataSourcesSearchQueryAction => ({
|
|
|
|
type: ActionTypes.SetDataSourcesSearchQuery,
|
|
|
|
payload: searchQuery,
|
|
|
|
});
|
|
|
|
|
|
|
|
export const setDataSourcesLayoutMode = (layoutMode: LayoutMode): SetDataSourcesLayoutModeAction => ({
|
|
|
|
type: ActionTypes.SetDataSourcesLayoutMode,
|
|
|
|
payload: layoutMode,
|
|
|
|
});
|
|
|
|
|
2018-10-04 04:42:17 -05:00
|
|
|
export const setDataSourceTypeSearchQuery = (query: string): SetDataSourceTypeSearchQueryAction => ({
|
|
|
|
type: ActionTypes.SetDataSourceTypeSearchQuery,
|
|
|
|
payload: query,
|
|
|
|
});
|
|
|
|
|
2018-10-30 10:40:08 -05:00
|
|
|
export const setDataSourceName = (name: string) => ({
|
|
|
|
type: ActionTypes.SetDataSourceName,
|
|
|
|
payload: name,
|
|
|
|
});
|
|
|
|
|
2018-12-05 04:47:02 -06:00
|
|
|
export const setIsDefault = (state: boolean) => ({
|
|
|
|
type: ActionTypes.SetIsDefault,
|
|
|
|
payload: state,
|
|
|
|
});
|
|
|
|
|
2018-10-03 02:56:15 -05:00
|
|
|
export type Action =
|
|
|
|
| LoadDataSourcesAction
|
|
|
|
| SetDataSourcesSearchQueryAction
|
|
|
|
| SetDataSourcesLayoutModeAction
|
|
|
|
| UpdateLocationAction
|
2018-10-04 04:42:17 -05:00
|
|
|
| LoadDataSourceTypesAction
|
2019-01-28 09:25:03 -06:00
|
|
|
| LoadedDataSourceTypesAction
|
2018-10-08 07:09:02 -05:00
|
|
|
| SetDataSourceTypeSearchQueryAction
|
|
|
|
| LoadDataSourceAction
|
2018-10-08 09:01:17 -05:00
|
|
|
| UpdateNavIndexAction
|
2018-10-30 10:40:08 -05:00
|
|
|
| LoadDataSourceMetaAction
|
2018-12-05 04:47:02 -06:00
|
|
|
| SetDataSourceNameAction
|
|
|
|
| SetIsDefaultAction;
|
2018-09-28 04:05:34 -05:00
|
|
|
|
|
|
|
type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action>;
|
|
|
|
|
|
|
|
export function loadDataSources(): ThunkResult<void> {
|
|
|
|
return async dispatch => {
|
|
|
|
const response = await getBackendSrv().get('/api/datasources');
|
|
|
|
dispatch(dataSourcesLoaded(response));
|
|
|
|
};
|
|
|
|
}
|
2018-10-02 09:50:34 -05:00
|
|
|
|
2018-10-08 07:09:02 -05:00
|
|
|
export function loadDataSource(id: number): ThunkResult<void> {
|
|
|
|
return async dispatch => {
|
|
|
|
const dataSource = await getBackendSrv().get(`/api/datasources/${id}`);
|
|
|
|
const pluginInfo = await getBackendSrv().get(`/api/plugins/${dataSource.type}/settings`);
|
|
|
|
dispatch(dataSourceLoaded(dataSource));
|
2018-10-08 09:01:17 -05:00
|
|
|
dispatch(dataSourceMetaLoaded(pluginInfo));
|
2018-10-08 07:09:02 -05:00
|
|
|
dispatch(updateNavIndex(buildNavModel(dataSource, pluginInfo)));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-10-05 04:33:41 -05:00
|
|
|
export function addDataSource(plugin: Plugin): ThunkResult<void> {
|
|
|
|
return async (dispatch, getStore) => {
|
2018-10-06 12:22:16 -05:00
|
|
|
await dispatch(loadDataSources());
|
2018-10-05 04:33:41 -05:00
|
|
|
|
2018-10-06 12:22:16 -05:00
|
|
|
const dataSources = getStore().dataSources.dataSources;
|
2018-10-05 04:33:41 -05:00
|
|
|
|
2018-10-06 12:22:16 -05:00
|
|
|
const newInstance = {
|
|
|
|
name: plugin.name,
|
|
|
|
type: plugin.id,
|
|
|
|
access: 'proxy',
|
|
|
|
isDefault: dataSources.length === 0,
|
|
|
|
};
|
2018-10-05 04:33:41 -05:00
|
|
|
|
2018-10-06 12:22:16 -05:00
|
|
|
if (nameExits(dataSources, newInstance.name)) {
|
|
|
|
newInstance.name = findNewName(dataSources, newInstance.name);
|
2018-10-05 04:33:41 -05:00
|
|
|
}
|
|
|
|
|
2018-10-06 12:22:16 -05:00
|
|
|
const result = await getBackendSrv().post('/api/datasources', newInstance);
|
2018-10-03 02:56:15 -05:00
|
|
|
dispatch(updateLocation({ path: `/datasources/edit/${result.id}` }));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function loadDataSourceTypes(): ThunkResult<void> {
|
|
|
|
return async dispatch => {
|
2019-01-28 09:25:03 -06:00
|
|
|
dispatch(dataSourceTypesLoad());
|
2018-10-03 02:56:15 -05:00
|
|
|
const result = await getBackendSrv().get('/api/plugins', { enabled: 1, type: 'datasource' });
|
|
|
|
dispatch(dataSourceTypesLoaded(result));
|
2018-10-02 09:50:34 -05:00
|
|
|
};
|
|
|
|
}
|
2018-10-05 04:33:41 -05:00
|
|
|
|
2019-01-17 11:51:07 -06:00
|
|
|
export function updateDataSource(dataSource: DataSourceSettings): ThunkResult<void> {
|
2018-11-01 05:19:40 -05:00
|
|
|
return async dispatch => {
|
2018-11-07 16:28:44 -06:00
|
|
|
await getBackendSrv().put(`/api/datasources/${dataSource.id}`, dataSource);
|
|
|
|
await updateFrontendSettings();
|
|
|
|
return dispatch(loadDataSource(dataSource.id));
|
2018-10-31 08:28:16 -05:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function deleteDataSource(): ThunkResult<void> {
|
|
|
|
return async (dispatch, getStore) => {
|
|
|
|
const dataSource = getStore().dataSources.dataSource;
|
|
|
|
|
|
|
|
await getBackendSrv().delete(`/api/datasources/${dataSource.id}`);
|
|
|
|
dispatch(updateLocation({ path: '/datasources' }));
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-10-05 04:33:41 -05:00
|
|
|
export function nameExits(dataSources, name) {
|
|
|
|
return (
|
|
|
|
dataSources.filter(dataSource => {
|
2018-12-12 01:47:08 -06:00
|
|
|
return dataSource.name.toLowerCase() === name.toLowerCase();
|
2018-10-05 04:33:41 -05:00
|
|
|
}).length > 0
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
export function findNewName(dataSources, name) {
|
|
|
|
// Need to loop through current data sources to make sure
|
|
|
|
// the name doesn't exist
|
|
|
|
while (nameExits(dataSources, name)) {
|
|
|
|
// If there's a duplicate name that doesn't end with '-x'
|
|
|
|
// we can add -1 to the name and be done.
|
|
|
|
if (!nameHasSuffix(name)) {
|
|
|
|
name = `${name}-1`;
|
|
|
|
} else {
|
|
|
|
// if there's a duplicate name that ends with '-x'
|
|
|
|
// we can try to increment the last digit until the name is unique
|
|
|
|
|
|
|
|
// remove the 'x' part and replace it with the new number
|
|
|
|
name = `${getNewName(name)}${incrementLastDigit(getLastDigit(name))}`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2018-11-05 09:33:43 -06:00
|
|
|
function updateFrontendSettings() {
|
|
|
|
return getBackendSrv()
|
|
|
|
.get('/api/frontend/settings')
|
|
|
|
.then(settings => {
|
|
|
|
config.datasources = settings.datasources;
|
|
|
|
config.defaultDatasource = settings.defaultDatasource;
|
|
|
|
getDatasourceSrv().init();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-10-05 04:33:41 -05:00
|
|
|
function nameHasSuffix(name) {
|
|
|
|
return name.endsWith('-', name.length - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
function getLastDigit(name) {
|
|
|
|
return parseInt(name.slice(-1), 10);
|
|
|
|
}
|
|
|
|
|
|
|
|
function incrementLastDigit(digit) {
|
|
|
|
return isNaN(digit) ? 1 : digit + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getNewName(name) {
|
|
|
|
return name.slice(0, name.length - 1);
|
|
|
|
}
|