Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: [M3-7272] - Disable Public IP Address for VPC only Linode #9899

Merged
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

Disable Public IP Address for VPC only Linode ([#9899](https://github.com/linode/manager/pull/9899))
hana-akamai marked this conversation as resolved.
Show resolved Hide resolved
52 changes: 38 additions & 14 deletions packages/manager/src/components/CopyTooltip/CopyTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export interface CopyTooltipProps {
* @default false
*/
copyableText?: boolean;
/**
* If true, the copy button will be disabled and there will be no tooltip.
* @default false
*/
disabled?: boolean;
/**
* Callback to be executed when the icon is clicked.
*/
Expand All @@ -38,7 +43,14 @@ export interface CopyTooltipProps {

export const CopyTooltip = (props: CopyTooltipProps) => {
const [copied, setCopied] = React.useState<boolean>(false);
const { className, copyableText, onClickCallback, placement, text } = props;
const {
className,
copyableText,
disabled,
onClickCallback,
placement,
text,
} = props;

const handleIconClick = () => {
setCopied(true);
Expand All @@ -49,30 +61,38 @@ export const CopyTooltip = (props: CopyTooltipProps) => {
}
};

const CopyButton = (
<StyledCopyButton
aria-label={`Copy ${text} to clipboard`}
className={className}
data-qa-copy-btn
name={text}
onClick={handleIconClick}
type="button"
{...props}
>
{copyableText ? text : <FileCopy />}
</StyledCopyButton>
);

if (disabled) {
return CopyButton;
}

return (
<Tooltip
className="copy-tooltip"
data-qa-copied
placement={placement ?? 'top'}
title={copied ? 'Copied!' : 'Copy'}
>
<StyledCopyTooltipButton
aria-label={`Copy ${text} to clipboard`}
className={className}
data-qa-copy-btn
name={text}
onClick={handleIconClick}
type="button"
{...props}
>
{copyableText ? text : <FileCopy />}
</StyledCopyTooltipButton>
{CopyButton}
</Tooltip>
);
};

const StyledCopyTooltipButton = styled('button', {
label: 'StyledCopyTooltipButton',
const StyledCopyButton = styled('button', {
label: 'StyledCopyButton',
shouldForwardProp: omittedProps(['copyableText', 'text']),
})<Omit<CopyTooltipProps, 'text'>>(({ theme, ...props }) => ({
'& svg': {
Expand Down Expand Up @@ -102,4 +122,8 @@ const StyledCopyTooltipButton = styled('button', {
font: 'inherit',
padding: 0,
}),
...(props.disabled && {
color: theme.color.disabledText,
cursor: 'default',
}),
}));
53 changes: 53 additions & 0 deletions packages/manager/src/features/Linodes/AccessTable.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { fireEvent } from '@testing-library/react';
import * as React from 'react';

import { linodeFactory } from 'src/factories';
import { PUBLIC_IPS_UNASSIGNED_TOOLTIP_TEXT } from 'src/features/Linodes/PublicIpsUnassignedTooltip';
import { renderWithTheme } from 'src/utilities/testHelpers';

import { AccessTable } from './AccessTable';

const linode = linodeFactory.build();

describe('AccessTable', () => {
it('should disable copy button and display help icon tooltip if isVPCOnlyLinode is true', async () => {
const { findByRole, getAllByRole } = renderWithTheme(
<AccessTable
isVPCOnlyLinode={true}
rows={[{ text: linode.ipv4[0] }, { text: linode.ipv4[1] }]}
title={'Public IP Addresses'}
/>
);

const buttons = getAllByRole('button');
const helpIconButton = buttons[0];
const copyButtons = buttons.slice(1);

fireEvent.mouseEnter(helpIconButton);

const publicIpsUnassignedTooltip = await findByRole(/tooltip/);
expect(publicIpsUnassignedTooltip).toContainHTML(
PUBLIC_IPS_UNASSIGNED_TOOLTIP_TEXT
);

copyButtons.forEach((copyButton) => {
expect(copyButton).toBeDisabled();
});
});

it('should not disable copy button if isVPCOnlyLinode is false', () => {
const { getAllByRole } = renderWithTheme(
<AccessTable
isVPCOnlyLinode={false}
rows={[{ text: linode.ipv4[0] }, { text: linode.ipv4[1] }]}
title={'Public IP Addresses'}
/>
);

const copyButtons = getAllByRole('button');

copyButtons.forEach((copyButton) => {
expect(copyButton).not.toBeDisabled();
});
});
});
86 changes: 86 additions & 0 deletions packages/manager/src/features/Linodes/AccessTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import Grid, { Grid2Props } from '@mui/material/Unstable_Grid2';
import { SxProps } from '@mui/system';
import * as React from 'react';

import { CopyTooltip } from 'src/components/CopyTooltip/CopyTooltip';
import { TableBody } from 'src/components/TableBody';
import { TableCell } from 'src/components/TableCell';
import { PublicIpsUnassignedTooltip } from 'src/features/Linodes/PublicIpsUnassignedTooltip';

import {
StyledColumnLabelGrid,
StyledCopyTooltip,
StyledGradientDiv,
StyledTable,
StyledTableCell,
StyledTableGrid,
StyledTableRow,
} from './LinodeEntityDetail.styles';

interface AccessTableRow {
heading?: string;
text: null | string;
hana-akamai marked this conversation as resolved.
Show resolved Hide resolved
}

interface AccessTableProps {
footer?: JSX.Element;
gridProps?: Grid2Props;
isVPCOnlyLinode: boolean;
rows: AccessTableRow[];
sx?: SxProps;
title: string;
}

export const AccessTable = React.memo((props: AccessTableProps) => {
hana-akamai marked this conversation as resolved.
Show resolved Hide resolved
return (
<Grid
container
direction="column"
md={6}
spacing={1}
sx={props.sx}
{...props.gridProps}
>
<StyledColumnLabelGrid>
{props.title}{' '}
{props.isVPCOnlyLinode && props.title.includes('Public IP Address') && (
<PublicIpsUnassignedTooltip />
)}
hana-akamai marked this conversation as resolved.
Show resolved Hide resolved
</StyledColumnLabelGrid>
<StyledTableGrid>
<StyledTable>
<TableBody>
{props.rows.map((thisRow) => {
return thisRow.text ? (
<StyledTableRow
disabled={props.isVPCOnlyLinode}
key={thisRow.text}
>
{thisRow.heading ? (
<TableCell component="th" scope="row">
{thisRow.heading}
</TableCell>
) : null}
<StyledTableCell>
<StyledGradientDiv>
<CopyTooltip
copyableText
disabled={props.isVPCOnlyLinode}
text={thisRow.text}
/>
</StyledGradientDiv>
<StyledCopyTooltip
disabled={props.isVPCOnlyLinode}
text={thisRow.text}
/>
hana-akamai marked this conversation as resolved.
Show resolved Hide resolved
</StyledTableCell>
</StyledTableRow>
) : null;
})}
</TableBody>
</StyledTable>
{props.footer ? <Grid sx={{ padding: 0 }}>{props.footer}</Grid> : null}
</StyledTableGrid>
</Grid>
);
});
Loading