From 20c086923880739be92caced9f0f8b0b62cde416 Mon Sep 17 00:00:00 2001
From: Mariah Jacobs <114685994+mjac0bs@users.noreply.github.com>
Date: Mon, 11 Mar 2024 09:15:13 -0600
Subject: [PATCH] fix: [M3-7269] - Display parent email in user menu when no
company name is available for restricted parent user (#10248)
* Display username if no company name; update tests
* Wrap links for all long usernames
* Commit forgotten changesets
* Use email instead of username
* Remove change to company field in apiv4; cannot be null
* Update unit test to use email rather than username
* Update changeset
* Improve styling for very long usernames
* Revert more changes from when we though company could be null
---
...r-10248-upcoming-features-1709325591286.md | 5 ++
.../TopMenu/UserMenu/UserMenu.test.tsx | 44 +++++++++++++++++
.../features/TopMenu/UserMenu/UserMenu.tsx | 48 ++++++++-----------
3 files changed, 70 insertions(+), 27 deletions(-)
create mode 100644 packages/manager/.changeset/pr-10248-upcoming-features-1709325591286.md
diff --git a/packages/manager/.changeset/pr-10248-upcoming-features-1709325591286.md b/packages/manager/.changeset/pr-10248-upcoming-features-1709325591286.md
new file mode 100644
index 00000000000..a235d89664f
--- /dev/null
+++ b/packages/manager/.changeset/pr-10248-upcoming-features-1709325591286.md
@@ -0,0 +1,5 @@
+---
+"@linode/manager": Upcoming Features
+---
+
+Display parent email in user menu for restricted parent users without access to company name ([#10248](https://github.com/linode/manager/pull/10248))
diff --git a/packages/manager/src/features/TopMenu/UserMenu/UserMenu.test.tsx b/packages/manager/src/features/TopMenu/UserMenu/UserMenu.test.tsx
index a4424eabad5..9254b677082 100644
--- a/packages/manager/src/features/TopMenu/UserMenu/UserMenu.test.tsx
+++ b/packages/manager/src/features/TopMenu/UserMenu/UserMenu.test.tsx
@@ -197,4 +197,48 @@ describe('UserMenu', () => {
expect(within(userMenuPopover).getByText('Child Company')).toBeVisible();
expect(within(userMenuPopover).getByText('Switch Account')).toBeVisible();
});
+
+ it('shows the parent email for a parent user if their company name is not set', async () => {
+ // Mock a forbidden request to the /account endpoint, which happens if Billing (Account) Access is None.
+ server.use(
+ rest.get('*/account/users/*/grants', (req, res, ctx) => {
+ return res(
+ ctx.json(
+ grantsFactory.build({
+ global: {
+ account_access: null,
+ },
+ })
+ )
+ );
+ }),
+ rest.get('*/account', (req, res, ctx) => {
+ return res(ctx.status(403));
+ }),
+ rest.get('*/profile', (req, res, ctx) => {
+ return res(
+ ctx.json(
+ profileFactory.build({
+ email: 'parent@parent.com',
+ user_type: 'parent',
+ username: 'parent-username',
+ })
+ )
+ );
+ })
+ );
+
+ const { findByLabelText, findByTestId } = renderWithTheme(, {
+ flags: { parentChildAccountAccess: true },
+ });
+
+ const userMenuButton = await findByLabelText('Profile & Account');
+ fireEvent.click(userMenuButton);
+
+ const userMenuPopover = await findByTestId('user-menu-popover');
+
+ expect(
+ within(userMenuPopover).getByText('parent@parent.com')
+ ).toBeVisible();
+ });
});
diff --git a/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx b/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx
index 68280bf0d39..d900920e35b 100644
--- a/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx
+++ b/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx
@@ -80,12 +80,16 @@ export const UserMenu = React.memo(() => {
((!isChildAccountAccessRestricted && isParentUser) || isProxyUser);
const open = Boolean(anchorEl);
const id = open ? 'user-menu-popover' : undefined;
- const companyName =
- (hasParentChildAccountAccess &&
- profile?.user_type !== 'default' &&
- account?.company) ??
- '';
- const showCompanyName = hasParentChildAccountAccess && companyName;
+
+ // If there is no company name to identify an account, fall back on the email.
+ // Covers an edge case in which a restricted parent user without `account_access` cannot access the account company.
+ const companyNameOrEmail =
+ hasParentChildAccountAccess &&
+ profile?.user_type !== 'default' &&
+ account?.company
+ ? account.company
+ : profile?.email;
+
const { isParentTokenExpired } = useParentTokenManagement({ isProxyUser });
// Used for fetching parent profile and account data by making a request with the parent's token.
@@ -117,11 +121,11 @@ export const UserMenu = React.memo(() => {
React.useEffect(() => {
// Run after we've switched to a proxy user.
if (isProxyUser) {
- enqueueSnackbar(`Account switched to ${companyName}.`, {
+ enqueueSnackbar(`Account switched to ${companyNameOrEmail}.`, {
variant: 'success',
});
}
- }, [isProxyUser, companyName, enqueueSnackbar]);
+ }, [isProxyUser, companyNameOrEmail, enqueueSnackbar]);
const accountLinks: MenuLink[] = React.useMemo(
() => [
@@ -223,19 +227,19 @@ export const UserMenu = React.memo(() => {
{userName}
- {showCompanyName && (
+ {companyNameOrEmail && (
({
fontFamily: theme.font.bold,
fontSize: '0.875rem',
})}
>
- {companyName}
+ {companyNameOrEmail}
)}
@@ -273,7 +277,9 @@ export const UserMenu = React.memo(() => {
fontSize="1.1rem"
>
- {canSwitchBetweenParentOrProxyAccount ? companyName : userName}
+ {canSwitchBetweenParentOrProxyAccount && companyNameOrEmail
+ ? companyNameOrEmail
+ : userName}
{canSwitchBetweenParentOrProxyAccount && (
@@ -289,23 +295,11 @@ export const UserMenu = React.memo(() => {
My Profile
-
-
+
+
{profileLinks.slice(0, 4).map(renderLink)}
-
+
{profileLinks.slice(4).map(renderLink)}