Skip to content

chore: Remove useAccountManagement hook and fix some restricted user UI #12223

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

Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/api-v4": Removed
---

`add_buckets` from `GlobalGrantTypes` ([#12223](https://github.com/linode/manager/pull/12223))
1 change: 0 additions & 1 deletion packages/api-v4/src/account/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,6 @@ export interface Grant {
}
export type GlobalGrantTypes =
| 'account_access'
| 'add_buckets'
| 'add_databases'
| 'add_domains'
| 'add_firewalls'
Expand Down
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-12223-fixed-1747346453830.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Fixed
---

Inconsistent restricted user notices on landing pages ([#12223](https://github.com/linode/manager/pull/12223))
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Tech Stories
---

Remove `useAccountManagement` hook ([#12223](https://github.com/linode/manager/pull/12223))
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* @file Integration tests for Cloud Manager account cancellation flows.
*/

import { profileFactory } from '@linode/utilities';
import { grantsFactory, profileFactory } from '@linode/utilities';
import {
cancellationDataLossWarning,
cancellationDialogTitle,
Expand All @@ -14,7 +14,10 @@ import {
mockGetAccount,
} from 'support/intercepts/account';
import { mockWebpageUrl } from 'support/intercepts/general';
import { mockGetProfile } from 'support/intercepts/profile';
import {
mockGetProfile,
mockGetProfileGrants,
} from 'support/intercepts/profile';
import { ui } from 'support/ui';
import {
randomDomainName,
Expand Down Expand Up @@ -170,14 +173,16 @@ describe('Account cancellation', () => {
email: '[email protected]',
restricted: true,
});
const mockGrants = grantsFactory.build();

mockGetAccount(mockAccount).as('getAccount');
mockGetProfile(mockProfile).as('getProfile');
mockGetProfileGrants(mockGrants).as('getGrants');
mockCancelAccountError('Unauthorized', 403).as('cancelAccount');

// Navigate to Account Settings page, click "Close Account" button.
cy.visitWithLogin('/account/settings');
cy.wait(['@getAccount', '@getProfile']);
cy.wait(['@getAccount', '@getProfile', '@getGrants']);

cy.findByTestId('close-account')
.should('be.visible')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
* @file Integration tests for Cloud Manager account enable Linode Managed flows.
*/

import { linodeFactory, profileFactory } from '@linode/utilities';
import {
grantsFactory,
linodeFactory,
profileFactory,
} from '@linode/utilities';
import {
visitUrlWithManagedDisabled,
visitUrlWithManagedEnabled,
Expand All @@ -17,7 +21,10 @@ import {
mockGetAccount,
} from 'support/intercepts/account';
import { mockGetLinodes } from 'support/intercepts/linodes';
import { mockGetProfile } from 'support/intercepts/profile';
import {
mockGetProfile,
mockGetProfileGrants,
} from 'support/intercepts/profile';
import { ui } from 'support/ui';
import { chooseRegion } from 'support/util/regions';

Expand Down Expand Up @@ -100,16 +107,18 @@ describe('Account Linode Managed', () => {
restricted: true,
username: 'mock-restricted-user',
});
const mockGrants = grantsFactory.build();
const errorMessage = 'Unauthorized';

mockGetLinodes([]);
mockGetAccount(mockAccount).as('getAccount');
mockGetProfile(mockProfile).as('getProfile');
mockGetProfileGrants(mockGrants).as('getGrants');
mockEnableLinodeManagedError(errorMessage, 403).as('enableLinodeManaged');

// Navigate to Account Settings page, click "Add Linode Managed" button.
visitUrlWithManagedDisabled('/account/settings');
cy.wait(['@getAccount', '@getProfile']);
cy.wait(['@getAccount', '@getProfile', '@getGrants']);

ui.button
.findByTitle('Add Linode Managed')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@
* @file Integration tests for Cloud Manager account login history flows.
*/

import { profileFactory } from '@linode/utilities';
import { grantsFactory, profileFactory } from '@linode/utilities';
import {
loginEmptyStateMessageText,
loginHelperText,
} from 'support/constants/account';
import { mockGetAccountLogins } from 'support/intercepts/account';
import { mockGetProfile } from 'support/intercepts/profile';
import {
mockGetProfile,
mockGetProfileGrants,
} from 'support/intercepts/profile';

import { accountLoginFactory } from 'src/factories/accountLogin';
import { PARENT_USER } from 'src/features/Account/constants';
Expand Down Expand Up @@ -100,12 +103,14 @@ describe('Account login history', () => {
user_type: 'child',
username: 'mock-child-user',
});
const mockGrants = grantsFactory.build();

mockGetProfile(mockProfile).as('getProfile');
mockGetProfileGrants(mockGrants).as('getGrants');

// Navigate to Account Login History page.
cy.visitWithLogin('/account/login-history');
cy.wait(['@getProfile']);
cy.wait(['@getProfile', '@getGrants']);

// Confirm helper text above table and table are not visible.
cy.findByText(loginHelperText).should('not.exist');
Expand Down Expand Up @@ -149,12 +154,14 @@ describe('Account login history', () => {
user_type: 'default',
username: 'mock-restricted-user',
});
const mockGrants = grantsFactory.build();

mockGetProfileGrants(mockGrants).as('getGrants');
mockGetProfile(mockProfile).as('getProfile');

// Navigate to Account Login History page.
cy.visitWithLogin('/account/login-history');
cy.wait(['@getProfile']);
cy.wait(['@getProfile', '@getGrants']);

// Confirm helper text above table and table are not visible.
cy.findByText(loginHelperText).should('not.exist');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { profileFactory } from '@linode/utilities';
import { grantsFactory, profileFactory } from '@linode/utilities';
import { getProfile } from 'support/api/account';
import { mockUpdateUsername } from 'support/intercepts/account';
import { interceptGetProfile } from 'support/intercepts/profile';
import {
interceptGetProfile,
mockGetProfileGrants,
} from 'support/intercepts/profile';
import { mockGetProfile } from 'support/intercepts/profile';
import { ui } from 'support/ui';
import { randomString } from 'support/util/random';
Expand Down Expand Up @@ -96,6 +99,9 @@ describe('Display Settings', () => {
username: 'restricted-proxy-user',
});

const mockGrants = grantsFactory.build();
mockGetProfileGrants(mockGrants);

verifyUsernameAndEmail(
mockRestrictedProxyProfile,
RESTRICTED_FIELD_TOOLTIP,
Expand Down Expand Up @@ -123,6 +129,9 @@ describe('Display Settings', () => {
username: 'regular-restricted-user',
});

const mockGrants = grantsFactory.build();
mockGetProfileGrants(mockGrants);

verifyUsernameAndEmail(
mockRegularRestrictedProfile,
'Restricted users cannot update their username. Please contact an account administrator.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,10 +249,6 @@ describe('restricted user details pages', () => {
cy.visitWithLogin(`/images`);
cy.wait(['@getCustomImages', '@getProfile', '@getRecoveryImages']);

cy.findByText(
`You don't have permissions to create Images. Please contact your ${ADMINISTRATOR} to request the necessary permissions.`
);

// Confirm that the "Create Image" button is visible and disabled
ui.button
.findByTitle('Create Image')
Expand Down Expand Up @@ -307,11 +303,6 @@ describe('restricted user details pages', () => {

cy.wait(['@getProfile', '@getVolumes']);

// Confirm that a warning message is displayed
cy.findByText(
`You don't have permissions to create or edit Volumes. Please contact your ${ADMINISTRATOR} to request the necessary permissions.`
);

// Confirm that the "Create Volume" button is disabled
ui.button
.findByTitle('Create Volume')
Expand Down Expand Up @@ -587,11 +578,6 @@ describe('restricted user details pages', () => {
cy.visitWithLogin('/longview');
cy.wait(['@getProfile', '@getLongviewClients']);

// Confirm that the warning message is displayed
cy.findByText(
`You don't have permissions to create Longview Clients. Please contact your ${ADMINISTRATOR} to request the necessary permissions.`
);

// Confirm that the "Add Client" button is disabled
ui.button
.findByTitle('Add Client')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,6 @@ describe('User permission management', () => {
...mockUserGrants,
global: {
account_access: 'read_only',
add_buckets: true,
add_databases: true,
add_domains: true,
add_firewalls: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { profileFactory, regionFactory } from '@linode/utilities';
import {
grantsFactory,
profileFactory,
regionFactory,
} from '@linode/utilities';
import { mockGetAccount } from 'support/intercepts/account';
import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags';
import {
mockGetAccessKeys,
mockGetObjectStorageEndpoints,
} from 'support/intercepts/object-storage';
import { mockGetProfile } from 'support/intercepts/profile';
import {
mockGetProfile,
mockGetProfileGrants,
} from 'support/intercepts/profile';
import { mockGetRegions } from 'support/intercepts/regions';
import { ui } from 'support/ui';

Expand Down Expand Up @@ -206,6 +213,7 @@ describe('Object Storage Gen2 create access key modal has disabled fields for re
restricted: true,
})
).as('getProfile');
mockGetProfileGrants(grantsFactory.build());
});

// access keys creation
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { profileFactory, regionFactory } from '@linode/utilities';
import {
grantsFactory,
profileFactory,
regionFactory,
} from '@linode/utilities';
import { mockGetAccount } from 'support/intercepts/account';
import { mockAppendFeatureFlags } from 'support/intercepts/feature-flags';
import {
Expand All @@ -9,7 +13,10 @@ import {
mockGetBuckets,
mockGetObjectStorageEndpoints,
} from 'support/intercepts/object-storage';
import { mockGetProfile } from 'support/intercepts/profile';
import {
mockGetProfile,
mockGetProfileGrants,
} from 'support/intercepts/profile';
import { mockGetRegions } from 'support/intercepts/regions';
import { ui } from 'support/ui';
import { checkRateLimitsTable } from 'support/util/object-storage-gen2';
Expand Down Expand Up @@ -756,12 +763,13 @@ describe('Object Storage Gen2 create bucket modal has disabled fields for restri
restricted: true,
})
).as('getProfile');
mockGetProfileGrants(grantsFactory.build()).as('getGrants');
});

// bucket creation
it('create bucket form', () => {
cy.visitWithLogin('/object-storage/buckets/create');
cy.wait(['@getFeatureFlags', '@getAccount', '@getProfile']);
cy.wait(['@getFeatureFlags', '@getAccount', '@getProfile', '@getGrants']);

// error message
ui.drawer
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { profileFactory } from '@linode/utilities';
import { grantsFactory, profileFactory } from '@linode/utilities';
import { accountFactory, appTokenFactory } from '@src/factories';
import { accountUserFactory } from '@src/factories/accountUsers';
import { DateTime } from 'luxon';
Expand All @@ -12,6 +12,7 @@ import {
mockGetAppTokens,
mockGetPersonalAccessTokens,
mockGetProfile,
mockGetProfileGrants,
} from 'support/intercepts/profile';
import { ui } from 'support/ui';
import { randomLabel, randomNumber, randomString } from 'support/util/random';
Expand All @@ -25,6 +26,8 @@ const mockParentProfile = profileFactory.build({
username: randomLabel(),
});

const mockGrants = grantsFactory.build();

const mockParentUser = accountUserFactory.build({
user_type: 'parent',
username: mockParentProfile.username,
Expand Down Expand Up @@ -55,6 +58,7 @@ describe('Token scopes', () => {
mockGetAccount(mockParentAccount);
mockGetChildAccounts([mockChildAccount]);
mockGetProfile({ ...mockParentProfile, restricted: true });
mockGetProfileGrants(mockGrants);
mockGetUser(mockParentUser);

mockGetPersonalAccessTokens([]).as('getTokens');
Expand Down
18 changes: 13 additions & 5 deletions packages/manager/src/GoTo.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import { useAccountSettings, useGrants, useProfile } from '@linode/queries';
import { Dialog, Select } from '@linode/ui';
import * as React from 'react';
import { useHistory } from 'react-router-dom';

import { useIsDatabasesEnabled } from './features/Databases/utilities';
import { useIsPlacementGroupsEnabled } from './features/PlacementGroups/utils';
import { useAccountManagement } from './hooks/useAccountManagement';
import { useGlobalKeyboardListener } from './hooks/useGlobalKeyboardListener';

import type { SelectOption } from '@linode/ui';

export const GoTo = React.memo(() => {
const routerHistory = useHistory();
const { _hasAccountAccess, _isManagedAccount } = useAccountManagement();

const { data: accountSettings } = useAccountSettings();
const { data: grants } = useGrants();
const { data: profile } = useProfile();

const isManagedAccount = accountSettings?.managed ?? false;

const hasAccountAccess =
!profile?.restricted || Boolean(grants?.global.account_access);

const { isPlacementGroupsEnabled } = useIsPlacementGroupsEnabled();
const { isDatabasesEnabled } = useIsDatabasesEnabled();
Expand All @@ -30,7 +38,7 @@
() => [
{
display: 'Managed',
hide: !_isManagedAccount,
hide: !isManagedAccount,
href: '/managed',
},
{
Expand Down Expand Up @@ -97,7 +105,7 @@
},
{
display: 'Account',
hide: !_hasAccountAccess,
hide: !hasAccountAccess,
href: '/account/billing',
},
{
Expand All @@ -109,7 +117,7 @@
href: '/profile/display',
},
],
[_hasAccountAccess, _isManagedAccount, isPlacementGroupsEnabled]
[hasAccountAccess, isManagedAccount, isPlacementGroupsEnabled]

Check warning on line 120 in packages/manager/src/GoTo.tsx

View workflow job for this annotation

GitHub Actions / ESLint Review (manager)

[eslint] reported by reviewdog 🐢 React Hook React.useMemo has a missing dependency: 'isDatabasesEnabled'. Either include it or remove the dependency array. Raw Output: {"ruleId":"react-hooks/exhaustive-deps","severity":1,"message":"React Hook React.useMemo has a missing dependency: 'isDatabasesEnabled'. Either include it or remove the dependency array.","line":120,"column":5,"nodeType":"ArrayExpression","endLine":120,"endColumn":67,"suggestions":[{"desc":"Update the dependencies array to be: [hasAccountAccess, isDatabasesEnabled, isManagedAccount, isPlacementGroupsEnabled]","fix":{"range":[2959,3021],"text":"[hasAccountAccess, isDatabasesEnabled, isManagedAccount, isPlacementGroupsEnabled]"}}]}
);

const options: SelectOption<string>[] = React.useMemo(
Expand Down
Loading