actions.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. import { ThunkAction } from 'redux-thunk';
  2. import { DataSource, Plugin, StoreState } from 'app/types';
  3. import { getBackendSrv } from '../../../core/services/backend_srv';
  4. import { LayoutMode } from '../../../core/components/LayoutSelector/LayoutSelector';
  5. import { updateLocation, updateNavIndex, UpdateNavIndexAction } from '../../../core/actions';
  6. import { UpdateLocationAction } from '../../../core/actions/location';
  7. import { buildNavModel } from './navModel';
  8. export enum ActionTypes {
  9. LoadDataSources = 'LOAD_DATA_SOURCES',
  10. LoadDataSourceTypes = 'LOAD_DATA_SOURCE_TYPES',
  11. LoadDataSource = 'LOAD_DATA_SOURCE',
  12. LoadDataSourceMeta = 'LOAD_DATA_SOURCE_META',
  13. SetDataSourcesSearchQuery = 'SET_DATA_SOURCES_SEARCH_QUERY',
  14. SetDataSourcesLayoutMode = 'SET_DATA_SOURCES_LAYOUT_MODE',
  15. SetDataSourceTypeSearchQuery = 'SET_DATA_SOURCE_TYPE_SEARCH_QUERY',
  16. }
  17. export interface LoadDataSourcesAction {
  18. type: ActionTypes.LoadDataSources;
  19. payload: DataSource[];
  20. }
  21. export interface SetDataSourcesSearchQueryAction {
  22. type: ActionTypes.SetDataSourcesSearchQuery;
  23. payload: string;
  24. }
  25. export interface SetDataSourcesLayoutModeAction {
  26. type: ActionTypes.SetDataSourcesLayoutMode;
  27. payload: LayoutMode;
  28. }
  29. export interface LoadDataSourceTypesAction {
  30. type: ActionTypes.LoadDataSourceTypes;
  31. payload: Plugin[];
  32. }
  33. export interface SetDataSourceTypeSearchQueryAction {
  34. type: ActionTypes.SetDataSourceTypeSearchQuery;
  35. payload: string;
  36. }
  37. export interface LoadDataSourceAction {
  38. type: ActionTypes.LoadDataSource;
  39. payload: DataSource;
  40. }
  41. export interface LoadDataSourceMetaAction {
  42. type: ActionTypes.LoadDataSourceMeta;
  43. payload: Plugin;
  44. }
  45. const dataSourcesLoaded = (dataSources: DataSource[]): LoadDataSourcesAction => ({
  46. type: ActionTypes.LoadDataSources,
  47. payload: dataSources,
  48. });
  49. const dataSourceLoaded = (dataSource: DataSource): LoadDataSourceAction => ({
  50. type: ActionTypes.LoadDataSource,
  51. payload: dataSource,
  52. });
  53. const dataSourceMetaLoaded = (dataSourceMeta: Plugin): LoadDataSourceMetaAction => ({
  54. type: ActionTypes.LoadDataSourceMeta,
  55. payload: dataSourceMeta,
  56. });
  57. const dataSourceTypesLoaded = (dataSourceTypes: Plugin[]): LoadDataSourceTypesAction => ({
  58. type: ActionTypes.LoadDataSourceTypes,
  59. payload: dataSourceTypes,
  60. });
  61. export const setDataSourcesSearchQuery = (searchQuery: string): SetDataSourcesSearchQueryAction => ({
  62. type: ActionTypes.SetDataSourcesSearchQuery,
  63. payload: searchQuery,
  64. });
  65. export const setDataSourcesLayoutMode = (layoutMode: LayoutMode): SetDataSourcesLayoutModeAction => ({
  66. type: ActionTypes.SetDataSourcesLayoutMode,
  67. payload: layoutMode,
  68. });
  69. export const setDataSourceTypeSearchQuery = (query: string): SetDataSourceTypeSearchQueryAction => ({
  70. type: ActionTypes.SetDataSourceTypeSearchQuery,
  71. payload: query,
  72. });
  73. export type Action =
  74. | LoadDataSourcesAction
  75. | SetDataSourcesSearchQueryAction
  76. | SetDataSourcesLayoutModeAction
  77. | UpdateLocationAction
  78. | LoadDataSourceTypesAction
  79. | SetDataSourceTypeSearchQueryAction
  80. | LoadDataSourceAction
  81. | UpdateNavIndexAction
  82. | LoadDataSourceMetaAction;
  83. type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action>;
  84. export function loadDataSources(): ThunkResult<void> {
  85. return async dispatch => {
  86. const response = await getBackendSrv().get('/api/datasources');
  87. dispatch(dataSourcesLoaded(response));
  88. };
  89. }
  90. export function loadDataSource(id: number): ThunkResult<void> {
  91. return async dispatch => {
  92. const dataSource = await getBackendSrv().get(`/api/datasources/${id}`);
  93. const pluginInfo = await getBackendSrv().get(`/api/plugins/${dataSource.type}/settings`);
  94. dispatch(dataSourceLoaded(dataSource));
  95. dispatch(dataSourceMetaLoaded(pluginInfo));
  96. dispatch(updateNavIndex(buildNavModel(dataSource, pluginInfo)));
  97. };
  98. }
  99. export function addDataSource(plugin: Plugin): ThunkResult<void> {
  100. return async (dispatch, getStore) => {
  101. await dispatch(loadDataSources());
  102. const dataSources = getStore().dataSources.dataSources;
  103. const newInstance = {
  104. name: plugin.name,
  105. type: plugin.id,
  106. access: 'proxy',
  107. isDefault: dataSources.length === 0,
  108. };
  109. if (nameExits(dataSources, newInstance.name)) {
  110. newInstance.name = findNewName(dataSources, newInstance.name);
  111. }
  112. const result = await getBackendSrv().post('/api/datasources', newInstance);
  113. dispatch(updateLocation({ path: `/datasources/edit/${result.id}` }));
  114. };
  115. }
  116. export function loadDataSourceTypes(): ThunkResult<void> {
  117. return async dispatch => {
  118. const result = await getBackendSrv().get('/api/plugins', { enabled: 1, type: 'datasource' });
  119. dispatch(dataSourceTypesLoaded(result));
  120. };
  121. }
  122. export function nameExits(dataSources, name) {
  123. return (
  124. dataSources.filter(dataSource => {
  125. return dataSource.name === name;
  126. }).length > 0
  127. );
  128. }
  129. export function findNewName(dataSources, name) {
  130. // Need to loop through current data sources to make sure
  131. // the name doesn't exist
  132. while (nameExits(dataSources, name)) {
  133. // If there's a duplicate name that doesn't end with '-x'
  134. // we can add -1 to the name and be done.
  135. if (!nameHasSuffix(name)) {
  136. name = `${name}-1`;
  137. } else {
  138. // if there's a duplicate name that ends with '-x'
  139. // we can try to increment the last digit until the name is unique
  140. // remove the 'x' part and replace it with the new number
  141. name = `${getNewName(name)}${incrementLastDigit(getLastDigit(name))}`;
  142. }
  143. }
  144. return name;
  145. }
  146. function nameHasSuffix(name) {
  147. return name.endsWith('-', name.length - 1);
  148. }
  149. function getLastDigit(name) {
  150. return parseInt(name.slice(-1), 10);
  151. }
  152. function incrementLastDigit(digit) {
  153. return isNaN(digit) ? 1 : digit + 1;
  154. }
  155. function getNewName(name) {
  156. return name.slice(0, name.length - 1);
  157. }