From 5007212a689962785d68a6fb3979a8fbc70ae336 Mon Sep 17 00:00:00 2001 From: Jaalah Ramos Date: Tue, 23 Jan 2024 22:41:53 -0500 Subject: [PATCH 1/8] upcoming: [M3-7530] - Restrict proxy users from updating username/email --- .../SingleTextFieldForm/SingleTextFieldForm.tsx | 17 +++++++++++------ .../Profile/DisplaySettings/DisplaySettings.tsx | 10 +++++++++- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/packages/manager/src/components/SingleTextFieldForm/SingleTextFieldForm.tsx b/packages/manager/src/components/SingleTextFieldForm/SingleTextFieldForm.tsx index 3843eb6c91f..eb699bc8598 100644 --- a/packages/manager/src/components/SingleTextFieldForm/SingleTextFieldForm.tsx +++ b/packages/manager/src/components/SingleTextFieldForm/SingleTextFieldForm.tsx @@ -1,5 +1,4 @@ import { APIError } from '@linode/api-v4/lib/types'; -import { Theme } from '@mui/material/styles'; import * as React from 'react'; import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel'; @@ -69,9 +68,11 @@ export const SingleTextFieldForm = React.memo((props: Props) => { ({ [theme.breakpoints.down('md')]: { + alignItems: 'flex-start', flexDirection: 'column', }, })} + alignItems="flex-end" display="flex" justifyContent="space-between" > @@ -88,7 +89,6 @@ export const SingleTextFieldForm = React.memo((props: Props) => { label={label} onBlur={(e) => setValue(e.target.value)} onChange={(e) => setValue(e.target.value)} - tooltipText={tooltipText ? tooltipText : undefined} trimmed={trimmed} value={value} /> @@ -98,12 +98,17 @@ export const SingleTextFieldForm = React.memo((props: Props) => { label: `Update ${label}`, loading: submitting, onClick: handleSubmit, - sx: (theme: Theme) => ({ + sx: () => ({ + margin: '0 !important', // Investigate why I can't override with `!important` minWidth: 180, - [theme.breakpoints.up('md')]: { - marginTop: 2, - }, }), + tooltipText: + tooltipText && typeof tooltipText === 'string' + ? tooltipText + : undefined, + }} + sx={{ + padding: 0, }} /> diff --git a/packages/manager/src/features/Profile/DisplaySettings/DisplaySettings.tsx b/packages/manager/src/features/Profile/DisplaySettings/DisplaySettings.tsx index 7a05360ef1a..28e16b2f852 100644 --- a/packages/manager/src/features/Profile/DisplaySettings/DisplaySettings.tsx +++ b/packages/manager/src/features/Profile/DisplaySettings/DisplaySettings.tsx @@ -30,6 +30,8 @@ export const DisplaySettings = () => { const location = useLocation<{ focusEmail: boolean }>(); const emailRef = React.createRef(); + const isProxyUser = profile?.user_type === 'proxy'; + React.useEffect(() => { if (location.state?.focusEmail && emailRef.current) { emailRef.current.focus(); @@ -63,6 +65,8 @@ export const DisplaySettings = () => { ); + const restrictedProxyUserTooltip = 'Proxy users cannot update this field.'; + return ( { tooltipText={ profile?.restricted ? 'Restricted users cannot update their username. Please contact an account administrator.' + : isProxyUser + ? restrictedProxyUserTooltip : undefined } - disabled={profile?.restricted} + disabled={profile?.restricted || isProxyUser} initialValue={profile?.username} key={usernameResetToken} label="Username" @@ -125,11 +131,13 @@ export const DisplaySettings = () => { refetch(); } }} + disabled={isProxyUser} initialValue={profile?.email} inputRef={emailRef} key={emailResetToken} label="Email" submitForm={updateEmail} + tooltipText={isProxyUser ? restrictedProxyUserTooltip : undefined} trimmed type="email" /> From a34ebce3e01d3dffee75d0644bd9ac6937054fd8 Mon Sep 17 00:00:00 2001 From: Jaalah Ramos Date: Tue, 23 Jan 2024 22:50:47 -0500 Subject: [PATCH 2/8] upcoming: [M3-7530] - Restrict proxy users from updating username/email --- .../SingleTextFieldForm.tsx | 2 +- .../DisplaySettings/DisplaySettings.test.tsx | 35 +++++++++++++++++++ .../Profile/DisplaySettings/TimezoneForm.tsx | 11 +++++- 3 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 packages/manager/src/features/Profile/DisplaySettings/DisplaySettings.test.tsx diff --git a/packages/manager/src/components/SingleTextFieldForm/SingleTextFieldForm.tsx b/packages/manager/src/components/SingleTextFieldForm/SingleTextFieldForm.tsx index eb699bc8598..f2b1ae4c748 100644 --- a/packages/manager/src/components/SingleTextFieldForm/SingleTextFieldForm.tsx +++ b/packages/manager/src/components/SingleTextFieldForm/SingleTextFieldForm.tsx @@ -99,7 +99,7 @@ export const SingleTextFieldForm = React.memo((props: Props) => { loading: submitting, onClick: handleSubmit, sx: () => ({ - margin: '0 !important', // Investigate why I can't override with `!important` + margin: '0 !important', // Investigate why I can't override without `!important` minWidth: 180, }), tooltipText: diff --git a/packages/manager/src/features/Profile/DisplaySettings/DisplaySettings.test.tsx b/packages/manager/src/features/Profile/DisplaySettings/DisplaySettings.test.tsx new file mode 100644 index 00000000000..6177be0b25a --- /dev/null +++ b/packages/manager/src/features/Profile/DisplaySettings/DisplaySettings.test.tsx @@ -0,0 +1,35 @@ +import { screen } from '@testing-library/react'; +import React from 'react'; + +import { profileFactory } from 'src/factories/profile'; +import { DisplaySettings } from 'src/features/Profile/DisplaySettings/DisplaySettings'; +import { renderWithTheme } from 'src/utilities/testHelpers'; + +// Mock the useProfile hooks to immediately return the expected data, circumventing the HTTP request and loading state. +const queryMocks = vi.hoisted(() => ({ + useProfile: vi.fn().mockReturnValue({}), +})); + +vi.mock('src/queries/profile', async () => { + const actual = await vi.importActual('src/queries/profile'); + return { + ...actual, + useProfile: queryMocks.useProfile, + }; +}); + +describe('DisplaySettings component', () => { + it('should disable SingleTextFieldForm components based on isProxyUser', () => { + queryMocks.useProfile.mockReturnValue({ + data: profileFactory.build({ user_type: 'proxy' }), + }); + + renderWithTheme(); + + const usernameInput = screen.getByLabelText('Username'); + expect(usernameInput).toHaveAttribute('disabled'); + + const emailInput = screen.getByLabelText('Email'); + expect(emailInput).toHaveAttribute('disabled'); + }); +}); diff --git a/packages/manager/src/features/Profile/DisplaySettings/TimezoneForm.tsx b/packages/manager/src/features/Profile/DisplaySettings/TimezoneForm.tsx index 52682b97ce0..11a2a5eb0dd 100644 --- a/packages/manager/src/features/Profile/DisplaySettings/TimezoneForm.tsx +++ b/packages/manager/src/features/Profile/DisplaySettings/TimezoneForm.tsx @@ -86,7 +86,11 @@ export const TimezoneForm = (props: Props) => { ) : null} - +