diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 01097ccc4a..1241f9a0f0 100644 --- a/frontend/package-lock.json +++ b/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", diff --git a/frontend/package.json b/frontend/package.json index ab89b19943..e1fd95695c 100644 --- a/frontend/package.json +++ b/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", diff --git a/frontend/src/components/Topics/List/List.tsx b/frontend/src/components/Topics/List/List.tsx index 544ab7468b..96fefe5ef2 100644 --- a/frontend/src/components/Topics/List/List.tsx +++ b/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 = ({ topics, + externalTopics, }) => { + const [showInternal, setShowInternal] = React.useState(true); + + const handleSwitch = () => setShowInternal(!showInternal); + + const items = showInternal ? topics : externalTopics; + return ( <>
+
+
+ + +
+
@@ -22,7 +45,7 @@ const List: React.FC = ({ - {topics.map((topic) => ( + {items.map((topic) => ( ({ topics: getTopicList(state), - totalBrokers: getTotalBrokers(state), + externalTopics: getExternalTopicList(state), }); diff --git a/frontend/src/components/Topics/TopicsContainer.ts b/frontend/src/components/Topics/TopicsContainer.ts index 0982639210..b7d4a167ea 100644 --- a/frontend/src/components/Topics/TopicsContainer.ts +++ b/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'; diff --git a/frontend/src/redux/reducers/actionType.ts b/frontend/src/redux/reducers/actionType.ts index 981f2da3f1..33006ca457 100644 --- a/frontend/src/redux/reducers/actionType.ts +++ b/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, }; diff --git a/frontend/src/redux/reducers/brokers/actionType.ts b/frontend/src/redux/reducers/brokers/actionType.ts new file mode 100644 index 0000000000..85c501c677 --- /dev/null +++ b/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; diff --git a/frontend/src/redux/reducers/brokers/actions.ts b/frontend/src/redux/reducers/brokers/actions.ts new file mode 100644 index 0000000000..3163a5bd57 --- /dev/null +++ b/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, +)(); diff --git a/frontend/src/redux/reducers/brokers/reducer.ts b/frontend/src/redux/reducers/brokers/reducer.ts new file mode 100644 index 0000000000..a44771accf --- /dev/null +++ b/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; diff --git a/frontend/src/redux/reducers/brokers/selectors.ts b/frontend/src/redux/reducers/brokers/selectors.ts new file mode 100644 index 0000000000..4dbb6cd089 --- /dev/null +++ b/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), +); diff --git a/frontend/src/redux/reducers/brokers/thunks.ts b/frontend/src/redux/reducers/brokers/thunks.ts new file mode 100644 index 0000000000..c2cee03a7a --- /dev/null +++ b/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 => async (dispatch) => { + dispatch(fetchBrokersAction.request()); + try { + const { brokers } = await getBrokers(clusterId); + dispatch(fetchBrokersAction.success(brokers)); + } catch (e) { + dispatch(fetchBrokersAction.failure()); + } +} diff --git a/frontend/src/redux/reducers/clusters/reducer.ts b/frontend/src/redux/reducers/clusters/reducer.ts index 0e8fa376b6..dd1431e2e5 100644 --- a/frontend/src/redux/reducers/clusters/reducer.ts +++ b/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; diff --git a/frontend/src/redux/reducers/clusters/selectors.ts b/frontend/src/redux/reducers/clusters/selectors.ts index 6808c60450..e631378493 100644 --- a/frontend/src/redux/reducers/clusters/selectors.ts +++ b/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); diff --git a/frontend/src/redux/reducers/index.ts b/frontend/src/redux/reducers/index.ts index 5245a7959d..77437dc5c8 100644 --- a/frontend/src/redux/reducers/index.ts +++ b/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({ topics, clusters, + brokers, loader, }); diff --git a/frontend/src/redux/reducers/topics/actionType.ts b/frontend/src/redux/reducers/topics/actionType.ts index bdbc41070a..27ce978a99 100644 --- a/frontend/src/redux/reducers/topics/actionType.ts +++ b/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; diff --git a/frontend/src/redux/reducers/topics/actions.ts b/frontend/src/redux/reducers/topics/actions.ts index 46bc047108..b98f1d953c 100644 --- a/frontend/src/redux/reducers/topics/actions.ts +++ b/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, )(); - -export const fetchBrokersAction = createAsyncAction( - ActionType.BROKERS__FETCH_REQUEST, - ActionType.BROKERS__FETCH_SUCCESS, - ActionType.BROKERS__FETCH_FAILURE, -)(); diff --git a/frontend/src/redux/reducers/topics/reducer.ts b/frontend/src/redux/reducers/topics/reducer.ts index 736c06904d..804e612eee 100644 --- a/frontend/src/redux/reducers/topics/reducer.ts +++ b/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; } diff --git a/frontend/src/redux/reducers/topics/selectors.ts b/frontend/src/redux/reducers/topics/selectors.ts index bfa5565bb6..de7b4143e5 100644 --- a/frontend/src/redux/reducers/topics/selectors.ts +++ b/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}; diff --git a/frontend/src/redux/reducers/topics/thunks.ts b/frontend/src/redux/reducers/topics/thunks.ts index aa6d9ec1fa..3af05f4e8f 100644 --- a/frontend/src/redux/reducers/topics/thunks.ts +++ b/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 => async (dispatch) => { dispatch(fetchTopicListAction.request()); @@ -21,13 +13,3 @@ export const fetchTopicList = (clusterId: ClusterId): PromiseThunk => asyn dispatch(fetchTopicListAction.failure()); } } - -export const fetchBrokers = (clusterId: ClusterId): PromiseThunk => async (dispatch) => { - dispatch(fetchBrokersAction.request()); - try { - const { brokers } = await getBrokers(clusterId); - dispatch(fetchBrokersAction.success(brokers)); - } catch (e) { - dispatch(fetchBrokersAction.failure()); - } -} diff --git a/frontend/src/theme/bulma_overrides.scss b/frontend/src/theme/bulma_overrides.scss index edc607ddec..484343687b 100644 --- a/frontend/src/theme/bulma_overrides.scss +++ b/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"; diff --git a/frontend/src/types/broker.ts b/frontend/src/types/broker.ts new file mode 100644 index 0000000000..29698732d3 --- /dev/null +++ b/frontend/src/types/broker.ts @@ -0,0 +1,4 @@ +export interface Broker { + id: string, + host: "broker", +}; diff --git a/frontend/src/types/cluster.ts b/frontend/src/types/cluster.ts index fcaa4b0726..b80bacaa0f 100644 --- a/frontend/src/types/cluster.ts +++ b/frontend/src/types/cluster.ts @@ -14,5 +14,3 @@ export interface Cluster { onlinePartitionCount: number; topicCount: number; } - -export type ClustersState = Cluster[]; diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index e687b779df..20b02263a8 100644 --- a/frontend/src/types/index.ts +++ b/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; +export type Action = ActionType; export type PromiseThunk = ThunkAction, RootState, undefined, AnyAction>; diff --git a/frontend/src/types/topic.ts b/frontend/src/types/topic.ts index 4a2eb5f83d..070cca8bae 100644 --- a/frontend/src/types/topic.ts +++ b/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", -};