Browse Source

Implement functionality for copying and downloading data

GneyHabub 4 năm trước cách đây
mục cha
commit
af8c300c78

+ 23 - 0
kafka-ui-react-app/src/components/App.scss

@@ -36,3 +36,26 @@ $navbar-width: 250px;
 .react-datepicker-popper {
   z-index: 30 !important;
 }
+
+.topic-message-button {
+  &::after {
+    content: attr(data-title);
+    position: absolute;
+    top: -140%;
+    z-index: 1;
+    background: #F5F5F5;
+    color: rgb(89, 89, 89);
+    border-radius: 5px;
+    font-size: 15px;
+    padding: 5px 10px;
+    opacity: 0;
+    pointer-events: none;
+    transition: .2s opacity;
+    transition-delay: 0s;
+  }
+
+  &:hover::after {
+    opacity: 1;
+    transition-delay: .5s;
+   }
+}

+ 67 - 10
kafka-ui-react-app/src/components/Topics/Details/Messages/MessageItem.tsx

@@ -15,15 +15,72 @@ const MessageItem: React.FC<MessageItemProp> = ({
   offset,
   timestamp,
   content,
-}) => (
-  <tr>
-    <td style={{ width: 200 }}>{format(timestamp, 'yyyy-MM-dd HH:mm:ss')}</td>
-    <td style={{ width: 150 }}>{offset}</td>
-    <td style={{ width: 100 }}>{partition}</td>
-    <td style={{ wordBreak: 'break-word' }}>
-      {content && <JSONViewer data={content as { [key: string]: string }} />}
-    </td>
-  </tr>
-);
+}) => {
+  const copyData = () => {
+    if (navigator.clipboard)
+      navigator.clipboard.writeText(JSON.stringify(content || {}));
+  };
+  const saveFile = () => {
+    let extension = 'json';
+    if (typeof content === 'string') {
+      try {
+        JSON.parse(content);
+      } catch (e) {
+        extension = 'txt';
+      }
+    }
+    const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent(
+      JSON.stringify(content || {})
+    )}`;
+    const downloadAnchorNode = document.createElement('a');
+    downloadAnchorNode.setAttribute('href', dataStr);
+    downloadAnchorNode.setAttribute(
+      'download',
+      `topic-message[${timestamp}].${extension}`
+    );
+    document.body.appendChild(downloadAnchorNode);
+    downloadAnchorNode.click();
+    downloadAnchorNode.remove();
+  };
+
+  const buttonStyle = {
+    height: '30px',
+  };
+  const buttonClasses = 'button is-link is-outlined topic-message-button';
+  return (
+    <tr>
+      <td style={{ width: 200 }}>{format(timestamp, 'yyyy-MM-dd HH:mm:ss')}</td>
+      <td style={{ width: 150 }}>{offset}</td>
+      <td style={{ width: 100 }}>{partition}</td>
+      <td style={{ wordBreak: 'break-word' }}>
+        {content && (
+          <div>
+            <div style={{ display: 'flex', justifyContent: 'center' }}>
+              <button
+                className={buttonClasses}
+                data-title="Copy the message to the clipboard"
+                type="button"
+                style={{ ...buttonStyle, marginRight: '5px' }}
+                onClick={copyData}
+              >
+                <i className="far fa-clipboard" />
+              </button>
+              <button
+                className={buttonClasses}
+                data-title="Download the message as a .json/.txt file"
+                type="button"
+                style={buttonStyle}
+                onClick={saveFile}
+              >
+                <i className="fas fa-file-download" />
+              </button>
+            </div>
+            <JSONViewer data={content as { [key: string]: string }} />
+          </div>
+        )}
+      </td>
+    </tr>
+  );
+};
 
 export default MessageItem;

+ 49 - 7
kafka-ui-react-app/src/components/Topics/Details/Messages/__test__/__snapshots__/MessageItem.spec.tsx.snap

@@ -36,14 +36,56 @@ exports[`MessageItem when content is defined matches snapshot 1`] = `
       }
     }
   >
-    <JSONViewer
-      data={
-        Object {
-          "foo": "bar",
-          "key": "val",
+    <div>
+      <div
+        style={
+          Object {
+            "display": "flex",
+            "justifyContent": "center",
+          }
         }
-      }
-    />
+      >
+        <button
+          className="button is-link is-outlined topic-message-button"
+          data-title="Copy the message to the clipboard"
+          onClick={[Function]}
+          style={
+            Object {
+              "height": "30px",
+              "marginRight": "5px",
+            }
+          }
+          type="button"
+        >
+          <i
+            className="far fa-clipboard"
+          />
+        </button>
+        <button
+          className="button is-link is-outlined topic-message-button"
+          data-title="Download the message as a .json/.txt file"
+          onClick={[Function]}
+          style={
+            Object {
+              "height": "30px",
+            }
+          }
+          type="button"
+        >
+          <i
+            className="fas fa-file-download"
+          />
+        </button>
+      </div>
+      <JSONViewer
+        data={
+          Object {
+            "foo": "bar",
+            "key": "val",
+          }
+        }
+      />
+    </div>
   </td>
 </tr>
 `;