diff --git a/packages/api-v4/src/account/types.ts b/packages/api-v4/src/account/types.ts index 7dd8c6ab700..4dacb0bb2b6 100644 --- a/packages/api-v4/src/account/types.ts +++ b/packages/api-v4/src/account/types.ts @@ -209,6 +209,7 @@ export type GlobalGrantTypes = | 'add_vpcs' | 'cancel_account' | 'child_account_access' + | 'add_buckets' | 'longview_subscription'; export interface GlobalGrants { diff --git a/packages/manager/.changeset/pr-11672-fixed-1739863532671.md b/packages/manager/.changeset/pr-11672-fixed-1739863532671.md new file mode 100644 index 00000000000..4cb90fe4701 --- /dev/null +++ b/packages/manager/.changeset/pr-11672-fixed-1739863532671.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Fixed +--- + +OBJ Create flow for Restricted user ([#11672](https://github.com/linode/manager/pull/11672)) diff --git a/packages/manager/cypress/e2e/core/account/user-permissions.spec.ts b/packages/manager/cypress/e2e/core/account/user-permissions.spec.ts index 7d97c8251f5..4c432546837 100644 --- a/packages/manager/cypress/e2e/core/account/user-permissions.spec.ts +++ b/packages/manager/cypress/e2e/core/account/user-permissions.spec.ts @@ -280,6 +280,7 @@ describe('User permission management', () => { account_access: 'read_only', cancel_account: true, child_account_access: true, + add_buckets: true, add_domains: true, add_databases: true, add_firewalls: true, diff --git a/packages/manager/cypress/e2e/core/objectStorageGen2/bucket-create-gen2.spec.ts b/packages/manager/cypress/e2e/core/objectStorageGen2/bucket-create-gen2.spec.ts index 69aca1c76c6..5be1defc9f2 100644 --- a/packages/manager/cypress/e2e/core/objectStorageGen2/bucket-create-gen2.spec.ts +++ b/packages/manager/cypress/e2e/core/objectStorageGen2/bucket-create-gen2.spec.ts @@ -763,10 +763,10 @@ describe('Object Storage Gen2 create bucket modal has disabled fields for restri .should('be.visible') .should('be.disabled'); ui.regionSelect.find().should('be.visible').should('be.disabled'); - // submit button should be enabled + // submit button should be disabled cy.findByTestId('create-bucket-button') .should('be.visible') - .should('be.enabled'); + .should('be.disabled'); }); }); }); diff --git a/packages/manager/src/factories/grants.ts b/packages/manager/src/factories/grants.ts index b641263ca03..3d8f631f5d3 100644 --- a/packages/manager/src/factories/grants.ts +++ b/packages/manager/src/factories/grants.ts @@ -31,6 +31,7 @@ export const grantsFactory = Factory.Sync.makeFactory({ ], global: { account_access: 'read_write', + add_buckets: true, add_databases: true, add_domains: true, add_firewalls: true, diff --git a/packages/manager/src/features/Account/constants.ts b/packages/manager/src/features/Account/constants.ts index 992e72762e5..575c0ccf20c 100644 --- a/packages/manager/src/features/Account/constants.ts +++ b/packages/manager/src/features/Account/constants.ts @@ -4,6 +4,7 @@ export const CUSTOMER_SUPPORT = 'customer support'; export const grantTypeMap = { account: 'Account', + bucket: 'Buckets', database: 'Databases', domain: 'Domains', firewall: 'Firewalls', diff --git a/packages/manager/src/features/ObjectStorage/BucketLanding/BucketLandingEmptyState.tsx b/packages/manager/src/features/ObjectStorage/BucketLanding/BucketLandingEmptyState.tsx index 1437b514465..117ec2e6ebf 100644 --- a/packages/manager/src/features/ObjectStorage/BucketLanding/BucketLandingEmptyState.tsx +++ b/packages/manager/src/features/ObjectStorage/BucketLanding/BucketLandingEmptyState.tsx @@ -2,6 +2,8 @@ import * as React from 'react'; import { useHistory } from 'react-router-dom'; import { ResourcesSection } from 'src/components/EmptyLandingPageResources/ResourcesSection'; +import { getRestrictedResourceText } from 'src/features/Account/utils'; +import { useRestrictedGlobalGrantCheck } from 'src/hooks/useRestrictedGlobalGrantCheck'; import { sendEvent } from 'src/utilities/analytics/utils'; import { @@ -15,12 +17,16 @@ import { StyledBucketIcon } from './StylesBucketIcon'; export const BucketLandingEmptyState = () => { const history = useHistory(); + const isBucketCreationRestricted = useRestrictedGlobalGrantCheck({ + globalGrantType: 'add_buckets', + }); + return ( { sendEvent({ action: 'Click:button', @@ -29,6 +35,11 @@ export const BucketLandingEmptyState = () => { }); history.replace('/object-storage/buckets/create'); }, + tooltipText: getRestrictedResourceText({ + action: 'create', + isSingular: false, + resourceType: 'Buckets', + }), }, ]} gettingStartedGuidesData={gettingStartedGuides} diff --git a/packages/manager/src/features/ObjectStorage/BucketLanding/CreateBucketDrawer.tsx b/packages/manager/src/features/ObjectStorage/BucketLanding/CreateBucketDrawer.tsx index 6c01457358f..2d514dd0631 100644 --- a/packages/manager/src/features/ObjectStorage/BucketLanding/CreateBucketDrawer.tsx +++ b/packages/manager/src/features/ObjectStorage/BucketLanding/CreateBucketDrawer.tsx @@ -8,6 +8,7 @@ import { Controller, useForm } from 'react-hook-form'; import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel'; import { Drawer } from 'src/components/Drawer'; import { EUAgreementCheckbox } from 'src/features/Account/Agreements/EUAgreementCheckbox'; +import { useRestrictedGlobalGrantCheck } from 'src/hooks/useRestrictedGlobalGrantCheck'; import { reportAgreementSigningError, useAccountAgreements, @@ -57,6 +58,10 @@ export const CreateBucketDrawer = (props: Props) => { isInitialLoading: isLoadingTransferTypes, } = useNetworkTransferPricesQuery(isOpen); + const isBucketCreationRestricted = useRestrictedGlobalGrantCheck({ + globalGrantType: 'add_buckets', + }); + const isErrorTypes = isErrorTransferTypes || isErrorObjTypes; const isLoadingTypes = isLoadingTransferTypes || isLoadingObjTypes; const isInvalidPrice = @@ -197,7 +202,10 @@ export const CreateBucketDrawer = (props: Props) => { { const hasSingleEndpointType = filteredEndpointOptions?.length === 1; + const isBucketCreationRestricted = useRestrictedGlobalGrantCheck({ + globalGrantType: 'add_buckets', + }); + const selectedEndpointOption = React.useMemo(() => { const currentEndpointType = watch('endpoint_type'); const currentS3Endpoint = watch('s3_endpoint'); @@ -391,7 +396,9 @@ export const OMC_CreateBucketDrawer = (props: Props) => { primaryButtonProps={{ 'data-testid': 'create-bucket-button', disabled: - (showGDPRCheckbox && !state.hasSignedAgreement) || isErrorTypes, + (showGDPRCheckbox && !state.hasSignedAgreement) || + isErrorTypes || + isBucketCreationRestricted, label: 'Create Bucket', loading: isPending || Boolean(selectedRegion?.id && isLoadingTypes), tooltipText: diff --git a/packages/manager/src/features/ObjectStorage/ObjectStorageLanding.tsx b/packages/manager/src/features/ObjectStorage/ObjectStorageLanding.tsx index 65f19ac5c33..5852a3156f9 100644 --- a/packages/manager/src/features/ObjectStorage/ObjectStorageLanding.tsx +++ b/packages/manager/src/features/ObjectStorage/ObjectStorageLanding.tsx @@ -18,9 +18,11 @@ import { Tabs } from 'src/components/Tabs/Tabs'; import { useAccountManagement } from 'src/hooks/useAccountManagement'; import { useFlags } from 'src/hooks/useFlags'; import { useOpenClose } from 'src/hooks/useOpenClose'; +import { useRestrictedGlobalGrantCheck } from 'src/hooks/useRestrictedGlobalGrantCheck'; import { useObjectStorageBuckets } from 'src/queries/object-storage/queries'; import { isFeatureEnabledV2 } from 'src/utilities/accountCapabilities'; +import { getRestrictedResourceText } from '../Account/utils'; import { CreateBucketDrawer } from './BucketLanding/CreateBucketDrawer'; import { OMC_BucketLanding } from './BucketLanding/OMC_BucketLanding'; import { OMC_CreateBucketDrawer } from './BucketLanding/OMC_CreateBucketDrawer'; @@ -95,6 +97,10 @@ export const ObjectStorageLanding = () => { userHasNoBucketCreated && accountSettings?.object_storage === 'active'; + const isBucketCreationRestricted = useRestrictedGlobalGrantCheck({ + globalGrantType: 'add_buckets', + }); + const shouldHideDocsAndCreateButtons = !areBucketsLoading && tab === 'buckets' && userHasNoBucketCreated; @@ -129,8 +135,16 @@ export const ObjectStorageLanding = () => { }`} />