Repository: provectus/kafka-ui
Issue: Not functional 'Next' button within Messages/Topic
Labels: type/bug
scope/frontend
status/accepted
status/confirmed

**Describe the bug**
'Next' button is not working for Messages within Topic


**Steps to Reproduce**
Steps to reproduce the behavior:

1. Open the Topic which has Messages
2. Navigate to 'Messages' tab
3. Press 'Next' button


**Expected behavior**
'Next' button should not exist as it's not functional for Messages.


**Screenshots**

https://user-images.githubusercontent.com/104780608/169489025-f90118d6-e715-49bc-a29a-47a61c475798.mov




Issue comments:
Hello there armenuikafka! 👋

Thank you and congratulations 🎉 for opening your very first issue in this project! 💖

In case you want to claim this issue, please comment down below! We will try to get back to you as soon as we can. 👀

Pull request review comments:

Patch that resolved the issue:
diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/MessagesTable.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/MessagesTable.tsx
index 6c2e69aa0fa..83192b3f908 100644
--- a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/MessagesTable.tsx
+++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/MessagesTable.tsx
@@ -1,12 +1,9 @@
 import PageLoader from 'components/common/PageLoader/PageLoader';
 import { Table } from 'components/common/table/Table/Table.styled';
 import TableHeaderCell from 'components/common/table/TableHeaderCell/TableHeaderCell';
-import { SeekDirection, TopicMessage } from 'generated-sources';
-import styled from 'styled-components';
-import { compact, concat, groupBy, map, maxBy, minBy } from 'lodash';
+import { TopicMessage } from 'generated-sources';
 import React, { useContext } from 'react';
 import { useSelector } from 'react-redux';
-import { useHistory } from 'react-router-dom';
 import {
   getTopicMessges,
   getIsTopicMessagesFetching,
@@ -14,110 +11,52 @@ import {
 import TopicMessagesContext from 'components/contexts/TopicMessagesContext';
 
 import Message from './Message';
-import * as S from './MessageContent/MessageContent.styled';
-
-const MessagesPaginationWrapperStyled = styled.div`
-  padding: 16px;
-  display: flex;
-  justify-content: flex-start;
-`;
 
 const MessagesTable: React.FC = () => {
-  const history = useHistory();
-
-  const { searchParams, isLive } = useContext(TopicMessagesContext);
+  const { isLive } = useContext(TopicMessagesContext);
 
   const messages = useSelector(getTopicMessges);
   const isFetching = useSelector(getIsTopicMessagesFetching);
 
-  const handleNextClick = () => {
-    const seekTo = searchParams.get('seekTo');
-
-    if (seekTo) {
-      const selectedPartitions = seekTo.split(',').map((item) => {
-        const [partition] = item.split('::');
-        return { offset: 0, partition: parseInt(partition, 10) };
-      });
-
-      const seekDirection = searchParams.get('seekDirection');
-      const isBackward = seekDirection === SeekDirection.BACKWARD;
-
-      const messageUniqs = map(groupBy(messages, 'partition'), (v) =>
-        isBackward ? minBy(v, 'offset') : maxBy(v, 'offset')
-      ).map((message) => ({
-        offset: message?.offset || 0,
-        partition: message?.partition || 0,
-      }));
-
-      const nextSeekTo = compact(
-        map(
-          groupBy(concat(selectedPartitions, messageUniqs), 'partition'),
-          (v) => maxBy(v, 'offset')
-        )
-      )
-        .map(({ offset, partition }) => {
-          const offsetQuery = isBackward ? offset : offset + 1;
-
-          return `${partition}::${offsetQuery}`;
-        })
-        .join(',');
-
-      searchParams.set('seekTo', nextSeekTo);
-
-      history.push({
-        search: `?${searchParams.toString()}`,
-      });
-    }
-  };
-
   return (
-    <>
-      <Table isFullwidth>
-        <thead>
+    <Table isFullwidth>
+      <thead>
+        <tr>
+          <TableHeaderCell> </TableHeaderCell>
+          <TableHeaderCell title="Offset" />
+          <TableHeaderCell title="Partition" />
+          <TableHeaderCell title="Timestamp" />
+          <TableHeaderCell title="Key" />
+          <TableHeaderCell title="Content" />
+          <TableHeaderCell> </TableHeaderCell>
+        </tr>
+      </thead>
+      <tbody>
+        {messages.map((message: TopicMessage) => (
+          <Message
+            key={[
+              message.offset,
+              message.timestamp,
+              message.key,
+              message.partition,
+            ].join('-')}
+            message={message}
+          />
+        ))}
+        {isFetching && isLive && !messages.length && (
+          <tr>
+            <td colSpan={10}>
+              <PageLoader />
+            </td>
+          </tr>
+        )}
+        {messages.length === 0 && !isFetching && (
           <tr>
-            <TableHeaderCell> </TableHeaderCell>
-            <TableHeaderCell title="Offset" />
-            <TableHeaderCell title="Partition" />
-            <TableHeaderCell title="Timestamp" />
-            <TableHeaderCell title="Key" />
-            <TableHeaderCell title="Content" />
-            <TableHeaderCell> </TableHeaderCell>
+            <td colSpan={10}>No messages found</td>
           </tr>
-        </thead>
-        <tbody>
-          {messages.map((message: TopicMessage) => (
-            <Message
-              key={[
-                message.offset,
-                message.timestamp,
-                message.key,
-                message.partition,
-              ].join('-')}
-              message={message}
-            />
-          ))}
-          {isFetching && isLive && !messages.length && (
-            <tr>
-              <td colSpan={10}>
-                <PageLoader />
-              </td>
-            </tr>
-          )}
-          {messages.length === 0 && !isFetching && (
-            <tr>
-              <td colSpan={10}>No messages found</td>
-            </tr>
-          )}
-        </tbody>
-      </Table>
-      {!isLive && (
-        <MessagesPaginationWrapperStyled>
-          <S.PaginationButton onClick={handleNextClick}>
-            Next
-          </S.PaginationButton>
-        </MessagesPaginationWrapperStyled>
-      )}
-    </>
+        )}
+      </tbody>
+    </Table>
   );
 };
 
diff --git a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/__test__/MessagesTable.spec.tsx b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/__test__/MessagesTable.spec.tsx
index 351a55f5f03..e3b09f5b182 100644
--- a/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/__test__/MessagesTable.spec.tsx
+++ b/kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/__test__/MessagesTable.spec.tsx
@@ -5,7 +5,6 @@ import MessagesTable from 'components/Topics/Topic/Details/Messages/MessagesTabl
 import { Router } from 'react-router-dom';
 import { createMemoryHistory, MemoryHistory } from 'history';
 import { SeekDirection, SeekType, TopicMessage } from 'generated-sources';
-import userEvent from '@testing-library/user-event';
 import TopicMessagesContext, {
   ContextProps,
 } from 'components/contexts/TopicMessagesContext';
@@ -71,13 +70,6 @@ describe('MessagesTable', () => {
     it('should check the if no elements is rendered in the table', () => {
       expect(screen.getByText(/No messages found/i)).toBeInTheDocument();
     });
-
-    it('should check if next button exist and check the click after next click', () => {
-      const nextBtnElement = screen.getByText(/next/i);
-      expect(nextBtnElement).toBeInTheDocument();
-      userEvent.click(nextBtnElement);
-      expect(screen.getByText(/No messages found/i)).toBeInTheDocument();
-    });
   });
 
   describe('Custom Setup with different props value', () => {
@@ -90,44 +82,6 @@ describe('MessagesTable', () => {
       setUpComponent(searchParams, { ...contextValue, isLive: true }, [], true);
       expect(screen.getByRole('progressbar')).toBeInTheDocument();
     });
-
-    it('should check the seekTo parameter in the url if no seekTo is found should noy change the history', () => {
-      const customSearchParam = new URLSearchParams(searchParamsValue);
-
-      const mockedHistory = createMemoryHistory({
-        initialEntries: [customSearchParam.toString()],
-      });
-      jest.spyOn(mockedHistory, 'push');
-
-      setUpComponent(customSearchParam, contextValue, [], false, mockedHistory);
-
-      userEvent.click(screen.getByRole('button', { name: 'Next' }));
-      expect(mockedHistory.push).toHaveBeenCalledWith({
-        search: searchParamsValue.replace(seekToResult, '&seekTo=0%3A%3A1'),
-      });
-    });
-
-    it('should check the seekTo parameter in the url if no seekTo is found should change the history', () => {
-      const customSearchParam = new URLSearchParams(
-        searchParamsValue.replace(seekToResult, '')
-      );
-
-      const mockedHistory = createMemoryHistory({
-        initialEntries: [customSearchParam.toString()],
-      });
-      jest.spyOn(mockedHistory, 'push');
-
-      setUpComponent(
-        customSearchParam,
-        { ...contextValue, searchParams: customSearchParam },
-        [],
-        false,
-        mockedHistory
-      );
-
-      userEvent.click(screen.getByRole('button', { name: 'Next' }));
-      expect(mockedHistory.push).not.toHaveBeenCalled();
-    });
   });
 
   describe('should render Messages table with data', () => {
diff --git a/kafka-ui-react-app/src/components/Version/Version.tsx b/kafka-ui-react-app/src/components/Version/Version.tsx
index 39ecc5227e2..ecda8f4a6ee 100644
--- a/kafka-ui-react-app/src/components/Version/Version.tsx
+++ b/kafka-ui-react-app/src/components/Version/Version.tsx
@@ -29,7 +29,6 @@ const Version: React.FC<VesionProps> = ({ tag, commit }) => {
   }, [tag]);
 
   const { outdated, latestTag } = latestVersionInfo;
-
   return (
     <S.Wrapper>
       <S.CurrentVersion>{tag}</S.CurrentVersion>
diff --git a/kafka-ui-react-app/src/lib/constants.ts b/kafka-ui-react-app/src/lib/constants.ts
index 1366db367a2..ba70329e7bb 100644
--- a/kafka-ui-react-app/src/lib/constants.ts
+++ b/kafka-ui-react-app/src/lib/constants.ts
@@ -16,7 +16,7 @@ export const BASE_PARAMS: ConfigurationParameters = {
 };
 
 export const TOPIC_NAME_VALIDATION_PATTERN = /^[.,A-Za-z0-9_-]+$/;
-export const SCHEMA_NAME_VALIDATION_PATTERN = /^[.,A-Za-z0-9_-]+$/;
+export const SCHEMA_NAME_VALIDATION_PATTERN = /^[.,A-Za-z0-9_/-]+$/;
 
 export const TOPIC_CUSTOM_PARAMS_PREFIX = 'customParams';
 export const TOPIC_CUSTOM_PARAMS: Record<string, string> = {


Test patch: