Repository: provectus/kafka-ui
Issue: Migrate Topic Overview to the new version of table
Labels: good first issue
scope/frontend
type/refactoring
status/accepted

### Describe the solution you'd like
Migrate `src/components/Topics/Topic/Overview/Overview.tsx` to new version of tables  `src/components/common/NewTable/Table.tsx`

### Additional context
Topics -> Topic

Issue comments:

Pull request review comments:
Let's make dropdown item disabled instead of removing it from dom
it is disabled for internal
should be disabled
```suggestion
      expect(screen.getByLabelText('Dropdown Toggle')).toBeDisabled();
```
```suggestion
      expect(screen.getByLabelText('Dropdown Toggle')).toBeDisabled();
```
remove this line to make experiment clear
remove this line to make experiment clear
we can completely remove this `it` case

Patch that resolved the issue:
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 00000000000..a9f4eb15e8d
--- /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<CellContext<Partition, unknown>> = ({ row }) => {
+  const { clusterName, topicName } = useAppParams<RouteParamsClusterTopic>();
+  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 (
+    <Dropdown disabled={disabled}>
+      <DropdownItem onClick={clearTopicMessagesHandler} danger>
+        Clear Messages
+      </DropdownItem>
+    </Dropdown>
+  );
+};
+
+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 2bd1c4a78a6..cada465548f 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<RouteParamsClusterTopic>();
-  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<ColumnDef<Partition>[]>(
+    () => [
+      {
+        header: 'Partition ID',
+        enableSorting: false,
+        accessorKey: 'partition',
+      },
+      {
+        header: 'Replicas',
+        enableSorting: false,
+
+        accessorKey: 'replicas',
+        cell: ({ getValue }) => {
+          const replicas = getValue<Partition['replicas']>();
+          if (replicas === undefined || replicas.length === 0) {
+            return 0;
+          }
+          return replicas?.map(({ broker, leader }: Replica) => (
+            <S.Replica
+              leader={leader}
+              key={broker}
+              title={leader ? 'Leader' : ''}
+            >
+              {broker}
+            </S.Replica>
+          ));
+        },
+      },
+      {
+        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 (
     <>
       <Metrics.Wrapper>
@@ -90,66 +143,12 @@ const Overview: React.FC = () => {
           </Metrics.Indicator>
         </Metrics.Section>
       </Metrics.Wrapper>
-      <Table isFullwidth>
-        <thead>
-          <tr>
-            <TableHeaderCell title="Partition ID" />
-            <TableHeaderCell title="Replicas" />
-            <TableHeaderCell title="First Offset" />
-            <TableHeaderCell title="Next Offset" />
-            <TableHeaderCell title="Message Count" />
-            <TableHeaderCell title=" " />
-          </tr>
-        </thead>
-        <tbody>
-          {data?.partitions?.map((partition: Partition) => (
-            <tr key={`partition-list-item-key-${partition.partition}`}>
-              <td>{partition.partition}</td>
-              <td>
-                {partition.replicas?.map(({ broker, leader }: Replica) => (
-                  <S.Replica
-                    leader={leader}
-                    key={broker}
-                    title={leader ? 'Leader' : ''}
-                  >
-                    {broker}
-                  </S.Replica>
-                ))}
-              </td>
-              <td>{partition.offsetMin}</td>
-              <td>{partition.offsetMax}</td>
-              <td>{partition.offsetMax - partition.offsetMin}</td>
-              <td style={{ width: '5%' }}>
-                {!data?.internal &&
-                !isReadOnly &&
-                data?.cleanUpPolicy === 'DELETE' ? (
-                  <Dropdown>
-                    <DropdownItem
-                      onClick={() =>
-                        dispatch(
-                          clearTopicMessages({
-                            clusterName,
-                            topicName,
-                            partitions: [partition.partition],
-                          })
-                        ).unwrap()
-                      }
-                      danger
-                    >
-                      Clear Messages
-                    </DropdownItem>
-                  </Dropdown>
-                ) : null}
-              </td>
-            </tr>
-          ))}
-          {data?.partitions?.length === 0 && (
-            <tr>
-              <td colSpan={10}>No Partitions found</td>
-            </tr>
-          )}
-        </tbody>
-      </Table>
+      <Table
+        columns={columns}
+        data={newData}
+        enableSorting
+        emptyMessage="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 f49606747e4..e0efd0db9ec 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();
     });
   });
 });


Test patch: