[UI] Normalize Topic State

This commit is contained in:
Oleg Shuralev 2020-01-08 15:19:52 +03:00
parent b49fb14623
commit ff6b28487a
No known key found for this signature in database
GPG key ID: 0459DF80E1A2FD1B
7 changed files with 65 additions and 41 deletions

View file

@ -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>

View file

@ -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;
} }

View file

@ -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],
); );

View file

@ -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; }
}

View file

@ -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; }
}

View file

@ -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;

View file

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