diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Overview/ActionsCell.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Overview/ActionsCell.tsx new file mode 100644 index 0000000000..a9f4eb15e8 --- /dev/null +++ b/kafka-ui-react-app/src/components/Topics/Topic/Overview/ActionsCell.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { Partition } from 'generated-sources'; +import { CellContext } from '@tanstack/react-table'; +import { useAppDispatch } from 'lib/hooks/redux'; +import ClusterContext from 'components/contexts/ClusterContext'; +import { RouteParamsClusterTopic } from 'lib/paths'; +import useAppParams from 'lib/hooks/useAppParams'; +import { clearTopicMessages } from 'redux/reducers/topicMessages/topicMessagesSlice'; +import { Dropdown, DropdownItem } from 'components/common/Dropdown'; +import { useTopicDetails } from 'lib/hooks/api/topics'; + +const ActionsCell: React.FC> = ({ row }) => { + const { clusterName, topicName } = useAppParams(); + const { data } = useTopicDetails({ clusterName, topicName }); + const { isReadOnly } = React.useContext(ClusterContext); + const { partition } = row.original; + const dispatch = useAppDispatch(); + + const clearTopicMessagesHandler = async () => { + await dispatch( + clearTopicMessages({ clusterName, topicName, partitions: [partition] }) + ).unwrap(); + }; + const disabled = + data?.internal || isReadOnly || data?.cleanUpPolicy !== 'DELETE'; + return ( + + + Clear Messages + + + ); +}; + +export default ActionsCell; diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Overview/Overview.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Overview/Overview.tsx index 2bd1c4a78a..cada465548 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/Overview/Overview.tsx +++ b/kafka-ui-react-app/src/components/Topics/Topic/Overview/Overview.tsx @@ -1,25 +1,20 @@ import React from 'react'; import { Partition, Replica } from 'generated-sources'; -import ClusterContext from 'components/contexts/ClusterContext'; import BytesFormatted from 'components/common/BytesFormatted/BytesFormatted'; -import { Table } from 'components/common/table/Table/Table.styled'; -import TableHeaderCell from 'components/common/table/TableHeaderCell/TableHeaderCell'; +import Table from 'components/common/NewTable'; import * as Metrics from 'components/common/Metrics'; import { Tag } from 'components/common/Tag/Tag.styled'; -import { useAppDispatch } from 'lib/hooks/redux'; import { RouteParamsClusterTopic } from 'lib/paths'; import useAppParams from 'lib/hooks/useAppParams'; -import { Dropdown, DropdownItem } from 'components/common/Dropdown'; -import { clearTopicMessages } from 'redux/reducers/topicMessages/topicMessagesSlice'; import { useTopicDetails } from 'lib/hooks/api/topics'; +import { ColumnDef } from '@tanstack/react-table'; import * as S from './Overview.styled'; +import ActionsCell from './ActionsCell'; const Overview: React.FC = () => { const { clusterName, topicName } = useAppParams(); - const dispatch = useAppDispatch(); const { data } = useTopicDetails({ clusterName, topicName }); - const { isReadOnly } = React.useContext(ClusterContext); const messageCount = React.useMemo( () => @@ -28,7 +23,65 @@ const Overview: React.FC = () => { }, 0), [data] ); + const newData = React.useMemo(() => { + if (!data?.partitions) return []; + return data.partitions.map((items: Partition) => { + return { + ...items, + messageCount: items.offsetMax - items.offsetMin, + }; + }); + }, [data?.partitions]); + + const columns = React.useMemo[]>( + () => [ + { + header: 'Partition ID', + enableSorting: false, + accessorKey: 'partition', + }, + { + header: 'Replicas', + enableSorting: false, + + accessorKey: 'replicas', + cell: ({ getValue }) => { + const replicas = getValue(); + if (replicas === undefined || replicas.length === 0) { + return 0; + } + return replicas?.map(({ broker, leader }: Replica) => ( + + {broker} + + )); + }, + }, + { + header: 'First Offset', + enableSorting: false, + accessorKey: 'offsetMin', + }, + { header: 'Next Offset', enableSorting: false, accessorKey: 'offsetMax' }, + { + header: 'Message Count', + enableSorting: false, + accessorKey: `messageCount`, + }, + { + header: '', + enableSorting: false, + accessorKey: 'actions', + cell: ActionsCell, + }, + ], + [] + ); return ( <> @@ -90,66 +143,12 @@ const Overview: React.FC = () => { - - - - - - - - - - - - - {data?.partitions?.map((partition: Partition) => ( - - - - - - - - - ))} - {data?.partitions?.length === 0 && ( - - - - )} - -
{partition.partition} - {partition.replicas?.map(({ broker, leader }: Replica) => ( - - {broker} - - ))} - {partition.offsetMin}{partition.offsetMax}{partition.offsetMax - partition.offsetMin} - {!data?.internal && - !isReadOnly && - data?.cleanUpPolicy === 'DELETE' ? ( - - - dispatch( - clearTopicMessages({ - clusterName, - topicName, - partitions: [partition.partition], - }) - ).unwrap() - } - danger - > - Clear Messages - - - ) : null} -
No Partitions found
+ ); }; diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Overview/__test__/Overview.spec.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Overview/__test__/Overview.spec.tsx index f49606747e..e0efd0db9e 100644 --- a/kafka-ui-react-app/src/components/Topics/Topic/Overview/__test__/Overview.spec.tsx +++ b/kafka-ui-react-app/src/components/Topics/Topic/Overview/__test__/Overview.spec.tsx @@ -122,39 +122,29 @@ describe('Overview', () => { }); describe('when the table partition dropdown appearance', () => { - it('should check if the dropdown is not present when it is readOnly', () => { + it('should check if the dropdown is disabled when it is readOnly', () => { renderComponent( { - ...internalTopicPayload, - cleanUpPolicy: CleanUpPolicy.DELETE, + ...externalTopicPayload, }, { ...defaultContextValues, isReadOnly: true } ); - expect(screen.queryByText('Clear Messages')).not.toBeInTheDocument(); + expect(screen.getByLabelText('Dropdown Toggle')).toBeDisabled(); }); - it('should check if the dropdown is not present when it is internal', () => { + it('should check if the dropdown is disabled when it is internal', () => { renderComponent({ ...internalTopicPayload, - cleanUpPolicy: CleanUpPolicy.DELETE, }); - expect(screen.queryByText('Clear Messages')).not.toBeInTheDocument(); + expect(screen.getByLabelText('Dropdown Toggle')).toBeDisabled(); }); - it('should check if the dropdown is not present when cleanUpPolicy is not DELETE', () => { + it('should check if the dropdown is disabled when cleanUpPolicy is not DELETE', () => { renderComponent({ ...externalTopicPayload, cleanUpPolicy: CleanUpPolicy.COMPACT, }); - expect(screen.queryByText('Clear Messages')).not.toBeInTheDocument(); - }); - - it('should check if the dropdown action to be in visible', () => { - renderComponent({ - ...externalTopicPayload, - cleanUpPolicy: CleanUpPolicy.DELETE, - }); - expect(screen.getByText('Clear Messages')).toBeInTheDocument(); + expect(screen.getByLabelText('Dropdown Toggle')).toBeDisabled(); }); }); });