浏览代码

[UI] Use new loader reducer + switch

Oleg Shuralev 5 年之前
父节点
当前提交
ee1fff204c

+ 5 - 0
frontend/package-lock.json

@@ -2930,6 +2930,11 @@
       "resolved": "https://registry.npmjs.org/bulma/-/bulma-0.8.0.tgz",
       "integrity": "sha512-nhf3rGyiZh/VM7FrSJ/5KeLlfaFkXz0nYcXriynfPH4vVpnxnqyEwaNGdNCVzHyyCA3cHgkQAMpdF/SFbFGZfA=="
     },
+    "bulma-switch": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/bulma-switch/-/bulma-switch-2.0.0.tgz",
+      "integrity": "sha512-myD38zeUfjmdduq+pXabhJEe3x2hQP48l/OI+Y0fO3HdDynZUY/VJygucvEAJKRjr4HxD5DnEm4yx+oDOBXpAA=="
+    },
     "bytes": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",

+ 1 - 0
frontend/package.json

@@ -16,6 +16,7 @@
     "@types/redux": "^3.6.0",
     "@types/redux-thunk": "^2.1.0",
     "bulma": "^0.8.0",
+    "bulma-switch": "^2.0.0",
     "classnames": "^2.2.6",
     "node-sass": "^4.13.0",
     "react": "^16.12.0",

+ 24 - 1
frontend/src/components/Topics/List/List.tsx

@@ -4,14 +4,37 @@ import ListItem from './ListItem';
 
 interface Props {
   topics: Topic[];
+  externalTopics: Topic[];
 }
 
 const List: React.FC<Props> = ({
   topics,
+  externalTopics,
 }) => {
+  const [showInternal, setShowInternal] = React.useState<boolean>(true);
+
+  const handleSwitch = () => setShowInternal(!showInternal);
+
+  const items = showInternal ? topics : externalTopics;
+
   return (
     <>
       <div className="section">
+        <div className="box">
+          <div className="field">
+            <input
+              id="switchRoundedDefault"
+              type="checkbox"
+              name="switchRoundedDefault"
+              className="switch is-rounded"
+              checked={showInternal}
+              onChange={handleSwitch}
+            />
+            <label htmlFor="switchRoundedDefault">
+              Show Internal Topics
+            </label>
+          </div>
+        </div>
         <div className="box">
           <table className="table is-striped is-fullwidth">
             <thead>
@@ -22,7 +45,7 @@ const List: React.FC<Props> = ({
               </tr>
             </thead>
             <tbody>
-              {topics.map((topic) => (
+              {items.map((topic) => (
                 <ListItem
                   key={topic.name}
                   {...topic}

+ 2 - 5
frontend/src/components/Topics/List/ListContainer.ts

@@ -1,14 +1,11 @@
 import { connect } from 'react-redux';
-import {
-  getTopicList,
-  getTotalBrokers,
-} from 'redux/reducers/topics/selectors';
 import { RootState } from 'types';
+import { getTopicList, getExternalTopicList } from 'redux/reducers/topics/selectors';
 import List from './List';
 
 const mapStateToProps = (state: RootState) => ({
   topics: getTopicList(state),
-  totalBrokers: getTotalBrokers(state),
+  externalTopics: getExternalTopicList(state),
 });
 
 

+ 2 - 4
frontend/src/components/Topics/TopicsContainer.ts

@@ -1,8 +1,6 @@
 import { connect } from 'react-redux';
-import {
-  fetchTopicList,
-  fetchBrokers,
-} from 'redux/reducers/topics/thunks';
+import { fetchTopicList } from 'redux/reducers/topics/thunks';
+import { fetchBrokers } from 'redux/reducers/brokers/thunks';
 import Topics from './Topics';
 import { getIsTopicListFetched } from 'redux/reducers/topics/selectors';
 import { RootState, ClusterId } from 'types';

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

@@ -1,7 +1,9 @@
 import topicsActionType from './topics/actionType';
 import clustersActionType from './clusters/actionType';
+import brokersActionType from './brokers/actionType';
 
 export default {
   ...topicsActionType,
   ...clustersActionType,
+  ...brokersActionType,
 };

+ 7 - 0
frontend/src/redux/reducers/brokers/actionType.ts

@@ -0,0 +1,7 @@
+enum ActionType {
+  GET_BROKERS__REQUEST = 'GET_BROKERS__REQUEST',
+  GET_BROKERS__SUCCESS = 'GET_BROKERS__SUCCESS',
+  GET_BROKERS__FAILURE = 'GET_BROKERS__FAILURE',
+}
+
+export default ActionType;

+ 9 - 0
frontend/src/redux/reducers/brokers/actions.ts

@@ -0,0 +1,9 @@
+import { createAsyncAction} from 'typesafe-actions';
+import ActionType from './actionType';
+import { Broker } from 'types';
+
+export const fetchBrokersAction = createAsyncAction(
+  ActionType.GET_BROKERS__REQUEST,
+  ActionType.GET_BROKERS__SUCCESS,
+  ActionType.GET_BROKERS__FAILURE,
+)<undefined, Broker[], undefined>();

+ 15 - 0
frontend/src/redux/reducers/brokers/reducer.ts

@@ -0,0 +1,15 @@
+import { Broker, Action } from 'types';
+import actionType from 'redux/reducers/actionType';
+
+export const initialState: Broker[] = [];
+
+const reducer = (state = initialState, action: Action): Broker[] => {
+  switch (action.type) {
+    case actionType.GET_BROKERS__SUCCESS:
+      return action.payload;
+    default:
+      return state;
+  }
+};
+
+export default reducer;

+ 20 - 0
frontend/src/redux/reducers/brokers/selectors.ts

@@ -0,0 +1,20 @@
+import { createSelector } from 'reselect';
+import { RootState, FetchStatus, Broker } from 'types';
+import { createFetchingSelector } from 'redux/reducers/loader/selectors';
+
+const brokersState = ({ brokers }: RootState): Broker[] => brokers;
+
+const getBrokerListFetchingStatus = createFetchingSelector('GET_BROKERS');
+
+export const getIsBrokerListFetched = createSelector(
+  getBrokerListFetchingStatus,
+  (status) => status === FetchStatus.fetched,
+);
+
+const getBrokerList = createSelector(brokersState, (brokers) => brokers);
+
+export const getTotalBrokers = createSelector(
+  getIsBrokerListFetched,
+  getBrokerList,
+  (isFetched, brokers) => (isFetched && brokers !== undefined ? brokers.length : undefined),
+);

+ 14 - 0
frontend/src/redux/reducers/brokers/thunks.ts

@@ -0,0 +1,14 @@
+import { getBrokers } from 'lib/api';
+import { fetchBrokersAction } from './actions';
+import { PromiseThunk, ClusterId } from 'types';
+
+
+export const fetchBrokers = (clusterId: ClusterId): PromiseThunk<void> => async (dispatch) => {
+  dispatch(fetchBrokersAction.request());
+  try {
+    const { brokers } = await getBrokers(clusterId);
+    dispatch(fetchBrokersAction.success(brokers));
+  } catch (e) {
+    dispatch(fetchBrokersAction.failure());
+  }
+}

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

@@ -1,9 +1,9 @@
-import { ClustersState, Action } from 'types';
+import { Cluster, Action } from 'types';
 import actionType from 'redux/reducers/actionType';
 
-export const initialState: ClustersState = [];
+export const initialState: Cluster[] = [];
 
-const reducer = (state = initialState, action: Action): ClustersState => {
+const reducer = (state = initialState, action: Action): Cluster[] => {
   switch (action.type) {
     case actionType.GET_CLUSTERS__SUCCESS:
       return action.payload;

+ 7 - 4
frontend/src/redux/reducers/clusters/selectors.ts

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

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

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

+ 3 - 7
frontend/src/redux/reducers/topics/actionType.ts

@@ -1,11 +1,7 @@
 enum ActionType {
-  TOPICS__FETCH_REQUEST = 'TOPICS__FETCH_REQUEST',
-  TOPICS__FETCH_SUCCESS = 'TOPICS__FETCH_SUCCESS',
-  TOPICS__FETCH_FAILURE = 'TOPICS__FETCH_FAILURE',
-
-  BROKERS__FETCH_REQUEST = 'BROKERS__FETCH_REQUEST',
-  BROKERS__FETCH_SUCCESS = 'BROKERS__FETCH_SUCCESS',
-  BROKERS__FETCH_FAILURE = 'BROKERS__FETCH_FAILURE',
+  GET_TOPICS__REQUEST = 'GET_TOPICS__REQUEST',
+  GET_TOPICS__SUCCESS = 'GET_TOPICS__SUCCESS',
+  GET_TOPICS__FAILURE = 'GET_TOPICS__FAILURE',
 }
 
 export default ActionType;

+ 4 - 10
frontend/src/redux/reducers/topics/actions.ts

@@ -1,15 +1,9 @@
 import { createAsyncAction} from 'typesafe-actions';
 import ActionType from './actionType';
-import { Topic, Broker } from 'types';
+import { Topic} from 'types';
 
 export const fetchTopicListAction = createAsyncAction(
-  ActionType.TOPICS__FETCH_REQUEST,
-  ActionType.TOPICS__FETCH_SUCCESS,
-  ActionType.TOPICS__FETCH_FAILURE,
+  ActionType.GET_TOPICS__REQUEST,
+  ActionType.GET_TOPICS__SUCCESS,
+  ActionType.GET_TOPICS__FAILURE,
 )<undefined, Topic[], undefined>();
-
-export const fetchBrokersAction = createAsyncAction(
-  ActionType.BROKERS__FETCH_REQUEST,
-  ActionType.BROKERS__FETCH_SUCCESS,
-  ActionType.BROKERS__FETCH_FAILURE,
-)<undefined, Broker[], undefined>();

+ 5 - 39
frontend/src/redux/reducers/topics/reducer.ts

@@ -1,46 +1,12 @@
-import { TopicsState, FetchStatus, Action } from 'types';
+import { Topic, Action } from 'types';
 import actionType from 'redux/reducers/actionType';
 
-export const initialState: TopicsState = {
-  fetchStatus: FetchStatus.notFetched,
-  items: [],
-  brokers: undefined,
-};
+export const initialState: Topic[] = [];
 
-const reducer = (state = initialState, action: Action): TopicsState => {
+const reducer = (state = initialState, action: Action): Topic[] => {
   switch (action.type) {
-    case actionType.TOPICS__FETCH_REQUEST:
-      return {
-        ...state,
-        fetchStatus: FetchStatus.fetching,
-      };
-    case actionType.TOPICS__FETCH_SUCCESS:
-      return {
-        ...state,
-        fetchStatus: FetchStatus.fetched,
-        items: action.payload,
-      };
-    case actionType.TOPICS__FETCH_FAILURE:
-      return {
-        ...state,
-        fetchStatus: FetchStatus.errorFetching,
-      };
-
-    case actionType.BROKERS__FETCH_REQUEST:
-      return {
-        ...state,
-        brokers: undefined,
-      };
-    case actionType.BROKERS__FETCH_SUCCESS:
-      return {
-        ...state,
-        brokers: action.payload,
-      };
-    case actionType.BROKERS__FETCH_FAILURE:
-      return {
-        ...state,
-        brokers: undefined,
-      };
+    case actionType.GET_TOPICS__SUCCESS:
+      return action.payload;
     default:
       return state;
   }

+ 16 - 6
frontend/src/redux/reducers/topics/selectors.ts

@@ -1,15 +1,25 @@
 import { createSelector } from 'reselect';
-import { TopicsState, RootState, Topic, TopicName, FetchStatus } from 'types';
+import { RootState, Topic, TopicName, FetchStatus } from 'types';
+import { createFetchingSelector } from 'redux/reducers/loader/selectors';
 
-const topicsState = ({ topics }: RootState): TopicsState => topics;
+const topicsState = ({ topics }: RootState): Topic[] => topics;
 
-export const getIsTopicListFetched = createSelector(topicsState, ({ fetchStatus }) => fetchStatus === FetchStatus.fetched);
+const getTopicListFetchingStatus = createFetchingSelector('GET_TOPICS');
 
-export const getTopicList = createSelector(topicsState, ({ items }) => items);
+export const getIsTopicListFetched = createSelector(
+  getTopicListFetchingStatus,
+  (status) => status === FetchStatus.fetched,
+);
 
-export const getTotalBrokers = createSelector(
+export const getTopicList = createSelector(
+  getIsTopicListFetched,
   topicsState,
-  ({ brokers }) => (brokers !== undefined ? brokers.length : undefined),
+  (isFetched, topics) => isFetched ? topics : [],
+);
+
+export const getExternalTopicList = createSelector(
+  getTopicList,
+  (topics) => topics.filter(({ internal }) => !internal),
 );
 
 interface TopicMap {[key: string]: Topic};

+ 3 - 21
frontend/src/redux/reducers/topics/thunks.ts

@@ -1,14 +1,6 @@
-import {
-  getTopics,
-  getTopic,
-  getBrokers,
-} from 'lib/api';
-import {
-  fetchTopicListAction,
-  fetchBrokersAction,
-} from './actions';
-import { Topic, TopicName, PromiseThunk, ClusterId } from 'types';
-
+import { getTopics } from 'lib/api';
+import { fetchTopicListAction } from './actions';
+import { PromiseThunk, ClusterId } from 'types';
 
 export const fetchTopicList = (clusterId: ClusterId): PromiseThunk<void> => async (dispatch) => {
   dispatch(fetchTopicListAction.request());
@@ -21,13 +13,3 @@ export const fetchTopicList = (clusterId: ClusterId): PromiseThunk<void> => asyn
     dispatch(fetchTopicListAction.failure());
   }
 }
-
-export const fetchBrokers = (clusterId: ClusterId): PromiseThunk<void> => async (dispatch) => {
-  dispatch(fetchBrokersAction.request());
-  try {
-    const { brokers } = await getBrokers(clusterId);
-    dispatch(fetchBrokersAction.success(brokers));
-  } catch (e) {
-    dispatch(fetchBrokersAction.failure());
-  }
-}

+ 1 - 0
frontend/src/theme/bulma_overrides.scss

@@ -5,3 +5,4 @@
 @import "../../node_modules/bulma/sass/components/_all.sass";
 @import "../../node_modules/bulma/sass/grid/_all.sass";
 @import "../../node_modules/bulma/sass/layout/_all.sass";
+@import "../../node_modules/bulma-switch/src/sass/index.sass";

+ 4 - 0
frontend/src/types/broker.ts

@@ -0,0 +1,4 @@
+export interface Broker {
+  id: string,
+  host: "broker",
+};

+ 0 - 2
frontend/src/types/cluster.ts

@@ -14,5 +14,3 @@ export interface Cluster {
   onlinePartitionCount: number;
   topicCount: number;
 }
-
-export type ClustersState = Cluster[];

+ 13 - 7
frontend/src/types/index.ts

@@ -1,14 +1,19 @@
+import { AnyAction } from 'redux';
 import { ActionType } from 'typesafe-actions';
+import { ThunkAction } from 'redux-thunk';
+
 import * as topicsActions from 'redux/reducers/topics/actions';
 import * as clustersActions from 'redux/reducers/clusters/actions';
-import { ThunkAction } from 'redux-thunk';
-import { TopicsState } from './topic';
-import { AnyAction } from 'redux';
-import { ClustersState } from './cluster';
+import * as brokersActions from 'redux/reducers/brokers/actions';
+
+import { Topic } from './topic';
+import { Cluster } from './cluster';
+import { Broker } from './broker';
 import { LoaderState } from './loader';
 
 export * from './topic';
 export * from './cluster';
+export * from './broker';
 export * from './loader';
 
 export enum FetchStatus {
@@ -19,11 +24,12 @@ export enum FetchStatus {
 }
 
 export interface RootState {
-  topics: TopicsState;
-  clusters: ClustersState;
+  topics: Topic[];
+  clusters: Cluster[];
+  brokers: Broker[];
   loader: LoaderState;
 }
 
-export type Action = ActionType<typeof topicsActions | typeof clustersActions>;
+export type Action = ActionType<typeof topicsActions | typeof clustersActions | typeof brokersActions>;
 
 export type PromiseThunk<T> = ThunkAction<Promise<T>, RootState, undefined, AnyAction>;

+ 0 - 13
frontend/src/types/topic.ts

@@ -1,5 +1,3 @@
-import { FetchStatus } from 'types';
-
 export type TopicName = string;
 export interface TopicConfigs {
   [key: string]: string;
@@ -22,14 +20,3 @@ export interface Topic {
   internal: boolean;
   partitions: TopicPartition[];
 }
-
-export interface TopicsState {
-  fetchStatus: FetchStatus;
-  items: Topic[];
-  brokers?: Broker[];
-}
-
-export interface Broker {
-  id: 1,
-  host: "broker",
-};