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:
parent
ee09fc73b6
commit
b4e52afbdb
7 changed files with 80 additions and 17 deletions
|
@ -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);
|
||||||
|
|
|
@ -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', () => {
|
||||||
|
|
|
@ -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')();
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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));
|
||||||
});
|
});
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Add table
Reference in a new issue