Ver código fonte

Refactor

Abstract dynamic button to a separate component;
Move buttons to the JSONViewer;
Move data-saving to a hook;
GneyHabub 4 anos atrás
pai
commit
f0b1e9c7d9

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

@@ -36,26 +36,3 @@ $navbar-width: 250px;
 .react-datepicker-popper {
 .react-datepicker-popper {
   z-index: 30 !important;
   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;
-   }
-}

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

@@ -15,72 +15,19 @@ const MessageItem: React.FC<MessageItemProp> = ({
   offset,
   offset,
   timestamp,
   timestamp,
   content,
   content,
-}) => {
-  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>
-  );
-};
+}) => (
+  <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>
+          <JSONViewer data={content as { [key: string]: string }} />
+        </div>
+      )}
+    </td>
+  </tr>
+);
 
 
 export default MessageItem;
 export default MessageItem;

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

@@ -37,46 +37,6 @@ exports[`MessageItem when content is defined matches snapshot 1`] = `
     }
     }
   >
   >
     <div>
     <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
       <JSONViewer
         data={
         data={
           Object {
           Object {

+ 44 - 0
kafka-ui-react-app/src/components/common/JSONViewer/DynamicButton.tsx

@@ -0,0 +1,44 @@
+import React from 'react';
+
+interface ButtonProps {
+  callback: () => void;
+  classes?: string;
+  title: string;
+  style?: { [key: string]: string | number };
+  text: {
+    default: string;
+    dynamic: string;
+  };
+}
+
+const DynamicButton: React.FC<ButtonProps> = ({
+  callback,
+  classes,
+  title,
+  style,
+  text,
+  children,
+}) => {
+  const [buttonText, setButtonText] = React.useState(text.default);
+  let timeout: number;
+  const clickHandler = () => {
+    callback();
+    setButtonText(text.dynamic);
+    timeout = window.setTimeout(() => setButtonText(text.default), 3000);
+  };
+  React.useEffect(() => () => window.clearTimeout(timeout), [callback]);
+  return (
+    <button
+      className={classes}
+      title={title}
+      type="button"
+      style={style}
+      onClick={clickHandler}
+    >
+      {children}
+      <span>{buttonText}</span>
+    </button>
+  );
+};
+
+export default DynamicButton;

+ 48 - 3
kafka-ui-react-app/src/components/common/JSONViewer/JSONViewer.tsx

@@ -1,6 +1,8 @@
 import React from 'react';
 import React from 'react';
 import JSONTree from 'react-json-tree';
 import JSONTree from 'react-json-tree';
+import useDataSaver from 'lib/hooks/useDataSaver';
 import theme from './themes/google';
 import theme from './themes/google';
+import DynamicButton from './DynamicButton';
 
 
 interface JSONViewerProps {
 interface JSONViewerProps {
   data: {
   data: {
@@ -8,8 +10,51 @@ interface JSONViewerProps {
   };
   };
 }
 }
 
 
-const JSONViewer: React.FC<JSONViewerProps> = ({ data }) => (
-  <JSONTree data={data} theme={theme} shouldExpandNode={() => true} hideRoot />
-);
+const JSONViewer: React.FC<JSONViewerProps> = ({ data }) => {
+  const { copyToClipboard, saveFile } = useDataSaver();
+  const copyButtonHandler = () => {
+    copyToClipboard(JSON.stringify(data));
+  };
+  const buttonClasses = 'button is-link is-outlined is-small is-centered';
+  return (
+    <div>
+      <div
+        className="field has-addons"
+        style={{
+          justifyContent: 'flex-end',
+        }}
+      >
+        <DynamicButton
+          callback={copyButtonHandler}
+          classes={buttonClasses}
+          title="Copy the message to the clipboard"
+          style={{ marginRight: '5px' }}
+          text={{ default: 'Copy', dynamic: 'Copied!' }}
+        >
+          <span className="icon">
+            <i className="far fa-clipboard" />
+          </span>
+        </DynamicButton>
+        <button
+          className={buttonClasses}
+          title="Download the message as a .json/.txt file"
+          type="button"
+          onClick={() => saveFile(JSON.stringify(data), `topic-message`)}
+        >
+          <span className="icon">
+            <i className="fas fa-file-download" />
+          </span>
+          <span>Save</span>
+        </button>
+      </div>
+      <JSONTree
+        data={data}
+        theme={theme}
+        shouldExpandNode={() => true}
+        hideRoot
+      />
+    </div>
+  );
+};
 
 
 export default JSONViewer;
 export default JSONViewer;

+ 27 - 0
kafka-ui-react-app/src/lib/hooks/useDataSaver.tsx

@@ -0,0 +1,27 @@
+const useDataSaver = () => {
+  const copyToClipboard = (content: string) => {
+    if (navigator.clipboard) navigator.clipboard.writeText(content);
+  };
+
+  const saveFile = (content: string, fileName: string) => {
+    let extension = 'json';
+    try {
+      JSON.parse(content);
+    } catch (e) {
+      extension = 'txt';
+    }
+    const dataStr = `data:text/json;charset=utf-8,${encodeURIComponent(
+      content
+    )}`;
+    const downloadAnchorNode = document.createElement('a');
+    downloadAnchorNode.setAttribute('href', dataStr);
+    downloadAnchorNode.setAttribute('download', `${fileName}.${extension}`);
+    document.body.appendChild(downloadAnchorNode);
+    downloadAnchorNode.click();
+    downloadAnchorNode.remove();
+  };
+
+  return { copyToClipboard, saveFile };
+};
+
+export default useDataSaver;