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>
This commit is contained in:
Mgrdich 2022-04-14 20:24:58 +04:00 committed by GitHub
parent ee09fc73b6
commit b4e52afbdb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 80 additions and 17 deletions

View file

@ -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);

View file

@ -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({ expect(actions.addTopicMessage({ message: topicMessagePayload })).toEqual(
{
type: 'ADD_TOPIC_MESSAGE', type: 'ADD_TOPIC_MESSAGE',
payload: topicMessagePayload, payload: { message: topicMessagePayload },
}); }
);
}); });
it('creates RESET_TOPIC_MESSAGES', () => { it('creates RESET_TOPIC_MESSAGES', () => {

View file

@ -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 = export const addTopicMessage = createAction('ADD_TOPIC_MESSAGE')<{
createAction('ADD_TOPIC_MESSAGE')<TopicMessage>(); message: TopicMessage;
prepend?: boolean;
}>();
export const resetTopicMessages = createAction('RESET_TOPIC_MESSAGES')(); export const resetTopicMessages = createAction('RESET_TOPIC_MESSAGES')();

View file

@ -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,

View file

@ -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());

View file

@ -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));
}); });

View file

@ -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):