[UI] Use new loader reducer + switch
This commit is contained in:
parent
a70a688b64
commit
ee1fff204c
24 changed files with 162 additions and 122 deletions
5
frontend/package-lock.json
generated
5
frontend/package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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),
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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
frontend/src/redux/reducers/brokers/actionType.ts
Normal file
7
frontend/src/redux/reducers/brokers/actionType.ts
Normal file
|
@ -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
frontend/src/redux/reducers/brokers/actions.ts
Normal file
9
frontend/src/redux/reducers/brokers/actions.ts
Normal file
|
@ -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
frontend/src/redux/reducers/brokers/reducer.ts
Normal file
15
frontend/src/redux/reducers/brokers/reducer.ts
Normal file
|
@ -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
frontend/src/redux/reducers/brokers/selectors.ts
Normal file
20
frontend/src/redux/reducers/brokers/selectors.ts
Normal file
|
@ -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
frontend/src/redux/reducers/brokers/thunks.ts
Normal file
14
frontend/src/redux/reducers/brokers/thunks.ts
Normal file
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
frontend/src/types/broker.ts
Normal file
4
frontend/src/types/broker.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export interface Broker {
|
||||
id: string,
|
||||
host: "broker",
|
||||
};
|
|
@ -14,5 +14,3 @@ export interface Cluster {
|
|||
onlinePartitionCount: number;
|
||||
topicCount: number;
|
||||
}
|
||||
|
||||
export type ClustersState = Cluster[];
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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",
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue