actions.ts 4.5 KB

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