From 3307e8d55db064b707aa521b27ef0f2797501a6e Mon Sep 17 00:00:00 2001 From: Hana Xu Date: Wed, 16 Nov 2022 14:31:47 -0500 Subject: [PATCH 1/5] copyable ip address text in linodes landing table --- .../CopyableTextWithTooltip.tsx | 83 +++++++++++++++++++ .../CopyableTextWithTooltip/index.ts | 2 + .../linodes/LinodesLanding/IPAddress.test.tsx | 1 + .../linodes/LinodesLanding/IPAddress.tsx | 3 +- 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 packages/manager/src/components/CopyableTextWithTooltip/CopyableTextWithTooltip.tsx create mode 100644 packages/manager/src/components/CopyableTextWithTooltip/index.ts diff --git a/packages/manager/src/components/CopyableTextWithTooltip/CopyableTextWithTooltip.tsx b/packages/manager/src/components/CopyableTextWithTooltip/CopyableTextWithTooltip.tsx new file mode 100644 index 00000000000..64941c8821a --- /dev/null +++ b/packages/manager/src/components/CopyableTextWithTooltip/CopyableTextWithTooltip.tsx @@ -0,0 +1,83 @@ +import copy from 'copy-to-clipboard'; +import * as React from 'react'; +import { makeStyles, Theme } from 'src/components/core/styles'; +import ToolTip from 'src/components/core/Tooltip'; + +interface Props { + text: string; + className?: string; + displayText?: string; + onClickCallback?: () => void; +} + +const useStyles = makeStyles((theme: Theme) => ({ + root: { + position: 'relative', + padding: 4, + backgroundColor: 'transparent', + transition: theme.transitions.create(['background-color']), + borderRadius: 4, + border: 'none', + cursor: 'pointer', + color: theme.color.grey1, + '& svg': { + transition: theme.transitions.create(['color']), + color: theme.color.grey1, + margin: 0, + position: 'relative', + width: 20, + height: 20, + }, + '&:hover': { + backgroundColor: theme.color.white, + }, + }, + flex: { + display: 'flex', + width: 'auto !important', + }, + displayText: { + color: theme.textColors.linkActiveLight, + marginLeft: 6, + }, + copyBtn: { + padding: 0, + backgroundColor: 'transparent', + border: 'none', + cursor: 'pointer', + font: 'inherit', + color: theme.palette.text.primary, + }, +})); + +export const CopyableTextWithTooltip: React.FC = (props) => { + const classes = useStyles(); + const [copied, setCopied] = React.useState(false); + + const { text, onClickCallback } = props; + + const handleIconClick = () => { + setCopied(true); + window.setTimeout(() => setCopied(false), 1500); + copy(text); + if (onClickCallback) { + onClickCallback(); + } + }; + + return ( + + + + ); +}; + +export default CopyableTextWithTooltip; diff --git a/packages/manager/src/components/CopyableTextWithTooltip/index.ts b/packages/manager/src/components/CopyableTextWithTooltip/index.ts new file mode 100644 index 00000000000..993e99e5d04 --- /dev/null +++ b/packages/manager/src/components/CopyableTextWithTooltip/index.ts @@ -0,0 +1,2 @@ +import CopyableTextWithTooltip from './CopyableTextWithTooltip'; +export default CopyableTextWithTooltip; diff --git a/packages/manager/src/features/linodes/LinodesLanding/IPAddress.test.tsx b/packages/manager/src/features/linodes/LinodesLanding/IPAddress.test.tsx index 13163fc54f6..a627469e84a 100644 --- a/packages/manager/src/features/linodes/LinodesLanding/IPAddress.test.tsx +++ b/packages/manager/src/features/linodes/LinodesLanding/IPAddress.test.tsx @@ -16,6 +16,7 @@ const classes = { multipleAddresses: '', ipLink: '', hide: 'hide', + ipCopyBtn: '', }; const component = shallow( diff --git a/packages/manager/src/features/linodes/LinodesLanding/IPAddress.tsx b/packages/manager/src/features/linodes/LinodesLanding/IPAddress.tsx index 766d4c9b977..717a467742c 100644 --- a/packages/manager/src/features/linodes/LinodesLanding/IPAddress.tsx +++ b/packages/manager/src/features/linodes/LinodesLanding/IPAddress.tsx @@ -1,6 +1,7 @@ import copy from 'copy-to-clipboard'; import { tail } from 'ramda'; import * as React from 'react'; +import CopyableTextWithTooltip from 'src/components/CopyableTextWithTooltip/CopyableTextWithTooltip'; import CopyTooltip from 'src/components/CopyTooltip'; import { createStyles, @@ -131,7 +132,7 @@ export class IPAddress extends React.Component> { className={`${classes.row} ${showAll && classes.multipleAddresses}`} data-qa-ip-main > - {ip} + {this.renderCopyIcon(ip)} ); From 12b7e1ed4c7b2f512473dd60ab96410eca25de63 Mon Sep 17 00:00:00 2001 From: Hana Xu Date: Wed, 16 Nov 2022 14:38:13 -0500 Subject: [PATCH 2/5] copyable ip address text in linode detail network table --- .../LinodesDetail/LinodeNetworking/LinodeNetworking.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/manager/src/features/linodes/LinodesDetail/LinodeNetworking/LinodeNetworking.tsx b/packages/manager/src/features/linodes/LinodesDetail/LinodeNetworking/LinodeNetworking.tsx index fb4ba80da61..2d4e64bd3fd 100644 --- a/packages/manager/src/features/linodes/LinodesDetail/LinodeNetworking/LinodeNetworking.tsx +++ b/packages/manager/src/features/linodes/LinodesDetail/LinodeNetworking/LinodeNetworking.tsx @@ -19,6 +19,7 @@ import { compose as recompose } from 'recompose'; import AddNewLink from 'src/components/AddNewLink'; import Button from 'src/components/Button'; import CircleProgress from 'src/components/CircleProgress'; +import CopyableTextWithTooltip from 'src/components/CopyableTextWithTooltip/CopyableTextWithTooltip'; import CopyTooltip from 'src/components/CopyTooltip'; import Hidden from 'src/components/core/Hidden'; import Paper from 'src/components/core/Paper'; @@ -407,7 +408,7 @@ class LinodeNetworking extends React.Component { className={classes.ipAddress} data-qa-ip-address > - {address} + From 03bef4dec80d905e85a00ba87c1c543b1b8ed3e4 Mon Sep 17 00:00:00 2001 From: Hana Xu Date: Wed, 16 Nov 2022 16:05:58 -0500 Subject: [PATCH 3/5] copyable address text in linode entity detail header --- .../features/linodes/LinodeEntityDetail.tsx | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/packages/manager/src/features/linodes/LinodeEntityDetail.tsx b/packages/manager/src/features/linodes/LinodeEntityDetail.tsx index 129ab09a0fd..dba374d2d94 100644 --- a/packages/manager/src/features/linodes/LinodeEntityDetail.tsx +++ b/packages/manager/src/features/linodes/LinodeEntityDetail.tsx @@ -7,6 +7,7 @@ import { Link } from 'react-router-dom'; import { HashLink } from 'react-router-hash-link'; import { compose } from 'recompose'; import Button from 'src/components/Button'; +import CopyableTextWithTooltip from 'src/components/CopyableTextWithTooltip/CopyableTextWithTooltip'; import CopyTooltip from 'src/components/CopyTooltip'; import Box from 'src/components/core/Box'; import Chip from 'src/components/core/Chip'; @@ -643,15 +644,23 @@ const useAccessTableStyles = makeStyles((theme: Theme) => ({ }, }, code: { + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', backgroundColor: theme.bg.bgAccessRow, color: theme.textColors.tableStatic, fontFamily: '"UbuntuMono", monospace, sans-serif', - padding: theme.spacing(), + padding: '4px 8px', position: 'relative', '& div': { fontSize: 15, }, }, + row: { + '&:hover $copy > svg, & $copy:focus > svg': { + opacity: 1, + }, + }, copyCell: { backgroundColor: theme.bg.lightBlue2, height: 33, @@ -671,15 +680,11 @@ const useAccessTableStyles = makeStyles((theme: Theme) => ({ }, }, }, - copyButton: { - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - borderRadius: 1, - height: '100%', - width: '100%', - '&:hover': { - backgroundColor: 'transparent', + copy: { + '& svg': { + height: `12px`, + width: `12px`, + opacity: 0, }, }, gradient: { @@ -722,18 +727,15 @@ export const AccessTable: React.FC = React.memo((props) => { {props.rows.map((thisRow) => { return thisRow.text ? ( - + {thisRow.heading ? ( {thisRow.heading} ) : null} -
{thisRow.text}
-
- - +
+ +
+
) : null; From 6ce476e70fb661a76d0b511946f051535fdbed5b Mon Sep 17 00:00:00 2001 From: Hana Xu Date: Thu, 17 Nov 2022 16:50:21 -0500 Subject: [PATCH 4/5] clean up --- .../components/CopyTooltip/CopyTooltip.tsx | 22 ++--- .../CopyableTextWithTooltip.tsx | 83 ------------------- .../CopyableTextWithTooltip/index.ts | 2 - .../features/linodes/LinodeEntityDetail.tsx | 3 +- .../LinodeNetworking/LinodeNetworking.tsx | 3 +- .../linodes/LinodesLanding/IPAddress.tsx | 3 +- 6 files changed, 14 insertions(+), 102 deletions(-) delete mode 100644 packages/manager/src/components/CopyableTextWithTooltip/CopyableTextWithTooltip.tsx delete mode 100644 packages/manager/src/components/CopyableTextWithTooltip/index.ts diff --git a/packages/manager/src/components/CopyTooltip/CopyTooltip.tsx b/packages/manager/src/components/CopyTooltip/CopyTooltip.tsx index 250cceda431..5b6d1e505dc 100644 --- a/packages/manager/src/components/CopyTooltip/CopyTooltip.tsx +++ b/packages/manager/src/components/CopyTooltip/CopyTooltip.tsx @@ -3,13 +3,12 @@ import copy from 'copy-to-clipboard'; import * as React from 'react'; import FileCopy from 'src/assets/icons/copy.svg'; import { makeStyles, Theme } from 'src/components/core/styles'; -import Typography from 'src/components/core/Typography'; import ToolTip from 'src/components/core/Tooltip'; interface Props { text: string; className?: string; - displayText?: string; + copyableText?: boolean; onClickCallback?: () => void; } @@ -39,9 +38,13 @@ const useStyles = makeStyles((theme: Theme) => ({ display: 'flex', width: 'auto !important', }, - displayText: { - color: theme.textColors.linkActiveLight, - marginLeft: 6, + copyableTextBtn: { + padding: 0, + backgroundColor: 'transparent', + border: 'none', + cursor: 'pointer', + font: 'inherit', + color: theme.palette.text.primary, }, })); @@ -49,7 +52,7 @@ export const CopyTooltip: React.FC = (props) => { const classes = useStyles(); const [copied, setCopied] = React.useState(false); - const { text, className, displayText, onClickCallback } = props; + const { text, className, copyableText, onClickCallback } = props; const handleIconClick = () => { setCopied(true); @@ -69,13 +72,10 @@ export const CopyTooltip: React.FC = (props) => { onClick={handleIconClick} className={classNames(className, { [classes.root]: true, - [classes.flex]: Boolean(displayText), + [classes.copyableTextBtn]: copyableText, })} > - - {displayText && ( - {displayText} - )} + {copyableText ? text : } ); diff --git a/packages/manager/src/components/CopyableTextWithTooltip/CopyableTextWithTooltip.tsx b/packages/manager/src/components/CopyableTextWithTooltip/CopyableTextWithTooltip.tsx deleted file mode 100644 index 64941c8821a..00000000000 --- a/packages/manager/src/components/CopyableTextWithTooltip/CopyableTextWithTooltip.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import copy from 'copy-to-clipboard'; -import * as React from 'react'; -import { makeStyles, Theme } from 'src/components/core/styles'; -import ToolTip from 'src/components/core/Tooltip'; - -interface Props { - text: string; - className?: string; - displayText?: string; - onClickCallback?: () => void; -} - -const useStyles = makeStyles((theme: Theme) => ({ - root: { - position: 'relative', - padding: 4, - backgroundColor: 'transparent', - transition: theme.transitions.create(['background-color']), - borderRadius: 4, - border: 'none', - cursor: 'pointer', - color: theme.color.grey1, - '& svg': { - transition: theme.transitions.create(['color']), - color: theme.color.grey1, - margin: 0, - position: 'relative', - width: 20, - height: 20, - }, - '&:hover': { - backgroundColor: theme.color.white, - }, - }, - flex: { - display: 'flex', - width: 'auto !important', - }, - displayText: { - color: theme.textColors.linkActiveLight, - marginLeft: 6, - }, - copyBtn: { - padding: 0, - backgroundColor: 'transparent', - border: 'none', - cursor: 'pointer', - font: 'inherit', - color: theme.palette.text.primary, - }, -})); - -export const CopyableTextWithTooltip: React.FC = (props) => { - const classes = useStyles(); - const [copied, setCopied] = React.useState(false); - - const { text, onClickCallback } = props; - - const handleIconClick = () => { - setCopied(true); - window.setTimeout(() => setCopied(false), 1500); - copy(text); - if (onClickCallback) { - onClickCallback(); - } - }; - - return ( - - - - ); -}; - -export default CopyableTextWithTooltip; diff --git a/packages/manager/src/components/CopyableTextWithTooltip/index.ts b/packages/manager/src/components/CopyableTextWithTooltip/index.ts deleted file mode 100644 index 993e99e5d04..00000000000 --- a/packages/manager/src/components/CopyableTextWithTooltip/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -import CopyableTextWithTooltip from './CopyableTextWithTooltip'; -export default CopyableTextWithTooltip; diff --git a/packages/manager/src/features/linodes/LinodeEntityDetail.tsx b/packages/manager/src/features/linodes/LinodeEntityDetail.tsx index dba374d2d94..29b1ee0cb84 100644 --- a/packages/manager/src/features/linodes/LinodeEntityDetail.tsx +++ b/packages/manager/src/features/linodes/LinodeEntityDetail.tsx @@ -7,7 +7,6 @@ import { Link } from 'react-router-dom'; import { HashLink } from 'react-router-hash-link'; import { compose } from 'recompose'; import Button from 'src/components/Button'; -import CopyableTextWithTooltip from 'src/components/CopyableTextWithTooltip/CopyableTextWithTooltip'; import CopyTooltip from 'src/components/CopyTooltip'; import Box from 'src/components/core/Box'; import Chip from 'src/components/core/Chip'; @@ -733,7 +732,7 @@ export const AccessTable: React.FC = React.memo((props) => { ) : null}
- +
diff --git a/packages/manager/src/features/linodes/LinodesDetail/LinodeNetworking/LinodeNetworking.tsx b/packages/manager/src/features/linodes/LinodesDetail/LinodeNetworking/LinodeNetworking.tsx index 2d4e64bd3fd..dfbd39a33a1 100644 --- a/packages/manager/src/features/linodes/LinodesDetail/LinodeNetworking/LinodeNetworking.tsx +++ b/packages/manager/src/features/linodes/LinodesDetail/LinodeNetworking/LinodeNetworking.tsx @@ -19,7 +19,6 @@ import { compose as recompose } from 'recompose'; import AddNewLink from 'src/components/AddNewLink'; import Button from 'src/components/Button'; import CircleProgress from 'src/components/CircleProgress'; -import CopyableTextWithTooltip from 'src/components/CopyableTextWithTooltip/CopyableTextWithTooltip'; import CopyTooltip from 'src/components/CopyTooltip'; import Hidden from 'src/components/core/Hidden'; import Paper from 'src/components/core/Paper'; @@ -408,7 +407,7 @@ class LinodeNetworking extends React.Component { className={classes.ipAddress} data-qa-ip-address > - +
diff --git a/packages/manager/src/features/linodes/LinodesLanding/IPAddress.tsx b/packages/manager/src/features/linodes/LinodesLanding/IPAddress.tsx index 717a467742c..c2da836630b 100644 --- a/packages/manager/src/features/linodes/LinodesLanding/IPAddress.tsx +++ b/packages/manager/src/features/linodes/LinodesLanding/IPAddress.tsx @@ -1,7 +1,6 @@ import copy from 'copy-to-clipboard'; import { tail } from 'ramda'; import * as React from 'react'; -import CopyableTextWithTooltip from 'src/components/CopyableTextWithTooltip/CopyableTextWithTooltip'; import CopyTooltip from 'src/components/CopyTooltip'; import { createStyles, @@ -132,7 +131,7 @@ export class IPAddress extends React.Component> { className={`${classes.row} ${showAll && classes.multipleAddresses}`} data-qa-ip-main > - + {this.renderCopyIcon(ip)} ); From 81a56e7a37a2cf5bafaa84539222c2ac0b8d5cc1 Mon Sep 17 00:00:00 2001 From: Hana Xu Date: Thu, 17 Nov 2022 17:56:54 -0500 Subject: [PATCH 5/5] update test --- packages/manager/src/components/CopyTooltip/CopyTooltip.tsx | 1 + .../src/features/linodes/LinodesLanding/IPAddress.test.tsx | 6 ++---- .../src/features/linodes/LinodesLanding/IPAddress.tsx | 3 +-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/manager/src/components/CopyTooltip/CopyTooltip.tsx b/packages/manager/src/components/CopyTooltip/CopyTooltip.tsx index 5b6d1e505dc..01ae964a1e0 100644 --- a/packages/manager/src/components/CopyTooltip/CopyTooltip.tsx +++ b/packages/manager/src/components/CopyTooltip/CopyTooltip.tsx @@ -74,6 +74,7 @@ export const CopyTooltip: React.FC = (props) => { [classes.root]: true, [classes.copyableTextBtn]: copyableText, })} + data-qa-copy-btn > {copyableText ? text : } diff --git a/packages/manager/src/features/linodes/LinodesLanding/IPAddress.test.tsx b/packages/manager/src/features/linodes/LinodesLanding/IPAddress.test.tsx index a627469e84a..4b68993555f 100644 --- a/packages/manager/src/features/linodes/LinodesLanding/IPAddress.test.tsx +++ b/packages/manager/src/features/linodes/LinodesLanding/IPAddress.test.tsx @@ -16,7 +16,6 @@ const classes = { multipleAddresses: '', ipLink: '', hide: 'hide', - ipCopyBtn: '', }; const component = shallow( @@ -26,11 +25,10 @@ const component = shallow( describe('IPAddress', () => { it('should render without error and display one IP address if showAll is false', () => { component.setProps({ showMore: true, showAll: false }); - const rendered = component.find('[data-qa-ip-main]'); - const ipText = rendered.text(); + const rendered = component.find('[data-qa-copy-ip-text]'); expect(rendered).toHaveLength(1); - expect(ipText).toContain('8.8.8.8'); + expect(rendered.prop('text')).toEqual('8.8.8.8'); }); it('should not display ShowMore button unless the showMore prop is true', () => { diff --git a/packages/manager/src/features/linodes/LinodesLanding/IPAddress.tsx b/packages/manager/src/features/linodes/LinodesLanding/IPAddress.tsx index c2da836630b..74e9093134e 100644 --- a/packages/manager/src/features/linodes/LinodesLanding/IPAddress.tsx +++ b/packages/manager/src/features/linodes/LinodesLanding/IPAddress.tsx @@ -129,9 +129,8 @@ export class IPAddress extends React.Component> {
- + {this.renderCopyIcon(ip)}
);