فهرست منبع

[UI] Loader reducer

Oleg Shuralev 5 سال پیش
والد
کامیت
a70a688b64

+ 3 - 3
frontend/src/redux/reducers/clusters/actionType.ts

@@ -1,7 +1,7 @@
 enum ActionType {
-  CLUSTERS__FETCH_REQUEST = 'CLUSTERS__FETCH_REQUEST',
-  CLUSTERS__FETCH_SUCCESS = 'CLUSTERS__FETCH_SUCCESS',
-  CLUSTERS__FETCH_FAILURE = 'CLUSTERS__FETCH_FAILURE',
+  GET_CLUSTERS__REQUEST = 'GET_CLUSTERS__REQUEST',
+  GET_CLUSTERS__SUCCESS = 'GET_CLUSTERS__SUCCESS',
+  GET_CLUSTERS__FAILURE = 'GET_CLUSTERS__FAILURE',
 }
 
 export default ActionType;

+ 3 - 3
frontend/src/redux/reducers/clusters/actions.ts

@@ -3,7 +3,7 @@ import ActionType from './actionType';
 import { Cluster } from 'types';
 
 export const fetchClusterListAction = createAsyncAction(
-  ActionType.CLUSTERS__FETCH_REQUEST,
-  ActionType.CLUSTERS__FETCH_SUCCESS,
-  ActionType.CLUSTERS__FETCH_FAILURE,
+  ActionType.GET_CLUSTERS__REQUEST,
+  ActionType.GET_CLUSTERS__SUCCESS,
+  ActionType.GET_CLUSTERS__FAILURE,
 )<undefined, Cluster[], undefined>();

+ 4 - 22
frontend/src/redux/reducers/clusters/reducer.ts

@@ -1,30 +1,12 @@
-import { ClustersState, FetchStatus, Action } from 'types';
+import { ClustersState, Action } from 'types';
 import actionType from 'redux/reducers/actionType';
 
-export const initialState: ClustersState = {
-  fetchStatus: FetchStatus.notFetched,
-  items: [],
-};
+export const initialState: ClustersState = [];
 
 const reducer = (state = initialState, action: Action): ClustersState => {
   switch (action.type) {
-    case actionType.CLUSTERS__FETCH_REQUEST:
-      return {
-        ...state,
-        fetchStatus: FetchStatus.fetching,
-      };
-    case actionType.CLUSTERS__FETCH_SUCCESS:
-      return {
-        ...state,
-        fetchStatus: FetchStatus.fetched,
-        items: action.payload,
-      };
-    case actionType.CLUSTERS__FETCH_FAILURE:
-      return {
-        ...state,
-        fetchStatus: FetchStatus.errorFetching,
-      };
-
+    case actionType.GET_CLUSTERS__SUCCESS:
+      return action.payload;
     default:
       return state;
   }

+ 5 - 2
frontend/src/redux/reducers/clusters/selectors.ts

@@ -1,8 +1,11 @@
 import { createSelector } from 'reselect';
 import { ClustersState, RootState, FetchStatus } from 'types';
+import { createFetchingSelector } from 'redux/reducers/loader/selectors';
 
 const clustersState = ({ clusters }: RootState): ClustersState => clusters;
 
-export const getIsClusterListFetched = createSelector(clustersState, ({ fetchStatus }) => fetchStatus === FetchStatus.fetched);
+const getClusterListFetchingStatus = createFetchingSelector('GET_CLUSTERS');
 
-export const getClusterList = createSelector(clustersState, ({ items }) => items);
+export const getIsClusterListFetched = createSelector(getClusterListFetchingStatus, (status) => status === FetchStatus.fetched);
+
+export const getClusterList = createSelector(clustersState, (items) => items);

+ 2 - 0
frontend/src/redux/reducers/index.ts

@@ -1,9 +1,11 @@
 import { combineReducers } from 'redux';
 import topics from './topics/reducer';
 import clusters from './clusters/reducer';
+import loader from './loader/reducer';
 import { RootState } from 'types';
 
 export default combineReducers<RootState>({
   topics,
   clusters,
+  loader,
 });

+ 35 - 0
frontend/src/redux/reducers/loader/reducer.ts

@@ -0,0 +1,35 @@
+import { FetchStatus, Action, LoaderState } from 'types';
+
+export const initialState: LoaderState = {};
+
+const reducer = (state = initialState, action: Action): LoaderState => {
+  const { type } = action;
+  const matches = /(.*)__(REQUEST|SUCCESS|FAILURE)/.exec(type);
+
+  // not a *__REQUEST / *__SUCCESS /  *__FAILURE actions, so we ignore them
+  if (!matches) return state;
+
+  const [, requestName, requestState] = matches;
+
+  switch (requestState) {
+    case 'REQUEST':
+      return {
+        ...state,
+        [requestName]: FetchStatus.fetching,
+      };
+    case 'SUCCESS':
+      return {
+        ...state,
+        [requestName]: FetchStatus.fetched,
+      };
+    case 'FAILURE':
+      return {
+        ...state,
+        [requestName]: FetchStatus.errorFetching,
+      };
+    default:
+      return state;
+  }
+};
+
+export default reducer;

+ 4 - 0
frontend/src/redux/reducers/loader/selectors.ts

@@ -0,0 +1,4 @@
+import { RootState, FetchStatus } from 'types';
+
+export const createFetchingSelector = (action: string) =>
+  (state: RootState) => (state.loader[action] || FetchStatus.notFetched);

+ 1 - 6
frontend/src/types/cluster.ts

@@ -1,5 +1,3 @@
-import { FetchStatus } from "types";
-
 export enum ClusterStatus {
   Online = 'online',
   Offline = 'offline',
@@ -17,7 +15,4 @@ export interface Cluster {
   topicCount: number;
 }
 
-export interface ClustersState {
-  fetchStatus: FetchStatus;
-  items: Cluster[];
-}
+export type ClustersState = Cluster[];

+ 3 - 0
frontend/src/types/index.ts

@@ -5,9 +5,11 @@ import { ThunkAction } from 'redux-thunk';
 import { TopicsState } from './topic';
 import { AnyAction } from 'redux';
 import { ClustersState } from './cluster';
+import { LoaderState } from './loader';
 
 export * from './topic';
 export * from './cluster';
+export * from './loader';
 
 export enum FetchStatus {
   notFetched = 'notFetched',
@@ -19,6 +21,7 @@ export enum FetchStatus {
 export interface RootState {
   topics: TopicsState;
   clusters: ClustersState;
+  loader: LoaderState;
 }
 
 export type Action = ActionType<typeof topicsActions | typeof clustersActions>;

+ 5 - 0
frontend/src/types/loader.ts

@@ -0,0 +1,5 @@
+import { FetchStatus } from "types";
+
+export interface LoaderState {
+  [key: string]: FetchStatus;
+}