Message.tsx 4.0 KB

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