Message.tsx 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import get from 'lodash/get';
  2. import React from 'react';
  3. import styled from 'styled-components';
  4. import useDataSaver from 'lib/hooks/useDataSaver';
  5. import { TopicMessage } from 'generated-sources';
  6. import { useTimeFormat } from 'lib/hooks/useTimeFormat';
  7. import MessageToggleIcon from 'components/common/Icons/MessageToggleIcon';
  8. import IconButtonWrapper from 'components/common/Icons/IconButtonWrapper';
  9. import { Dropdown, DropdownItem } from 'components/common/Dropdown';
  10. import MessageContent from './MessageContent/MessageContent';
  11. import * as S from './MessageContent/MessageContent.styled';
  12. const StyledDataCell = styled.td`
  13. overflow: hidden;
  14. white-space: nowrap;
  15. text-overflow: ellipsis;
  16. max-width: 350px;
  17. min-width: 350px;
  18. `;
  19. const ClickableRow = styled.tr`
  20. cursor: pointer;
  21. `;
  22. export interface PreviewFilter {
  23. field: string;
  24. path: string;
  25. }
  26. export interface Props {
  27. keyFilters: PreviewFilter[];
  28. contentFilters: PreviewFilter[];
  29. message: TopicMessage;
  30. }
  31. const Message: React.FC<Props> = ({
  32. message: {
  33. timestamp,
  34. timestampType,
  35. offset,
  36. key,
  37. partition,
  38. content,
  39. valueFormat,
  40. keyFormat,
  41. headers,
  42. },
  43. keyFilters,
  44. contentFilters,
  45. }) => {
  46. const [isOpen, setIsOpen] = React.useState(false);
  47. const savedMessageJson = {
  48. Content: content,
  49. Offset: offset,
  50. Key: key,
  51. Partition: partition,
  52. Headers: headers,
  53. Timestamp: timestamp,
  54. };
  55. const formatTimestamp = useTimeFormat();
  56. const savedMessage = JSON.stringify(savedMessageJson, null, '\t');
  57. const { copyToClipboard, saveFile } = useDataSaver(
  58. 'topic-message',
  59. savedMessage || ''
  60. );
  61. const toggleIsOpen = () => setIsOpen(!isOpen);
  62. const [vEllipsisOpen, setVEllipsisOpen] = React.useState(false);
  63. const getParsedJson = (jsonValue: string) => {
  64. try {
  65. return JSON.parse(jsonValue);
  66. } catch (e) {
  67. return {};
  68. }
  69. };
  70. const renderFilteredJson = (
  71. jsonValue?: string,
  72. filters?: PreviewFilter[]
  73. ) => {
  74. if (!filters?.length || !jsonValue) return jsonValue;
  75. const parsedJson = getParsedJson(jsonValue);
  76. return (
  77. <>
  78. {filters.map((item) => (
  79. <div>
  80. {item.field}: {get(parsedJson, item.path)}
  81. </div>
  82. ))}
  83. </>
  84. );
  85. };
  86. return (
  87. <>
  88. <ClickableRow
  89. onMouseEnter={() => setVEllipsisOpen(true)}
  90. onMouseLeave={() => setVEllipsisOpen(false)}
  91. onClick={toggleIsOpen}
  92. >
  93. <td>
  94. <IconButtonWrapper aria-hidden>
  95. <MessageToggleIcon isOpen={isOpen} />
  96. </IconButtonWrapper>
  97. </td>
  98. <td>{offset}</td>
  99. <td>{partition}</td>
  100. <td>
  101. <div>{formatTimestamp(timestamp)}</div>
  102. </td>
  103. <StyledDataCell title={key}>
  104. {renderFilteredJson(key, keyFilters)}
  105. </StyledDataCell>
  106. <StyledDataCell>
  107. <S.Metadata>
  108. <S.MetadataValue>
  109. {renderFilteredJson(content, contentFilters)}
  110. </S.MetadataValue>
  111. </S.Metadata>
  112. </StyledDataCell>
  113. <td style={{ width: '5%' }}>
  114. {vEllipsisOpen && (
  115. <Dropdown>
  116. <DropdownItem onClick={copyToClipboard}>
  117. Copy to clipboard
  118. </DropdownItem>
  119. <DropdownItem onClick={saveFile}>Save as a file</DropdownItem>
  120. </Dropdown>
  121. )}
  122. </td>
  123. </ClickableRow>
  124. {isOpen && (
  125. <MessageContent
  126. messageKey={key}
  127. messageKeyFormat={keyFormat}
  128. messageContent={content}
  129. messageContentFormat={valueFormat}
  130. headers={headers}
  131. timestamp={timestamp}
  132. timestampType={timestampType}
  133. />
  134. )}
  135. </>
  136. );
  137. };
  138. export default Message;