Browse Source

Reverse topic messages (#528)

* Add SeekDirection to the GET topic messages request

* Implement toggle for the direction of the messages
Alexander Krivonosov 4 years ago
parent
commit
53aec4d8c6

+ 46 - 7
kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Messages.tsx

@@ -1,6 +1,6 @@
 import 'react-datepicker/dist/react-datepicker.css';
 import React, { useCallback, useEffect, useRef } from 'react';
-import { groupBy, map, concat, maxBy } from 'lodash';
+import { groupBy, map, concat, maxBy, minBy } from 'lodash';
 import DatePicker from 'react-datepicker';
 import MultiSelect from 'react-multi-select-component';
 import { Option } from 'react-multi-select-component/dist/lib/interfaces';
@@ -10,7 +10,12 @@ import {
   TopicMessageQueryParams,
   TopicName,
 } from 'redux/interfaces';
-import { TopicMessage, Partition, SeekType } from 'generated-sources';
+import {
+  TopicMessage,
+  Partition,
+  SeekType,
+  SeekDirection,
+} from 'generated-sources';
 import PageLoader from 'components/common/PageLoader/PageLoader';
 
 import MessagesTable from './MessagesTable';
@@ -50,9 +55,8 @@ const Messages: React.FC<Props> = ({
   fetchTopicMessages,
 }) => {
   const [searchQuery, setSearchQuery] = React.useState<string>('');
-  const [searchTimestamp, setSearchTimestamp] = React.useState<Date | null>(
-    null
-  );
+  const [searchTimestamp, setSearchTimestamp] =
+    React.useState<Date | null>(null);
   const [filterProps, setFilterProps] = React.useState<FilterProps[]>([]);
   const [selectedSeekType, setSelectedSeekType] = React.useState<SeekType>(
     SeekType.OFFSET
@@ -72,6 +76,8 @@ const Messages: React.FC<Props> = ({
       setQueryParams({ ...queryParams, ...query }),
     1000
   );
+  const [selectedSeekDirection, setSelectedSeekDirection] =
+    React.useState<SeekDirection>(SeekDirection.FORWARD);
 
   const prevSearchTimestamp = usePrevious(searchTimestamp);
 
@@ -82,7 +88,10 @@ const Messages: React.FC<Props> = ({
     }));
     const messageUniqs: FilterProps[] = map(
       groupBy(messages, 'partition'),
-      (v) => maxBy(v, 'offset')
+      (v) =>
+        selectedSeekDirection === SeekDirection.FORWARD
+          ? maxBy(v, 'offset')
+          : minBy(v, 'offset')
     ).map((v) => ({
       offset: v ? v.offset : 0,
       partition: v ? v.partition : 0,
@@ -195,6 +204,23 @@ const Messages: React.FC<Props> = ({
     );
   };
 
+  const toggleSeekDirection = () => {
+    const nextSeekDirectionValue =
+      selectedSeekDirection === SeekDirection.FORWARD
+        ? SeekDirection.BACKWARD
+        : SeekDirection.FORWARD;
+    setSelectedSeekDirection(nextSeekDirectionValue);
+
+    debouncedCallback({
+      seekDirection: nextSeekDirectionValue,
+    });
+
+    fetchTopicMessages(clusterName, topicName, {
+      ...queryParams,
+      seekDirection: nextSeekDirectionValue,
+    });
+  };
+
   if (!isFetched) {
     return <PageLoader />;
   }
@@ -271,7 +297,20 @@ const Messages: React.FC<Props> = ({
         </div>
       </div>
       <div className="columns">
-        <div className="column is-full" style={{ textAlign: 'right' }}>
+        <div className="column is-half">
+          <div className="field">
+            <input
+              id="switchRoundedDefault"
+              type="checkbox"
+              name="switchRoundedDefault"
+              className="switch is-rounded"
+              checked={selectedSeekDirection === SeekDirection.BACKWARD}
+              onChange={toggleSeekDirection}
+            />
+            <label htmlFor="switchRoundedDefault">Newest first</label>
+          </div>
+        </div>
+        <div className="column is-half" style={{ textAlign: 'right' }}>
           <input
             type="submit"
             className="button is-primary"

+ 15 - 0
kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/__test__/Messages.spec.tsx

@@ -149,5 +149,20 @@ describe('Messages', () => {
         expect(mockedfetchTopicMessages).toHaveBeenCalled();
       });
     });
+
+    describe('Seek Direction', () => {
+      it('fetches topic messages', () => {
+        const mockedfetchTopicMessages = jest.fn();
+        const wrapper = mount(
+          setupWrapper({ fetchTopicMessages: mockedfetchTopicMessages })
+        );
+
+        wrapper.find('input[type="checkbox"]').simulate('change');
+        expect(mockedfetchTopicMessages).toHaveBeenCalled();
+
+        wrapper.find('input[type="checkbox"]').simulate('change');
+        expect(mockedfetchTopicMessages).toHaveBeenCalled();
+      });
+    });
   });
 });

+ 1 - 0
kafka-ui-react-app/src/redux/interfaces/topic.ts

@@ -31,6 +31,7 @@ export interface TopicMessageQueryParams {
   limit: GetTopicMessagesRequest['limit'];
   seekType: GetTopicMessagesRequest['seekType'];
   seekTo: GetTopicMessagesRequest['seekTo'];
+  seekDirection: GetTopicMessagesRequest['seekDirection'];
 }
 
 export interface TopicFormCustomParams {