
* improvement/consumer-topics-sort implement consumer topics sorting * improvement/consumer-topics-sort update typings after review
169 lines
4.6 KiB
TypeScript
169 lines
4.6 KiB
TypeScript
import { Table } from 'components/common/table/Table/Table.styled';
|
|
import TableHeaderCell from 'components/common/table/TableHeaderCell/TableHeaderCell';
|
|
import { ConsumerGroupTopicPartition, SortOrder } from 'generated-sources';
|
|
import React from 'react';
|
|
|
|
import { ContentBox, TopicContentWrapper } from './TopicContent.styled';
|
|
|
|
interface Props {
|
|
consumers: ConsumerGroupTopicPartition[];
|
|
}
|
|
|
|
type OrderByKey = keyof ConsumerGroupTopicPartition;
|
|
interface Headers {
|
|
title: string;
|
|
orderBy: OrderByKey | undefined;
|
|
}
|
|
|
|
const TABLE_HEADERS_MAP: Headers[] = [
|
|
{ title: 'Partition', orderBy: 'partition' },
|
|
{ title: 'Consumer ID', orderBy: 'consumerId' },
|
|
{ title: 'Host', orderBy: 'host' },
|
|
{ title: 'Messages Behind', orderBy: 'messagesBehind' },
|
|
{ title: 'Current Offset', orderBy: 'currentOffset' },
|
|
{ title: 'End offset', orderBy: 'endOffset' },
|
|
];
|
|
|
|
const ipV4ToNum = (ip?: string) => {
|
|
if (typeof ip === 'string' && ip.length !== 0) {
|
|
const withoutSlash = ip.indexOf('/') !== -1 ? ip.slice(1) : ip;
|
|
return Number(
|
|
withoutSlash
|
|
.split('.')
|
|
.map((octet) => `000${octet}`.slice(-3))
|
|
.join('')
|
|
);
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
type ComparatorFunction<T> = (
|
|
valueA: T,
|
|
valueB: T,
|
|
order: SortOrder,
|
|
property?: keyof T
|
|
) => number;
|
|
|
|
const numberComparator: ComparatorFunction<ConsumerGroupTopicPartition> = (
|
|
valueA,
|
|
valueB,
|
|
order,
|
|
property
|
|
) => {
|
|
if (property !== undefined) {
|
|
return order === SortOrder.ASC
|
|
? Number(valueA[property]) - Number(valueB[property])
|
|
: Number(valueB[property]) - Number(valueA[property]);
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
const ipComparator: ComparatorFunction<ConsumerGroupTopicPartition> = (
|
|
valueA,
|
|
valueB,
|
|
order
|
|
) =>
|
|
order === SortOrder.ASC
|
|
? ipV4ToNum(valueA.host) - ipV4ToNum(valueB.host)
|
|
: ipV4ToNum(valueB.host) - ipV4ToNum(valueA.host);
|
|
|
|
const consumerIdComparator: ComparatorFunction<ConsumerGroupTopicPartition> = (
|
|
valueA,
|
|
valueB,
|
|
order
|
|
) => {
|
|
if (valueA.consumerId && valueB.consumerId) {
|
|
if (order === SortOrder.ASC) {
|
|
if (valueA.consumerId?.toLowerCase() > valueB.consumerId?.toLowerCase()) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if (order === SortOrder.DESC) {
|
|
if (valueB.consumerId?.toLowerCase() > valueA.consumerId?.toLowerCase()) {
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
};
|
|
|
|
const TopicContents: React.FC<Props> = ({ consumers }) => {
|
|
const [orderBy, setOrderBy] = React.useState<OrderByKey>('partition');
|
|
const [sortOrder, setSortOrder] = React.useState<SortOrder>(SortOrder.DESC);
|
|
|
|
const handleOrder = React.useCallback((columnName: string | null) => {
|
|
if (typeof columnName === 'string') {
|
|
setOrderBy(columnName as OrderByKey);
|
|
setSortOrder((prevOrder) =>
|
|
prevOrder === SortOrder.DESC ? SortOrder.ASC : SortOrder.DESC
|
|
);
|
|
}
|
|
}, []);
|
|
|
|
const sortedConsumers = React.useMemo(() => {
|
|
if (orderBy && sortOrder) {
|
|
const isNumberProperty =
|
|
orderBy === 'partition' ||
|
|
orderBy === 'currentOffset' ||
|
|
orderBy === 'endOffset' ||
|
|
orderBy === 'messagesBehind';
|
|
|
|
let comparator: ComparatorFunction<ConsumerGroupTopicPartition>;
|
|
if (isNumberProperty) {
|
|
comparator = numberComparator;
|
|
}
|
|
|
|
if (orderBy === 'host') {
|
|
comparator = ipComparator;
|
|
}
|
|
|
|
if (orderBy === 'consumerId') {
|
|
comparator = consumerIdComparator;
|
|
}
|
|
|
|
return consumers.sort((a, b) => comparator(a, b, sortOrder, orderBy));
|
|
}
|
|
return consumers;
|
|
}, [orderBy, sortOrder, consumers]);
|
|
|
|
return (
|
|
<TopicContentWrapper>
|
|
<td colSpan={3}>
|
|
<ContentBox>
|
|
<Table isFullwidth>
|
|
<thead>
|
|
<tr>
|
|
{TABLE_HEADERS_MAP.map((header) => (
|
|
<TableHeaderCell
|
|
key={header.orderBy}
|
|
title={header.title}
|
|
orderBy={orderBy}
|
|
sortOrder={sortOrder}
|
|
orderValue={header.orderBy}
|
|
handleOrderBy={handleOrder}
|
|
/>
|
|
))}
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{sortedConsumers.map((consumer) => (
|
|
<tr key={consumer.partition}>
|
|
<td>{consumer.partition}</td>
|
|
<td>{consumer.consumerId}</td>
|
|
<td>{consumer.host}</td>
|
|
<td>{consumer.messagesBehind}</td>
|
|
<td>{consumer.currentOffset}</td>
|
|
<td>{consumer.endOffset}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</Table>
|
|
</ContentBox>
|
|
</td>
|
|
</TopicContentWrapper>
|
|
);
|
|
};
|
|
|
|
export default TopicContents;
|