Skip to content

Commit

Permalink
Merge branch 'linode:develop' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
cpathipa authored Sep 17, 2024
2 parents 8a19f9b + 451d63a commit 9e9c14f
Show file tree
Hide file tree
Showing 43 changed files with 457 additions and 523 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Upcoming Features
---

Update CSS for widget level filters and widget heading title for ACLP ([#10903](https://github.com/linode/manager/pull/10903))
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-10917-tests-1726061618551.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Tests
---

Add unit tests for Dialog and DeletionDialog components ([#10917](https://github.com/linode/manager/pull/10917))
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-10930-removed-1726159393499.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Removed
---

Support for Gravatar as user profile avatars ([#10930](https://github.com/linode/manager/pull/10930))
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-10938-fixed-1726262803311.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Fixed
---

Textarea tooltip icon focus area ([#10938](https://github.com/linode/manager/pull/10938))
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-10947-fixed-1726507951785.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Fixed
---

Flickering on the user profile page when updating the currently signed in user's username ([#10947](https://github.com/linode/manager/pull/10947))
2 changes: 1 addition & 1 deletion packages/manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"chart.js": "~2.9.4",
"copy-to-clipboard": "^3.0.8",
"country-region-data": "^3.0.0",
"dompurify": "^3.1.0",
"dompurify": "^3.1.3",
"flag-icons": "^6.6.5",
"font-logos": "^0.18.0",
"formik": "~2.1.3",
Expand Down
43 changes: 9 additions & 34 deletions packages/manager/src/components/AccessPanel/UserSSHKeyPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import { useProfile, useSSHKeysQuery } from 'src/queries/profile/profile';
import { truncateAndJoinList } from 'src/utilities/stringUtils';

import { Avatar } from '../Avatar/Avatar';
import { GravatarByEmail } from '../GravatarByEmail';
import { GravatarOrAvatar } from '../GravatarOrAvatar';
import { PaginationFooter } from '../PaginationFooter/PaginationFooter';
import { TableRowLoading } from '../TableRowLoading/TableRowLoading';

Expand All @@ -37,12 +35,6 @@ const useStyles = makeStyles()((theme: Theme) => ({
cellUser: {
width: '30%',
},
gravatar: {
borderRadius: '50%',
height: 24,
marginRight: theme.spacing(1),
width: 24,
},
title: {
marginBottom: theme.spacing(2),
},
Expand Down Expand Up @@ -150,15 +142,7 @@ const UserSSHKeyPanel = (props: Props) => {
</TableCell>
<TableCell className={classes.cellUser}>
<div className={classes.userWrapper}>
<GravatarOrAvatar
gravatar={
<GravatarByEmail
className={classes.gravatar}
email={profile.email}
/>
}
avatar={<Avatar sx={{ borderRadius: '50%', marginRight: 1 }} />}
/>
<Avatar sx={{ borderRadius: '50%', marginRight: 1 }} />
{profile.username}
</div>
</TableCell>
Expand Down Expand Up @@ -187,25 +171,16 @@ const UserSSHKeyPanel = (props: Props) => {
</TableCell>
<TableCell className={classes.cellUser}>
<div className={classes.userWrapper}>
<GravatarOrAvatar
avatar={
<Avatar
color={
user.username !== profile?.username
? theme.palette.primary.dark
: undefined
}
sx={{ borderRadius: '50%', marginRight: 1 }}
username={user.username}
/>
}
gravatar={
<GravatarByEmail
className={classes.gravatar}
email={user.email}
/>
<Avatar
color={
user.username !== profile?.username
? theme.palette.primary.dark
: undefined
}
sx={{ borderRadius: '50%', marginRight: 1 }}
username={user.username}
/>

{user.username}
</div>
</TableCell>
Expand Down
2 changes: 1 addition & 1 deletion packages/manager/src/components/Avatar/Avatar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ describe('Avatar', () => {
});

it('should render an svg instead of first letter for system users', async () => {
const systemUsernames = ['Linode', 'lke-service-account-123'];
const systemUsernames = ['Akamai', 'lke-service-account-123'];

systemUsernames.forEach((username, i) => {
const { getAllByRole, queryByTestId } = renderWithTheme(
Expand Down
2 changes: 1 addition & 1 deletion packages/manager/src/components/Avatar/Avatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export const Avatar = (props: AvatarProps) => {

const _username = username ?? profile?.username ?? '';
const isAkamai =
_username === 'Linode' || _username.startsWith('lke-service-account');
_username === 'Akamai' || _username.startsWith('lke-service-account');

const savedAvatarColor =
isAkamai || !preferences?.avatarColor
Expand Down
148 changes: 148 additions & 0 deletions packages/manager/src/components/DeletionDialog/DeletionDialog.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import { fireEvent } from '@testing-library/react';
import * as React from 'react';

import { renderWithTheme } from 'src/utilities/testHelpers';

import { DeletionDialog } from './DeletionDialog';

import type { DeletionDialogProps } from './DeletionDialog';

describe('DeletionDialog', () => {
const defaultArgs: DeletionDialogProps = {
entity: 'Linode',
label: 'my-linode-0',
loading: false,
onClose: vi.fn(),
onDelete: vi.fn(),
open: false,
};

it.each([
['not render', false],
['render', true],
])(
'should %s a DeletionDialog with the correct title, close button, and action buttons when open is %s',
(_, isOpen) => {
const { queryByRole, queryByTestId, queryByText } = renderWithTheme(
<DeletionDialog {...defaultArgs} open={isOpen} />
);
const title = queryByText(
`Delete ${defaultArgs.entity} ${defaultArgs.label}?`
);
const dialog = queryByTestId('drawer');
const closeButton = queryByRole('button', { name: 'Close' });
const cancelButton = queryByTestId('cancel');
const deleteButton = queryByTestId('confirm');

if (isOpen) {
expect(title).toBeInTheDocument();
expect(dialog).toBeInTheDocument();
expect(closeButton).toBeInTheDocument();
expect(cancelButton).toBeInTheDocument();
expect(deleteButton).toBeInTheDocument();
expect(deleteButton).toHaveTextContent(`Delete ${defaultArgs.entity}`);
} else {
expect(title).not.toBeInTheDocument();
expect(dialog).not.toBeInTheDocument();
expect(closeButton).not.toBeInTheDocument();
expect(cancelButton).not.toBeInTheDocument();
expect(deleteButton).not.toBeInTheDocument();
}
}
);

it('should call onClose when the DeletionDialog close button or Action cancel button is clicked', () => {
const { getByRole, getByTestId } = renderWithTheme(
<DeletionDialog {...defaultArgs} open={true} />
);

// For close icon button
const closeButton = getByRole('button', { name: 'Close' });
expect(closeButton).not.toBeDisabled();
fireEvent.click(closeButton);

expect(defaultArgs.onClose).toHaveBeenCalled();

// For action cancel button
const cancelButton = getByTestId('cancel');
expect(cancelButton).not.toBeDisabled();
fireEvent.click(cancelButton);

expect(defaultArgs.onClose).toHaveBeenCalled();
});

it('should call onDelete when the DeletionDialog delete button is clicked', () => {
const { getByTestId } = renderWithTheme(
<DeletionDialog {...defaultArgs} open={true} />
);

const deleteButton = getByTestId('confirm');
expect(deleteButton).not.toBeDisabled();
fireEvent.click(deleteButton);

expect(defaultArgs.onDelete).toHaveBeenCalled();
});

it('should render a DeletionDialog with an error message if provided', () => {
const { getByText } = renderWithTheme(
<DeletionDialog
{...defaultArgs}
error="Error that will be shown in the dialog."
open={true}
/>
);

expect(getByText('Error that will be shown in the dialog.')).toBeVisible();
});

it('should disable delete button and show loading icon if loading is true', () => {
const { getByTestId } = renderWithTheme(
<DeletionDialog {...defaultArgs} loading={true} open={true} />
);

const deleteButton = getByTestId('confirm');
expect(deleteButton).toBeInTheDocument();
expect(deleteButton).toBeDisabled();

const loadingSvgIcon = deleteButton.querySelector(
'[data-test-id="ReloadIcon"]'
);

expect(loadingSvgIcon).toBeInTheDocument();
});

it('should display the correct warning text in the DeletionDialog', () => {
const { getByTestId } = renderWithTheme(
<DeletionDialog {...defaultArgs} open={true} />
);

const dialog = getByTestId('drawer');
const warningText = `Warning: Deleting this ${defaultArgs.entity} is permanent and can\u2019t be undone.`;

expect(dialog).toHaveTextContent(warningText);
});

it.each([
['not render', false],
['render', true],
])(
'should %s input field with label when typeToConfirm is %s',
(_, typeToConfirm) => {
const { queryByTestId } = renderWithTheme(
<DeletionDialog
{...defaultArgs}
open={true}
typeToConfirm={typeToConfirm}
/>
);

if (typeToConfirm) {
expect(queryByTestId('inputLabelWrapper')).toBeInTheDocument();
expect(queryByTestId('textfield-input')).toBeInTheDocument();
} else {
expect(queryByTestId('inputLabelWrapper')).not.toBeInTheDocument();
expect(queryByTestId('textfield-input')).not.toBeInTheDocument();
}
}
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import { titlecase } from 'src/features/Linodes/presentation';
import { usePreferences } from 'src/queries/profile/preferences';
import { capitalize } from 'src/utilities/capitalize';

import { DialogProps } from '../Dialog/Dialog';
import type { DialogProps } from '../Dialog/Dialog';

interface DeletionDialogProps extends Omit<DialogProps, 'title'> {
export interface DeletionDialogProps extends Omit<DialogProps, 'title'> {
entity: string;
error?: string;
label: string;
Expand Down
69 changes: 69 additions & 0 deletions packages/manager/src/components/Dialog/Dialog.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { fireEvent } from '@testing-library/react';
import * as React from 'react';

import { renderWithTheme } from 'src/utilities/testHelpers';

import { Dialog } from './Dialog';

import type { DialogProps } from './Dialog';

describe('Dialog', () => {
const defaultArgs: DialogProps = {
onClose: vi.fn(),
open: false,
title: 'This is a Dialog',
};

it.each([
['not render', false],
['render', true],
])('should %s a Dialog with title when open is %s', (_, isOpen) => {
const { queryByTestId, queryByText } = renderWithTheme(
<Dialog {...defaultArgs} open={isOpen} />
);

const title = queryByText('This is a Dialog');
const dialog = queryByTestId('drawer');

if (isOpen) {
expect(title).toBeInTheDocument();
expect(dialog).toBeInTheDocument();
} else {
expect(title).not.toBeInTheDocument();
expect(dialog).not.toBeInTheDocument();
}
});

it('should render a Dialog with children if provided', () => {
const { getByText } = renderWithTheme(
<Dialog {...defaultArgs} open={true}>
<p>Child items can go here!</p>
</Dialog>
);

expect(getByText('Child items can go here!')).toBeInTheDocument();
});

it('should call onClose when the Dialog close button is clicked', () => {
const { getByRole } = renderWithTheme(
<Dialog {...defaultArgs} open={true} />
);

const closeButton = getByRole('button', { name: 'Close' });
fireEvent.click(closeButton);

expect(defaultArgs.onClose).toHaveBeenCalled();
});

it('should render a Dialog with an error message if provided', () => {
const { getByText } = renderWithTheme(
<Dialog
{...defaultArgs}
error="Error that will be shown in the dialog."
open={true}
/>
);

expect(getByText('Error that will be shown in the dialog.')).toBeVisible();
});
});
36 changes: 0 additions & 36 deletions packages/manager/src/components/GravatarByEmail.tsx

This file was deleted.

Loading

0 comments on commit 9e9c14f

Please sign in to comment.