Messages component refactoring (#174)

* ISSUE-169 Sort topics (#172)

* Messages Table component created

* Messages component refactored

* MessageItem component fixed

* MessageItem component updated

* MessageItem component refactored

Co-authored-by: German Osin <german.osin@gmail.com>
Co-authored-by: Oleg Shuralev <workshur@gmail.com>
This commit is contained in:
Guzel738 2021-02-05 16:53:41 +03:00 committed by GitHub
parent cc097e9327
commit 10a27ba60e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 138 additions and 93 deletions

View file

@ -0,0 +1,52 @@
import React from 'react';
import { format } from 'date-fns';
import JSONTree from 'react-json-tree';
import { TopicMessage } from 'generated-sources';
interface MessageItemProp {
partition: TopicMessage['partition'];
offset: TopicMessage['offset'];
timestamp: TopicMessage['timestamp'];
content: TopicMessage['content'];
}
const MessageItem: React.FC<MessageItemProp> = ({
partition,
offset,
timestamp,
content,
}) => (
<tr key="{timestamp}">
<td style={{ width: 200 }}>
{timestamp ? format(timestamp, 'yyyy-MM-dd HH:mm:ss') : null}
</td>
<td style={{ width: 150 }}>{offset}</td>
<td style={{ width: 100 }}>{partition}</td>
<td key="{content}" style={{ wordBreak: 'break-word' }}>
{content && (
<JSONTree
data={content}
hideRoot
invertTheme={false}
theme={{
tree: ({ style }) => ({
style: {
...style,
backgroundColor: undefined,
marginLeft: 0,
marginTop: 0,
},
}),
value: ({ style }) => ({
style: { ...style, marginLeft: 0 },
}),
base0D: '#3273dc',
base0B: '#363636',
}}
/>
)}
</td>
</tr>
);
export default MessageItem;

View file

@ -6,19 +6,15 @@ import {
} from 'redux/interfaces';
import { TopicMessage, Partition, SeekType } from 'generated-sources';
import PageLoader from 'components/common/PageLoader/PageLoader';
import { format } from 'date-fns';
import DatePicker from 'react-datepicker';
import JSONTree from 'react-json-tree';
import 'react-datepicker/dist/react-datepicker.css';
import CustomParamButton, {
CustomParamButtonType,
} from 'components/Topics/shared/Form/CustomParams/CustomParamButton';
import MultiSelect from 'react-multi-select-component';
import * as _ from 'lodash';
import { useDebouncedCallback } from 'use-debounce';
import { Option } from 'react-multi-select-component/dist/lib/interfaces';
import MessagesTable from './MessagesTable';
export interface Props {
clusterName: ClusterName;
@ -174,42 +170,6 @@ const Messages: React.FC<Props> = ({
fetchTopicMessages(clusterName, topicName, queryParams);
}, [clusterName, topicName, queryParams]);
const getFormattedDate = (date: Date) => {
if (!date) return null;
return format(date, 'yyyy-MM-dd HH:mm:ss');
};
const getMessageContentBody = (content: Record<string, unknown>) => {
try {
const contentObj =
typeof content !== 'object' ? JSON.parse(content) : content;
return (
<JSONTree
data={contentObj}
hideRoot
invertTheme={false}
theme={{
tree: ({ style }) => ({
style: {
...style,
backgroundColor: undefined,
marginLeft: 0,
marginTop: 0,
},
}),
value: ({ style }) => ({
style: { ...style, marginLeft: 0 },
}),
base0D: '#3273dc',
base0B: '#363636',
}}
/>
);
} catch (e) {
return content;
}
};
const onNext = (event: React.MouseEvent<HTMLButtonElement>) => {
event.preventDefault();
@ -236,52 +196,6 @@ const Messages: React.FC<Props> = ({
);
};
const getTopicMessagesTable = () => {
return messages.length > 0 ? (
<div>
<table className="table is-striped is-fullwidth">
<thead>
<tr>
<th>Timestamp</th>
<th>Offset</th>
<th>Partition</th>
<th>Content</th>
</tr>
</thead>
<tbody>
{messages.map((message) => (
<tr key={`${message.timestamp}${Math.random()}`}>
<td style={{ width: 200 }}>
{getFormattedDate(message.timestamp)}
</td>
<td style={{ width: 150 }}>{message.offset}</td>
<td style={{ width: 100 }}>{message.partition}</td>
<td key={Math.random()} style={{ wordBreak: 'break-word' }}>
{message.content &&
getMessageContentBody(
message.content as Record<string, unknown>
)}
</td>
</tr>
))}
</tbody>
</table>
<div className="columns">
<div className="column is-full">
<CustomParamButton
className="is-link is-pulled-right"
type={CustomParamButtonType.chevronRight}
onClick={onNext}
btnText="Next"
/>
</div>
</div>
</div>
) : (
<div>No messages at selected topic</div>
);
};
if (!isFetched) {
return <PageLoader isFullHeight={false} />;
}
@ -366,7 +280,7 @@ const Messages: React.FC<Props> = ({
/>
</div>
</div>
{getTopicMessagesTable()}
<MessagesTable messages={messages} onNext={onNext} />
</div>
);
};

View file

@ -0,0 +1,57 @@
import React from 'react';
import { TopicMessage } from 'generated-sources';
import CustomParamButton, {
CustomParamButtonType,
} from '../../shared/Form/CustomParams/CustomParamButton';
import MessageItem from './MessageItem';
interface MessagesTableProp {
messages: TopicMessage[];
onNext(event: React.MouseEvent<HTMLButtonElement>): void;
}
const MessagesTable: React.FC<MessagesTableProp> = ({ messages, onNext }) => {
if (!messages.length) {
return <div>No messages at selected topic</div>;
}
return (
<div>
<table className="table is-striped is-fullwidth">
<thead>
<tr>
<th>Timestamp</th>
<th>Offset</th>
<th>Partition</th>
<th>Content</th>
</tr>
</thead>
<tbody>
{messages.map(
({ partition, offset, timestamp, content }: TopicMessage) => (
<MessageItem
key={timestamp.toString()}
partition={partition}
offset={offset}
timestamp={timestamp}
content={content as Record<string, unknown>}
/>
)
)}
</tbody>
</table>
<div className="columns">
<div className="column is-full">
<CustomParamButton
className="is-link is-pulled-right"
type={CustomParamButtonType.chevronRight}
onClick={onNext}
btnText="Next"
/>
</div>
</div>
</div>
);
};
export default MessagesTable;

View file

@ -1,5 +1,5 @@
import { v4 } from 'uuid';
import { Topic } from 'generated-sources';
import { Topic, TopicMessage } from 'generated-sources';
import { Action, TopicsState } from 'redux/interfaces';
import ActionType from 'redux/actionType';
@ -41,6 +41,31 @@ const addToTopicList = (state: TopicsState, payload: Topic): TopicsState => {
return newState;
};
const transformTopicMessages = (
state: TopicsState,
messages: TopicMessage[]
): TopicsState => ({
...state,
messages: messages.map((mes) => {
const { content } = mes;
let parsedContent = content;
if (content) {
try {
parsedContent =
typeof content !== 'object' ? JSON.parse(content) : content;
} catch (_) {
// do nothing
}
}
return {
...mes,
content: parsedContent,
};
}),
});
const reducer = (state = initialState, action: Action): TopicsState => {
switch (action.type) {
case ActionType.GET_TOPICS__SUCCESS:
@ -57,10 +82,7 @@ const reducer = (state = initialState, action: Action): TopicsState => {
},
};
case ActionType.GET_TOPIC_MESSAGES__SUCCESS:
return {
...state,
messages: action.payload,
};
return transformTopicMessages(state, action.payload);
case ActionType.GET_TOPIC_CONFIG__SUCCESS:
return {
...state,