Преглед изворни кода

Issues/1740 live tailing order (#1824)

* fixing Message addition order during Live tailing

* fixing Message addition order during Live tailing adding tests suites

* minor changes in the function name for prepending addTopics during live mode

* delete minor code repetition

Co-authored-by: Roman Zabaluev <rzabaluev@provectus.com>
Mgrdich пре 3 година
родитељ
комит
b4e52afbdb

+ 9 - 4
kafka-ui-react-app/src/components/Topics/Topic/Details/Messages/Filters/Filters.tsx

@@ -1,6 +1,7 @@
 import 'react-datepicker/dist/react-datepicker.css';
 import 'react-datepicker/dist/react-datepicker.css';
 
 
 import {
 import {
+  MessageFilterType,
   Partition,
   Partition,
   SeekDirection,
   SeekDirection,
   SeekType,
   SeekType,
@@ -8,7 +9,6 @@ import {
   TopicMessageConsuming,
   TopicMessageConsuming,
   TopicMessageEvent,
   TopicMessageEvent,
   TopicMessageEventTypeEnum,
   TopicMessageEventTypeEnum,
-  MessageFilterType,
 } from 'generated-sources';
 } from 'generated-sources';
 import React, { useContext } from 'react';
 import React, { useContext } from 'react';
 import { omitBy } from 'lodash';
 import { omitBy } from 'lodash';
@@ -17,7 +17,7 @@ import DatePicker from 'react-datepicker';
 import MultiSelect from 'components/common/MultiSelect/MultiSelect.styled';
 import MultiSelect from 'components/common/MultiSelect/MultiSelect.styled';
 import { Option } from 'react-multi-select-component/dist/lib/interfaces';
 import { Option } from 'react-multi-select-component/dist/lib/interfaces';
 import BytesFormatted from 'components/common/BytesFormatted/BytesFormatted';
 import BytesFormatted from 'components/common/BytesFormatted/BytesFormatted';
-import { TopicName, ClusterName } from 'redux/interfaces';
+import { ClusterName, TopicName } from 'redux/interfaces';
 import { BASE_PARAMS } from 'lib/constants';
 import { BASE_PARAMS } from 'lib/constants';
 import Input from 'components/common/Input/Input';
 import Input from 'components/common/Input/Input';
 import Select from 'components/common/Select/Select';
 import Select from 'components/common/Select/Select';
@@ -45,7 +45,7 @@ export interface FiltersProps {
   partitions: Partition[];
   partitions: Partition[];
   meta: TopicMessageConsuming;
   meta: TopicMessageConsuming;
   isFetching: boolean;
   isFetching: boolean;
-  addMessage(message: TopicMessage): void;
+  addMessage(content: { message: TopicMessage; prepend: boolean }): void;
   resetMessages(): void;
   resetMessages(): void;
   updatePhase(phase: string): void;
   updatePhase(phase: string): void;
   updateMeta(meta: TopicMessageConsuming): void;
   updateMeta(meta: TopicMessageConsuming): void;
@@ -304,7 +304,12 @@ const Filters: React.FC<FiltersProps> = ({
 
 
         switch (type) {
         switch (type) {
           case TopicMessageEventTypeEnum.MESSAGE:
           case TopicMessageEventTypeEnum.MESSAGE:
-            if (message) addMessage(message);
+            if (message) {
+              addMessage({
+                message,
+                prepend: isLive,
+              });
+            }
             break;
             break;
           case TopicMessageEventTypeEnum.PHASE:
           case TopicMessageEventTypeEnum.PHASE:
             if (phase?.name) updatePhase(phase.name);
             if (phase?.name) updatePhase(phase.name);

+ 8 - 6
kafka-ui-react-app/src/redux/actions/__test__/actions.spec.ts

@@ -68,7 +68,7 @@ describe('Actions', () => {
   });
   });
 
 
   describe('setTopicsSearchAction', () => {
   describe('setTopicsSearchAction', () => {
-    it('creartes SET_TOPICS_SEARCH', () => {
+    it('creates SET_TOPICS_SEARCH', () => {
       expect(actions.setTopicsSearchAction('test')).toEqual({
       expect(actions.setTopicsSearchAction('test')).toEqual({
         type: 'SET_TOPICS_SEARCH',
         type: 'SET_TOPICS_SEARCH',
         payload: 'test',
         payload: 'test',
@@ -77,7 +77,7 @@ describe('Actions', () => {
   });
   });
 
 
   describe('setTopicsOrderByAction', () => {
   describe('setTopicsOrderByAction', () => {
-    it('creartes SET_TOPICS_ORDER_BY', () => {
+    it('creates SET_TOPICS_ORDER_BY', () => {
       expect(actions.setTopicsOrderByAction(TopicColumnsToSort.NAME)).toEqual({
       expect(actions.setTopicsOrderByAction(TopicColumnsToSort.NAME)).toEqual({
         type: 'SET_TOPICS_ORDER_BY',
         type: 'SET_TOPICS_ORDER_BY',
         payload: TopicColumnsToSort.NAME,
         payload: TopicColumnsToSort.NAME,
@@ -87,10 +87,12 @@ describe('Actions', () => {
 
 
   describe('topic messages', () => {
   describe('topic messages', () => {
     it('creates ADD_TOPIC_MESSAGE', () => {
     it('creates ADD_TOPIC_MESSAGE', () => {
-      expect(actions.addTopicMessage(topicMessagePayload)).toEqual({
-        type: 'ADD_TOPIC_MESSAGE',
-        payload: topicMessagePayload,
-      });
+      expect(actions.addTopicMessage({ message: topicMessagePayload })).toEqual(
+        {
+          type: 'ADD_TOPIC_MESSAGE',
+          payload: { message: topicMessagePayload },
+        }
+      );
     });
     });
 
 
     it('creates RESET_TOPIC_MESSAGES', () => {
     it('creates RESET_TOPIC_MESSAGES', () => {

+ 4 - 2
kafka-ui-react-app/src/redux/actions/actions.ts

@@ -161,8 +161,10 @@ export const fetchTopicConsumerGroupsAction = createAsyncAction(
   'GET_TOPIC_CONSUMER_GROUPS__FAILURE'
   'GET_TOPIC_CONSUMER_GROUPS__FAILURE'
 )<undefined, TopicsState, undefined>();
 )<undefined, TopicsState, undefined>();
 
 
-export const addTopicMessage =
-  createAction('ADD_TOPIC_MESSAGE')<TopicMessage>();
+export const addTopicMessage = createAction('ADD_TOPIC_MESSAGE')<{
+  message: TopicMessage;
+  prepend?: boolean;
+}>();
 
 
 export const resetTopicMessages = createAction('RESET_TOPIC_MESSAGES')();
 export const resetTopicMessages = createAction('RESET_TOPIC_MESSAGES')();
 
 

+ 6 - 0
kafka-ui-react-app/src/redux/reducers/topicMessages/__test__/fixtures.ts

@@ -15,6 +15,12 @@ export const topicMessagePayload: TopicMessage = {
     '{"host":"schemaregistry1","port":8085,"master_eligibility":true,"scheme":"http","version":1}',
     '{"host":"schemaregistry1","port":8085,"master_eligibility":true,"scheme":"http","version":1}',
 };
 };
 
 
+export const topicMessagePayloadV2: TopicMessage = {
+  ...topicMessagePayload,
+  partition: 28,
+  offset: 88,
+};
+
 export const topicMessagesMetaPayload: TopicMessageConsuming = {
 export const topicMessagesMetaPayload: TopicMessageConsuming = {
   bytesConsumed: 1830,
   bytesConsumed: 1830,
   elapsedMs: 440,
   elapsedMs: 440,

+ 46 - 3
kafka-ui-react-app/src/redux/reducers/topicMessages/__test__/reducer.spec.ts

@@ -6,16 +6,59 @@ import {
 } from 'redux/actions';
 } from 'redux/actions';
 import reducer from 'redux/reducers/topicMessages/reducer';
 import reducer from 'redux/reducers/topicMessages/reducer';
 
 
-import { topicMessagePayload, topicMessagesMetaPayload } from './fixtures';
+import {
+  topicMessagePayload,
+  topicMessagePayloadV2,
+  topicMessagesMetaPayload,
+} from './fixtures';
 
 
 describe('TopicMessages reducer', () => {
 describe('TopicMessages reducer', () => {
   it('Adds new message', () => {
   it('Adds new message', () => {
-    const state = reducer(undefined, addTopicMessage(topicMessagePayload));
+    const state = reducer(
+      undefined,
+      addTopicMessage({ message: topicMessagePayload })
+    );
     expect(state.messages.length).toEqual(1);
     expect(state.messages.length).toEqual(1);
     expect(state).toMatchSnapshot();
     expect(state).toMatchSnapshot();
   });
   });
+
+  it('Adds new message with live tailing one', () => {
+    const state = reducer(
+      undefined,
+      addTopicMessage({ message: topicMessagePayload })
+    );
+    const modifiedState = reducer(
+      state,
+      addTopicMessage({ message: topicMessagePayloadV2, prepend: true })
+    );
+    expect(modifiedState.messages.length).toEqual(2);
+    expect(modifiedState.messages).toEqual([
+      topicMessagePayloadV2,
+      topicMessagePayload,
+    ]);
+  });
+
+  it('Adds new message with live tailing off', () => {
+    const state = reducer(
+      undefined,
+      addTopicMessage({ message: topicMessagePayload })
+    );
+    const modifiedState = reducer(
+      state,
+      addTopicMessage({ message: topicMessagePayloadV2 })
+    );
+    expect(modifiedState.messages.length).toEqual(2);
+    expect(modifiedState.messages).toEqual([
+      topicMessagePayload,
+      topicMessagePayloadV2,
+    ]);
+  });
+
   it('Clears messages', () => {
   it('Clears messages', () => {
-    const state = reducer(undefined, addTopicMessage(topicMessagePayload));
+    const state = reducer(
+      undefined,
+      addTopicMessage({ message: topicMessagePayload })
+    );
     expect(state.messages.length).toEqual(1);
     expect(state.messages.length).toEqual(1);
 
 
     const newState = reducer(state, resetTopicMessages());
     const newState = reducer(state, resetTopicMessages());

+ 1 - 1
kafka-ui-react-app/src/redux/reducers/topicMessages/__test__/selectors.spec.ts

@@ -28,7 +28,7 @@ describe('TopicMessages selectors', () => {
 
 
   describe('state', () => {
   describe('state', () => {
     beforeAll(() => {
     beforeAll(() => {
-      store.dispatch(addTopicMessage(topicMessagePayload));
+      store.dispatch(addTopicMessage({ message: topicMessagePayload }));
       store.dispatch(updateTopicMessagesPhase('consuming'));
       store.dispatch(updateTopicMessagesPhase('consuming'));
       store.dispatch(updateTopicMessagesMeta(topicMessagesMetaPayload));
       store.dispatch(updateTopicMessagesMeta(topicMessagesMetaPayload));
     });
     });

+ 6 - 1
kafka-ui-react-app/src/redux/reducers/topicMessages/reducer.ts

@@ -1,6 +1,7 @@
 import { Action, TopicMessagesState } from 'redux/interfaces';
 import { Action, TopicMessagesState } from 'redux/interfaces';
 import { getType } from 'typesafe-actions';
 import { getType } from 'typesafe-actions';
 import * as actions from 'redux/actions';
 import * as actions from 'redux/actions';
+import { TopicMessage } from 'generated-sources';
 
 
 export const initialState: TopicMessagesState = {
 export const initialState: TopicMessagesState = {
   messages: [],
   messages: [],
@@ -17,9 +18,13 @@ export const initialState: TopicMessagesState = {
 const reducer = (state = initialState, action: Action): TopicMessagesState => {
 const reducer = (state = initialState, action: Action): TopicMessagesState => {
   switch (action.type) {
   switch (action.type) {
     case getType(actions.addTopicMessage): {
     case getType(actions.addTopicMessage): {
+      const messages: TopicMessage[] = action.payload.prepend
+        ? [action.payload.message, ...state.messages]
+        : [...state.messages, action.payload.message];
+
       return {
       return {
         ...state,
         ...state,
-        messages: [action.payload, ...state.messages],
+        messages,
       };
       };
     }
     }
     case getType(actions.resetTopicMessages):
     case getType(actions.resetTopicMessages):