[UI] Normalize Topic State
This commit is contained in:
parent
b49fb14623
commit
ff6b28487a
7 changed files with 65 additions and 41 deletions
|
@ -24,7 +24,7 @@ const Breadcrumb: React.FC<Props> = ({
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<li className="is-active">
|
<li className="is-active">
|
||||||
<a href="#">{children}</a>
|
<span className="">{children}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
@ -1,12 +1,24 @@
|
||||||
import { Topic, Action } from 'types';
|
import { Action, TopicsState } from 'types';
|
||||||
import actionType from 'redux/reducers/actionType';
|
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) {
|
switch (action.type) {
|
||||||
case actionType.GET_TOPICS__SUCCESS:
|
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:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
import { createSelector } from 'reselect';
|
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';
|
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');
|
const getTopicListFetchingStatus = createFetchingSelector('GET_TOPICS');
|
||||||
|
|
||||||
|
@ -13,8 +16,15 @@ export const getIsTopicListFetched = createSelector(
|
||||||
|
|
||||||
export const getTopicList = createSelector(
|
export const getTopicList = createSelector(
|
||||||
getIsTopicListFetched,
|
getIsTopicListFetched,
|
||||||
topicsState,
|
getAllNames,
|
||||||
(isFetched, topics) => isFetched ? topics : [],
|
getTopicMap,
|
||||||
|
(isFetched, allNames, byName) => {
|
||||||
|
if (isFetched) {
|
||||||
|
return allNames.map((name) => byName[name])
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getExternalTopicList = createSelector(
|
export const getExternalTopicList = createSelector(
|
||||||
|
@ -22,23 +32,10 @@ export const getExternalTopicList = createSelector(
|
||||||
(topics) => topics.filter(({ internal }) => !internal),
|
(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;
|
const getTopicName = (_: RootState, topicName: TopicName) => topicName;
|
||||||
|
|
||||||
export const getTopicByName = createSelector(
|
export const getTopicByName = createSelector(
|
||||||
getTopicMap,
|
getTopicMap,
|
||||||
getTopicName,
|
getTopicName,
|
||||||
(topics: TopicMap, topicName: TopicName) => topics[topicName],
|
(topics, topicName) => topics[topicName],
|
||||||
);
|
);
|
||||||
|
|
|
@ -6,3 +6,29 @@
|
||||||
@import "../../node_modules/bulma/sass/grid/_all.sass";
|
@import "../../node_modules/bulma/sass/grid/_all.sass";
|
||||||
@import "../../node_modules/bulma/sass/layout/_all.sass";
|
@import "../../node_modules/bulma/sass/layout/_all.sass";
|
||||||
@import "../../node_modules/bulma-switch/src/sass/index.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; }
|
||||||
|
}
|
||||||
|
|
|
@ -31,19 +31,3 @@ code {
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||||
monospace;
|
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; }
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import * as topicsActions from 'redux/reducers/topics/actions';
|
||||||
import * as clustersActions from 'redux/reducers/clusters/actions';
|
import * as clustersActions from 'redux/reducers/clusters/actions';
|
||||||
import * as brokersActions from 'redux/reducers/brokers/actions';
|
import * as brokersActions from 'redux/reducers/brokers/actions';
|
||||||
|
|
||||||
import { Topic } from './topic';
|
import { TopicsState } from './topic';
|
||||||
import { Cluster } from './cluster';
|
import { Cluster } from './cluster';
|
||||||
import { BrokersState } from './broker';
|
import { BrokersState } from './broker';
|
||||||
import { LoaderState } from './loader';
|
import { LoaderState } from './loader';
|
||||||
|
@ -24,7 +24,7 @@ export enum FetchStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RootState {
|
export interface RootState {
|
||||||
topics: Topic[];
|
topics: TopicsState;
|
||||||
clusters: Cluster[];
|
clusters: Cluster[];
|
||||||
brokers: BrokersState;
|
brokers: BrokersState;
|
||||||
loader: LoaderState;
|
loader: LoaderState;
|
||||||
|
|
|
@ -20,3 +20,8 @@ export interface Topic {
|
||||||
internal: boolean;
|
internal: boolean;
|
||||||
partitions: TopicPartition[];
|
partitions: TopicPartition[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface TopicsState {
|
||||||
|
byName: { [topicName: string]: Topic },
|
||||||
|
allNames: TopicName[],
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue