diff --git a/kafka-ui-react-app/src/components/Brokers/BrokersList/BrokersList.tsx b/kafka-ui-react-app/src/components/Brokers/BrokersList/BrokersList.tsx index 966edecf1f..7ce8277c88 100644 --- a/kafka-ui-react-app/src/components/Brokers/BrokersList/BrokersList.tsx +++ b/kafka-ui-react-app/src/components/Brokers/BrokersList/BrokersList.tsx @@ -11,7 +11,9 @@ import CheckMarkRoundIcon from 'components/common/Icons/CheckMarkRoundIcon'; import { ColumnDef } from '@tanstack/react-table'; import { clusterBrokerPath } from 'lib/paths'; import Tooltip from 'components/common/Tooltip/Tooltip'; +import ColoredCell from 'components/common/NewTable/ColoredCell'; +import SkewHeader from './SkewHeader/SkewHeader'; import * as S from './BrokersList.styled'; const NA = 'N/A'; @@ -57,11 +59,15 @@ const BrokersList: React.FC = () => { count: segmentCount || NA, port: broker?.port, host: broker?.host, + partitionsLeader: broker?.partitionsLeader, + partitionsSkew: broker?.partitionsSkew, + leadersSkew: broker?.leadersSkew, + inSyncPartitions: broker?.inSyncPartitions, }; }); }, [diskUsage, brokers]); - const columns = React.useMemo[]>( + const columns = React.useMemo[]>( () => [ { header: 'Broker ID', @@ -84,7 +90,7 @@ const BrokersList: React.FC = () => { ), }, { - header: 'Segment Size', + header: 'Disk usage', accessorKey: 'size', // eslint-disable-next-line react/no-unstable-nested-components cell: ({ getValue, table, cell, column, renderValue, row }) => @@ -98,10 +104,47 @@ const BrokersList: React.FC = () => { cell={cell} getValue={getValue} renderValue={renderValue} + renderSegments /> ), }, - { header: 'Segment Count', accessorKey: 'count' }, + { + // eslint-disable-next-line react/no-unstable-nested-components + header: () => , + accessorKey: 'partitionsSkew', + // eslint-disable-next-line react/no-unstable-nested-components + cell: ({ getValue }) => ( + () !== null ? `${getValue()}%` : '-'} + warn={getValue() >= 10 && getValue() < 20} + attention={getValue() >= 20} + /> + ), + }, + { header: 'Leaders', accessorKey: 'partitionsLeader' }, + { + header: 'Leader skew', + accessorKey: 'leadersSkew', + // eslint-disable-next-line react/no-unstable-nested-components + cell: ({ getValue }) => ( + () !== null ? `${getValue()}%` : '-'} + warn={getValue() >= 10 && getValue() < 20} + attention={getValue() >= 20} + /> + ), + }, + { + header: 'Online partitions', + accessorKey: 'inSyncPartitions', + // eslint-disable-next-line react/no-unstable-nested-components + cell: ({ getValue, row }) => ( + ()} + attention={getValue() !== row.original.count} + /> + ), + }, { header: 'Port', accessorKey: 'port' }, { header: 'Host', diff --git a/kafka-ui-react-app/src/components/Brokers/BrokersList/SkewHeader/SkewHeader.styled.ts b/kafka-ui-react-app/src/components/Brokers/BrokersList/SkewHeader/SkewHeader.styled.ts new file mode 100644 index 0000000000..576186e260 --- /dev/null +++ b/kafka-ui-react-app/src/components/Brokers/BrokersList/SkewHeader/SkewHeader.styled.ts @@ -0,0 +1,6 @@ +import styled from 'styled-components'; + +export const CellWrapper = styled.div` + display: flex; + gap: 10px; +`; diff --git a/kafka-ui-react-app/src/components/Brokers/BrokersList/SkewHeader/SkewHeader.tsx b/kafka-ui-react-app/src/components/Brokers/BrokersList/SkewHeader/SkewHeader.tsx new file mode 100644 index 0000000000..978d1768dd --- /dev/null +++ b/kafka-ui-react-app/src/components/Brokers/BrokersList/SkewHeader/SkewHeader.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import Tooltip from 'components/common/Tooltip/Tooltip'; +import InfoIcon from 'components/common/Icons/InfoIcon'; + +import * as S from './SkewHeader.styled'; + +const SkewHeader: React.FC = () => ( + + Partitions skew + } + content="The divergence from the average brokers' value" + /> + +); + +export default SkewHeader; diff --git a/kafka-ui-react-app/src/components/common/NewTable/ColoredCell.tsx b/kafka-ui-react-app/src/components/common/NewTable/ColoredCell.tsx new file mode 100644 index 0000000000..df8ab2d6a8 --- /dev/null +++ b/kafka-ui-react-app/src/components/common/NewTable/ColoredCell.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +import styled from 'styled-components'; + +interface CellProps { + isWarning?: boolean; + isAttention?: boolean; +} + +interface ColoredCellProps { + value: number | string; + warn?: boolean; + attention?: boolean; +} + +const Cell = styled.div` + color: ${(props) => { + if (props.isAttention) { + return props.theme.table.colored.color.attention; + } + + if (props.isWarning) { + return props.theme.table.colored.color.warning; + } + + return 'inherit'; + }}; +`; + +const ColoredCell: React.FC = ({ + value, + warn, + attention, +}) => { + return ( + + {value} + + ); +}; + +export default ColoredCell; diff --git a/kafka-ui-react-app/src/components/common/NewTable/SizeCell.tsx b/kafka-ui-react-app/src/components/common/NewTable/SizeCell.tsx index 00a60086d9..0217af5cf7 100644 --- a/kafka-ui-react-app/src/components/common/NewTable/SizeCell.tsx +++ b/kafka-ui-react-app/src/components/common/NewTable/SizeCell.tsx @@ -3,8 +3,11 @@ import { CellContext } from '@tanstack/react-table'; import BytesFormatted from 'components/common/BytesFormatted/BytesFormatted'; // eslint-disable-next-line @typescript-eslint/no-explicit-any -const SizeCell: React.FC> = ({ getValue }) => ( - ()} /> +const SizeCell: React.FC & { renderSegments?: boolean }> = ({ getValue, row, renderSegments = false }) => ( + <> + ()} /> + {renderSegments ? `, ${row?.original.count} segment(s)` : null} + ); export default SizeCell; diff --git a/kafka-ui-react-app/src/theme/theme.ts b/kafka-ui-react-app/src/theme/theme.ts index 978b694913..ed017e5dcf 100644 --- a/kafka-ui-react-app/src/theme/theme.ts +++ b/kafka-ui-react-app/src/theme/theme.ts @@ -529,6 +529,12 @@ export const theme = { active: Colors.neutral[90], }, }, + colored: { + color: { + attention: Colors.red[50], + warning: Colors.yellow[20], + }, + }, expander: { normal: Colors.brand[30], hover: Colors.brand[40], @@ -924,6 +930,12 @@ export const darkTheme: ThemeType = { active: Colors.neutral[0], }, }, + colored: { + color: { + attention: Colors.red[50], + warning: Colors.yellow[20], + }, + }, expander: { normal: Colors.brand[30], hover: Colors.brand[40],