瀏覽代碼

[UI] Normalize Topic State

Oleg Shuralev 5 年之前
父節點
當前提交
ff6b28487a

+ 1 - 1
frontend/src/components/common/Breadcrumb/Breadcrumb.tsx

@@ -24,7 +24,7 @@ const Breadcrumb: React.FC<Props> = ({
         ))}
 
         <li className="is-active">
-          <a href="#">{children}</a>
+          <span className="">{children}</span>
         </li>
       </ul>
     </nav>

+ 16 - 4
frontend/src/redux/reducers/topics/reducer.ts

@@ -1,12 +1,24 @@
-import { Topic, Action } from 'types';
+import { Action, TopicsState } from 'types';
 import actionType from 'redux/reducers/actionType';
 
-export const initialState: Topic[] = [];
+export const initialState: TopicsState = {
+  byName: {},
+  allNames: [],
+};
 
-const reducer = (state = initialState, action: Action): Topic[] => {
+const reducer = (state = initialState, action: Action): TopicsState => {
   switch (action.type) {
     case actionType.GET_TOPICS__SUCCESS:
-      return action.payload;
+      return action.payload.reduce(
+        (memo, topic) => {
+          const { name } = topic;
+          memo.byName[name] = topic;
+          memo.allNames.push(name);
+
+          return memo;
+        },
+        initialState,
+      );
     default:
       return state;
   }

+ 15 - 18
frontend/src/redux/reducers/topics/selectors.ts

@@ -1,8 +1,11 @@
 import { createSelector } from 'reselect';
-import { RootState, Topic, TopicName, FetchStatus } from 'types';
+import { RootState, TopicName, FetchStatus, TopicsState } from 'types';
 import { createFetchingSelector } from 'redux/reducers/loader/selectors';
 
-const topicsState = ({ topics }: RootState): Topic[] => topics;
+const topicsState = ({ topics }: RootState): TopicsState => topics;
+
+const getAllNames = (state: RootState) => topicsState(state).allNames;
+const getTopicMap = (state: RootState) => topicsState(state).byName;
 
 const getTopicListFetchingStatus = createFetchingSelector('GET_TOPICS');
 
@@ -13,8 +16,15 @@ export const getIsTopicListFetched = createSelector(
 
 export const getTopicList = createSelector(
   getIsTopicListFetched,
-  topicsState,
-  (isFetched, topics) => isFetched ? topics : [],
+  getAllNames,
+  getTopicMap,
+  (isFetched, allNames, byName) => {
+    if (isFetched) {
+      return allNames.map((name) => byName[name])
+    }
+
+    return [];
+  },
 );
 
 export const getExternalTopicList = createSelector(
@@ -22,23 +32,10 @@ export const getExternalTopicList = createSelector(
   (topics) => topics.filter(({ internal }) => !internal),
 );
 
-interface TopicMap {[key: string]: Topic};
-
-export const getTopicMap = createSelector(
-  getTopicList,
-  (topics) => topics.reduce<TopicMap>(
-    (memo: TopicMap, topic: Topic): TopicMap => ({
-      ...memo,
-      [topic.name]: { ...topic },
-    }),
-    {},
-  )
-);
-
 const getTopicName = (_: RootState, topicName: TopicName) => topicName;
 
 export const getTopicByName = createSelector(
   getTopicMap,
   getTopicName,
-  (topics: TopicMap, topicName: TopicName) => topics[topicName],
+  (topics, topicName) => topics[topicName],
 );

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

@@ -6,3 +6,29 @@
 @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";
+
+.has-text-overflow-ellipsis {
+  flex: 1;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+.breadcrumb li {
+  &.is-active > span {
+    padding: 0 0.75em;
+  }
+
+  &:first-child > span {
+    padding-left: 0;
+  }
+}
+
+.section {
+  animation: fadein .5s;
+}
+
+@keyframes fadein {
+  from { opacity: 0; }
+  to   { opacity: 1; }
+}

+ 0 - 16
frontend/src/theme/index.scss

@@ -31,19 +31,3 @@ code {
   font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
     monospace;
 }
-
-.has-text-overflow-ellipsis {
-  flex: 1;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-}
-
-.section {
-  animation: fadein .5s;
-}
-
-@keyframes fadein {
-  from { opacity: 0; }
-  to   { opacity: 1; }
-}

+ 2 - 2
frontend/src/types/index.ts

@@ -6,7 +6,7 @@ import * as topicsActions from 'redux/reducers/topics/actions';
 import * as clustersActions from 'redux/reducers/clusters/actions';
 import * as brokersActions from 'redux/reducers/brokers/actions';
 
-import { Topic } from './topic';
+import { TopicsState } from './topic';
 import { Cluster } from './cluster';
 import { BrokersState } from './broker';
 import { LoaderState } from './loader';
@@ -24,7 +24,7 @@ export enum FetchStatus {
 }
 
 export interface RootState {
-  topics: Topic[];
+  topics: TopicsState;
   clusters: Cluster[];
   brokers: BrokersState;
   loader: LoaderState;

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

@@ -20,3 +20,8 @@ export interface Topic {
   internal: boolean;
   partitions: TopicPartition[];
 }
+
+export interface TopicsState {
+  byName: { [topicName: string]: Topic },
+  allNames: TopicName[],
+}