You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by bb...@apache.org on 2022/04/13 17:33:06 UTC

[airflow] branch main updated: Add a clipboard button to grid details (#22988)

This is an automated email from the ASF dual-hosted git repository.

bbovenzi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new 5ba2f0dcb6 Add a clipboard button to grid details (#22988)
5ba2f0dcb6 is described below

commit 5ba2f0dcb6f260e0d00f141951d4e87eacabfe4e
Author: Brent Bovenzi <br...@gmail.com>
AuthorDate: Wed Apr 13 12:32:58 2022 -0500

    Add a clipboard button to grid details (#22988)
    
    * Add a clipboard button to grid details
    
    * rename otherProps
    
    * Remove Box
---
 airflow/www/static/js/tree/Clipboard.jsx           | 63 ++++++++++++++++++++++
 .../js/tree/details/content/dagRun/index.jsx       |  3 +-
 .../tree/details/content/taskInstance/Details.jsx  |  5 +-
 3 files changed, 68 insertions(+), 3 deletions(-)

diff --git a/airflow/www/static/js/tree/Clipboard.jsx b/airflow/www/static/js/tree/Clipboard.jsx
new file mode 100644
index 0000000000..11215d10b5
--- /dev/null
+++ b/airflow/www/static/js/tree/Clipboard.jsx
@@ -0,0 +1,63 @@
+import React from 'react';
+import {
+  Button,
+  IconButton,
+  Tooltip,
+  useClipboard,
+  forwardRef,
+} from '@chakra-ui/react';
+import { FiCopy } from 'react-icons/fi';
+
+import { useContainerRef } from './context/containerRef';
+
+export const ClipboardButton = forwardRef(
+  (
+    {
+      value,
+      variant = 'outline',
+      iconOnly = false,
+      label = 'copy',
+      title = 'Copy',
+      'aria-label': ariaLabel = 'Copy',
+      ...rest
+    },
+    ref,
+  ) => {
+    const { hasCopied, onCopy } = useClipboard(value);
+    const containerRef = useContainerRef();
+
+    const commonProps = {
+      onClick: onCopy,
+      variant,
+      title,
+      ref,
+      ...rest,
+    };
+
+    return (
+      <Tooltip
+        label="Copied"
+        isOpen={hasCopied}
+        isDisabled={!hasCopied}
+        closeDelay={500}
+        placement="top"
+        portalProps={{ containerRef }}
+      >
+        {iconOnly ? (
+          <IconButton icon={<FiCopy />} aria-label={ariaLabel} {...commonProps} />
+        ) : (
+          <Button leftIcon={<FiCopy />} {...commonProps}>
+            {label}
+          </Button>
+        )}
+      </Tooltip>
+    );
+  },
+);
+
+export const ClipboardText = ({ value }) => (
+  <>
+    {value}
+    <ClipboardButton value={value} iconOnly variant="ghost" size="xs" fontSize="lg" ml={1} />
+  </>
+);
diff --git a/airflow/www/static/js/tree/details/content/dagRun/index.jsx b/airflow/www/static/js/tree/details/content/dagRun/index.jsx
index a449d183d3..98e3cdcca6 100644
--- a/airflow/www/static/js/tree/details/content/dagRun/index.jsx
+++ b/airflow/www/static/js/tree/details/content/dagRun/index.jsx
@@ -28,6 +28,7 @@ import {
 import { MdPlayArrow, MdOutlineAccountTree } from 'react-icons/md';
 
 import { SimpleStatus } from '../../../StatusBox';
+import { ClipboardText } from '../../../Clipboard';
 import { formatDuration } from '../../../../datetime_utils';
 import Time from '../../../Time';
 import MarkFailedRun from './MarkFailedRun';
@@ -91,7 +92,7 @@ const DagRun = ({ runId }) => {
       <Text whiteSpace="nowrap">
         Run Id:
         {' '}
-        {runId}
+        <ClipboardText value={runId} />
       </Text>
       <Text>
         Run Type:
diff --git a/airflow/www/static/js/tree/details/content/taskInstance/Details.jsx b/airflow/www/static/js/tree/details/content/taskInstance/Details.jsx
index 6ef9fa7460..6d341e4c3c 100644
--- a/airflow/www/static/js/tree/details/content/taskInstance/Details.jsx
+++ b/airflow/www/static/js/tree/details/content/taskInstance/Details.jsx
@@ -28,6 +28,7 @@ import { finalStatesMap } from '../../../../utils';
 import { getDuration, formatDuration } from '../../../../datetime_utils';
 import { SimpleStatus } from '../../../StatusBox';
 import Time from '../../../Time';
+import { ClipboardText } from '../../../Clipboard';
 
 const Details = ({ instance, group, operator }) => {
   const isGroup = !!group.children;
@@ -114,12 +115,12 @@ const Details = ({ instance, group, operator }) => {
         <br />
         <Text>
           {taskIdTitle}
-          {taskId}
+          <ClipboardText value={taskId} />
         </Text>
         <Text whiteSpace="nowrap">
           Run Id:
           {' '}
-          {runId}
+          <ClipboardText value={runId} />
         </Text>
         {operator && (
           <Text>