[UI] Cleanup

This commit is contained in:
Oleg Shuralev 2020-01-08 04:10:10 +03:00
parent 5a94e9084f
commit 25a7bf0301
No known key found for this signature in database
GPG key ID: 0459DF80E1A2FD1B
7 changed files with 172 additions and 184 deletions

View file

@ -1,5 +1,4 @@
import React from 'react'; import React from 'react';
import PageLoader from 'components/common/PageLoader/PageLoader';
import { ClusterId, BrokerMetrics, ZooKeeperStatus } from 'types'; import { ClusterId, BrokerMetrics, ZooKeeperStatus } from 'types';
import useInterval from 'lib/hooks/useInterval'; import useInterval from 'lib/hooks/useInterval';
import formatBytes from 'lib/utils/formatBytes'; import formatBytes from 'lib/utils/formatBytes';
@ -41,134 +40,131 @@ const Topics: React.FC<Props> = ({
useInterval(() => { fetchBrokerMetrics(clusterId); }, 5000); useInterval(() => { fetchBrokerMetrics(clusterId); }, 5000);
if (isFetched) { const [minDiskUsageValue, minDiskUsageSize] = formatBytes(minDiskUsage);
const [minDiskUsageValue, minDiskUsageSize] = formatBytes(minDiskUsage); const [maxDiskUsageValue, maxDiskUsageSize] = formatBytes(maxDiskUsage);
const [maxDiskUsageValue, maxDiskUsageSize] = formatBytes(maxDiskUsage);
return ( return (
<div className="section"> <div className="section">
<div className="box"> <div className="box">
<h5 className="title is-5">Uptime</h5> <h5 className="title is-5">Uptime</h5>
<div className="level"> <div className="level">
<div className="level-item level-left"> <div className="level-item level-left">
<div> <div>
<p className="heading">Total Brokers</p> <p className="heading">Total Brokers</p>
<p className="title">{brokerCount}</p> <p className="title">{brokerCount}</p>
</div>
</div>
<div className="level-item level-left">
<div>
<p className="heading">Active Controllers</p>
<p className="title">{activeControllers}</p>
</div>
</div>
<div className="level-item level-left">
<div>
<p className="heading">Zookeeper Status</p>
<p className="title">
{zooKeeperStatus === ZooKeeperStatus.online ? (
<span className="tag is-primary">Online</span>
) : (
<span className="tag is-danger">Offline</span>
)}
</p>
</div>
</div> </div>
</div> </div>
</div> <div className="level-item level-left">
<div>
<div className="box"> <p className="heading">Active Controllers</p>
<h5 className="title is-5">Partitions</h5> <p className="title">{activeControllers}</p>
<div className="level">
<div className="level-item level-left">
<div>
<p className="heading">Online</p>
<p>
<span className={cx('title', {'has-text-danger': offlinePartitionCount !== 0})}>
{onlinePartitionCount}
</span>
<span className="subtitle"> of {onlinePartitionCount + offlinePartitionCount}</span>
</p>
</div>
</div>
<div className="level-item level-left">
<div>
<p className="heading">Under Replicated</p>
<p className="title">{underReplicatedPartitionCount}</p>
</div>
</div>
<div className="level-item level-left">
<div>
<p className="heading">In Sync Replicas</p>
<p className="title has-text-grey-lighter">Soon</p>
</div>
</div>
<div className="level-item level-left">
<div>
<p className="heading">Out of Sync Replicas</p>
<p className="title has-text-grey-lighter">Soon</p>
</div>
</div> </div>
</div> </div>
</div> <div className="level-item level-left">
<div>
<div className="box"> <p className="heading">Zookeeper Status</p>
<h5 className="title is-5">Disk</h5> <p className="title">
<div className="level"> {zooKeeperStatus === ZooKeeperStatus.online ? (
<div className="level-item level-left"> <span className="tag is-primary">Online</span>
<div> ) : (
<p className="heading">Max usage</p> <span className="tag is-danger">Offline</span>
<p> )}
<span className="title">{maxDiskUsageValue}</span> </p>
<span className="subtitle"> {maxDiskUsageSize}</span>
</p>
</div>
</div>
<div className="level-item level-left">
<div>
<p className="heading">Min Usage</p>
<p>
<span className="title">{minDiskUsageValue}</span>
<span className="subtitle"> {minDiskUsageSize}</span>
</p>
</div>
</div>
<div className="level-item level-left">
<div>
<p className="heading">Distribution</p>
<p className="title">{diskUsageDistribution}</p>
</div>
</div>
</div>
</div>
<div className="box">
<h5 className="title is-5">System</h5>
<div className="level">
<div className="level-item level-left">
<div>
<p className="heading">Network pool usage</p>
<p className="title">
{Math.round(networkPoolUsage * 10000) / 100}
<span className="subtitle">%</span>
</p>
</div>
</div>
<div className="level-item level-left">
<div>
<p className="heading">Request pool usage</p>
<p className="title">
{Math.round(requestPoolUsage * 10000) / 100}
<span className="subtitle">%</span>
</p>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
);
}
return (<PageLoader />); <div className="box">
<h5 className="title is-5">Partitions</h5>
<div className="level">
<div className="level-item level-left">
<div>
<p className="heading">Online</p>
<p>
<span className={cx('title', {'has-text-danger': offlinePartitionCount !== 0})}>
{onlinePartitionCount}
</span>
<span className="subtitle"> of {onlinePartitionCount + offlinePartitionCount}</span>
</p>
</div>
</div>
<div className="level-item level-left">
<div>
<p className="heading">Under Replicated</p>
<p className="title">{underReplicatedPartitionCount}</p>
</div>
</div>
<div className="level-item level-left">
<div>
<p className="heading">In Sync Replicas</p>
<p className="title has-text-grey-lighter">Soon</p>
</div>
</div>
<div className="level-item level-left">
<div>
<p className="heading">Out of Sync Replicas</p>
<p className="title has-text-grey-lighter">Soon</p>
</div>
</div>
</div>
</div>
<div className="box">
<h5 className="title is-5">Disk</h5>
<div className="level">
<div className="level-item level-left">
<div>
<p className="heading">Max usage</p>
<p>
<span className="title">{maxDiskUsageValue}</span>
<span className="subtitle"> {maxDiskUsageSize}</span>
</p>
</div>
</div>
<div className="level-item level-left">
<div>
<p className="heading">Min Usage</p>
<p>
<span className="title">{minDiskUsageValue}</span>
<span className="subtitle"> {minDiskUsageSize}</span>
</p>
</div>
</div>
<div className="level-item level-left">
<div>
<p className="heading">Distribution</p>
<p className="title is-capitalized">{diskUsageDistribution}</p>
</div>
</div>
</div>
</div>
<div className="box">
<h5 className="title is-5">System</h5>
<div className="level">
<div className="level-item level-left">
<div>
<p className="heading">Network pool usage</p>
<p className="title">
{Math.round(networkPoolUsage * 10000) / 100}
<span className="subtitle">%</span>
</p>
</div>
</div>
<div className="level-item level-left">
<div>
<p className="heading">Request pool usage</p>
<p className="title">
{Math.round(requestPoolUsage * 10000) / 100}
<span className="subtitle">%</span>
</p>
</div>
</div>
</div>
</div>
</div>
);
} }
export default Topics; export default Topics;

View file

@ -1,64 +1,20 @@
import React from 'react'; import React from 'react';
import { Topic, TopicConfigs } from 'types';
import ConfigRow from './ConfigRow';
import Partition from './Partition';
const Details: React.FC<{ topic: Topic }> = ({ const Details: React.FC = ({
topic: {
name,
partitions,
}
}) => { }) => {
const configs: TopicConfigs = {[ 'key-config']: '1' };
const configKeys = Object.keys(configs);
return ( return (
<> <div className="section">
<section className="hero is-info is-bold"> <div className="tabs">
<div className="hero-body"> <ul>
<div className="level has-text-white"> <li className="is-active">
<div className="level-item level-left"> <a>Pictures</a>
<div> </li>
<p className="heading">Name</p> <li><a>Music</a></li>
<p className="title has-text-white">{name}</p> <li><a>Videos</a></li>
</div> <li><a>Documents</a></li>
</div> </ul>
<div className="level-item level-left has-text-centered "> </div>
<div> </div>
<p className="heading">Partitions</p>
<p className="title has-text-white">{partitions.length}</p>
</div>
</div>
</div>
</div>
</section>
<section className="container is-fluid">
<div className="tile is-parent">
<div className="tile is-parent is-7 is-vertical is-narrow">
{partitions.map((partition) => <Partition {...partition} />)}
</div>
<div className="tile is-parent">
<div className="tile is-child box">
<h2 className="title is-5">Config</h2>
<table className="table is-striped is-fullwidth">
<thead>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{configKeys.map((key) => <ConfigRow name={key} key={key} value={configs[key]} />)}
</tbody>
</table>
</div>
</div>
</div>
</section>
</>
); );
} }

View file

@ -1,6 +1,5 @@
function formatBytes(bytes: number, decimals: number = 0) { function formatBytes(bytes: number, decimals: number = 0) {
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
if (bytes === 0) return [0, sizes[0]]; if (bytes === 0) return [0, sizes[0]];
const k = 1024; const k = 1024;

View file

@ -1,4 +1,4 @@
import { Action, BrokersState, ZooKeeperStatus } from 'types'; import { Action, BrokersState, ZooKeeperStatus, BrokerMetrics } from 'types';
import actionType from 'redux/reducers/actionType'; import actionType from 'redux/reducers/actionType';
export const initialState: BrokersState = { export const initialState: BrokersState = {
@ -12,20 +12,35 @@ export const initialState: BrokersState = {
offlinePartitionCount: 0, offlinePartitionCount: 0,
underReplicatedPartitionCount: 0, underReplicatedPartitionCount: 0,
diskUsageDistribution: undefined, diskUsageDistribution: undefined,
diskUsage: [],
};
const updateBrokerSegmentSize = (state: BrokersState, payload: BrokerMetrics) => {
const brokers = state.items;
const { diskUsage } = payload;
const items = brokers.map((broker) => {
const brokerMetrics = diskUsage.find(({ brokerId }) => brokerId === broker.brokerId);
if (brokerMetrics !== undefined) {
return { ...broker, ...brokerMetrics };
}
return broker;
});
return { ...state, items, ...payload };
}; };
const reducer = (state = initialState, action: Action): BrokersState => { const reducer = (state = initialState, action: Action): BrokersState => {
switch (action.type) { switch (action.type) {
case actionType.GET_BROKERS__REQUEST:
return initialState;
case actionType.GET_BROKERS__SUCCESS: case actionType.GET_BROKERS__SUCCESS:
return { return {
...state, ...state,
items: action.payload, items: action.payload,
}; };
case actionType.GET_BROKER_METRICS__SUCCESS: case actionType.GET_BROKER_METRICS__SUCCESS:
return { return updateBrokerSegmentSize(state, action.payload);
...state,
...action.payload,
};
default: default:
return state; return state;
} }

View file

@ -25,10 +25,22 @@ export const getUnderReplicatedPartitionCount = createSelector(brokersState, ({
export const getMinDiskUsage = createSelector( export const getMinDiskUsage = createSelector(
getBrokerList, getBrokerList,
(brokers) => Math.min(...brokers.map(({ segmentSize }) => segmentSize)), (brokers) => {
if (brokers.length === 0) {
return 0;
}
return Math.min(...brokers.map(({ segmentSize }) => segmentSize));
},
); );
export const getMaxDiskUsage = createSelector( export const getMaxDiskUsage = createSelector(
getBrokerList, getBrokerList,
(brokers) => Math.max(...brokers.map(({ segmentSize }) => segmentSize)), (brokers) => {
if (brokers.length === 0) {
return 0;
}
return Math.max(...brokers.map(({ segmentSize }) => segmentSize));
},
); );

View file

@ -38,3 +38,12 @@ code {
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.section {
animation: fadein .5s;
}
@keyframes fadein {
from { opacity: 0; }
to { opacity: 1; }
}

View file

@ -25,6 +25,7 @@ export interface BrokerMetrics {
offlinePartitionCount: number; offlinePartitionCount: number;
underReplicatedPartitionCount: number; underReplicatedPartitionCount: number;
diskUsageDistribution?: string; diskUsageDistribution?: string;
diskUsage: BrokerDiskUsage[];
} }
export interface BrokersState extends BrokerMetrics { export interface BrokersState extends BrokerMetrics {