Browse Source

Removed ActionTypes and fixed a noPayloadActionCreatorFactory

Hugo Häggmark 6 years ago
parent
commit
2f47b225a0

+ 37 - 7
public/app/core/redux/actionCreatorFactory.test.ts

@@ -1,4 +1,8 @@
-import { actionCreatorFactory, resetAllActionCreatorTypes } from './actionCreatorFactory';
+import {
+  actionCreatorFactory,
+  resetAllActionCreatorTypes,
+  noPayloadActionCreatorFactory,
+} from './actionCreatorFactory';
 
 interface Dummy {
   n: number;
@@ -11,15 +15,14 @@ interface Dummy {
   b: boolean;
 }
 
-const setup = (payload: Dummy) => {
+const setup = (payload?: Dummy) => {
   resetAllActionCreatorTypes();
   const actionCreator = actionCreatorFactory<Dummy>('dummy').create();
+  const noPayloadactionCreator = noPayloadActionCreatorFactory('NoPayload').create();
   const result = actionCreator(payload);
+  const noPayloadResult = noPayloadactionCreator();
 
-  return {
-    actionCreator,
-    result,
-  };
+  return { actionCreator, noPayloadactionCreator, result, noPayloadResult };
 };
 
 describe('actionCreatorFactory', () => {
@@ -46,7 +49,34 @@ describe('actionCreatorFactory', () => {
       setup(payload);
 
       expect(() => {
-        actionCreatorFactory<Dummy>('DuMmY').create();
+        noPayloadActionCreatorFactory('DuMmY').create();
+      }).toThrow();
+    });
+  });
+});
+
+describe('noPayloadActionCreatorFactory', () => {
+  describe('when calling create', () => {
+    it('then it should create correct type string', () => {
+      const { noPayloadResult, noPayloadactionCreator } = setup();
+
+      expect(noPayloadactionCreator.type).toEqual('NoPayload');
+      expect(noPayloadResult.type).toEqual('NoPayload');
+    });
+
+    it('then it should create correct payload', () => {
+      const { noPayloadResult } = setup();
+
+      expect(noPayloadResult.payload).toBeUndefined();
+    });
+  });
+
+  describe('when calling create with existing type', () => {
+    it('then it should throw error', () => {
+      setup();
+
+      expect(() => {
+        actionCreatorFactory<Dummy>('nOpAyLoAd').create();
       }).toThrow();
     });
   });

+ 23 - 0
public/app/core/redux/actionCreatorFactory.ts

@@ -12,10 +12,19 @@ export interface ActionCreator<Payload> {
   (payload: Payload): ActionOf<Payload>;
 }
 
+export interface NoPayloadActionCreator {
+  readonly type: string;
+  (): ActionOf<undefined>;
+}
+
 export interface ActionCreatorFactory<Payload> {
   create: () => ActionCreator<Payload>;
 }
 
+export interface NoPayloadActionCreatorFactory {
+  create: () => NoPayloadActionCreator;
+}
+
 export const actionCreatorFactory = <Payload>(type: string): ActionCreatorFactory<Payload> => {
   const create = (): ActionCreator<Payload> => {
     return Object.assign((payload: Payload): ActionOf<Payload> => ({ type, payload }), { type });
@@ -30,5 +39,19 @@ export const actionCreatorFactory = <Payload>(type: string): ActionCreatorFactor
   return { create };
 };
 
+export const noPayloadActionCreatorFactory = (type: string): NoPayloadActionCreatorFactory => {
+  const create = (): NoPayloadActionCreator => {
+    return Object.assign((): ActionOf<undefined> => ({ type, payload: undefined }), { type });
+  };
+
+  if (allActionCreators.some(t => (t && type ? t.toLocaleUpperCase() === type.toLocaleUpperCase() : false))) {
+    throw new Error(`There is already an actionCreator defined with the type ${type}`);
+  }
+
+  allActionCreators.push(type);
+
+  return { create };
+};
+
 // Should only be used by tests
 export const resetAllActionCreatorTypes = () => (allActionCreators.length = 0);

+ 3 - 3
public/app/core/redux/reducerFactory.test.ts

@@ -26,7 +26,7 @@ const dummyReducerIntialState: DummyReducerState = {
 const dummyActionCreator = actionCreatorFactory<DummyReducerState>('dummy').create();
 
 const dummyReducer = reducerFactory(dummyReducerIntialState)
-  .addHandler({
+  .addMapper({
     filter: dummyActionCreator,
     mapper: (state, action) => ({ ...state, ...action.payload }),
   })
@@ -76,7 +76,7 @@ describe('reducerFactory', () => {
   describe('given a handler is added', () => {
     describe('when a handler with the same creator is added', () => {
       it('then is should throw', () => {
-        const faultyReducer = reducerFactory(dummyReducerIntialState).addHandler({
+        const faultyReducer = reducerFactory(dummyReducerIntialState).addMapper({
           filter: dummyActionCreator,
           mapper: (state, action) => {
             return { ...state, ...action.payload };
@@ -84,7 +84,7 @@ describe('reducerFactory', () => {
         });
 
         expect(() => {
-          faultyReducer.addHandler({
+          faultyReducer.addMapper({
             filter: dummyActionCreator,
             mapper: state => {
               return state;

+ 17 - 19
public/app/core/redux/reducerFactory.ts

@@ -1,47 +1,45 @@
 import { ActionOf, ActionCreator } from './actionCreatorFactory';
+import { Reducer } from 'redux';
 
 export type Mapper<State, Payload> = (state: State, action: ActionOf<Payload>) => State;
 
-export interface HandlerConfig<State, Payload> {
+export interface MapperConfig<State, Payload> {
   filter: ActionCreator<Payload>;
   mapper: Mapper<State, Payload>;
 }
 
-export interface AddHandler<State> {
-  addHandler: <Payload>(config: HandlerConfig<State, Payload>) => CreateReducer<State>;
+export interface AddMapper<State> {
+  addMapper: <Payload>(config: MapperConfig<State, Payload>) => CreateReducer<State>;
 }
 
-export interface CreateReducer<State> extends AddHandler<State> {
-  create: () => Mapper<State, any>;
+export interface CreateReducer<State> extends AddMapper<State> {
+  create: () => Reducer<State, ActionOf<any>>;
 }
 
-export const reducerFactory = <State>(initialState: State): AddHandler<State> => {
-  const allHandlerConfigs: Array<HandlerConfig<State, any>> = [];
+export const reducerFactory = <State>(initialState: State): AddMapper<State> => {
+  const allMapperConfigs: Array<MapperConfig<State, any>> = [];
 
-  const addHandler = <Payload>(config: HandlerConfig<State, Payload>): CreateReducer<State> => {
-    if (allHandlerConfigs.some(c => c.filter.type === config.filter.type)) {
-      throw new Error(`There is already a handlers defined with the type ${config.filter.type}`);
+  const addMapper = <Payload>(config: MapperConfig<State, Payload>): CreateReducer<State> => {
+    if (allMapperConfigs.some(c => c.filter.type === config.filter.type)) {
+      throw new Error(`There is already a Mappers defined with the type ${config.filter.type}`);
     }
 
-    allHandlerConfigs.push(config);
+    allMapperConfigs.push(config);
 
     return instance;
   };
 
-  const create = () => (state: State = initialState, action: ActionOf<any>): State => {
-    const handlerConfig = allHandlerConfigs.filter(config => config.filter.type === action.type)[0];
+  const create = (): Reducer<State, ActionOf<any>> => (state: State = initialState, action: ActionOf<any>): State => {
+    const mapperConfig = allMapperConfigs.filter(config => config.filter.type === action.type)[0];
 
-    if (handlerConfig) {
-      return handlerConfig.mapper(state, action);
+    if (mapperConfig) {
+      return mapperConfig.mapper(state, action);
     }
 
     return state;
   };
 
-  const instance: CreateReducer<State> = {
-    addHandler,
-    create,
-  };
+  const instance: CreateReducer<State> = { addMapper, create };
 
   return instance;
 };

+ 20 - 29
public/app/features/datasources/state/actions.ts

@@ -9,51 +9,42 @@ import { buildNavModel } from './navModel';
 import { DataSourceSettings } from '@grafana/ui/src/types';
 import { Plugin, StoreState } from 'app/types';
 import { actionCreatorFactory } from 'app/core/redux';
-import { ActionOf } from 'app/core/redux/actionCreatorFactory';
-
-export enum ActionTypes {
-  LoadDataSources = 'LOAD_DATA_SOURCES',
-  LoadDataSourceTypes = 'LOAD_DATA_SOURCE_TYPES',
-  LoadedDataSourceTypes = 'LOADED_DATA_SOURCE_TYPES',
-  LoadDataSource = 'LOAD_DATA_SOURCE',
-  LoadDataSourceMeta = 'LOAD_DATA_SOURCE_META',
-  SetDataSourcesSearchQuery = 'SET_DATA_SOURCES_SEARCH_QUERY',
-  SetDataSourcesLayoutMode = 'SET_DATA_SOURCES_LAYOUT_MODE',
-  SetDataSourceTypeSearchQuery = 'SET_DATA_SOURCE_TYPE_SEARCH_QUERY',
-  SetDataSourceName = 'SET_DATA_SOURCE_NAME',
-  SetIsDefault = 'SET_IS_DEFAULT',
-}
+import { ActionOf, noPayloadActionCreatorFactory } from 'app/core/redux/actionCreatorFactory';
 
-export const dataSourceLoaded = actionCreatorFactory<DataSourceSettings>(ActionTypes.LoadDataSource).create();
+export const dataSourceLoaded = actionCreatorFactory<DataSourceSettings>('LOAD_DATA_SOURCE').create();
 
-export const dataSourcesLoaded = actionCreatorFactory<DataSourceSettings[]>(ActionTypes.LoadDataSources).create();
+export const dataSourcesLoaded = actionCreatorFactory<DataSourceSettings[]>('LOAD_DATA_SOURCES').create();
 
-export const dataSourceMetaLoaded = actionCreatorFactory<Plugin>(ActionTypes.LoadDataSourceMeta).create();
+export const dataSourceMetaLoaded = actionCreatorFactory<Plugin>('LOAD_DATA_SOURCE_META').create();
 
-export const dataSourceTypesLoad = actionCreatorFactory(ActionTypes.LoadDataSourceTypes).create();
+export const dataSourceTypesLoad = noPayloadActionCreatorFactory('LOAD_DATA_SOURCE_TYPES').create();
 
-export const dataSourceTypesLoaded = actionCreatorFactory<Plugin[]>(ActionTypes.LoadedDataSourceTypes).create();
+export const dataSourceTypesLoaded = actionCreatorFactory<Plugin[]>('LOADED_DATA_SOURCE_TYPES').create();
 
-export const setDataSourcesSearchQuery = actionCreatorFactory<string>(ActionTypes.SetDataSourcesSearchQuery).create();
+export const setDataSourcesSearchQuery = actionCreatorFactory<string>('SET_DATA_SOURCES_SEARCH_QUERY').create();
 
-export const setDataSourcesLayoutMode = actionCreatorFactory<LayoutMode>(ActionTypes.SetDataSourcesLayoutMode).create();
+export const setDataSourcesLayoutMode = actionCreatorFactory<LayoutMode>('SET_DATA_SOURCES_LAYOUT_MODE').create();
 
-export const setDataSourceTypeSearchQuery = actionCreatorFactory<string>(
-  ActionTypes.SetDataSourceTypeSearchQuery
-).create();
+export const setDataSourceTypeSearchQuery = actionCreatorFactory<string>('SET_DATA_SOURCE_TYPE_SEARCH_QUERY').create();
 
-export const setDataSourceName = actionCreatorFactory<string>(ActionTypes.SetDataSourceName).create();
+export const setDataSourceName = actionCreatorFactory<string>('SET_DATA_SOURCE_NAME').create();
 
-export const setIsDefault = actionCreatorFactory<boolean>(ActionTypes.SetIsDefault).create();
+export const setIsDefault = actionCreatorFactory<boolean>('SET_IS_DEFAULT').create();
 
-export type Action = UpdateLocationAction | UpdateNavIndexAction | ActionOf<any>;
+export type Action =
+  | UpdateLocationAction
+  | UpdateNavIndexAction
+  | ActionOf<DataSourceSettings>
+  | ActionOf<DataSourceSettings[]>
+  | ActionOf<Plugin>
+  | ActionOf<Plugin[]>;
 
 type ThunkResult<R> = ThunkAction<R, StoreState, undefined, Action>;
 
 export function loadDataSources(): ThunkResult<void> {
   return async dispatch => {
     const response = await getBackendSrv().get('/api/datasources');
-    dataSourcesLoaded(response);
+    dispatch(dataSourcesLoaded(response));
   };
 }
 
@@ -91,7 +82,7 @@ export function addDataSource(plugin: Plugin): ThunkResult<void> {
 
 export function loadDataSourceTypes(): ThunkResult<void> {
   return async dispatch => {
-    dispatch(dataSourceTypesLoad({}));
+    dispatch(dataSourceTypesLoad());
     const result = await getBackendSrv().get('/api/plugins', { enabled: 1, type: 'datasource' });
     dispatch(dataSourceTypesLoaded(result));
   };

+ 10 - 10
public/app/features/datasources/state/reducers.ts

@@ -29,7 +29,7 @@ const initialState: DataSourcesState = {
 };
 
 export const dataSourcesReducer = reducerFactory(initialState)
-  .addHandler({
+  .addMapper({
     filter: dataSourcesLoaded,
     mapper: (state, action) => ({
       ...state,
@@ -38,23 +38,23 @@ export const dataSourcesReducer = reducerFactory(initialState)
       dataSourcesCount: action.payload.length,
     }),
   })
-  .addHandler({
+  .addMapper({
     filter: dataSourceLoaded,
     mapper: (state, action) => ({ ...state, dataSource: action.payload }),
   })
-  .addHandler({
+  .addMapper({
     filter: setDataSourcesSearchQuery,
     mapper: (state, action) => ({ ...state, searchQuery: action.payload }),
   })
-  .addHandler({
+  .addMapper({
     filter: setDataSourcesLayoutMode,
     mapper: (state, action) => ({ ...state, layoutMode: action.payload }),
   })
-  .addHandler({
+  .addMapper({
     filter: dataSourceTypesLoad,
     mapper: state => ({ ...state, dataSourceTypes: [], isLoadingDataSources: true }),
   })
-  .addHandler({
+  .addMapper({
     filter: dataSourceTypesLoaded,
     mapper: (state, action) => ({
       ...state,
@@ -62,19 +62,19 @@ export const dataSourcesReducer = reducerFactory(initialState)
       isLoadingDataSources: false,
     }),
   })
-  .addHandler({
+  .addMapper({
     filter: setDataSourceTypeSearchQuery,
     mapper: (state, action) => ({ ...state, dataSourceTypeSearchQuery: action.payload }),
   })
-  .addHandler({
+  .addMapper({
     filter: dataSourceMetaLoaded,
     mapper: (state, action) => ({ ...state, dataSourceMeta: action.payload }),
   })
-  .addHandler({
+  .addMapper({
     filter: setDataSourceName,
     mapper: (state, action) => ({ ...state, dataSource: { ...state.dataSource, name: action.payload } }),
   })
-  .addHandler({
+  .addMapper({
     filter: setIsDefault,
     mapper: (state, action) => ({
       ...state,