[UI] Topics Ui
This commit is contained in:
parent
ed95095254
commit
3bfa1a7d1e
12 changed files with 81 additions and 66 deletions
|
@ -31,14 +31,12 @@ const App: React.FC<AppProps> = ({
|
|||
<main className="Layout__container">
|
||||
<NavConatiner className="Layout__navbar" />
|
||||
{isClusterListFetched ? (
|
||||
<section className="section">
|
||||
<Switch>
|
||||
<Route path="/clusters/:clusterId/topics" component={TopicsContainer} />
|
||||
<Route exact path="/">
|
||||
Dashboard
|
||||
</Route>
|
||||
</Switch>
|
||||
</section>
|
||||
<Switch>
|
||||
<Route path="/clusters/:clusterId/topics" component={TopicsContainer} />
|
||||
<Route exact path="/">
|
||||
Dashboard
|
||||
</Route>
|
||||
</Switch>
|
||||
) : (
|
||||
<PageLoader />
|
||||
)}
|
||||
|
|
|
@ -31,7 +31,10 @@ const ClusterMenu: React.FC<Props> = ({
|
|||
{name}
|
||||
</NavLink>
|
||||
<ul>
|
||||
<NavLink to={`/clusters/${id}/topics`} activeClassName="is-active" title="Dashboard">
|
||||
<NavLink to={`/clusters/${id}/brokers`} activeClassName="is-active" title="Brokers">
|
||||
Brokers
|
||||
</NavLink>
|
||||
<NavLink to={`/clusters/${id}/topics`} activeClassName="is-active" title="Topics">
|
||||
Topics
|
||||
</NavLink>
|
||||
</ul>
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
import React from 'react';
|
||||
import { Topic } from 'types';
|
||||
import { Topic, TopicConfigs } from 'types';
|
||||
import ConfigRow from './ConfigRow';
|
||||
import Partition from './Partition';
|
||||
|
||||
const Details: React.FC<{ topic: Topic }> = ({
|
||||
topic: {
|
||||
name,
|
||||
configs,
|
||||
partitions,
|
||||
}
|
||||
}) => {
|
||||
const configs: TopicConfigs = {[ 'key-config']: '1' };
|
||||
const configKeys = Object.keys(configs);
|
||||
|
||||
return (
|
||||
|
|
|
@ -7,7 +7,7 @@ interface Props extends TopicReplica {
|
|||
}
|
||||
|
||||
const Replica: React.FC<Props> = ({
|
||||
in_sync,
|
||||
inSync,
|
||||
leader,
|
||||
broker,
|
||||
index,
|
||||
|
@ -22,8 +22,8 @@ const Replica: React.FC<Props> = ({
|
|||
LEADER
|
||||
</span>
|
||||
)}
|
||||
<span className={cx('tag', in_sync ? 'is-success' : 'is-danger')}>
|
||||
{in_sync ? 'IN SYNC' : 'OUT OF SYNC'}
|
||||
<span className={cx('tag', inSync ? 'is-success' : 'is-danger')}>
|
||||
{inSync ? 'IN SYNC' : 'OUT OF SYNC'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,56 +1,36 @@
|
|||
import React from 'react';
|
||||
import { Topic } from 'types';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
||||
const ListItem: React.FC<Topic> = ({
|
||||
name,
|
||||
partitions,
|
||||
}) => {
|
||||
return (
|
||||
<li className="tile is-child box">
|
||||
<NavLink exact to={`/topics/${name}`} activeClassName="is-active" className="title is-6">
|
||||
{name} <i className="fas fa-arrow-circle-right has-text-link"></i>
|
||||
</NavLink>
|
||||
<p>Partitions: {partitions.length}</p>
|
||||
<p>Replications: {partitions ? partitions[0].replicas.length : 0}</p>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
import ListItem from './ListItem';
|
||||
|
||||
interface Props {
|
||||
topics: Topic[];
|
||||
totalBrokers?: number;
|
||||
}
|
||||
|
||||
const List: React.FC<Props> = ({
|
||||
topics,
|
||||
totalBrokers,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<section className="hero is-info is-bold">
|
||||
<div className="hero-body">
|
||||
<div className="level has-text-white is-mobile">
|
||||
<div className="level-item has-text-centered ">
|
||||
<div>
|
||||
<p className="heading">Brokers</p>
|
||||
<p className="title has-text-white">{totalBrokers}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="level-item has-text-centered">
|
||||
<div>
|
||||
<p className="heading">Topics</p>
|
||||
<p className="title has-text-white">{topics.length}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="section">
|
||||
<div className="box">
|
||||
<table className="table is-striped is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Topic Name</th>
|
||||
<th>Total Partitions</th>
|
||||
<th>Out of sync replicas</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{topics.map((topic) => (
|
||||
<ListItem
|
||||
key={topic.name}
|
||||
{...topic}
|
||||
/>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div className="container is-fluid">
|
||||
<ul className="tile is-parent is-vertical">
|
||||
{topics.map((topic) => <ListItem {...topic} key={topic.name} />)}
|
||||
</ul>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -4,7 +4,6 @@ import {
|
|||
getTotalBrokers,
|
||||
} from 'redux/reducers/topics/selectors';
|
||||
import { RootState } from 'types';
|
||||
|
||||
import List from './List';
|
||||
|
||||
const mapStateToProps = (state: RootState) => ({
|
||||
|
@ -12,4 +11,5 @@ const mapStateToProps = (state: RootState) => ({
|
|||
totalBrokers: getTotalBrokers(state),
|
||||
});
|
||||
|
||||
|
||||
export default connect(mapStateToProps)(List);
|
||||
|
|
34
frontend/src/components/Topics/List/ListItem.tsx
Normal file
34
frontend/src/components/Topics/List/ListItem.tsx
Normal file
|
@ -0,0 +1,34 @@
|
|||
import React from 'react';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
import { Topic } from 'types';
|
||||
|
||||
|
||||
const ListItem: React.FC<Topic> = ({
|
||||
name,
|
||||
partitions,
|
||||
}) => {
|
||||
const outOfSyncReplicas = React.useMemo(() => {
|
||||
if (partitions === undefined || partitions.length === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return partitions.reduce((memo: number, { replicas }) => {
|
||||
const outOfSync = replicas.filter(({ inSync }) => !inSync)
|
||||
return memo + outOfSync.length;
|
||||
}, 0);
|
||||
}, [partitions])
|
||||
|
||||
return (
|
||||
<tr>
|
||||
<td>
|
||||
<NavLink exact to={`topics/${name}`} activeClassName="is-active" className="title is-6">
|
||||
{name}
|
||||
</NavLink>
|
||||
</td>
|
||||
<td>{partitions.length}</td>
|
||||
<td>{outOfSyncReplicas}</td>
|
||||
</tr>
|
||||
);
|
||||
}
|
||||
|
||||
export default ListItem;
|
|
@ -22,13 +22,13 @@ const Topics: React.FC<Props> = ({
|
|||
fetchTopicList,
|
||||
}) => {
|
||||
React.useEffect(() => { fetchTopicList(clusterId); }, [fetchTopicList, clusterId]);
|
||||
React.useEffect(() => { fetchBrokers(clusterId); }, [fetchBrokers, clusterId]);
|
||||
// React.useEffect(() => { fetchBrokers(clusterId); }, [fetchBrokers, clusterId]);
|
||||
|
||||
if (isFetched) {
|
||||
return (
|
||||
<Switch>
|
||||
<Route exact path="/topics/:topicName" component={DetailsContainer} />
|
||||
<Route exact path="/topics" component={ListContainer} />
|
||||
<Route exact path="/clusters/:clusterId/topics/:topicName" component={DetailsContainer} />
|
||||
<Route exact path="/clusters/:clusterId/topics" component={ListContainer} />
|
||||
</Switch>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ export const getTopic = (name: TopicName): Promise<Topic> =>
|
|||
fetch(`${BASE_URL}/topics/${name}`, { ...BASE_PARAMS })
|
||||
.then(res => res.json());
|
||||
|
||||
export const getTopics = (clusterId: ClusterId): Promise<TopicName[]> =>
|
||||
export const getTopics = (clusterId: ClusterId): Promise<Topic[]> =>
|
||||
fetch(`${BASE_URL}/clusters/${clusterId}/topics`, { ...BASE_PARAMS })
|
||||
.then(res => res.json());
|
||||
|
||||
|
|
|
@ -15,9 +15,8 @@ export const fetchTopicList = (clusterId: ClusterId): PromiseThunk<void> => asyn
|
|||
|
||||
try {
|
||||
const topics = await getTopics(clusterId);
|
||||
const detailedList = await Promise.all(topics.map((topic: TopicName): Promise<Topic> => getTopic(topic)));
|
||||
|
||||
dispatch(fetchTopicListAction.success(detailedList));
|
||||
dispatch(fetchTopicListAction.success(topics));
|
||||
} catch (e) {
|
||||
dispatch(fetchTopicListAction.failure());
|
||||
}
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
@import './bulma_overrides.scss';
|
||||
|
||||
#root, body, html {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
|
|
|
@ -8,7 +8,7 @@ export interface TopicConfigs {
|
|||
export interface TopicReplica {
|
||||
broker: number;
|
||||
leader: boolean;
|
||||
in_sync: true;
|
||||
inSync: true;
|
||||
}
|
||||
|
||||
export interface TopicPartition {
|
||||
|
@ -19,7 +19,7 @@ export interface TopicPartition {
|
|||
|
||||
export interface Topic {
|
||||
name: TopicName;
|
||||
configs: TopicConfigs;
|
||||
internal: boolean;
|
||||
partitions: TopicPartition[];
|
||||
}
|
||||
|
||||
|
@ -29,4 +29,7 @@ export interface TopicsState {
|
|||
brokers?: Broker[];
|
||||
}
|
||||
|
||||
export type Broker = number;
|
||||
export interface Broker {
|
||||
id: 1,
|
||||
host: "broker",
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue