Przeglądaj źródła

Added testing state in reducer

Peter Holmberg 7 lat temu
rodzic
commit
b7d494551c

+ 2 - 1
public/app/features/datasources/settings/DataSourceSettings.test.tsx

@@ -1,7 +1,7 @@
 import React from 'react';
 import React from 'react';
 import { shallow } from 'enzyme';
 import { shallow } from 'enzyme';
 import { DataSourceSettings, Props } from './DataSourceSettings';
 import { DataSourceSettings, Props } from './DataSourceSettings';
-import { DataSource, NavModel } from '../../../types';
+import { DataSource, DataSourceTest, NavModel } from '../../../types';
 import { getMockDataSource } from '../__mocks__/dataSourcesMocks';
 import { getMockDataSource } from '../__mocks__/dataSourcesMocks';
 import { getMockPlugin } from '../../plugins/__mocks__/pluginMocks';
 import { getMockPlugin } from '../../plugins/__mocks__/pluginMocks';
 
 
@@ -15,6 +15,7 @@ const setup = (propOverrides?: object) => {
     loadDataSource: jest.fn(),
     loadDataSource: jest.fn(),
     setDataSourceName: jest.fn(),
     setDataSourceName: jest.fn(),
     updateDataSource: jest.fn(),
     updateDataSource: jest.fn(),
+    testing: {} as DataSourceTest,
   };
   };
 
 
   Object.assign(props, propOverrides);
   Object.assign(props, propOverrides);

+ 28 - 2
public/app/features/datasources/settings/DataSourceSettings.tsx

@@ -1,7 +1,7 @@
 import React, { PureComponent } from 'react';
 import React, { PureComponent } from 'react';
 import { hot } from 'react-hot-loader';
 import { hot } from 'react-hot-loader';
 import { connect } from 'react-redux';
 import { connect } from 'react-redux';
-import { DataSource, NavModel, Plugin } from 'app/types/';
+import { DataSource, DataSourceTest, NavModel, Plugin } from 'app/types/';
 import PageHeader from '../../../core/components/PageHeader/PageHeader';
 import PageHeader from '../../../core/components/PageHeader/PageHeader';
 import PageLoader from '../../../core/components/PageLoader/PageLoader';
 import PageLoader from '../../../core/components/PageLoader/PageLoader';
 import PluginSettings from './PluginSettings';
 import PluginSettings from './PluginSettings';
@@ -18,6 +18,7 @@ export interface Props {
   dataSource: DataSource;
   dataSource: DataSource;
   dataSourceMeta: Plugin;
   dataSourceMeta: Plugin;
   pageId: number;
   pageId: number;
+  testing: DataSourceTest;
   deleteDataSource: typeof deleteDataSource;
   deleteDataSource: typeof deleteDataSource;
   loadDataSource: typeof loadDataSource;
   loadDataSource: typeof loadDataSource;
   setDataSourceName: typeof setDataSourceName;
   setDataSourceName: typeof setDataSourceName;
@@ -111,7 +112,7 @@ export class DataSourceSettings extends PureComponent<Props, State> {
   }
   }
 
 
   render() {
   render() {
-    const { dataSource, dataSourceMeta, navModel } = this.props;
+    const { dataSource, dataSourceMeta, navModel, testing } = this.props;
 
 
     return (
     return (
       <div>
       <div>
@@ -137,6 +138,30 @@ export class DataSourceSettings extends PureComponent<Props, State> {
                     onModelChange={this.onModelChange}
                     onModelChange={this.onModelChange}
                   />
                   />
                 )}
                 )}
+
+                <div className="gf-form-group section">
+                  {testing.inProgress && (
+                    <h5>
+                      Testing.... <i className="fa fa-spiner fa-spin" />
+                    </h5>
+                  )}
+                  {!testing.inProgress &&
+                    testing.status && (
+                      <div className={`alert-${testing.status} alert`}>
+                        <div className="alert-icon">
+                          {testing.status === 'error' ? (
+                            <i className="fa fa-exclamation-triangle" />
+                          ) : (
+                            <i className="fa fa-check" />
+                          )}
+                        </div>
+                        <div className="alert-body">
+                          <div className="alert-title">{testing.message}</div>
+                        </div>
+                      </div>
+                    )}
+                </div>
+
                 <ButtonRow
                 <ButtonRow
                   onSubmit={event => this.onSubmit(event)}
                   onSubmit={event => this.onSubmit(event)}
                   isReadOnly={this.isReadOnly()}
                   isReadOnly={this.isReadOnly()}
@@ -160,6 +185,7 @@ function mapStateToProps(state) {
     dataSource: getDataSource(state.dataSources, pageId),
     dataSource: getDataSource(state.dataSources, pageId),
     dataSourceMeta: getDataSourceMeta(state.dataSources, dataSource.type),
     dataSourceMeta: getDataSourceMeta(state.dataSources, dataSource.type),
     pageId: pageId,
     pageId: pageId,
+    testing: state.dataSources.testing,
   };
   };
 }
 }
 
 

+ 12 - 0
public/app/features/datasources/settings/__snapshots__/DataSourceSettings.test.tsx.snap

@@ -79,6 +79,9 @@ exports[`Render should render alpha info text 1`] = `
           }
           }
           onModelChange={[Function]}
           onModelChange={[Function]}
         />
         />
+        <div
+          className="gf-form-group section"
+        />
         <ButtonRow
         <ButtonRow
           isReadOnly={false}
           isReadOnly={false}
           onDelete={[Function]}
           onDelete={[Function]}
@@ -169,6 +172,9 @@ exports[`Render should render beta info text 1`] = `
           }
           }
           onModelChange={[Function]}
           onModelChange={[Function]}
         />
         />
+        <div
+          className="gf-form-group section"
+        />
         <ButtonRow
         <ButtonRow
           isReadOnly={false}
           isReadOnly={false}
           onDelete={[Function]}
           onDelete={[Function]}
@@ -254,6 +260,9 @@ exports[`Render should render component 1`] = `
           }
           }
           onModelChange={[Function]}
           onModelChange={[Function]}
         />
         />
+        <div
+          className="gf-form-group section"
+        />
         <ButtonRow
         <ButtonRow
           isReadOnly={false}
           isReadOnly={false}
           onDelete={[Function]}
           onDelete={[Function]}
@@ -344,6 +353,9 @@ exports[`Render should render is ready only message 1`] = `
           }
           }
           onModelChange={[Function]}
           onModelChange={[Function]}
         />
         />
+        <div
+          className="gf-form-group section"
+        />
         <ButtonRow
         <ButtonRow
           isReadOnly={true}
           isReadOnly={true}
           onDelete={[Function]}
           onDelete={[Function]}

+ 50 - 10
public/app/features/datasources/state/actions.ts

@@ -18,6 +18,9 @@ export enum ActionTypes {
   SetDataSourcesLayoutMode = 'SET_DATA_SOURCES_LAYOUT_MODE',
   SetDataSourcesLayoutMode = 'SET_DATA_SOURCES_LAYOUT_MODE',
   SetDataSourceTypeSearchQuery = 'SET_DATA_SOURCE_TYPE_SEARCH_QUERY',
   SetDataSourceTypeSearchQuery = 'SET_DATA_SOURCE_TYPE_SEARCH_QUERY',
   SetDataSourceName = 'SET_DATA_SOURCE_NAME',
   SetDataSourceName = 'SET_DATA_SOURCE_NAME',
+  SetDataSourceTestingProgess = 'SET_TESTING_PROGRESS',
+  SetDataSourceTestingSuccess = 'SET_DATA_SOURCE_TESTING_SUCCESS',
+  SetDataSourceTestingFail = 'SET_DATA_SOURCE_TESTING_FAIL',
 }
 }
 
 
 interface LoadDataSourcesAction {
 interface LoadDataSourcesAction {
@@ -60,6 +63,21 @@ interface SetDataSourceNameAction {
   payload: string;
   payload: string;
 }
 }
 
 
+interface SetDataSourceTestingProgessAction {
+  type: ActionTypes.SetDataSourceTestingProgess;
+  payload: boolean;
+}
+
+interface SetDataSourceTestingSuccessAction {
+  type: ActionTypes.SetDataSourceTestingSuccess;
+  payload: { status: string; message: string };
+}
+
+interface SetDataSourceTestingFailAction {
+  type: ActionTypes.SetDataSourceTestingFail;
+  payload: string;
+}
+
 const dataSourcesLoaded = (dataSources: DataSource[]): LoadDataSourcesAction => ({
 const dataSourcesLoaded = (dataSources: DataSource[]): LoadDataSourcesAction => ({
   type: ActionTypes.LoadDataSources,
   type: ActionTypes.LoadDataSources,
   payload: dataSources,
   payload: dataSources,
@@ -100,6 +118,24 @@ export const setDataSourceName = (name: string) => ({
   payload: name,
   payload: name,
 });
 });
 
 
+const setDataSourceTestingProgress = (state: boolean): SetDataSourceTestingProgessAction => ({
+  type: ActionTypes.SetDataSourceTestingProgess,
+  payload: state,
+});
+
+const setDataSourceTestingSuccess = (status: string, message: string): SetDataSourceTestingSuccessAction => ({
+  type: ActionTypes.SetDataSourceTestingSuccess,
+  payload: {
+    status: status,
+    message: message,
+  },
+});
+
+const setDataSourceTestingFail = (message: string): SetDataSourceTestingFailAction => ({
+  type: ActionTypes.SetDataSourceTestingFail,
+  payload: message,
+});
+
 export type Action =
 export type Action =
   | LoadDataSourcesAction
   | LoadDataSourcesAction
   | SetDataSourcesSearchQueryAction
   | SetDataSourcesSearchQueryAction
@@ -110,7 +146,10 @@ export type Action =
   | LoadDataSourceAction
   | LoadDataSourceAction
   | UpdateNavIndexAction
   | UpdateNavIndexAction
   | LoadDataSourceMetaAction
   | LoadDataSourceMetaAction
-  | SetDataSourceNameAction;
+  | SetDataSourceNameAction
+  | SetDataSourceTestingProgessAction
+  | SetDataSourceTestingSuccessAction
+  | SetDataSourceTestingFailAction;
 
 
 type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action>;
 type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action>;
 
 
@@ -166,7 +205,7 @@ export function updateDataSource(dataSource: DataSource): ThunkResult<void> {
       .put(`/api/datasources/${dataSource.id}`, dataSource)
       .put(`/api/datasources/${dataSource.id}`, dataSource)
       .then(response => {
       .then(response => {
         updateFrontendSettings().then(() => {
         updateFrontendSettings().then(() => {
-          testDataSource(response.name);
+          testDataSource(dispatch, response.name);
         });
         });
       });
       });
 
 
@@ -221,7 +260,8 @@ function updateFrontendSettings() {
     });
     });
 }
 }
 
 
-function testDataSource(name) {
+function testDataSource(dispatch, name) {
+  dispatch(setDataSourceTestingProgress(true));
   getDatasourceSrv()
   getDatasourceSrv()
     .get(name)
     .get(name)
     .then(dataSource => {
     .then(dataSource => {
@@ -229,27 +269,27 @@ function testDataSource(name) {
         return;
         return;
       }
       }
 
 
-      const testing = { done: false, status: 'error', message: '' };
-
       // make test call in no backend cache context
       // make test call in no backend cache context
       getBackendSrv()
       getBackendSrv()
         .withNoBackendCache(() => {
         .withNoBackendCache(() => {
           return dataSource
           return dataSource
             .testDatasource()
             .testDatasource()
             .then(result => {
             .then(result => {
-              testing.message = result.message;
-              testing.status = result.status;
+              dispatch(setDataSourceTestingSuccess(result.status, result.message));
             })
             })
             .catch(err => {
             .catch(err => {
+              let message = '';
+
               if (err.statusText) {
               if (err.statusText) {
-                testing.message = 'HTTP Error ' + err.statusText;
+                message = 'HTTP Error ' + err.statusText;
               } else {
               } else {
-                testing.message = err.message;
+                message = err.message;
               }
               }
+              dispatch(setDataSourceTestingFail(message));
             });
             });
         })
         })
         .finally(() => {
         .finally(() => {
-          testing.done = true;
+          dispatch(setDataSourceTestingProgress(false));
         });
         });
     });
     });
 }
 }

+ 21 - 1
public/app/features/datasources/state/reducers.ts

@@ -1,4 +1,4 @@
-import { DataSource, DataSourcesState, Plugin } from 'app/types';
+import { DataSource, DataSourcesState, DataSourceTest, Plugin } from 'app/types';
 import { Action, ActionTypes } from './actions';
 import { Action, ActionTypes } from './actions';
 import { LayoutModes } from '../../../core/components/LayoutSelector/LayoutSelector';
 import { LayoutModes } from '../../../core/components/LayoutSelector/LayoutSelector';
 
 
@@ -12,6 +12,7 @@ const initialState: DataSourcesState = {
   dataSourceTypeSearchQuery: '',
   dataSourceTypeSearchQuery: '',
   hasFetched: false,
   hasFetched: false,
   dataSourceMeta: {} as Plugin,
   dataSourceMeta: {} as Plugin,
+  testing: {} as DataSourceTest,
 };
 };
 
 
 export const dataSourcesReducer = (state = initialState, action: Action): DataSourcesState => {
 export const dataSourcesReducer = (state = initialState, action: Action): DataSourcesState => {
@@ -39,6 +40,25 @@ export const dataSourcesReducer = (state = initialState, action: Action): DataSo
 
 
     case ActionTypes.SetDataSourceName:
     case ActionTypes.SetDataSourceName:
       return { ...state, dataSource: { ...state.dataSource, name: action.payload } };
       return { ...state, dataSource: { ...state.dataSource, name: action.payload } };
+
+    case ActionTypes.SetDataSourceTestingProgess:
+      return { ...state, testing: { ...state.testing, inProgress: action.payload } };
+
+    case ActionTypes.SetDataSourceTestingSuccess:
+      return {
+        ...state,
+        testing: {
+          status: action.payload.status,
+          message: action.payload.message,
+          inProgress: false,
+        },
+      };
+
+    case ActionTypes.SetDataSourceTestingFail:
+      return {
+        ...state,
+        testing: { status: 'error', message: action.payload, inProgress: false },
+      };
   }
   }
 
 
   return state;
   return state;

+ 7 - 0
public/app/types/datasources.ts

@@ -25,6 +25,12 @@ export interface DataSource {
   testDatasource?: () => Promise<any>;
   testDatasource?: () => Promise<any>;
 }
 }
 
 
+export interface DataSourceTest {
+  inProgress: boolean;
+  message: string;
+  status: string;
+}
+
 export interface DataSourcesState {
 export interface DataSourcesState {
   dataSources: DataSource[];
   dataSources: DataSource[];
   searchQuery: string;
   searchQuery: string;
@@ -35,4 +41,5 @@ export interface DataSourcesState {
   dataSource: DataSource;
   dataSource: DataSource;
   dataSourceMeta: Plugin;
   dataSourceMeta: Plugin;
   hasFetched: boolean;
   hasFetched: boolean;
+  testing: DataSourceTest;
 }
 }

+ 2 - 1
public/app/types/index.ts

@@ -7,7 +7,7 @@ import { DashboardState } from './dashboard';
 import { DashboardAcl, OrgRole, PermissionLevel } from './acl';
 import { DashboardAcl, OrgRole, PermissionLevel } from './acl';
 import { ApiKey, ApiKeysState, NewApiKey } from './apiKeys';
 import { ApiKey, ApiKeysState, NewApiKey } from './apiKeys';
 import { Invitee, OrgUser, User, UsersState, UserState } from './user';
 import { Invitee, OrgUser, User, UsersState, UserState } from './user';
-import { DataSource, DataSourcesState } from './datasources';
+import { DataSource, DataSourceTest, DataSourcesState } from './datasources';
 import {
 import {
   TimeRange,
   TimeRange,
   LoadingState,
   LoadingState,
@@ -88,6 +88,7 @@ export {
   AppNotificationTimeout,
   AppNotificationTimeout,
   DashboardSearchHit,
   DashboardSearchHit,
   UserState,
   UserState,
+  DataSourceTest,
 };
 };
 
 
 export interface StoreState {
 export interface StoreState {