18559: Add copy to clipboard to rendered UUIDs
authorStephen Smith <stephen@curii.com>
Thu, 31 Mar 2022 00:51:27 +0000 (20:51 -0400)
committerStephen Smith <stephen@curii.com>
Thu, 31 Mar 2022 00:51:27 +0000 (20:51 -0400)
Arvados-DCO-1.1-Signed-off-by: Stephen Smith <stephen@curii.com>

src/components/copy-to-clipboard-snackbar/copy-to-clipboard-snackbar.tsx [new file with mode: 0644]
src/views-components/data-explorer/renderers.tsx
src/views/user-profile-panel/user-profile-panel-root.tsx

diff --git a/src/components/copy-to-clipboard-snackbar/copy-to-clipboard-snackbar.tsx b/src/components/copy-to-clipboard-snackbar/copy-to-clipboard-snackbar.tsx
new file mode 100644 (file)
index 0000000..3b2ff68
--- /dev/null
@@ -0,0 +1,58 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+import React from "react";
+import { connect, DispatchProp } from "react-redux";
+import { StyleRulesCallback, Tooltip, WithStyles, withStyles } from "@material-ui/core";
+import { ArvadosTheme } from 'common/custom-theme';
+import CopyToClipboard from 'react-copy-to-clipboard';
+import { snackbarActions, SnackbarKind } from 'store/snackbar/snackbar-actions';
+import { CopyIcon } from 'components/icon/icon';
+
+type CssRules = 'copyIcon';
+
+const styles: StyleRulesCallback<CssRules> = (theme: ArvadosTheme) => ({
+  copyIcon: {
+    marginLeft: theme.spacing.unit,
+    color: theme.palette.grey["500"],
+    cursor: 'pointer',
+    display: 'inline',
+    '& svg': {
+      fontSize: '1rem',
+      verticalAlign: 'middle',
+    }
+  }
+});
+
+interface CopyToClipboardDataProps {
+  children?: React.ReactNode;
+  value: string;
+}
+
+type CopyToClipboardProps = CopyToClipboardDataProps & WithStyles<CssRules> & DispatchProp;
+
+export const CopyToClipboardSnackbar = connect()(withStyles(styles)(
+  class CopyToClipboardSnackbar extends React.Component<CopyToClipboardProps> {
+    onCopy = () => {
+      this.props.dispatch(snackbarActions.OPEN_SNACKBAR({
+        message: 'Copied',
+        hideDuration: 2000,
+        kind: SnackbarKind.SUCCESS
+    }));
+    };
+
+    render() {
+      const { children, value, classes } = this.props;
+      return (
+        <Tooltip title="Copy to clipboard">
+          <span className={classes.copyIcon}>
+            <CopyToClipboard text={value} onCopy={this.onCopy}>
+              {children || <CopyIcon />}
+            </CopyToClipboard>
+          </span>
+        </Tooltip>
+      );
+    }
+  }
+));
index 51b7dcc839274e858ef37ffde0c7f2ac276929eb..d1fed3a9a124c146be33e0f8448d2a43f8c75228 100644 (file)
@@ -50,6 +50,7 @@ import { PermissionLevel } from 'models/permission';
 import { openPermissionEditContextMenu } from 'store/context-menu/context-menu-actions';
 import { getUserUuid } from 'common/getuser';
 import { VirtualMachinesResource } from 'models/virtual-machines';
+import { CopyToClipboardSnackbar } from 'components/copy-to-clipboard-snackbar/copy-to-clipboard-snackbar';
 
 const renderName = (dispatch: Dispatch, item: GroupContentsResource) => {
 
@@ -192,15 +193,15 @@ export const UserResourceFullName = connect(
         return {item: resource || { uuid: '', firstName: '', lastName: '' }, link: props.link};
     })((props: {item: {uuid: string, firstName: string, lastName: string}, link?: boolean} & DispatchProp<any>) => renderFullName(props.dispatch, props.item, props.link));
 
-
 const renderUuid = (item: { uuid: string }) =>
-    <Typography data-cy="uuid" noWrap>{item.uuid}</Typography>;
+    <Typography data-cy="uuid" noWrap>
+        {item.uuid}
+        <CopyToClipboardSnackbar value={item.uuid} />
+    </Typography>;
 
-export const ResourceUuid = connect(
-    (state: RootState, props: { uuid: string }) => {
-        const resource = getResource<UserResource>(props.uuid)(state.resources);
-        return resource || { uuid: '' };
-    })(renderUuid);
+export const ResourceUuid = connect((state: RootState, props: { uuid: string }) => (
+        getResource<UserResource>(props.uuid)(state.resources) || { uuid: '' }
+    ))(renderUuid);
 
 const renderEmail = (item: { email: string }) =>
     <Typography noWrap>{item.email}</Typography>;
index f89ca5c5e8ebe5580aed3995bc270e9d00a730f8..6a3adb92617b9d6a3968493a808d0c9f02196920 100644 (file)
@@ -28,14 +28,13 @@ import { DataTableDefaultView } from 'components/data-table-default-view/data-ta
 import { PROFILE_EMAIL_VALIDATION } from "validators/validators";
 import { USER_PROFILE_PANEL_ID } from 'store/user-profile/user-profile-actions';
 import { noop } from 'lodash';
-import { CopyIcon, DetailsIcon, GroupsIcon, MoreOptionsIcon } from 'components/icon/icon';
+import { DetailsIcon, GroupsIcon, MoreOptionsIcon } from 'components/icon/icon';
 import { DataColumns } from 'components/data-table/data-table';
 import { ResourceLinkHeadUuid, ResourceLinkHeadPermissionLevel, ResourceLinkHead, ResourceLinkDelete, ResourceLinkTailIsVisible } from 'views-components/data-explorer/renderers';
 import { createTree } from 'models/tree';
 import { getResource, ResourcesState } from 'store/resources/resources';
-import { snackbarActions, SnackbarKind } from 'store/snackbar/snackbar-actions';
-import CopyToClipboard from 'react-copy-to-clipboard';
 import { DefaultView } from 'components/default-view/default-view';
+import { CopyToClipboardSnackbar } from 'components/copy-to-clipboard-snackbar/copy-to-clipboard-snackbar';
 
 type CssRules = 'root' | 'emptyRoot' | 'gridItem' | 'label' | 'readOnlyValue' | 'title' | 'description' | 'actions' | 'content' | 'copyIcon';
 
@@ -188,14 +187,6 @@ export const UserProfilePanelRoot = withStyles(styles)(
             this.setState({ value: TABS.PROFILE});
         }
 
-        onCopy = (message: string) => {
-            this.props.dispatch(snackbarActions.OPEN_SNACKBAR({
-                message,
-                hideDuration: 2000,
-                kind: SnackbarKind.SUCCESS
-            }));
-        }
-
         render() {
             if (this.props.isInaccessible) {
                 return (
@@ -217,13 +208,7 @@ export const UserProfilePanelRoot = withStyles(styles)(
                                 <Grid item xs={11}>
                                     <Typography className={this.props.classes.title}>
                                         {this.props.userUuid}
-                                        <Tooltip title="Copy to clipboard">
-                                            <span className={this.props.classes.copyIcon}>
-                                                <CopyToClipboard text={this.props.userUuid || ""} onCopy={() => this.onCopy!("Copied")}>
-                                                    <CopyIcon />
-                                                </CopyToClipboard>
-                                            </span>
-                                        </Tooltip>
+                                        <CopyToClipboardSnackbar value={this.props.userUuid} />
                                     </Typography>
                                 </Grid>
                                 <Grid item xs={1} style={{ textAlign: "right" }}>