From 03f19b0afb52aa38c1ee67641f45eb4b1ca9faba Mon Sep 17 00:00:00 2001 From: Hussain Khalil <122488130+hkhalil-akamai@users.noreply.github.com> Date: Fri, 24 Jan 2025 14:04:16 -0500 Subject: [PATCH] upcoming: [M3-9064] - Quotas tab placeholder (#11551) * API spec update * Create feature-flagged placeholder Account Quotas tab * Add DocumentTitleSegment * Added changeset: Add placeholder Quotas tab in Accounts page * Added changeset: Quotas API spec to make region field optional * PR feedback @abailly-akamai @mjac0bs --- .../pr-11551-changed-1737735976057.md | 5 ++ packages/api-v4/src/quotas/types.ts | 4 +- ...r-11551-upcoming-features-1737587942784.md | 5 ++ .../src/features/Account/AccountLanding.tsx | 20 +++++++ .../manager/src/features/Account/Quotas.tsx | 53 +++++++++++++++++++ .../features/TopMenu/UserMenu/UserMenu.tsx | 4 ++ .../src/mocks/presets/crud/handlers/quotas.ts | 3 -- 7 files changed, 90 insertions(+), 4 deletions(-) create mode 100644 packages/api-v4/.changeset/pr-11551-changed-1737735976057.md create mode 100644 packages/manager/.changeset/pr-11551-upcoming-features-1737587942784.md create mode 100644 packages/manager/src/features/Account/Quotas.tsx diff --git a/packages/api-v4/.changeset/pr-11551-changed-1737735976057.md b/packages/api-v4/.changeset/pr-11551-changed-1737735976057.md new file mode 100644 index 00000000000..56330dcef6e --- /dev/null +++ b/packages/api-v4/.changeset/pr-11551-changed-1737735976057.md @@ -0,0 +1,5 @@ +--- +"@linode/api-v4": Changed +--- + +Quotas API spec to make region field optional ([#11551](https://github.com/linode/manager/pull/11551)) diff --git a/packages/api-v4/src/quotas/types.ts b/packages/api-v4/src/quotas/types.ts index 23c42f00165..9c833f4bdd2 100644 --- a/packages/api-v4/src/quotas/types.ts +++ b/packages/api-v4/src/quotas/types.ts @@ -49,8 +49,10 @@ export interface Quota { /** * The region slug to which this limit applies. + * + * OBJ limits are applied by endpoint, not region. */ - region_applied: Region['id'] | 'global'; + region_applied?: Region['id'] | 'global'; /** * The OBJ endpoint type to which this limit applies. diff --git a/packages/manager/.changeset/pr-11551-upcoming-features-1737587942784.md b/packages/manager/.changeset/pr-11551-upcoming-features-1737587942784.md new file mode 100644 index 00000000000..fa5e0d8d438 --- /dev/null +++ b/packages/manager/.changeset/pr-11551-upcoming-features-1737587942784.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +Add placeholder Quotas tab in Accounts page ([#11551](https://github.com/linode/manager/pull/11551)) diff --git a/packages/manager/src/features/Account/AccountLanding.tsx b/packages/manager/src/features/Account/AccountLanding.tsx index 8857068450f..980b1ef25ce 100644 --- a/packages/manager/src/features/Account/AccountLanding.tsx +++ b/packages/manager/src/features/Account/AccountLanding.tsx @@ -12,6 +12,7 @@ import { Tabs } from 'src/components/Tabs/Tabs'; import { switchAccountSessionContext } from 'src/context/switchAccountSessionContext'; import { useIsParentTokenExpired } from 'src/features/Account/SwitchAccounts/useIsParentTokenExpired'; import { getRestrictedResourceText } from 'src/features/Account/utils'; +import { useFlags } from 'src/hooks/useFlags'; import { useRestrictedGlobalGrantCheck } from 'src/hooks/useRestrictedGlobalGrantCheck'; import { useAccount } from 'src/queries/account/account'; import { useProfile } from 'src/queries/profile/profile'; @@ -40,6 +41,9 @@ const Users = React.lazy(() => default: module.UsersLanding, })) ); +const Quotas = React.lazy(() => + import('./Quotas').then((module) => ({ default: module.Quotas })) +); const GlobalSettings = React.lazy(() => import('./GlobalSettings')); const MaintenanceLanding = React.lazy( () => import('./Maintenance/MaintenanceLanding') @@ -50,6 +54,7 @@ const AccountLanding = () => { const location = useLocation(); const { data: account } = useAccount(); const { data: profile } = useProfile(); + const { limitsEvolution } = useFlags(); const [isDrawerOpen, setIsDrawerOpen] = React.useState(false); const sessionContext = React.useContext(switchAccountSessionContext); @@ -59,6 +64,8 @@ const AccountLanding = () => { const isChildUser = profile?.user_type === 'child'; const isParentUser = profile?.user_type === 'parent'; + const showQuotasTab = limitsEvolution?.enabled ?? false; + const isReadOnly = useRestrictedGlobalGrantCheck({ globalGrantType: 'account_access', @@ -80,6 +87,14 @@ const AccountLanding = () => { routeName: '/account/users', title: 'Users & Grants', }, + ...(showQuotasTab + ? [ + { + routeName: '/account/quotas', + title: 'Quotas', + }, + ] + : []), { routeName: '/account/login-history', title: 'Login History', @@ -193,6 +208,11 @@ const AccountLanding = () => { + {showQuotasTab && ( + + + + )} diff --git a/packages/manager/src/features/Account/Quotas.tsx b/packages/manager/src/features/Account/Quotas.tsx new file mode 100644 index 00000000000..ef2c78c8930 --- /dev/null +++ b/packages/manager/src/features/Account/Quotas.tsx @@ -0,0 +1,53 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { Autocomplete, Divider, Paper, Stack, Typography } from '@linode/ui'; +import { DateTime } from 'luxon'; +import * as React from 'react'; + +import { DateTimeDisplay } from 'src/components/DateTimeDisplay'; +import { DocsLink } from 'src/components/DocsLink/DocsLink'; +import { DocumentTitleSegment } from 'src/components/DocumentTitle'; +import { RegionSelect } from 'src/components/RegionSelect/RegionSelect'; + +import type { Theme } from '@mui/material'; + +export const Quotas = () => { + // @ts-expect-error TODO: this is a placeholder to be replaced with the actual query + const [lastUpdatedDate, setLastUpdatedDate] = React.useState(Date.now()); + + return ( + <> + + ({ + marginTop: theme.spacing(2), + })} + variant="outlined" + > + }> + + + + + + Quotas + + + Last updated:{' '} + + + + {/* TODO: update once link is available */} + + + + + + + ); +}; diff --git a/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx b/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx index 30224c72fe0..54286c4c6bc 100644 --- a/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx +++ b/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx @@ -131,6 +131,10 @@ export const UserMenu = React.memo(() => { hide: isRestrictedUser, href: '/account/users', }, + { + display: 'Quotas', + href: '/account/quotas', + }, // Restricted users can't view the Transfers tab regardless of their grants { display: 'Service Transfers', diff --git a/packages/manager/src/mocks/presets/crud/handlers/quotas.ts b/packages/manager/src/mocks/presets/crud/handlers/quotas.ts index d01593a8214..025046a34ca 100644 --- a/packages/manager/src/mocks/presets/crud/handlers/quotas.ts +++ b/packages/manager/src/mocks/presets/crud/handlers/quotas.ts @@ -73,7 +73,6 @@ const mockQuotas: Record = { endpoint_type: 'E3', quota_limit: 1_000_000_000_000_000, // a petabyte quota_name: 'Total Capacity', - region_applied: 'us-east', resource_metric: 'byte', s3_endpoint: 'us-east-1.linodeobjects.com', used: 900_000_000_000_000, @@ -82,7 +81,6 @@ const mockQuotas: Record = { endpoint_type: 'E3', quota_limit: 1000, quota_name: 'Number of Buckets', - region_applied: 'us-east', resource_metric: 'bucket', s3_endpoint: 'us-east-1.linodeobjects.com', }), @@ -90,7 +88,6 @@ const mockQuotas: Record = { endpoint_type: 'E3', quota_limit: 10_000_000, quota_name: 'Number of Objects', - region_applied: 'us-east', resource_metric: 'object', s3_endpoint: 'us-east-1.linodeobjects.com', }),