Skip to content

FE: Messages: Implement messages export #740

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions frontend/src/components/Topics/Topic/Messages/MessagesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import * as S from 'components/common/NewTable/Table.styled';
import { usePaginateTopics, useIsLiveMode } from 'lib/hooks/useMessagesFilters';
import { useMessageFiltersStore } from 'lib/hooks/useMessageFiltersStore';
import useDataSaver from 'lib/hooks/useDataSaver';
import Select, { SelectOption } from 'components/common/Select/Select';

import PreviewModal from './PreviewModal';
import Message, { PreviewFilter } from './Message';
Expand All @@ -16,6 +18,33 @@
isFetching: boolean;
}

interface MessageData {
Value: string | undefined;
Offset: number;
Key: string | undefined;
Partition: number;
Headers: { [key: string]: string | undefined; } | undefined;

Check warning on line 26 in frontend/src/components/Topics/Topic/Messages/MessagesTable.tsx

View workflow job for this annotation

GitHub Actions / build / build-and-test

Delete `;`
Timestamp: Date;
}

type DownloadFormat = 'json' | 'csv';

function padCurrentDateTimeString(): string {
const now: Date = new Date();

const year: string = now.getFullYear().toString();
const month: string = (now.getMonth() + 1).toString().padStart(2, '0');
const day: string = now.getDate().toString().padStart(2, '0');
const hours: string = now.getHours().toString().padStart(2, '0');
const minutes: string = now.getMinutes().toString().padStart(2, '0');
const seconds: string = now.getSeconds().toString().padStart(2, '0');

const dateTimeString: string = `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`;

return `_${dateTimeString}`;
}


Check warning on line 47 in frontend/src/components/Topics/Topic/Messages/MessagesTable.tsx

View workflow job for this annotation

GitHub Actions / build / build-and-test

Delete `⏎`
const MessagesTable: React.FC<MessagesTableProps> = ({
messages,
isFetching,
Expand All @@ -28,8 +57,79 @@
const nextCursor = useMessageFiltersStore((state) => state.nextCursor);
const isLive = useIsLiveMode();

const [selectedFormat, setSelectedFormat] = useState<DownloadFormat>('json');

const formatOptions: SelectOption<DownloadFormat>[] = [
{ label: 'JSON', value: 'json' },
{ label: 'CSV', value: 'csv' }

Check warning on line 64 in frontend/src/components/Topics/Topic/Messages/MessagesTable.tsx

View workflow job for this annotation

GitHub Actions / build / build-and-test

Insert `,`
];

const handleFormatSelect = (format: DownloadFormat) => {
setSelectedFormat(format);
};

const handleDownload = () => {

Check warning on line 72 in frontend/src/components/Topics/Topic/Messages/MessagesTable.tsx

View workflow job for this annotation

GitHub Actions / build / build-and-test

Replace `⏎··const·savedMessagesJson:·MessageData[]·=·messages.map(message` with `····const·savedMessagesJson:·MessageData[]·=·messages.map((message)`
const savedMessagesJson: MessageData[] = messages.map(message => ({
Value: message.content,

Check warning on line 74 in frontend/src/components/Topics/Topic/Messages/MessagesTable.tsx

View workflow job for this annotation

GitHub Actions / build / build-and-test

Replace `····` with `······`
Offset: message.offset,

Check warning on line 75 in frontend/src/components/Topics/Topic/Messages/MessagesTable.tsx

View workflow job for this annotation

GitHub Actions / build / build-and-test

Insert `··`
Key: message.key,

Check warning on line 76 in frontend/src/components/Topics/Topic/Messages/MessagesTable.tsx

View workflow job for this annotation

GitHub Actions / build / build-and-test

Replace `····` with `······`
Partition: message.partition,

Check warning on line 77 in frontend/src/components/Topics/Topic/Messages/MessagesTable.tsx

View workflow job for this annotation

GitHub Actions / build / build-and-test

Insert `··`
Headers: message.headers,

Check warning on line 78 in frontend/src/components/Topics/Topic/Messages/MessagesTable.tsx

View workflow job for this annotation

GitHub Actions / build / build-and-test

Replace `····` with `······`
Timestamp: message.timestamp,

Check warning on line 79 in frontend/src/components/Topics/Topic/Messages/MessagesTable.tsx

View workflow job for this annotation

GitHub Actions / build / build-and-test

Insert `··`
}));

const convertToCSV = (messages: MessageData[]) => {

Check failure on line 82 in frontend/src/components/Topics/Topic/Messages/MessagesTable.tsx

View workflow job for this annotation

GitHub Actions / build / build-and-test

'messages' is already declared in the upper scope on line 49 column 3
const headers = ['Value', 'Offset', 'Key', 'Partition', 'Headers', 'Timestamp'] as const;

const rows = messages.map(msg =>
headers.map(header => {
const value = msg[header];
if (header === 'Headers') {
return JSON.stringify(value || {});
}
return String(value ?? '');
}).join(',')
);

return [headers.join(','), ...rows].join('\n');
};

const baseFileName = 'topic-messages'+padCurrentDateTimeString();

Check failure on line 98 in frontend/src/components/Topics/Topic/Messages/MessagesTable.tsx

View workflow job for this annotation

GitHub Actions / build / build-and-test

Unexpected string concatenation
const jsonSaver = useDataSaver(`${baseFileName}.json`, JSON.stringify(savedMessagesJson, null, '\t'));

Check failure on line 99 in frontend/src/components/Topics/Topic/Messages/MessagesTable.tsx

View workflow job for this annotation

GitHub Actions / build / build-and-test

React Hook "useDataSaver" is called in function "handleDownload" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use"
const csvSaver = useDataSaver(`${baseFileName}.csv`, convertToCSV(savedMessagesJson));

Check failure on line 100 in frontend/src/components/Topics/Topic/Messages/MessagesTable.tsx

View workflow job for this annotation

GitHub Actions / build / build-and-test

React Hook "useDataSaver" is called in function "handleDownload" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use"

if (selectedFormat === 'json') {
jsonSaver.saveFile();
} else {
csvSaver.saveFile();
}
};

return (
<div style={{ position: 'relative' }}>
<div style={{ display: 'flex', gap: '8px', marginLeft: '1rem', marginBottom: '1rem' }}>
<Select<DownloadFormat>
id="download-format"
name="download-format"
onChange={handleFormatSelect}
options={formatOptions}
value={selectedFormat}
minWidth="70px"
selectSize="M"
placeholder="Select format to download"
disabled={isFetching || messages.length === 0}
/>
<Button
disabled={isFetching || messages.length === 0}
buttonType="secondary"
buttonSize="M"
onClick={handleDownload}
>
Download All Messages
</Button>
</div>

{previewFor !== null && (
<PreviewModal
values={previewFor === 'key' ? keyFilters : contentFilters}
Expand Down
Loading