diff --git a/packages/manager/src/features/Managed/ManagedDashboardCard/ManagedChartPanel.tsx b/packages/manager/src/features/Managed/ManagedDashboardCard/ManagedChartPanel.tsx
index 83bb9e33cba..9b3d4b2bfbc 100644
--- a/packages/manager/src/features/Managed/ManagedDashboardCard/ManagedChartPanel.tsx
+++ b/packages/manager/src/features/Managed/ManagedDashboardCard/ManagedChartPanel.tsx
@@ -1,10 +1,8 @@
-import { DataSeries, ManagedStatsData } from '@linode/api-v4/lib/managed';
+import { Box } from '@linode/ui';
import { useTheme } from '@mui/material/styles';
-import { Theme } from '@mui/material/styles';
import * as React from 'react';
import { AreaChart } from 'src/components/AreaChart/AreaChart';
-import { Box } from 'src/components/Box';
import { CircleProgress } from 'src/components/CircleProgress';
import { ErrorState } from 'src/components/ErrorState/ErrorState';
import { TabbedPanel } from 'src/components/TabbedPanel/TabbedPanel';
@@ -23,6 +21,9 @@ import {
StyledRootDiv,
} from './ManagedChartPanel.styles';
+import type { DataSeries, ManagedStatsData } from '@linode/api-v4/lib/managed';
+import type { Theme } from '@mui/material/styles';
+
const chartHeight = 300;
interface NetworkTransferProps {
diff --git a/packages/manager/src/features/Managed/SSHAccess/LinodePubKey.tsx b/packages/manager/src/features/Managed/SSHAccess/LinodePubKey.tsx
index 2c1b1f3b631..5cf329f02c9 100644
--- a/packages/manager/src/features/Managed/SSHAccess/LinodePubKey.tsx
+++ b/packages/manager/src/features/Managed/SSHAccess/LinodePubKey.tsx
@@ -1,8 +1,8 @@
+import { Box } from '@linode/ui';
import Grid from '@mui/material/Unstable_Grid2';
import copy from 'copy-to-clipboard';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { ErrorState } from 'src/components/ErrorState/ErrorState';
import { Link } from 'src/components/Link';
diff --git a/packages/manager/src/features/NodeBalancers/ConfigNodeIPSelect.tsx b/packages/manager/src/features/NodeBalancers/ConfigNodeIPSelect.tsx
index 5b086692862..706cacadcce 100644
--- a/packages/manager/src/features/NodeBalancers/ConfigNodeIPSelect.tsx
+++ b/packages/manager/src/features/NodeBalancers/ConfigNodeIPSelect.tsx
@@ -1,8 +1,8 @@
+import { Box } from '@linode/ui';
import React from 'react';
import { Autocomplete } from 'src/components/Autocomplete/Autocomplete';
import { SelectedIcon } from 'src/components/Autocomplete/Autocomplete.styles';
-import { Box } from 'src/components/Box';
import { Stack } from 'src/components/Stack';
import { Typography } from 'src/components/Typography';
import { useAllLinodesQuery } from 'src/queries/linodes/linodes';
diff --git a/packages/manager/src/features/NodeBalancers/NodeBalancerConfigNode.tsx b/packages/manager/src/features/NodeBalancers/NodeBalancerConfigNode.tsx
index c97f7bc1345..00a6c05c09c 100644
--- a/packages/manager/src/features/NodeBalancers/NodeBalancerConfigNode.tsx
+++ b/packages/manager/src/features/NodeBalancers/NodeBalancerConfigNode.tsx
@@ -1,9 +1,9 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import Grid from '@mui/material/Unstable_Grid2';
import * as React from 'react';
import { Autocomplete } from 'src/components/Autocomplete/Autocomplete';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { Chip } from 'src/components/Chip';
import { Divider } from 'src/components/Divider';
diff --git a/packages/manager/src/features/NodeBalancers/NodeBalancerCreate.tsx b/packages/manager/src/features/NodeBalancers/NodeBalancerCreate.tsx
index 8957d664cc4..096cc3925ce 100644
--- a/packages/manager/src/features/NodeBalancers/NodeBalancerCreate.tsx
+++ b/packages/manager/src/features/NodeBalancers/NodeBalancerCreate.tsx
@@ -1,3 +1,4 @@
+import { Box } from '@linode/ui';
import { useTheme } from '@mui/material';
import useMediaQuery from '@mui/material/useMediaQuery';
import { createLazyRoute } from '@tanstack/react-router';
@@ -15,7 +16,6 @@ import { useHistory } from 'react-router-dom';
import { Accordion } from 'src/components/Accordion';
import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { CheckoutSummary } from 'src/components/CheckoutSummary/CheckoutSummary';
import { ConfirmationDialog } from 'src/components/ConfirmationDialog/ConfirmationDialog';
@@ -55,8 +55,8 @@ import { sendCreateNodeBalancerEvent } from 'src/utilities/analytics/customEvent
import { getAPIErrorOrDefault } from 'src/utilities/errorUtils';
import { getGDPRDetails } from 'src/utilities/formatRegion';
import { getAPIErrorFor } from 'src/utilities/getAPIErrorFor';
-import { DOCS_LINK_LABEL_DC_PRICING } from 'src/utilities/pricing/constants';
import { PRICE_ERROR_TOOLTIP_TEXT } from 'src/utilities/pricing/constants';
+import { DOCS_LINK_LABEL_DC_PRICING } from 'src/utilities/pricing/constants';
import {
getDCSpecificPriceByType,
renderMonthlyPriceToCorrectDecimalPlace,
diff --git a/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerConfigurations.tsx b/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerConfigurations.tsx
index 66e713df1a8..ad4237c39ee 100644
--- a/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerConfigurations.tsx
+++ b/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerConfigurations.tsx
@@ -8,6 +8,7 @@ import {
updateNodeBalancerConfig,
updateNodeBalancerConfigNode,
} from '@linode/api-v4/lib/nodebalancers';
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import {
append,
@@ -26,7 +27,6 @@ import { compose as composeC } from 'recompose';
import { Accordion } from 'src/components/Accordion';
import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { ConfirmationDialog } from 'src/components/ConfirmationDialog/ConfirmationDialog';
import { DocumentTitleSegment } from 'src/components/DocumentTitle';
diff --git a/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerFirewalls.tsx b/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerFirewalls.tsx
index a328bac072e..0ab0801891f 100644
--- a/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerFirewalls.tsx
+++ b/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerFirewalls.tsx
@@ -1,8 +1,8 @@
/* eslint-disable jsx-a11y/anchor-is-valid */
+import { Box } from '@linode/ui';
import { Stack } from '@mui/material';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Link } from 'src/components/Link';
import { Table } from 'src/components/Table';
import { TableBody } from 'src/components/TableBody';
diff --git a/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerSummary/TablesPanel.tsx b/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerSummary/TablesPanel.tsx
index f981ac37906..98342107eee 100644
--- a/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerSummary/TablesPanel.tsx
+++ b/packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerSummary/TablesPanel.tsx
@@ -1,3 +1,4 @@
+import { Box } from '@linode/ui';
import { useTheme } from '@mui/material/styles';
import { styled } from '@mui/material/styles';
import * as React from 'react';
@@ -5,7 +6,6 @@ import { useParams } from 'react-router-dom';
import PendingIcon from 'src/assets/icons/pending.svg';
import { AreaChart } from 'src/components/AreaChart/AreaChart';
-import { Box } from 'src/components/Box';
import { CircleProgress } from 'src/components/CircleProgress';
import { ErrorState } from 'src/components/ErrorState/ErrorState';
import { Paper } from 'src/components/Paper';
diff --git a/packages/manager/src/features/components/PlansPanel/DistributedRegionPlanTable.tsx b/packages/manager/src/features/components/PlansPanel/DistributedRegionPlanTable.tsx
index 1f56b1ce1b5..0512c10190c 100644
--- a/packages/manager/src/features/components/PlansPanel/DistributedRegionPlanTable.tsx
+++ b/packages/manager/src/features/components/PlansPanel/DistributedRegionPlanTable.tsx
@@ -1,7 +1,7 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import React from 'react';
-import { Box } from 'src/components/Box';
import { Notice } from 'src/components/Notice/Notice';
import { Paper } from 'src/components/Paper';
import { Typography } from 'src/components/Typography';
diff --git a/packages/ui/.changeset/pr-11163-added-1729870035646.md b/packages/ui/.changeset/pr-11163-added-1729870035646.md
new file mode 100644
index 00000000000..715546f8923
--- /dev/null
+++ b/packages/ui/.changeset/pr-11163-added-1729870035646.md
@@ -0,0 +1,5 @@
+---
+"@linode/ui": Added
+---
+
+`Box` component from `manager` to `ui` package, part 1 ([#11163](https://github.com/linode/manager/pull/11163))
diff --git a/packages/manager/src/components/Box.stories.tsx b/packages/ui/src/components/Box/Box.stories.tsx
similarity index 85%
rename from packages/manager/src/components/Box.stories.tsx
rename to packages/ui/src/components/Box/Box.stories.tsx
index 11b944f45cb..bd3c2d899bf 100644
--- a/packages/manager/src/components/Box.stories.tsx
+++ b/packages/ui/src/components/Box/Box.stories.tsx
@@ -1,8 +1,9 @@
-import { Meta, StoryObj } from '@storybook/react';
import React from 'react';
import { Box } from './Box';
+import type { Meta, StoryObj } from '@storybook/react';
+
const meta: Meta = {
component: Box,
title: 'Foundations/Box',
diff --git a/packages/ui/src/components/Box/Box.tsx b/packages/ui/src/components/Box/Box.tsx
new file mode 100644
index 00000000000..b7f8b802eca
--- /dev/null
+++ b/packages/ui/src/components/Box/Box.tsx
@@ -0,0 +1,14 @@
+import { default as _Box } from '@mui/material/Box';
+import React from 'react';
+
+import type { BoxProps } from '@mui/material/Box';
+
+/**
+ * The Box component serves as a wrapper for creating simple layouts or styles.
+ * It uses a `
` unless unless you change it with the `component` prop
+ */
+export const Box = (props: BoxProps) => {
+ return <_Box {...props} />;
+};
+
+export type { BoxProps };
diff --git a/packages/ui/src/components/Box/index.ts b/packages/ui/src/components/Box/index.ts
new file mode 100644
index 00000000000..305f81d78bc
--- /dev/null
+++ b/packages/ui/src/components/Box/index.ts
@@ -0,0 +1 @@
+export * from './Box';
diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts
index ec50522e5dc..d05c00c3913 100644
--- a/packages/ui/src/components/index.ts
+++ b/packages/ui/src/components/index.ts
@@ -1,5 +1,6 @@
-export * from './Chip';
export * from './BetaChip';
+export * from './Box';
+export * from './Chip';
export * from './FormControl';
export * from './FormHelperText';
export * from './IconButton';
From fef87a9d20e7260916e422b21e50f33553cc0be4 Mon Sep 17 00:00:00 2001
From: Connie Liu <139280159+coliu-akamai@users.noreply.github.com>
Date: Wed, 30 Oct 2024 11:51:40 -0400
Subject: [PATCH 22/66] refactor: [M3-8641] - Move Box component to ui package
(Part 2) (#11164)
* move box to ui package part 2
* consolidate double imports to linode/ui
* Added changeset: `Box` component from `manager` to `ui` package, part 2
* missed box import
---
.../components/ActionsPanel/ActionsPanel.tsx | 5 +-
.../AkamaiBanner/AkamaiBanner.styles.ts | 2 +-
.../components/AkamaiBanner/AkamaiBanner.tsx | 2 +-
.../components/Autocomplete/Autocomplete.tsx | 3 +-
.../manager/src/components/AvatarForProxy.tsx | 2 +-
packages/manager/src/components/Box.tsx | 12 -----
.../CircleProgress/CircleProgress.tsx | 2 +-
.../CopyableTextField/CopyableTextField.tsx | 2 +-
.../DescriptionList/DescriptionList.tsx | 2 +-
.../manager/src/components/Dialog/Dialog.tsx | 2 +-
.../components/DialogTitle/DialogTitle.tsx | 4 +-
.../DismissibleBanner/DismissibleBanner.tsx | 2 +-
.../EditableInput.styles.tsx | 7 +--
.../EnhancedNumberInput.tsx | 2 +-
.../EnhancedSelect/EnhancedSelect.stories.tsx | 3 +-
.../EntityHeader/EntityHeader.stories.tsx | 2 +-
packages/manager/src/components/Flag.tsx | 5 +-
.../LineGraph/AccessibleGraphData.tsx | 3 +-
.../manager/src/components/LinkButton.tsx | 5 +-
.../src/components/MainContentBanner.tsx | 3 +-
.../src/components/MaintenanceScreen.tsx | 6 ++-
packages/manager/src/components/OSIcon.tsx | 5 +-
.../PaginationFooter/PaginationFooter.tsx | 4 +-
.../PlacementGroupSelectOption.tsx | 3 +-
.../src/components/PrimaryNav/PrimaryNav.tsx | 3 +-
.../PrimaryNav/SideMenu.stories.tsx | 3 +-
.../PromiseLoader/PromiseLoader.test.tsx | 2 +-
.../src/components/Radio/Radio.stories.tsx | 3 +-
.../RegionMultiSelect.stories.tsx | 2 +-
.../components/RegionSelect/RegionOption.tsx | 3 +-
.../RegionSelect/RegionSelect.stories.tsx | 2 +-
.../RegionSelect/RegionSelect.styles.ts | 2 +-
.../RemovableSelectionsList.style.ts | 2 +-
.../RemovableSelectionsList.tsx | 4 +-
.../SelectFirewallPanel.tsx | 2 +-
.../SelectRegionPanel/RegionHelperText.tsx | 5 +-
.../manager/src/components/SplashScreen.tsx | 3 +-
.../components/StackScript/StackScript.tsx | 8 +--
.../src/components/StatusIcon/StatusIcon.tsx | 3 +-
.../components/TabbedPanel/TabbedPanel.tsx | 4 +-
.../src/components/TagCell.stories.tsx | 3 +-
.../TagsInput/TagsInput.stories.tsx | 5 +-
packages/manager/src/components/TextField.tsx | 6 +--
.../TransferDisplay/TransferDisplay.styles.ts | 3 +-
.../TransferDisplay/TransferDisplay.tsx | 2 +-
.../TransferDisplay/TransferDisplayDialog.tsx | 4 +-
.../DatabaseLanding/DatabaseLogo.tsx | 3 +-
.../NodePoolsDisplay/NodePool.tsx | 3 +-
.../LinodeNetworking/AddIPDrawer.tsx | 3 +-
.../LinodesLanding/DisplayGroupedLinodes.tsx | 3 +-
.../Events/NotificationCenterEvent.tsx | 2 +-
.../NotificationCenter.styles.ts | 2 +-
.../NotificationCenterNotificationMessage.tsx | 2 +-
...tificationCenterNotificationsContainer.tsx | 2 +-
.../AccessKeyRegions/SelectedRegionsList.tsx | 2 +-
.../AccessKeyLanding/CopyAllHostnames.tsx | 3 +-
.../AccessKeyLanding/HostNamesDrawer.tsx | 2 +-
.../AccessKeyLanding/HostNamesList.tsx | 2 +-
.../BucketDetail/BucketDetail.tsx | 5 +-
.../BucketDetail/ObjectTableRow.tsx | 4 +-
.../BucketLanding/BucketRateLimitTable.tsx | 2 +-
.../BucketLanding/OveragePricing.tsx | 2 +-
.../PlacementGroupPolicyRadioGroup.tsx | 2 +-
.../PlacementGroupsAssignLinodesDrawer.tsx | 4 +-
.../PlacementGroupsSummary.tsx | 4 +-
.../PlacementGroupsDetailPanel.tsx | 2 +-
.../Profile/APITokens/APITokenTable.tsx | 2 +-
.../PhoneVerification.styles.ts | 3 +-
.../PhoneVerification/PhoneVerification.tsx | 3 +-
.../AuthenticationSettings/ResetPassword.tsx | 2 +-
.../AuthenticationSettings/SMSMessaging.tsx | 2 +-
.../QuestionAndAnswerPair.tsx | 3 +-
.../SecurityQuestions/SecurityQuestions.tsx | 2 +-
.../AuthenticationSettings/TPAProviders.tsx | 7 +--
.../TwoFactor/ConfirmToken.tsx | 2 +-
.../Profile/DisplaySettings/AvatarForm.tsx | 2 +-
.../Profile/LishSettings/LishSettings.tsx | 3 +-
.../Profile/OAuthClients/OAuthClients.tsx | 2 +-
.../SecretTokenDialog/SecretTokenDialog.tsx | 2 +-
.../Profile/Settings/PreferenceEditor.tsx | 6 ++-
.../SelectStackScriptPanel.tsx | 52 +++++++++----------
.../UserDefinedFieldsPanel.styles.ts | 2 +-
.../UserDefinedFieldsPanel.tsx | 2 +-
.../manager/src/features/Support/Hively.tsx | 4 +-
.../SupportTickets/SupportTicketDialog.tsx | 2 +-
.../features/Support/TicketAttachmentRow.tsx | 2 +-
.../NotificationMenu/NotificationMenu.tsx | 2 +-
.../TopMenu/SearchBar/SearchSuggestion.tsx | 7 +--
.../manager/src/features/TopMenu/TopMenu.tsx | 3 +-
.../features/TopMenu/UserMenu/UserMenu.tsx | 3 +-
.../src/features/Users/UserPermissions.tsx | 2 +-
.../Users/UserPermissionsEntitySection.tsx | 2 +-
.../Users/UserProfile/DeleteUserPanel.tsx | 2 +-
.../manager/src/features/Users/UserRow.tsx | 2 +-
.../src/features/Users/UsersLanding.tsx | 2 +-
.../VPCs/VPCCreateDrawer/VPCCreateDrawer.tsx | 2 +-
.../VPCs/VPCDetail/AssignIPRanges.tsx | 2 +-
.../SubnetAssignLinodesDrawer.styles.ts | 2 +-
.../VPCDetail/SubnetAssignLinodesDrawer.tsx | 3 +-
.../VPCs/VPCDetail/SubnetLinodeRow.tsx | 2 +-
.../VPCDetail/SubnetUnassignLinodesDrawer.tsx | 2 +-
.../VPCs/VPCDetail/VPCDetail.styles.ts | 2 +-
.../src/features/VPCs/VPCDetail/VPCDetail.tsx | 2 +-
.../VPCs/VPCDetail/VPCSubnetsTable.tsx | 2 +-
.../features/Volumes/AttachVolumeDrawer.tsx | 3 +-
.../features/Volumes/CloneVolumeDrawer.tsx | 2 +-
.../src/features/Volumes/EditVolumeDrawer.tsx | 2 +-
.../src/features/Volumes/VolumeCreate.tsx | 2 +-
.../VolumeDrawer/LinodeVolumeCreateForm.tsx | 2 +-
.../Volumes/VolumeDrawer/PricePanel.tsx | 2 +-
.../Volumes/VolumeDrawer/SizeField.tsx | 3 +-
.../src/features/Volumes/VolumeTableRow.tsx | 2 +-
.../pr-11164-added-1729871599808.md | 5 ++
113 files changed, 177 insertions(+), 211 deletions(-)
delete mode 100644 packages/manager/src/components/Box.tsx
create mode 100644 packages/ui/.changeset/pr-11164-added-1729871599808.md
diff --git a/packages/manager/src/components/ActionsPanel/ActionsPanel.tsx b/packages/manager/src/components/ActionsPanel/ActionsPanel.tsx
index d6ccc6a7053..e743777f5a0 100644
--- a/packages/manager/src/components/ActionsPanel/ActionsPanel.tsx
+++ b/packages/manager/src/components/ActionsPanel/ActionsPanel.tsx
@@ -1,12 +1,11 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import * as React from 'react';
import { useStyles } from 'tss-react/mui';
import { Button } from 'src/components/Button/Button';
-import { Box } from '../Box';
-
-import type { BoxProps } from '../Box';
+import type { BoxProps } from '@linode/ui';
import type { ButtonProps } from 'src/components/Button/Button';
interface ActionButtonsProps extends ButtonProps {
diff --git a/packages/manager/src/components/AkamaiBanner/AkamaiBanner.styles.ts b/packages/manager/src/components/AkamaiBanner/AkamaiBanner.styles.ts
index 39dc67c1658..1788f53a67e 100644
--- a/packages/manager/src/components/AkamaiBanner/AkamaiBanner.styles.ts
+++ b/packages/manager/src/components/AkamaiBanner/AkamaiBanner.styles.ts
@@ -1,10 +1,10 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import Warning from 'src/assets/icons/warning.svg';
import AkamaiLogo from 'src/assets/logo/akamai-logo.svg';
import { omittedProps } from 'src/utilities/omittedProps';
-import { Box } from '../Box';
import { Stack } from '../Stack';
export const StyledAkamaiLogo = styled(AkamaiLogo, {
diff --git a/packages/manager/src/components/AkamaiBanner/AkamaiBanner.tsx b/packages/manager/src/components/AkamaiBanner/AkamaiBanner.tsx
index ea5d2bce76d..1e7421ac180 100644
--- a/packages/manager/src/components/AkamaiBanner/AkamaiBanner.tsx
+++ b/packages/manager/src/components/AkamaiBanner/AkamaiBanner.tsx
@@ -1,3 +1,4 @@
+import { Box } from '@linode/ui';
import { useMediaQuery, useTheme } from '@mui/material';
import * as React from 'react';
@@ -6,7 +7,6 @@ import { Typography } from 'src/components/Typography';
import { useFlags } from 'src/hooks/useFlags';
import { replaceNewlinesWithLineBreaks } from 'src/utilities/replaceNewlinesWithLineBreaks';
-import { Box } from '../Box';
import { Stack } from '../Stack';
import {
StyledAkamaiLogo,
diff --git a/packages/manager/src/components/Autocomplete/Autocomplete.tsx b/packages/manager/src/components/Autocomplete/Autocomplete.tsx
index 7e8ac138df6..a02b78db4a7 100644
--- a/packages/manager/src/components/Autocomplete/Autocomplete.tsx
+++ b/packages/manager/src/components/Autocomplete/Autocomplete.tsx
@@ -1,10 +1,9 @@
-import { InputAdornment } from '@linode/ui';
+import { Box, InputAdornment } from '@linode/ui';
import CloseIcon from '@mui/icons-material/Close';
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import MuiAutocomplete from '@mui/material/Autocomplete';
import React from 'react';
-import { Box } from 'src/components/Box';
import { TextField } from 'src/components/TextField';
import { CircleProgress } from '../CircleProgress';
diff --git a/packages/manager/src/components/AvatarForProxy.tsx b/packages/manager/src/components/AvatarForProxy.tsx
index 16840219df4..d144b083e53 100644
--- a/packages/manager/src/components/AvatarForProxy.tsx
+++ b/packages/manager/src/components/AvatarForProxy.tsx
@@ -1,8 +1,8 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import * as React from 'react';
import ProxyUserIcon from 'src/assets/icons/parent-child.svg';
-import { Box } from 'src/components/Box';
interface Props {
height?: number;
diff --git a/packages/manager/src/components/Box.tsx b/packages/manager/src/components/Box.tsx
deleted file mode 100644
index 3bc8cfdb69e..00000000000
--- a/packages/manager/src/components/Box.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { default as _Box, BoxProps } from '@mui/material/Box';
-import React from 'react';
-
-/**
- * The Box component serves as a wrapper for creating simple layouts or styles.
- * It uses a `
` unless unless you change it with the `component` prop
- */
-export const Box = (props: BoxProps) => {
- return <_Box {...props} />;
-};
-
-export type { BoxProps };
diff --git a/packages/manager/src/components/CircleProgress/CircleProgress.tsx b/packages/manager/src/components/CircleProgress/CircleProgress.tsx
index 474e6e05c9c..1d177ce85e0 100644
--- a/packages/manager/src/components/CircleProgress/CircleProgress.tsx
+++ b/packages/manager/src/components/CircleProgress/CircleProgress.tsx
@@ -1,8 +1,8 @@
+import { Box } from '@linode/ui';
import _CircularProgress from '@mui/material/CircularProgress';
import { styled } from '@mui/material/styles';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { omittedProps } from 'src/utilities/omittedProps';
import type { CircularProgressProps } from '@mui/material/CircularProgress';
diff --git a/packages/manager/src/components/CopyableTextField/CopyableTextField.tsx b/packages/manager/src/components/CopyableTextField/CopyableTextField.tsx
index fbccbae4da6..b26c74a7267 100644
--- a/packages/manager/src/components/CopyableTextField/CopyableTextField.tsx
+++ b/packages/manager/src/components/CopyableTextField/CopyableTextField.tsx
@@ -1,7 +1,7 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { CopyTooltip } from 'src/components/CopyTooltip/CopyTooltip';
import { TextField } from 'src/components/TextField';
diff --git a/packages/manager/src/components/DescriptionList/DescriptionList.tsx b/packages/manager/src/components/DescriptionList/DescriptionList.tsx
index 4711612dd7d..424d53fd90a 100644
--- a/packages/manager/src/components/DescriptionList/DescriptionList.tsx
+++ b/packages/manager/src/components/DescriptionList/DescriptionList.tsx
@@ -1,7 +1,7 @@
+import { Box } from '@linode/ui';
import useMediaQuery from '@mui/material/useMediaQuery';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { TooltipIcon } from 'src/components/TooltipIcon';
import { Typography } from 'src/components/Typography';
diff --git a/packages/manager/src/components/Dialog/Dialog.tsx b/packages/manager/src/components/Dialog/Dialog.tsx
index 1ab4366ca12..8a217c008ea 100644
--- a/packages/manager/src/components/Dialog/Dialog.tsx
+++ b/packages/manager/src/components/Dialog/Dialog.tsx
@@ -1,9 +1,9 @@
+import { Box } from '@linode/ui';
import _Dialog from '@mui/material/Dialog';
import DialogContent from '@mui/material/DialogContent';
import { styled, useTheme } from '@mui/material/styles';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { DialogTitle } from 'src/components/DialogTitle/DialogTitle';
import { Notice } from 'src/components/Notice/Notice';
import { omittedProps } from 'src/utilities/omittedProps';
diff --git a/packages/manager/src/components/DialogTitle/DialogTitle.tsx b/packages/manager/src/components/DialogTitle/DialogTitle.tsx
index 711c328c419..ecf01cd0200 100644
--- a/packages/manager/src/components/DialogTitle/DialogTitle.tsx
+++ b/packages/manager/src/components/DialogTitle/DialogTitle.tsx
@@ -1,11 +1,9 @@
-import { IconButton } from '@linode/ui';
+import { Box, IconButton } from '@linode/ui';
import Close from '@mui/icons-material/Close';
import { Typography } from '@mui/material';
import _DialogTitle from '@mui/material/DialogTitle';
import * as React from 'react';
-import { Box } from 'src/components/Box';
-
import type { SxProps, Theme } from '@mui/material';
interface DialogTitleProps {
diff --git a/packages/manager/src/components/DismissibleBanner/DismissibleBanner.tsx b/packages/manager/src/components/DismissibleBanner/DismissibleBanner.tsx
index 2f1781f9125..0322ed2ffbf 100644
--- a/packages/manager/src/components/DismissibleBanner/DismissibleBanner.tsx
+++ b/packages/manager/src/components/DismissibleBanner/DismissibleBanner.tsx
@@ -1,8 +1,8 @@
+import { Box } from '@linode/ui';
import Close from '@mui/icons-material/Close';
import Grid from '@mui/material/Unstable_Grid2';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { useDismissibleNotifications } from 'src/hooks/useDismissibleNotifications';
import { StyledButton, StyledNotice } from './DismissibleBanner.styles';
diff --git a/packages/manager/src/components/EditableEntityLabel/EditableInput.styles.tsx b/packages/manager/src/components/EditableEntityLabel/EditableInput.styles.tsx
index 5532318f7f7..303542ee695 100644
--- a/packages/manager/src/components/EditableEntityLabel/EditableInput.styles.tsx
+++ b/packages/manager/src/components/EditableEntityLabel/EditableInput.styles.tsx
@@ -1,13 +1,14 @@
+import { Box } from '@linode/ui';
import Edit from '@mui/icons-material/Edit';
import { styled } from '@mui/material/styles';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
-import { TextField, TextFieldProps } from 'src/components/TextField';
+import { TextField } from 'src/components/TextField';
import { Typography } from 'src/components/Typography';
import { fadeIn } from 'src/styles/keyframes';
-import { EditableTextVariant } from './EditableInput';
+import type { EditableTextVariant } from './EditableInput';
+import type { TextFieldProps } from 'src/components/TextField';
export const StyledTypography = styled(Typography, {
label: 'EditableInput__StyledTypography',
diff --git a/packages/manager/src/components/EnhancedNumberInput/EnhancedNumberInput.tsx b/packages/manager/src/components/EnhancedNumberInput/EnhancedNumberInput.tsx
index 6d8d47f0307..cc28261f750 100644
--- a/packages/manager/src/components/EnhancedNumberInput/EnhancedNumberInput.tsx
+++ b/packages/manager/src/components/EnhancedNumberInput/EnhancedNumberInput.tsx
@@ -1,9 +1,9 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import * as React from 'react';
import Minus from 'src/assets/icons/LKEminusSign.svg';
import Plus from 'src/assets/icons/LKEplusSign.svg';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { TextField } from 'src/components/TextField';
diff --git a/packages/manager/src/components/EnhancedSelect/EnhancedSelect.stories.tsx b/packages/manager/src/components/EnhancedSelect/EnhancedSelect.stories.tsx
index dcb03e8fa85..dea546aca84 100644
--- a/packages/manager/src/components/EnhancedSelect/EnhancedSelect.stories.tsx
+++ b/packages/manager/src/components/EnhancedSelect/EnhancedSelect.stories.tsx
@@ -1,8 +1,7 @@
+import { Box } from '@linode/ui';
import { Typography } from '@mui/material';
import React from 'react';
-import { Box } from 'src/components/Box';
-
import Select from './Select';
import type { Item } from './Select';
diff --git a/packages/manager/src/components/EntityHeader/EntityHeader.stories.tsx b/packages/manager/src/components/EntityHeader/EntityHeader.stories.tsx
index e1b05f120ad..abc97c5a100 100644
--- a/packages/manager/src/components/EntityHeader/EntityHeader.stories.tsx
+++ b/packages/manager/src/components/EntityHeader/EntityHeader.stories.tsx
@@ -1,7 +1,7 @@
+import { Box } from '@linode/ui';
import { action } from '@storybook/addon-actions';
import React from 'react';
-import { Box } from 'src/components/Box';
import { EntityHeader } from 'src/components/EntityHeader/EntityHeader';
import { Hidden } from 'src/components/Hidden';
import { LinodeActionMenu } from 'src/features/Linodes/LinodesLanding/LinodeActionMenu/LinodeActionMenu';
diff --git a/packages/manager/src/components/Flag.tsx b/packages/manager/src/components/Flag.tsx
index bd01d381754..5653b3d2fa8 100644
--- a/packages/manager/src/components/Flag.tsx
+++ b/packages/manager/src/components/Flag.tsx
@@ -1,11 +1,10 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import 'flag-icons/css/flag-icons.min.css';
import React from 'react';
-import { Box } from './Box';
-
-import type { BoxProps } from './Box';
import type { Country } from '@linode/api-v4';
+import type { BoxProps } from '@linode/ui';
const COUNTRY_FLAG_OVERRIDES = {
uk: 'gb',
diff --git a/packages/manager/src/components/LineGraph/AccessibleGraphData.tsx b/packages/manager/src/components/LineGraph/AccessibleGraphData.tsx
index dfca22fd283..054c111feed 100644
--- a/packages/manager/src/components/LineGraph/AccessibleGraphData.tsx
+++ b/packages/manager/src/components/LineGraph/AccessibleGraphData.tsx
@@ -2,12 +2,11 @@
* ONLY USED IN THE LINE GRAPH COMPONENT (Longview)
* Delete when LineGraph is sunsetted
*/
+import { Box } from '@linode/ui';
import { visuallyHidden } from '@mui/utils';
import { DateTime } from 'luxon';
import * as React from 'react';
-import { Box } from 'src/components/Box';
-
import type { ChartData, ChartPoint } from 'chart.js';
export interface GraphTabledDataProps {
diff --git a/packages/manager/src/components/LinkButton.tsx b/packages/manager/src/components/LinkButton.tsx
index bcb5a83c521..d3d7caa7f09 100644
--- a/packages/manager/src/components/LinkButton.tsx
+++ b/packages/manager/src/components/LinkButton.tsx
@@ -1,12 +1,13 @@
-import { Theme } from '@mui/material/styles';
+import { Box } from '@linode/ui';
import * as React from 'react';
import { makeStyles } from 'tss-react/mui';
import { CircleProgress } from 'src/components/CircleProgress';
-import { Box } from './Box';
import { StyledLinkButton } from './Button/StyledLinkButton';
+import type { Theme } from '@mui/material/styles';
+
const useStyles = makeStyles()((theme: Theme) => ({
disabled: {
color: theme.palette.text.primary,
diff --git a/packages/manager/src/components/MainContentBanner.tsx b/packages/manager/src/components/MainContentBanner.tsx
index dc1cfb4f56b..a71c8fb0f37 100644
--- a/packages/manager/src/components/MainContentBanner.tsx
+++ b/packages/manager/src/components/MainContentBanner.tsx
@@ -1,3 +1,4 @@
+import { Box } from '@linode/ui';
import Close from '@mui/icons-material/Close';
import { IconButton } from '@mui/material';
import * as React from 'react';
@@ -10,8 +11,6 @@ import {
usePreferences,
} from 'src/queries/profile/preferences';
-import { Box } from './Box';
-
export const MainContentBanner = React.memo(() => {
// Uncomment this to test this banner:
//
diff --git a/packages/manager/src/components/MaintenanceScreen.tsx b/packages/manager/src/components/MaintenanceScreen.tsx
index 7b320806fb4..03d1c85efae 100644
--- a/packages/manager/src/components/MaintenanceScreen.tsx
+++ b/packages/manager/src/components/MaintenanceScreen.tsx
@@ -1,14 +1,16 @@
+import { Box } from '@linode/ui';
import BuildIcon from '@mui/icons-material/Build';
-import { Theme, useTheme } from '@mui/material/styles';
+import { useTheme } from '@mui/material/styles';
import * as React from 'react';
import Logo from 'src/assets/logo/akamai-logo.svg';
-import { Box } from 'src/components/Box';
import { ErrorState } from 'src/components/ErrorState/ErrorState';
import { Link } from 'src/components/Link';
import { Stack } from 'src/components/Stack';
import { Typography } from 'src/components/Typography';
+import type { Theme } from '@mui/material/styles';
+
export const MaintenanceScreen = () => {
const theme = useTheme();
diff --git a/packages/manager/src/components/OSIcon.tsx b/packages/manager/src/components/OSIcon.tsx
index 3a0524da8a5..6ddb6034e40 100644
--- a/packages/manager/src/components/OSIcon.tsx
+++ b/packages/manager/src/components/OSIcon.tsx
@@ -1,10 +1,9 @@
+import { Box } from '@linode/ui';
import 'font-logos/assets/font-logos.css';
import React from 'react';
-import { Box } from './Box';
-
-import type { BoxProps } from './Box';
import type { Image } from '@linode/api-v4';
+import type { BoxProps } from '@linode/ui';
interface Props extends BoxProps {
/**
diff --git a/packages/manager/src/components/PaginationFooter/PaginationFooter.tsx b/packages/manager/src/components/PaginationFooter/PaginationFooter.tsx
index 7bef8e245ca..eefa46d7d30 100644
--- a/packages/manager/src/components/PaginationFooter/PaginationFooter.tsx
+++ b/packages/manager/src/components/PaginationFooter/PaginationFooter.tsx
@@ -1,9 +1,9 @@
+import { Box } from '@linode/ui';
import { styled, useTheme } from '@mui/material/styles';
import * as React from 'react';
import { Autocomplete } from 'src/components/Autocomplete/Autocomplete';
-import { Box } from '../Box';
import { PaginationControls } from '../PaginationControls/PaginationControls';
export const MIN_PAGE_SIZE = 25;
@@ -67,9 +67,9 @@ export const PaginationFooter = (props: Props) => {
background: theme.bg.bgPaper,
}}
alignItems="center"
+ data-qa-table-pagination
display="flex"
justifyContent="space-between"
- data-qa-table-pagination
>
{!isShowingAll && (
void;
diff --git a/packages/manager/src/components/SplashScreen.tsx b/packages/manager/src/components/SplashScreen.tsx
index 5b5836a5d3c..4890a2af50d 100644
--- a/packages/manager/src/components/SplashScreen.tsx
+++ b/packages/manager/src/components/SplashScreen.tsx
@@ -1,10 +1,9 @@
+import { Box } from '@linode/ui';
import * as React from 'react';
import { CircleProgress } from 'src/components/CircleProgress';
import { srSpeak } from 'src/utilities/accessibility';
-import { Box } from './Box';
-
export const SplashScreen = () => {
React.useEffect(() => {
srSpeak('Loading Linode Cloud Manager', 'polite');
diff --git a/packages/manager/src/components/StackScript/StackScript.tsx b/packages/manager/src/components/StackScript/StackScript.tsx
index 331584a3952..2951c34ee34 100644
--- a/packages/manager/src/components/StackScript/StackScript.tsx
+++ b/packages/manager/src/components/StackScript/StackScript.tsx
@@ -1,10 +1,9 @@
-import { StackScript as StackScriptType } from '@linode/api-v4/lib/stackscripts';
-import { Theme, useTheme } from '@mui/material/styles';
+import { Box } from '@linode/ui';
+import { useTheme } from '@mui/material/styles';
import * as React from 'react';
import { Link, useHistory } from 'react-router-dom';
import { makeStyles } from 'tss-react/mui';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { Chip } from 'src/components/Chip';
import { CopyTooltip } from 'src/components/CopyTooltip/CopyTooltip';
@@ -19,6 +18,9 @@ import { useAllImagesQuery } from 'src/queries/images';
import { TooltipIcon } from '../TooltipIcon';
+import type { StackScript as StackScriptType } from '@linode/api-v4/lib/stackscripts';
+import type { Theme } from '@mui/material/styles';
+
const useStyles = makeStyles()((theme: Theme) => ({
author: {
marginBottom: theme.spacing(2),
diff --git a/packages/manager/src/components/StatusIcon/StatusIcon.tsx b/packages/manager/src/components/StatusIcon/StatusIcon.tsx
index 54d84bfee4f..26a10cb1756 100644
--- a/packages/manager/src/components/StatusIcon/StatusIcon.tsx
+++ b/packages/manager/src/components/StatusIcon/StatusIcon.tsx
@@ -1,9 +1,10 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material';
import * as React from 'react';
import { omittedProps } from 'src/utilities/omittedProps';
-import { Box, BoxProps } from '../Box';
+import type { BoxProps } from '@linode/ui';
export type Status = 'active' | 'error' | 'inactive' | 'other';
diff --git a/packages/manager/src/components/TabbedPanel/TabbedPanel.tsx b/packages/manager/src/components/TabbedPanel/TabbedPanel.tsx
index 2dfcbb35378..668aba1514b 100644
--- a/packages/manager/src/components/TabbedPanel/TabbedPanel.tsx
+++ b/packages/manager/src/components/TabbedPanel/TabbedPanel.tsx
@@ -1,4 +1,4 @@
-import { Tooltip } from '@linode/ui';
+import { Box, Tooltip } from '@linode/ui';
import HelpOutline from '@mui/icons-material/HelpOutline';
import { styled } from '@mui/material/styles';
import React, { useEffect, useState } from 'react';
@@ -12,8 +12,6 @@ import { TabPanels } from 'src/components/Tabs/TabPanels';
import { Tabs } from 'src/components/Tabs/Tabs';
import { Typography } from 'src/components/Typography';
-import { Box } from '../Box';
-
import type { SxProps, Theme } from '@mui/material/styles';
export interface Tab {
diff --git a/packages/manager/src/components/TagCell.stories.tsx b/packages/manager/src/components/TagCell.stories.tsx
index 5ef910867e6..c42f8d4d910 100644
--- a/packages/manager/src/components/TagCell.stories.tsx
+++ b/packages/manager/src/components/TagCell.stories.tsx
@@ -1,8 +1,7 @@
+import { Box } from '@linode/ui';
import { useArgs } from '@storybook/preview-api';
import React from 'react';
-import { Box } from 'src/components/Box';
-
import { TagCell } from './TagCell/TagCell';
import type { TagCellProps } from './TagCell/TagCell';
diff --git a/packages/manager/src/components/TagsInput/TagsInput.stories.tsx b/packages/manager/src/components/TagsInput/TagsInput.stories.tsx
index 8ef43546232..63a00960b1c 100644
--- a/packages/manager/src/components/TagsInput/TagsInput.stories.tsx
+++ b/packages/manager/src/components/TagsInput/TagsInput.stories.tsx
@@ -1,12 +1,11 @@
+import { Box } from '@linode/ui';
import { useArgs } from '@storybook/preview-api';
-import { Meta, StoryObj } from '@storybook/react';
import React from 'react';
-import { Box } from 'src/components/Box';
-
import { TagsInput } from './TagsInput';
import type { Tag, TagsInputProps } from './TagsInput';
+import type { Meta, StoryObj } from '@storybook/react';
export const Default: StoryObj = {
args: {
diff --git a/packages/manager/src/components/TextField.tsx b/packages/manager/src/components/TextField.tsx
index 74abf82b7e1..8c8eafc6776 100644
--- a/packages/manager/src/components/TextField.tsx
+++ b/packages/manager/src/components/TextField.tsx
@@ -1,4 +1,4 @@
-import { FormHelperText, InputAdornment, InputLabel } from '@linode/ui';
+import { Box, FormHelperText, InputAdornment, InputLabel } from '@linode/ui';
import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown';
import { useTheme } from '@mui/material/styles';
import { default as _TextField } from '@mui/material/TextField';
@@ -6,15 +6,13 @@ import { clamp } from 'ramda';
import * as React from 'react';
import { makeStyles } from 'tss-react/mui';
-import { Box } from 'src/components/Box';
import { CircleProgress } from 'src/components/CircleProgress';
import { TooltipIcon } from 'src/components/TooltipIcon';
import { convertToKebabCase } from 'src/utilities/convertToKebobCase';
-import type { TooltipProps } from '@linode/ui';
+import type { BoxProps, TooltipProps } from '@linode/ui';
import type { Theme } from '@mui/material/styles';
import type { StandardTextFieldProps } from '@mui/material/TextField';
-import type { BoxProps } from 'src/components/Box';
const useStyles = makeStyles()((theme: Theme) => ({
absolute: {
diff --git a/packages/manager/src/components/TransferDisplay/TransferDisplay.styles.ts b/packages/manager/src/components/TransferDisplay/TransferDisplay.styles.ts
index 38be68d3215..ae1035f4a56 100644
--- a/packages/manager/src/components/TransferDisplay/TransferDisplay.styles.ts
+++ b/packages/manager/src/components/TransferDisplay/TransferDisplay.styles.ts
@@ -1,7 +1,6 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
-import { Box } from 'src/components/Box';
-
export const StyledTransferDisplayContainer = styled(Box, {
label: 'StyledTransferDisplayTypography',
})(({ theme }) => ({
diff --git a/packages/manager/src/components/TransferDisplay/TransferDisplay.tsx b/packages/manager/src/components/TransferDisplay/TransferDisplay.tsx
index 971ec80d6b7..ff3e9b810f8 100644
--- a/packages/manager/src/components/TransferDisplay/TransferDisplay.tsx
+++ b/packages/manager/src/components/TransferDisplay/TransferDisplay.tsx
@@ -1,6 +1,6 @@
+import { Box } from '@linode/ui';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { CircleProgress } from 'src/components/CircleProgress';
import { Typography } from 'src/components/Typography';
import { useAccountNetworkTransfer } from 'src/queries/account/transfer';
diff --git a/packages/manager/src/components/TransferDisplay/TransferDisplayDialog.tsx b/packages/manager/src/components/TransferDisplay/TransferDisplayDialog.tsx
index 00357b36505..e5ad1ec0225 100644
--- a/packages/manager/src/components/TransferDisplay/TransferDisplayDialog.tsx
+++ b/packages/manager/src/components/TransferDisplay/TransferDisplayDialog.tsx
@@ -1,8 +1,8 @@
-import { styled } from '@mui/material/styles';
+import { Box } from '@linode/ui';
import { useTheme } from '@mui/material/styles';
+import { styled } from '@mui/material/styles';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Dialog } from 'src/components/Dialog/Dialog';
import { Divider } from 'src/components/Divider';
import { Link } from 'src/components/Link';
diff --git a/packages/manager/src/features/Databases/DatabaseLanding/DatabaseLogo.tsx b/packages/manager/src/features/Databases/DatabaseLanding/DatabaseLogo.tsx
index 18ae6f24825..83534aafe20 100644
--- a/packages/manager/src/features/Databases/DatabaseLanding/DatabaseLogo.tsx
+++ b/packages/manager/src/features/Databases/DatabaseLanding/DatabaseLogo.tsx
@@ -1,5 +1,4 @@
-import { Box } from '@linode/ui';
-import { BetaChip } from '@linode/ui';
+import { BetaChip, Box } from '@linode/ui';
import { useTheme } from '@mui/material/styles';
import * as React from 'react';
diff --git a/packages/manager/src/features/Kubernetes/KubernetesClusterDetail/NodePoolsDisplay/NodePool.tsx b/packages/manager/src/features/Kubernetes/KubernetesClusterDetail/NodePoolsDisplay/NodePool.tsx
index 5542f2054b9..25de0fc0093 100644
--- a/packages/manager/src/features/Kubernetes/KubernetesClusterDetail/NodePoolsDisplay/NodePool.tsx
+++ b/packages/manager/src/features/Kubernetes/KubernetesClusterDetail/NodePoolsDisplay/NodePool.tsx
@@ -1,5 +1,4 @@
-import { Box } from '@linode/ui';
-import { Tooltip } from '@linode/ui';
+import { Box, Tooltip } from '@linode/ui';
import Grid from '@mui/material/Unstable_Grid2';
import * as React from 'react';
import { makeStyles } from 'tss-react/mui';
diff --git a/packages/manager/src/features/Linodes/LinodesDetail/LinodeNetworking/AddIPDrawer.tsx b/packages/manager/src/features/Linodes/LinodesDetail/LinodeNetworking/AddIPDrawer.tsx
index 0b00c30cfa4..4f98b28637e 100644
--- a/packages/manager/src/features/Linodes/LinodesDetail/LinodeNetworking/AddIPDrawer.tsx
+++ b/packages/manager/src/features/Linodes/LinodesDetail/LinodeNetworking/AddIPDrawer.tsx
@@ -1,5 +1,4 @@
-import { Tooltip } from '@linode/ui';
-import { Box } from '@linode/ui';
+import { Box, Tooltip } from '@linode/ui';
import { styled } from '@mui/material/styles';
import * as React from 'react';
diff --git a/packages/manager/src/features/Linodes/LinodesLanding/DisplayGroupedLinodes.tsx b/packages/manager/src/features/Linodes/LinodesLanding/DisplayGroupedLinodes.tsx
index 4624f642627..cd44009569a 100644
--- a/packages/manager/src/features/Linodes/LinodesLanding/DisplayGroupedLinodes.tsx
+++ b/packages/manager/src/features/Linodes/LinodesLanding/DisplayGroupedLinodes.tsx
@@ -1,5 +1,4 @@
-import { Box } from '@linode/ui';
-import { Tooltip } from '@linode/ui';
+import { Box, Tooltip } from '@linode/ui';
import Grid from '@mui/material/Unstable_Grid2';
import { compose } from 'ramda';
import * as React from 'react';
diff --git a/packages/manager/src/features/NotificationCenter/Events/NotificationCenterEvent.tsx b/packages/manager/src/features/NotificationCenter/Events/NotificationCenterEvent.tsx
index 9940a8527d7..ee2da2ca32c 100644
--- a/packages/manager/src/features/NotificationCenter/Events/NotificationCenterEvent.tsx
+++ b/packages/manager/src/features/NotificationCenter/Events/NotificationCenterEvent.tsx
@@ -1,8 +1,8 @@
+import { Box } from '@linode/ui';
import { useTheme } from '@mui/material';
import * as React from 'react';
import { BarPercent } from 'src/components/BarPercent';
-import { Box } from 'src/components/Box';
import { Typography } from 'src/components/Typography';
import {
formatProgressEvent,
diff --git a/packages/manager/src/features/NotificationCenter/NotificationCenter.styles.ts b/packages/manager/src/features/NotificationCenter/NotificationCenter.styles.ts
index 6820ce92683..574587da698 100644
--- a/packages/manager/src/features/NotificationCenter/NotificationCenter.styles.ts
+++ b/packages/manager/src/features/NotificationCenter/NotificationCenter.styles.ts
@@ -1,9 +1,9 @@
+import { Box } from '@linode/ui';
import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown';
import { styled } from '@mui/material';
import { makeStyles } from 'tss-react/mui';
import { Avatar } from 'src/components/Avatar/Avatar';
-import { Box } from 'src/components/Box';
import { Link } from 'src/components/Link';
import { Typography } from 'src/components/Typography';
import { omittedProps } from 'src/utilities/omittedProps';
diff --git a/packages/manager/src/features/NotificationCenter/Notifications/NotificationCenterNotificationMessage.tsx b/packages/manager/src/features/NotificationCenter/Notifications/NotificationCenterNotificationMessage.tsx
index 30b9b3e01f2..dedfb32743c 100644
--- a/packages/manager/src/features/NotificationCenter/Notifications/NotificationCenterNotificationMessage.tsx
+++ b/packages/manager/src/features/NotificationCenter/Notifications/NotificationCenterNotificationMessage.tsx
@@ -1,9 +1,9 @@
+import { Box } from '@linode/ui';
import ErrorIcon from '@mui/icons-material/Error';
import WarningIcon from '@mui/icons-material/Warning';
import { useTheme } from '@mui/material/styles';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Divider } from 'src/components/Divider';
import { Typography } from 'src/components/Typography';
import { sanitizeHTML } from 'src/utilities/sanitizeHTML';
diff --git a/packages/manager/src/features/NotificationCenter/Notifications/NotificationCenterNotificationsContainer.tsx b/packages/manager/src/features/NotificationCenter/Notifications/NotificationCenterNotificationsContainer.tsx
index bc11526630e..4a2f4e03f56 100644
--- a/packages/manager/src/features/NotificationCenter/Notifications/NotificationCenterNotificationsContainer.tsx
+++ b/packages/manager/src/features/NotificationCenter/Notifications/NotificationCenterNotificationsContainer.tsx
@@ -1,7 +1,7 @@
+import { Box } from '@linode/ui';
import * as React from 'react';
import { Accordion } from 'src/components/Accordion';
-import { Box } from 'src/components/Box';
import { Hidden } from 'src/components/Hidden';
import { Link } from 'src/components/Link';
import { Typography } from 'src/components/Typography';
diff --git a/packages/manager/src/features/ObjectStorage/AccessKeyLanding/AccessKeyRegions/SelectedRegionsList.tsx b/packages/manager/src/features/ObjectStorage/AccessKeyLanding/AccessKeyRegions/SelectedRegionsList.tsx
index 571139055ea..401f2f9aed0 100644
--- a/packages/manager/src/features/ObjectStorage/AccessKeyLanding/AccessKeyRegions/SelectedRegionsList.tsx
+++ b/packages/manager/src/features/ObjectStorage/AccessKeyLanding/AccessKeyRegions/SelectedRegionsList.tsx
@@ -1,6 +1,6 @@
+import { Box } from '@linode/ui';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Flag } from 'src/components/Flag';
import { RemovableSelectionsList } from 'src/components/RemovableSelectionsList/RemovableSelectionsList';
diff --git a/packages/manager/src/features/ObjectStorage/AccessKeyLanding/CopyAllHostnames.tsx b/packages/manager/src/features/ObjectStorage/AccessKeyLanding/CopyAllHostnames.tsx
index 695ae8a1bc1..b1a42407491 100644
--- a/packages/manager/src/features/ObjectStorage/AccessKeyLanding/CopyAllHostnames.tsx
+++ b/packages/manager/src/features/ObjectStorage/AccessKeyLanding/CopyAllHostnames.tsx
@@ -1,9 +1,8 @@
-import { InputLabel, Tooltip } from '@linode/ui';
+import { Box, InputLabel, Tooltip } from '@linode/ui';
import { styled } from '@mui/material/styles';
import copy from 'copy-to-clipboard';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { StyledLinkButton } from 'src/components/Button/StyledLinkButton';
export interface Props {
diff --git a/packages/manager/src/features/ObjectStorage/AccessKeyLanding/HostNamesDrawer.tsx b/packages/manager/src/features/ObjectStorage/AccessKeyLanding/HostNamesDrawer.tsx
index 96944066b59..f81a8658735 100644
--- a/packages/manager/src/features/ObjectStorage/AccessKeyLanding/HostNamesDrawer.tsx
+++ b/packages/manager/src/features/ObjectStorage/AccessKeyLanding/HostNamesDrawer.tsx
@@ -1,6 +1,6 @@
+import { Box } from '@linode/ui';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { CopyableTextField } from 'src/components/CopyableTextField/CopyableTextField';
import { Drawer } from 'src/components/Drawer';
import { useRegionsQuery } from 'src/queries/regions/regions';
diff --git a/packages/manager/src/features/ObjectStorage/AccessKeyLanding/HostNamesList.tsx b/packages/manager/src/features/ObjectStorage/AccessKeyLanding/HostNamesList.tsx
index da1e0406a3f..daca1d84ee5 100644
--- a/packages/manager/src/features/ObjectStorage/AccessKeyLanding/HostNamesList.tsx
+++ b/packages/manager/src/features/ObjectStorage/AccessKeyLanding/HostNamesList.tsx
@@ -1,7 +1,7 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import React, { useRef } from 'react';
-import { Box } from 'src/components/Box';
import { CopyableTextField } from 'src/components/CopyableTextField/CopyableTextField';
import { List } from 'src/components/List';
import { useRegionsQuery } from 'src/queries/regions/regions';
diff --git a/packages/manager/src/features/ObjectStorage/BucketDetail/BucketDetail.tsx b/packages/manager/src/features/ObjectStorage/BucketDetail/BucketDetail.tsx
index ec2f91870a0..94dd1071e05 100644
--- a/packages/manager/src/features/ObjectStorage/BucketDetail/BucketDetail.tsx
+++ b/packages/manager/src/features/ObjectStorage/BucketDetail/BucketDetail.tsx
@@ -1,5 +1,6 @@
import { getObjectList, getObjectURL } from '@linode/api-v4/lib/object-storage';
-import { InfiniteData, useQueryClient } from '@tanstack/react-query';
+import { Box } from '@linode/ui';
+import { useQueryClient } from '@tanstack/react-query';
import produce from 'immer';
import { useSnackbar } from 'notistack';
import * as React from 'react';
@@ -8,7 +9,6 @@ import { Waypoint } from 'react-waypoint';
import { debounce } from 'throttle-debounce';
import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
-import { Box } from 'src/components/Box';
import { ConfirmationDialog } from 'src/components/ConfirmationDialog/ConfirmationDialog';
import { Hidden } from 'src/components/Hidden';
import { Table } from 'src/components/Table';
@@ -58,6 +58,7 @@ import type {
ObjectStorageObject,
ObjectStorageObjectList,
} from '@linode/api-v4';
+import type { InfiniteData } from '@tanstack/react-query';
interface MatchParams {
bucketName: string;
diff --git a/packages/manager/src/features/ObjectStorage/BucketDetail/ObjectTableRow.tsx b/packages/manager/src/features/ObjectStorage/BucketDetail/ObjectTableRow.tsx
index 96d32373fd1..7cbcf7d4989 100644
--- a/packages/manager/src/features/ObjectStorage/BucketDetail/ObjectTableRow.tsx
+++ b/packages/manager/src/features/ObjectStorage/BucketDetail/ObjectTableRow.tsx
@@ -1,8 +1,8 @@
-import Grid from '@mui/material/Unstable_Grid2';
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
+import Grid from '@mui/material/Unstable_Grid2';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { StyledLinkButton } from 'src/components/Button/StyledLinkButton';
import { DateTimeDisplay } from 'src/components/DateTimeDisplay';
import { EntityIcon } from 'src/components/EntityIcon/EntityIcon';
diff --git a/packages/manager/src/features/ObjectStorage/BucketLanding/BucketRateLimitTable.tsx b/packages/manager/src/features/ObjectStorage/BucketLanding/BucketRateLimitTable.tsx
index aa2a9571982..b7ab4530a89 100644
--- a/packages/manager/src/features/ObjectStorage/BucketLanding/BucketRateLimitTable.tsx
+++ b/packages/manager/src/features/ObjectStorage/BucketLanding/BucketRateLimitTable.tsx
@@ -1,6 +1,6 @@
+import { Box } from '@linode/ui';
import React from 'react';
-import { Box } from 'src/components/Box';
import { FormControlLabel } from 'src/components/FormControlLabel';
import { FormLabel } from 'src/components/FormLabel';
import { Link } from 'src/components/Link';
diff --git a/packages/manager/src/features/ObjectStorage/BucketLanding/OveragePricing.tsx b/packages/manager/src/features/ObjectStorage/BucketLanding/OveragePricing.tsx
index f8c25b11f11..7b7b1b2513b 100644
--- a/packages/manager/src/features/ObjectStorage/BucketLanding/OveragePricing.tsx
+++ b/packages/manager/src/features/ObjectStorage/BucketLanding/OveragePricing.tsx
@@ -1,7 +1,7 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import React from 'react';
-import { Box } from 'src/components/Box';
import { CircleProgress } from 'src/components/CircleProgress';
import { TextTooltip } from 'src/components/TextTooltip';
import { Typography } from 'src/components/Typography';
diff --git a/packages/manager/src/features/PlacementGroups/PlacementGroupPolicyRadioGroup.tsx b/packages/manager/src/features/PlacementGroups/PlacementGroupPolicyRadioGroup.tsx
index f50763a2c44..27d4b7f299d 100644
--- a/packages/manager/src/features/PlacementGroups/PlacementGroupPolicyRadioGroup.tsx
+++ b/packages/manager/src/features/PlacementGroups/PlacementGroupPolicyRadioGroup.tsx
@@ -1,6 +1,6 @@
+import { Box } from '@linode/ui';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { FormControlLabel } from 'src/components/FormControlLabel';
import { FormLabel } from 'src/components/FormLabel';
import { Notice } from 'src/components/Notice/Notice';
diff --git a/packages/manager/src/features/PlacementGroups/PlacementGroupsAssignLinodesDrawer.tsx b/packages/manager/src/features/PlacementGroups/PlacementGroupsAssignLinodesDrawer.tsx
index a7662421b52..8aaa0e6eae6 100644
--- a/packages/manager/src/features/PlacementGroups/PlacementGroupsAssignLinodesDrawer.tsx
+++ b/packages/manager/src/features/PlacementGroups/PlacementGroupsAssignLinodesDrawer.tsx
@@ -1,12 +1,12 @@
import {
- PLACEMENT_GROUP_TYPES,
PLACEMENT_GROUP_POLICIES,
+ PLACEMENT_GROUP_TYPES,
} from '@linode/api-v4';
+import { Box } from '@linode/ui';
import { useSnackbar } from 'notistack';
import * as React from 'react';
import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
-import { Box } from 'src/components/Box';
import { DescriptionList } from 'src/components/DescriptionList/DescriptionList';
import { Divider } from 'src/components/Divider';
import { Drawer } from 'src/components/Drawer';
diff --git a/packages/manager/src/features/PlacementGroups/PlacementGroupsDetail/PlacementGroupsSummary/PlacementGroupsSummary.tsx b/packages/manager/src/features/PlacementGroups/PlacementGroupsDetail/PlacementGroupsSummary/PlacementGroupsSummary.tsx
index 1778518729c..da952cfd61f 100644
--- a/packages/manager/src/features/PlacementGroups/PlacementGroupsDetail/PlacementGroupsSummary/PlacementGroupsSummary.tsx
+++ b/packages/manager/src/features/PlacementGroups/PlacementGroupsDetail/PlacementGroupsSummary/PlacementGroupsSummary.tsx
@@ -1,12 +1,12 @@
import {
- PLACEMENT_GROUP_TYPES,
PLACEMENT_GROUP_POLICIES,
+ PLACEMENT_GROUP_TYPES,
} from '@linode/api-v4';
+import { Box } from '@linode/ui';
import { useTheme } from '@mui/material';
import { styled } from '@mui/material/styles';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { DescriptionList } from 'src/components/DescriptionList/DescriptionList';
import { Link } from 'src/components/Link';
import { Notice } from 'src/components/Notice/Notice';
diff --git a/packages/manager/src/features/PlacementGroups/PlacementGroupsDetailPanel.tsx b/packages/manager/src/features/PlacementGroups/PlacementGroupsDetailPanel.tsx
index 29aaa7f91f6..5b6d526718c 100644
--- a/packages/manager/src/features/PlacementGroups/PlacementGroupsDetailPanel.tsx
+++ b/packages/manager/src/features/PlacementGroups/PlacementGroupsDetailPanel.tsx
@@ -1,7 +1,7 @@
+import { Box } from '@linode/ui';
import { useTheme } from '@mui/material/styles';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { ListItem } from 'src/components/ListItem';
import { Notice } from 'src/components/Notice/Notice';
diff --git a/packages/manager/src/features/Profile/APITokens/APITokenTable.tsx b/packages/manager/src/features/Profile/APITokens/APITokenTable.tsx
index e8f84e4f94d..3f2f4c42378 100644
--- a/packages/manager/src/features/Profile/APITokens/APITokenTable.tsx
+++ b/packages/manager/src/features/Profile/APITokens/APITokenTable.tsx
@@ -1,6 +1,6 @@
+import { Box } from '@linode/ui';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { DateTimeDisplay } from 'src/components/DateTimeDisplay';
import { PaginationFooter } from 'src/components/PaginationFooter/PaginationFooter';
diff --git a/packages/manager/src/features/Profile/AuthenticationSettings/PhoneVerification/PhoneVerification.styles.ts b/packages/manager/src/features/Profile/AuthenticationSettings/PhoneVerification/PhoneVerification.styles.ts
index c4c8ab5226e..858bc1c1475 100644
--- a/packages/manager/src/features/Profile/AuthenticationSettings/PhoneVerification/PhoneVerification.styles.ts
+++ b/packages/manager/src/features/Profile/AuthenticationSettings/PhoneVerification/PhoneVerification.styles.ts
@@ -1,8 +1,7 @@
-import { FormHelperText } from '@linode/ui';
+import { Box, FormHelperText } from '@linode/ui';
import { styled } from '@mui/material/styles';
import { Autocomplete } from 'src/components/Autocomplete/Autocomplete';
-import { Box } from 'src/components/Box';
import { TextField } from 'src/components/TextField';
import { Typography } from 'src/components/Typography';
import { omittedProps } from 'src/utilities/omittedProps';
diff --git a/packages/manager/src/features/Profile/AuthenticationSettings/PhoneVerification/PhoneVerification.tsx b/packages/manager/src/features/Profile/AuthenticationSettings/PhoneVerification/PhoneVerification.tsx
index baed20e7e5d..15d4f289d7c 100644
--- a/packages/manager/src/features/Profile/AuthenticationSettings/PhoneVerification/PhoneVerification.tsx
+++ b/packages/manager/src/features/Profile/AuthenticationSettings/PhoneVerification/PhoneVerification.tsx
@@ -1,11 +1,10 @@
-import { InputAdornment } from '@linode/ui';
+import { Box, InputAdornment } from '@linode/ui';
import { useQueryClient } from '@tanstack/react-query';
import { useFormik } from 'formik';
import { parsePhoneNumber } from 'libphonenumber-js';
import { useSnackbar } from 'notistack';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { LinkButton } from 'src/components/LinkButton';
import { TextField } from 'src/components/TextField';
diff --git a/packages/manager/src/features/Profile/AuthenticationSettings/ResetPassword.tsx b/packages/manager/src/features/Profile/AuthenticationSettings/ResetPassword.tsx
index 14cfecec3d2..f23bc2d2ebb 100644
--- a/packages/manager/src/features/Profile/AuthenticationSettings/ResetPassword.tsx
+++ b/packages/manager/src/features/Profile/AuthenticationSettings/ResetPassword.tsx
@@ -1,7 +1,7 @@
+import { Box } from '@linode/ui';
import { styled, useTheme } from '@mui/material/styles';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Link } from 'src/components/Link';
import { Typography } from 'src/components/Typography';
import { LOGIN_ROOT } from 'src/constants';
diff --git a/packages/manager/src/features/Profile/AuthenticationSettings/SMSMessaging.tsx b/packages/manager/src/features/Profile/AuthenticationSettings/SMSMessaging.tsx
index 04c6ab8247b..d9cde16e883 100644
--- a/packages/manager/src/features/Profile/AuthenticationSettings/SMSMessaging.tsx
+++ b/packages/manager/src/features/Profile/AuthenticationSettings/SMSMessaging.tsx
@@ -1,9 +1,9 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import { useSnackbar } from 'notistack';
import * as React from 'react';
import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { ConfirmationDialog } from 'src/components/ConfirmationDialog/ConfirmationDialog';
import { Link } from 'src/components/Link';
diff --git a/packages/manager/src/features/Profile/AuthenticationSettings/SecurityQuestions/QuestionAndAnswerPair.tsx b/packages/manager/src/features/Profile/AuthenticationSettings/SecurityQuestions/QuestionAndAnswerPair.tsx
index cab647664d9..b04e6601611 100644
--- a/packages/manager/src/features/Profile/AuthenticationSettings/SecurityQuestions/QuestionAndAnswerPair.tsx
+++ b/packages/manager/src/features/Profile/AuthenticationSettings/SecurityQuestions/QuestionAndAnswerPair.tsx
@@ -1,8 +1,7 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import * as React from 'react';
-import { Box } from 'src/components/Box';
-
import { Answer } from './Answer';
import { Question } from './Question';
diff --git a/packages/manager/src/features/Profile/AuthenticationSettings/SecurityQuestions/SecurityQuestions.tsx b/packages/manager/src/features/Profile/AuthenticationSettings/SecurityQuestions/SecurityQuestions.tsx
index d47fd939c4e..e0cba8feed9 100644
--- a/packages/manager/src/features/Profile/AuthenticationSettings/SecurityQuestions/SecurityQuestions.tsx
+++ b/packages/manager/src/features/Profile/AuthenticationSettings/SecurityQuestions/SecurityQuestions.tsx
@@ -1,9 +1,9 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import { useFormik } from 'formik';
import { useSnackbar } from 'notistack';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { CircleProgress } from 'src/components/CircleProgress';
import { Link } from 'src/components/Link';
diff --git a/packages/manager/src/features/Profile/AuthenticationSettings/TPAProviders.tsx b/packages/manager/src/features/Profile/AuthenticationSettings/TPAProviders.tsx
index 4520dc713d6..caed45a3d8f 100644
--- a/packages/manager/src/features/Profile/AuthenticationSettings/TPAProviders.tsx
+++ b/packages/manager/src/features/Profile/AuthenticationSettings/TPAProviders.tsx
@@ -1,13 +1,12 @@
-import { TPAProvider } from '@linode/api-v4/lib/profile';
-import Grid from '@mui/material/Unstable_Grid2';
+import { Box } from '@linode/ui';
import { useTheme } from '@mui/material/styles';
+import Grid from '@mui/material/Unstable_Grid2';
import * as React from 'react';
import EnabledIcon from 'src/assets/icons/checkmark-enabled.svg';
import AkamaiWaveOnlyIcon from 'src/assets/icons/providers/akamai-logo-rgb-waveOnly.svg';
import GitHubIcon from 'src/assets/icons/providers/github-logo.svg';
import GoogleIcon from 'src/assets/icons/providers/google-logo.svg';
-import { Box } from 'src/components/Box';
import { Divider } from 'src/components/Divider';
import { Link } from 'src/components/Link';
import { Typography } from 'src/components/Typography';
@@ -23,6 +22,8 @@ import {
StyledRootContainer,
} from './TPAProviders.styles';
+import type { TPAProvider } from '@linode/api-v4/lib/profile';
+
interface Props {
authType: TPAProvider;
}
diff --git a/packages/manager/src/features/Profile/AuthenticationSettings/TwoFactor/ConfirmToken.tsx b/packages/manager/src/features/Profile/AuthenticationSettings/TwoFactor/ConfirmToken.tsx
index f81eed13103..2584b7bd3d1 100644
--- a/packages/manager/src/features/Profile/AuthenticationSettings/TwoFactor/ConfirmToken.tsx
+++ b/packages/manager/src/features/Profile/AuthenticationSettings/TwoFactor/ConfirmToken.tsx
@@ -1,7 +1,7 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { Notice } from 'src/components/Notice/Notice';
import { TextField } from 'src/components/TextField';
diff --git a/packages/manager/src/features/Profile/DisplaySettings/AvatarForm.tsx b/packages/manager/src/features/Profile/DisplaySettings/AvatarForm.tsx
index f6ad7df75b0..87d29ba8c34 100644
--- a/packages/manager/src/features/Profile/DisplaySettings/AvatarForm.tsx
+++ b/packages/manager/src/features/Profile/DisplaySettings/AvatarForm.tsx
@@ -1,8 +1,8 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import React from 'react';
import { Avatar } from 'src/components/Avatar/Avatar';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { Typography } from 'src/components/Typography';
diff --git a/packages/manager/src/features/Profile/LishSettings/LishSettings.tsx b/packages/manager/src/features/Profile/LishSettings/LishSettings.tsx
index 67c86bc3574..c9889bb5d72 100644
--- a/packages/manager/src/features/Profile/LishSettings/LishSettings.tsx
+++ b/packages/manager/src/features/Profile/LishSettings/LishSettings.tsx
@@ -1,4 +1,4 @@
-import { FormControl } from '@linode/ui';
+import { Box, FormControl } from '@linode/ui';
import { useTheme } from '@mui/material/styles';
import { createLazyRoute } from '@tanstack/react-router';
import { equals, lensPath, remove, set } from 'ramda';
@@ -6,7 +6,6 @@ import * as React from 'react';
import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
import { Autocomplete } from 'src/components/Autocomplete/Autocomplete';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { DocumentTitleSegment } from 'src/components/DocumentTitle';
import { Notice } from 'src/components/Notice/Notice';
diff --git a/packages/manager/src/features/Profile/OAuthClients/OAuthClients.tsx b/packages/manager/src/features/Profile/OAuthClients/OAuthClients.tsx
index b30f1e6168e..aa2840216d3 100644
--- a/packages/manager/src/features/Profile/OAuthClients/OAuthClients.tsx
+++ b/packages/manager/src/features/Profile/OAuthClients/OAuthClients.tsx
@@ -1,7 +1,7 @@
+import { Box } from '@linode/ui';
import { createLazyRoute } from '@tanstack/react-router';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { DocumentTitleSegment } from 'src/components/DocumentTitle';
import { Hidden } from 'src/components/Hidden';
diff --git a/packages/manager/src/features/Profile/SecretTokenDialog/SecretTokenDialog.tsx b/packages/manager/src/features/Profile/SecretTokenDialog/SecretTokenDialog.tsx
index b5f225153c4..6bb1e386a0f 100644
--- a/packages/manager/src/features/Profile/SecretTokenDialog/SecretTokenDialog.tsx
+++ b/packages/manager/src/features/Profile/SecretTokenDialog/SecretTokenDialog.tsx
@@ -1,8 +1,8 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
import * as React from 'react';
import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
-import { Box } from 'src/components/Box';
import { ConfirmationDialog } from 'src/components/ConfirmationDialog/ConfirmationDialog';
import { CopyableTextField } from 'src/components/CopyableTextField/CopyableTextField';
import { Notice } from 'src/components/Notice/Notice';
diff --git a/packages/manager/src/features/Profile/Settings/PreferenceEditor.tsx b/packages/manager/src/features/Profile/Settings/PreferenceEditor.tsx
index dd2fc9ac06c..c5905bb42f2 100644
--- a/packages/manager/src/features/Profile/Settings/PreferenceEditor.tsx
+++ b/packages/manager/src/features/Profile/Settings/PreferenceEditor.tsx
@@ -1,8 +1,8 @@
+import { Box } from '@linode/ui';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
-import { Dialog, DialogProps } from 'src/components/Dialog/Dialog';
+import { Dialog } from 'src/components/Dialog/Dialog';
import { Link } from 'src/components/Link';
import { Notice } from 'src/components/Notice/Notice';
import { Typography } from 'src/components/Typography';
@@ -11,6 +11,8 @@ import {
usePreferences,
} from 'src/queries/profile/preferences';
+import type { DialogProps } from 'src/components/Dialog/Dialog';
+
type Props = Pick;
export const PreferenceEditor = (props: Props) => {
diff --git a/packages/manager/src/features/StackScripts/SelectStackScriptPanel/SelectStackScriptPanel.tsx b/packages/manager/src/features/StackScripts/SelectStackScriptPanel/SelectStackScriptPanel.tsx
index 007a63c7914..bf16b9481cf 100644
--- a/packages/manager/src/features/StackScripts/SelectStackScriptPanel/SelectStackScriptPanel.tsx
+++ b/packages/manager/src/features/StackScripts/SelectStackScriptPanel/SelectStackScriptPanel.tsx
@@ -1,25 +1,14 @@
-import { Grant } from '@linode/api-v4/lib/account';
-import { Image } from '@linode/api-v4/lib/images';
-import { Linode } from '@linode/api-v4/lib/linodes';
-import {
- StackScript,
- UserDefinedField,
- getStackScript,
-} from '@linode/api-v4/lib/stackscripts';
-import { Filter, Params, ResourcePage } from '@linode/api-v4/lib/types';
+import { getStackScript } from '@linode/api-v4/lib/stackscripts';
+import { Box } from '@linode/ui';
import * as React from 'react';
import { compose } from 'recompose';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { CircleProgress } from 'src/components/CircleProgress';
import { Notice } from 'src/components/Notice/Notice';
-import { RenderGuard, RenderGuardProps } from 'src/components/RenderGuard';
+import { RenderGuard } from 'src/components/RenderGuard';
import { Typography } from 'src/components/Typography';
-import {
- WithProfileProps,
- withProfile,
-} from 'src/containers/profile.container';
+import { withProfile } from 'src/containers/profile.container';
import { formatDate } from 'src/utilities/formatDate';
import { getQueryParamFromQueryString } from 'src/utilities/queryParams';
import { truncate } from 'src/utilities/truncate';
@@ -34,6 +23,17 @@ import {
import SelectStackScriptPanelContent from './SelectStackScriptPanelContent';
import StackScriptSelectionRow from './StackScriptSelectionRow';
+import type { Grant } from '@linode/api-v4/lib/account';
+import type { Image } from '@linode/api-v4/lib/images';
+import type { Linode } from '@linode/api-v4/lib/linodes';
+import type {
+ StackScript,
+ UserDefinedField,
+} from '@linode/api-v4/lib/stackscripts';
+import type { Filter, Params, ResourcePage } from '@linode/api-v4/lib/types';
+import type { RenderGuardProps } from 'src/components/RenderGuard';
+import type { WithProfileProps } from 'src/containers/profile.container';
+
export interface ExtendedLinode extends Linode {
heading: string;
subHeadings: string[];
@@ -76,6 +76,17 @@ class SelectStackScriptPanel extends React.Component<
SelectStackScriptPanelProps,
State
> {
+ mounted: boolean = false;
+
+ resetStackScript = () => {
+ this.setState({ stackScript: undefined, stackScriptLoading: false });
+ };
+
+ state: State = {
+ stackScriptError: false,
+ stackScriptLoading: false,
+ };
+
componentDidMount() {
const selected = +getQueryParamFromQueryString(
location.search,
@@ -187,17 +198,6 @@ class SelectStackScriptPanel extends React.Component<
);
}
-
- mounted: boolean = false;
-
- resetStackScript = () => {
- this.setState({ stackScript: undefined, stackScriptLoading: false });
- };
-
- state: State = {
- stackScriptError: false,
- stackScriptLoading: false,
- };
}
export default compose(
diff --git a/packages/manager/src/features/StackScripts/UserDefinedFieldsPanel/UserDefinedFieldsPanel.styles.ts b/packages/manager/src/features/StackScripts/UserDefinedFieldsPanel/UserDefinedFieldsPanel.styles.ts
index 111d44794ae..bec7c1fc296 100644
--- a/packages/manager/src/features/StackScripts/UserDefinedFieldsPanel/UserDefinedFieldsPanel.styles.ts
+++ b/packages/manager/src/features/StackScripts/UserDefinedFieldsPanel/UserDefinedFieldsPanel.styles.ts
@@ -1,6 +1,6 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
-import { Box } from 'src/components/Box';
import { Paper } from 'src/components/Paper';
import { omittedProps } from 'src/utilities/omittedProps';
diff --git a/packages/manager/src/features/StackScripts/UserDefinedFieldsPanel/UserDefinedFieldsPanel.tsx b/packages/manager/src/features/StackScripts/UserDefinedFieldsPanel/UserDefinedFieldsPanel.tsx
index 7888367a821..a87a4e5a2e7 100644
--- a/packages/manager/src/features/StackScripts/UserDefinedFieldsPanel/UserDefinedFieldsPanel.tsx
+++ b/packages/manager/src/features/StackScripts/UserDefinedFieldsPanel/UserDefinedFieldsPanel.tsx
@@ -1,8 +1,8 @@
+import { Box } from '@linode/ui';
import Grid from '@mui/material/Unstable_Grid2';
import * as React from 'react';
import { Link } from 'react-router-dom';
-import { Box } from 'src/components/Box';
import { Divider } from 'src/components/Divider';
import { Notice } from 'src/components/Notice/Notice';
import { RenderGuard } from 'src/components/RenderGuard';
diff --git a/packages/manager/src/features/Support/Hively.tsx b/packages/manager/src/features/Support/Hively.tsx
index 2ef3716a197..9c146e8649a 100644
--- a/packages/manager/src/features/Support/Hively.tsx
+++ b/packages/manager/src/features/Support/Hively.tsx
@@ -1,14 +1,14 @@
-import { Stack } from 'src/components/Stack';
+import { Box } from '@linode/ui';
import { DateTime } from 'luxon';
import * as React from 'react';
import { Divider } from 'src/components/Divider';
import { Link } from 'src/components/Link';
+import { Stack } from 'src/components/Stack';
import { Typography } from 'src/components/Typography';
import { parseAPIDate } from 'src/utilities/date';
import { OFFICIAL_USERNAMES } from './ticketUtils';
-import { Box } from 'src/components/Box';
interface Props {
/** The username of the Linode user who created the ticket. */
diff --git a/packages/manager/src/features/Support/SupportTickets/SupportTicketDialog.tsx b/packages/manager/src/features/Support/SupportTickets/SupportTicketDialog.tsx
index e80beeeda03..066ac25045c 100644
--- a/packages/manager/src/features/Support/SupportTickets/SupportTicketDialog.tsx
+++ b/packages/manager/src/features/Support/SupportTickets/SupportTicketDialog.tsx
@@ -1,5 +1,6 @@
import { yupResolver } from '@hookform/resolvers/yup';
import { uploadAttachment } from '@linode/api-v4/lib/support';
+import { Box } from '@linode/ui';
import { update } from 'ramda';
import * as React from 'react';
import { Controller, FormProvider, useForm } from 'react-hook-form';
@@ -9,7 +10,6 @@ import { debounce } from 'throttle-debounce';
import { Accordion } from 'src/components/Accordion';
import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
import { Autocomplete } from 'src/components/Autocomplete/Autocomplete';
-import { Box } from 'src/components/Box';
import { Dialog } from 'src/components/Dialog/Dialog';
import { Notice } from 'src/components/Notice/Notice';
import { TextField } from 'src/components/TextField';
diff --git a/packages/manager/src/features/Support/TicketAttachmentRow.tsx b/packages/manager/src/features/Support/TicketAttachmentRow.tsx
index 8f148dd93b9..30c3b1a4627 100644
--- a/packages/manager/src/features/Support/TicketAttachmentRow.tsx
+++ b/packages/manager/src/features/Support/TicketAttachmentRow.tsx
@@ -1,6 +1,6 @@
+import { Box } from '@linode/ui';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Divider } from 'src/components/Divider';
import { Paper } from 'src/components/Paper';
import { Stack } from 'src/components/Stack';
diff --git a/packages/manager/src/features/TopMenu/NotificationMenu/NotificationMenu.tsx b/packages/manager/src/features/TopMenu/NotificationMenu/NotificationMenu.tsx
index f3f8f2dfe22..195bc0d7b65 100644
--- a/packages/manager/src/features/TopMenu/NotificationMenu/NotificationMenu.tsx
+++ b/packages/manager/src/features/TopMenu/NotificationMenu/NotificationMenu.tsx
@@ -1,3 +1,4 @@
+import { Box } from '@linode/ui';
import AutorenewIcon from '@mui/icons-material/Autorenew';
import { IconButton } from '@mui/material';
import Popover from '@mui/material/Popover';
@@ -6,7 +7,6 @@ import * as React from 'react';
import { useHistory } from 'react-router-dom';
import Bell from 'src/assets/icons/notification.svg';
-import { Box } from 'src/components/Box';
import { Chip } from 'src/components/Chip';
import { Divider } from 'src/components/Divider';
import { LinkButton } from 'src/components/LinkButton';
diff --git a/packages/manager/src/features/TopMenu/SearchBar/SearchSuggestion.tsx b/packages/manager/src/features/TopMenu/SearchBar/SearchSuggestion.tsx
index 43d84821037..ac3b73b753d 100644
--- a/packages/manager/src/features/TopMenu/SearchBar/SearchSuggestion.tsx
+++ b/packages/manager/src/features/TopMenu/SearchBar/SearchSuggestion.tsx
@@ -1,9 +1,7 @@
-import { LinodeStatus } from '@linode/api-v4/lib/linodes';
+import { Box } from '@linode/ui';
import { pathOr } from 'ramda';
import * as React from 'react';
-import { OptionProps } from 'react-select';
-import { Box } from 'src/components/Box';
import { EntityIcon } from 'src/components/EntityIcon/EntityIcon';
import { Tag } from 'src/components/Tag/Tag';
import { linodeInTransition } from 'src/features/Linodes/transitions';
@@ -17,6 +15,9 @@ import {
StyledWrapperDiv,
} from './SearchSuggestion.styles';
+import type { LinodeStatus } from '@linode/api-v4/lib/linodes';
+import type { OptionProps } from 'react-select';
+
export interface SearchSuggestionT {
description: string;
history: any;
diff --git a/packages/manager/src/features/TopMenu/TopMenu.tsx b/packages/manager/src/features/TopMenu/TopMenu.tsx
index d494d8c1ff0..00802f82ebb 100644
--- a/packages/manager/src/features/TopMenu/TopMenu.tsx
+++ b/packages/manager/src/features/TopMenu/TopMenu.tsx
@@ -1,9 +1,8 @@
-import { IconButton } from '@linode/ui';
+import { Box, IconButton } from '@linode/ui';
import MenuIcon from '@mui/icons-material/Menu';
import * as React from 'react';
import { AppBar } from 'src/components/AppBar';
-import { Box } from 'src/components/Box';
import { Hidden } from 'src/components/Hidden';
import { Toolbar } from 'src/components/Toolbar';
import { Typography } from 'src/components/Typography';
diff --git a/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx b/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx
index 8d2aeffd7e6..6ea3b004c25 100644
--- a/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx
+++ b/packages/manager/src/features/TopMenu/UserMenu/UserMenu.tsx
@@ -1,4 +1,4 @@
-import { Tooltip } from '@linode/ui';
+import { Box, Tooltip } from '@linode/ui';
import KeyboardArrowDown from '@mui/icons-material/KeyboardArrowDown';
import KeyboardArrowUp from '@mui/icons-material/KeyboardArrowUp';
import { styled, useMediaQuery } from '@mui/material';
@@ -9,7 +9,6 @@ import * as React from 'react';
import { Avatar } from 'src/components/Avatar/Avatar';
import { AvatarForProxy } from 'src/components/AvatarForProxy';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { Divider } from 'src/components/Divider';
import { Hidden } from 'src/components/Hidden';
diff --git a/packages/manager/src/features/Users/UserPermissions.tsx b/packages/manager/src/features/Users/UserPermissions.tsx
index ec85b41df06..8bad43671f2 100644
--- a/packages/manager/src/features/Users/UserPermissions.tsx
+++ b/packages/manager/src/features/Users/UserPermissions.tsx
@@ -4,6 +4,7 @@ import {
updateGrants,
updateUser,
} from '@linode/api-v4/lib/account';
+import { Box } from '@linode/ui';
import { Paper } from '@mui/material';
import Grid from '@mui/material/Unstable_Grid2';
import { enqueueSnackbar } from 'notistack';
@@ -11,7 +12,6 @@ import { compose, flatten, lensPath, omit, set } from 'ramda';
import * as React from 'react';
import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
-import { Box } from 'src/components/Box';
import { CircleProgress } from 'src/components/CircleProgress';
import { DocumentTitleSegment } from 'src/components/DocumentTitle';
import { FormControlLabel } from 'src/components/FormControlLabel';
diff --git a/packages/manager/src/features/Users/UserPermissionsEntitySection.tsx b/packages/manager/src/features/Users/UserPermissionsEntitySection.tsx
index 7876e6cdec7..9ff26232bf7 100644
--- a/packages/manager/src/features/Users/UserPermissionsEntitySection.tsx
+++ b/packages/manager/src/features/Users/UserPermissionsEntitySection.tsx
@@ -6,10 +6,10 @@
* I'll create a tech debt ticket in jira to keep track of this issue.
*/
+import { Box } from '@linode/ui';
import { useTheme } from '@mui/material/styles';
import React from 'react';
-import { Box } from 'src/components/Box';
import { FormControlLabel } from 'src/components/FormControlLabel';
import { createDisplayPage } from 'src/components/Paginate';
import { PaginationFooter } from 'src/components/PaginationFooter/PaginationFooter';
diff --git a/packages/manager/src/features/Users/UserProfile/DeleteUserPanel.tsx b/packages/manager/src/features/Users/UserProfile/DeleteUserPanel.tsx
index 4c9eac1481e..b17597a805b 100644
--- a/packages/manager/src/features/Users/UserProfile/DeleteUserPanel.tsx
+++ b/packages/manager/src/features/Users/UserProfile/DeleteUserPanel.tsx
@@ -1,7 +1,7 @@
+import { Box } from '@linode/ui';
import React, { useState } from 'react';
import { useHistory } from 'react-router-dom';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { Paper } from 'src/components/Paper';
import { Stack } from 'src/components/Stack';
diff --git a/packages/manager/src/features/Users/UserRow.tsx b/packages/manager/src/features/Users/UserRow.tsx
index 9b580c3714a..c98039fe58f 100644
--- a/packages/manager/src/features/Users/UserRow.tsx
+++ b/packages/manager/src/features/Users/UserRow.tsx
@@ -1,8 +1,8 @@
+import { Box } from '@linode/ui';
import { useTheme } from '@mui/material/styles';
import React from 'react';
import { Avatar } from 'src/components/Avatar/Avatar';
-import { Box } from 'src/components/Box';
import { Chip } from 'src/components/Chip';
import { DateTimeDisplay } from 'src/components/DateTimeDisplay';
import { Hidden } from 'src/components/Hidden';
diff --git a/packages/manager/src/features/Users/UsersLanding.tsx b/packages/manager/src/features/Users/UsersLanding.tsx
index a0298e8690f..0b758c36b04 100644
--- a/packages/manager/src/features/Users/UsersLanding.tsx
+++ b/packages/manager/src/features/Users/UsersLanding.tsx
@@ -1,8 +1,8 @@
+import { Box } from '@linode/ui';
import { useTheme } from '@mui/material/styles';
import useMediaQuery from '@mui/material/useMediaQuery';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { DocumentTitleSegment } from 'src/components/DocumentTitle';
import { PaginationFooter } from 'src/components/PaginationFooter/PaginationFooter';
diff --git a/packages/manager/src/features/VPCs/VPCCreateDrawer/VPCCreateDrawer.tsx b/packages/manager/src/features/VPCs/VPCCreateDrawer/VPCCreateDrawer.tsx
index ff58f41063a..44fa198a62a 100644
--- a/packages/manager/src/features/VPCs/VPCCreateDrawer/VPCCreateDrawer.tsx
+++ b/packages/manager/src/features/VPCs/VPCCreateDrawer/VPCCreateDrawer.tsx
@@ -1,9 +1,9 @@
+import { Box } from '@linode/ui';
import { useTheme } from '@mui/material/styles';
import Grid from '@mui/material/Unstable_Grid2';
import * as React from 'react';
import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
-import { Box } from 'src/components/Box';
import { Drawer } from 'src/components/Drawer';
import { Notice } from 'src/components/Notice/Notice';
import { CannotCreateVPCNotice } from 'src/features/VPCs/VPCCreate/FormComponents/CannotCreateVPCNotice';
diff --git a/packages/manager/src/features/VPCs/VPCDetail/AssignIPRanges.tsx b/packages/manager/src/features/VPCs/VPCDetail/AssignIPRanges.tsx
index a917a31a595..8856b1c656a 100644
--- a/packages/manager/src/features/VPCs/VPCDetail/AssignIPRanges.tsx
+++ b/packages/manager/src/features/VPCs/VPCDetail/AssignIPRanges.tsx
@@ -1,7 +1,7 @@
+import { Box } from '@linode/ui';
import { styled, useTheme } from '@mui/material/styles';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Divider } from 'src/components/Divider';
import { Link } from 'src/components/Link';
import { MultipleIPInput } from 'src/components/MultipleIPInput/MultipleIPInput';
diff --git a/packages/manager/src/features/VPCs/VPCDetail/SubnetAssignLinodesDrawer.styles.ts b/packages/manager/src/features/VPCs/VPCDetail/SubnetAssignLinodesDrawer.styles.ts
index 8bb12531112..295cf905c69 100644
--- a/packages/manager/src/features/VPCs/VPCDetail/SubnetAssignLinodesDrawer.styles.ts
+++ b/packages/manager/src/features/VPCs/VPCDetail/SubnetAssignLinodesDrawer.styles.ts
@@ -1,6 +1,6 @@
+import { Box } from '@linode/ui';
import { styled } from '@mui/material/styles';
-import { Box } from 'src/components/Box';
export const StyledButtonBox = styled(Box, { label: 'StyledButtonBox' })(
({ theme }) => ({
display: 'flex',
diff --git a/packages/manager/src/features/VPCs/VPCDetail/SubnetAssignLinodesDrawer.tsx b/packages/manager/src/features/VPCs/VPCDetail/SubnetAssignLinodesDrawer.tsx
index 946c7f3ae30..7a53ece0254 100644
--- a/packages/manager/src/features/VPCs/VPCDetail/SubnetAssignLinodesDrawer.tsx
+++ b/packages/manager/src/features/VPCs/VPCDetail/SubnetAssignLinodesDrawer.tsx
@@ -1,11 +1,10 @@
import { appendConfigInterface } from '@linode/api-v4';
-import { FormHelperText } from '@linode/ui';
+import { Box, FormHelperText } from '@linode/ui';
import { useTheme } from '@mui/material/styles';
import { useFormik } from 'formik';
import * as React from 'react';
import { Autocomplete } from 'src/components/Autocomplete/Autocomplete';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { Checkbox } from 'src/components/Checkbox';
import { DownloadCSV } from 'src/components/DownloadCSV/DownloadCSV';
diff --git a/packages/manager/src/features/VPCs/VPCDetail/SubnetLinodeRow.tsx b/packages/manager/src/features/VPCs/VPCDetail/SubnetLinodeRow.tsx
index d6c162886bd..725f74c4bb3 100644
--- a/packages/manager/src/features/VPCs/VPCDetail/SubnetLinodeRow.tsx
+++ b/packages/manager/src/features/VPCs/VPCDetail/SubnetLinodeRow.tsx
@@ -1,7 +1,7 @@
+import { Box } from '@linode/ui';
import ErrorOutline from '@mui/icons-material/ErrorOutline';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { CircleProgress } from 'src/components/CircleProgress';
import { Hidden } from 'src/components/Hidden';
import { InlineMenuAction } from 'src/components/InlineMenuAction/InlineMenuAction';
diff --git a/packages/manager/src/features/VPCs/VPCDetail/SubnetUnassignLinodesDrawer.tsx b/packages/manager/src/features/VPCs/VPCDetail/SubnetUnassignLinodesDrawer.tsx
index e4a91888e61..8b726a12699 100644
--- a/packages/manager/src/features/VPCs/VPCDetail/SubnetUnassignLinodesDrawer.tsx
+++ b/packages/manager/src/features/VPCs/VPCDetail/SubnetUnassignLinodesDrawer.tsx
@@ -1,3 +1,4 @@
+import { Box } from '@linode/ui';
import { Stack, Typography } from '@mui/material';
import { useQueryClient } from '@tanstack/react-query';
import { useFormik } from 'formik';
@@ -5,7 +6,6 @@ import * as React from 'react';
import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
import { Autocomplete } from 'src/components/Autocomplete/Autocomplete';
-import { Box } from 'src/components/Box';
import { DownloadCSV } from 'src/components/DownloadCSV/DownloadCSV';
import { Drawer } from 'src/components/Drawer';
import { Notice } from 'src/components/Notice/Notice';
diff --git a/packages/manager/src/features/VPCs/VPCDetail/VPCDetail.styles.ts b/packages/manager/src/features/VPCs/VPCDetail/VPCDetail.styles.ts
index 614b5e7a3a7..328171d1e2a 100644
--- a/packages/manager/src/features/VPCs/VPCDetail/VPCDetail.styles.ts
+++ b/packages/manager/src/features/VPCs/VPCDetail/VPCDetail.styles.ts
@@ -1,7 +1,7 @@
+import { Box } from '@linode/ui';
import { Typography } from '@mui/material';
import { styled } from '@mui/material/styles';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
export const StyledActionButton = styled(Button, {
diff --git a/packages/manager/src/features/VPCs/VPCDetail/VPCDetail.tsx b/packages/manager/src/features/VPCs/VPCDetail/VPCDetail.tsx
index 581d55a4959..48c43928aba 100644
--- a/packages/manager/src/features/VPCs/VPCDetail/VPCDetail.tsx
+++ b/packages/manager/src/features/VPCs/VPCDetail/VPCDetail.tsx
@@ -1,10 +1,10 @@
+import { Box } from '@linode/ui';
import { Typography } from '@mui/material';
import { useTheme } from '@mui/material/styles';
import { createLazyRoute } from '@tanstack/react-router';
import * as React from 'react';
import { useParams } from 'react-router-dom';
-import { Box } from 'src/components/Box';
import { StyledLinkButton } from 'src/components/Button/StyledLinkButton';
import { CircleProgress } from 'src/components/CircleProgress/CircleProgress';
import { DocumentTitleSegment } from 'src/components/DocumentTitle';
diff --git a/packages/manager/src/features/VPCs/VPCDetail/VPCSubnetsTable.tsx b/packages/manager/src/features/VPCs/VPCDetail/VPCSubnetsTable.tsx
index 2ecd40d4080..e14512d60c9 100644
--- a/packages/manager/src/features/VPCs/VPCDetail/VPCSubnetsTable.tsx
+++ b/packages/manager/src/features/VPCs/VPCDetail/VPCSubnetsTable.tsx
@@ -1,7 +1,7 @@
+import { Box } from '@linode/ui';
import { styled, useTheme } from '@mui/material/styles';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { CircleProgress } from 'src/components/CircleProgress/CircleProgress';
import { CollapsibleTable } from 'src/components/CollapsibleTable/CollapsibleTable';
diff --git a/packages/manager/src/features/Volumes/AttachVolumeDrawer.tsx b/packages/manager/src/features/Volumes/AttachVolumeDrawer.tsx
index 9b53b283243..b71987020a3 100644
--- a/packages/manager/src/features/Volumes/AttachVolumeDrawer.tsx
+++ b/packages/manager/src/features/Volumes/AttachVolumeDrawer.tsx
@@ -1,4 +1,4 @@
-import { FormHelperText } from '@linode/ui';
+import { Box, FormHelperText } from '@linode/ui';
import { styled } from '@mui/material/styles';
import { useFormik } from 'formik';
import { useSnackbar } from 'notistack';
@@ -6,7 +6,6 @@ import * as React from 'react';
import { number, object } from 'yup';
import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
-import { Box } from 'src/components/Box';
import { Checkbox } from 'src/components/Checkbox';
import { Drawer } from 'src/components/Drawer';
import { BLOCK_STORAGE_ENCRYPTION_SETTING_IMMUTABLE_COPY } from 'src/components/Encryption/constants';
diff --git a/packages/manager/src/features/Volumes/CloneVolumeDrawer.tsx b/packages/manager/src/features/Volumes/CloneVolumeDrawer.tsx
index 4d4d6b7845d..1bd690b3043 100644
--- a/packages/manager/src/features/Volumes/CloneVolumeDrawer.tsx
+++ b/packages/manager/src/features/Volumes/CloneVolumeDrawer.tsx
@@ -1,9 +1,9 @@
+import { Box } from '@linode/ui';
import { CloneVolumeSchema } from '@linode/validation/lib/volumes.schema';
import { useFormik } from 'formik';
import * as React from 'react';
import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
-import { Box } from 'src/components/Box';
import { Checkbox } from 'src/components/Checkbox';
import { Drawer } from 'src/components/Drawer';
import { BLOCK_STORAGE_CLONING_INHERITANCE_CAVEAT } from 'src/components/Encryption/constants';
diff --git a/packages/manager/src/features/Volumes/EditVolumeDrawer.tsx b/packages/manager/src/features/Volumes/EditVolumeDrawer.tsx
index 92108dd6406..94865d8de53 100644
--- a/packages/manager/src/features/Volumes/EditVolumeDrawer.tsx
+++ b/packages/manager/src/features/Volumes/EditVolumeDrawer.tsx
@@ -1,9 +1,9 @@
+import { Box } from '@linode/ui';
import { UpdateVolumeSchema } from '@linode/validation';
import { useFormik } from 'formik';
import React from 'react';
import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
-import { Box } from 'src/components/Box';
import { Checkbox } from 'src/components/Checkbox';
import { Drawer } from 'src/components/Drawer';
import { BLOCK_STORAGE_ENCRYPTION_SETTING_IMMUTABLE_COPY } from 'src/components/Encryption/constants';
diff --git a/packages/manager/src/features/Volumes/VolumeCreate.tsx b/packages/manager/src/features/Volumes/VolumeCreate.tsx
index ae3b9bae2ce..dc96018b93f 100644
--- a/packages/manager/src/features/Volumes/VolumeCreate.tsx
+++ b/packages/manager/src/features/Volumes/VolumeCreate.tsx
@@ -1,3 +1,4 @@
+import { Box } from '@linode/ui';
import { CreateVolumeSchema } from '@linode/validation/lib/volumes.schema';
import { useTheme } from '@mui/material/styles';
import { createLazyRoute } from '@tanstack/react-router';
@@ -7,7 +8,6 @@ import * as React from 'react';
import { useHistory } from 'react-router-dom';
import { makeStyles } from 'tss-react/mui';
-import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { DocumentTitleSegment } from 'src/components/DocumentTitle';
import {
diff --git a/packages/manager/src/features/Volumes/VolumeDrawer/LinodeVolumeCreateForm.tsx b/packages/manager/src/features/Volumes/VolumeDrawer/LinodeVolumeCreateForm.tsx
index 63a076abc8a..bc07204f6ba 100644
--- a/packages/manager/src/features/Volumes/VolumeDrawer/LinodeVolumeCreateForm.tsx
+++ b/packages/manager/src/features/Volumes/VolumeDrawer/LinodeVolumeCreateForm.tsx
@@ -1,10 +1,10 @@
+import { Box } from '@linode/ui';
import { CreateVolumeSchema } from '@linode/validation/lib/volumes.schema';
import { useFormik } from 'formik';
import { useSnackbar } from 'notistack';
import * as React from 'react';
import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel';
-import { Box } from 'src/components/Box';
import {
BLOCK_STORAGE_ENCRYPTION_GENERAL_DESCRIPTION,
BLOCK_STORAGE_ENCRYPTION_OVERHEAD_CAVEAT,
diff --git a/packages/manager/src/features/Volumes/VolumeDrawer/PricePanel.tsx b/packages/manager/src/features/Volumes/VolumeDrawer/PricePanel.tsx
index c7159947886..aebc1294fd0 100644
--- a/packages/manager/src/features/Volumes/VolumeDrawer/PricePanel.tsx
+++ b/packages/manager/src/features/Volumes/VolumeDrawer/PricePanel.tsx
@@ -1,6 +1,6 @@
+import { Box } from '@linode/ui';
import * as React from 'react';
-import { Box } from 'src/components/Box';
import { CircleProgress } from 'src/components/CircleProgress';
import { DisplayPrice } from 'src/components/DisplayPrice';
import { MAX_VOLUME_SIZE } from 'src/constants';
diff --git a/packages/manager/src/features/Volumes/VolumeDrawer/SizeField.tsx b/packages/manager/src/features/Volumes/VolumeDrawer/SizeField.tsx
index 48b1d04e4a1..6577ff113c7 100644
--- a/packages/manager/src/features/Volumes/VolumeDrawer/SizeField.tsx
+++ b/packages/manager/src/features/Volumes/VolumeDrawer/SizeField.tsx
@@ -1,8 +1,7 @@
-import { FormHelperText, InputAdornment } from '@linode/ui';
+import { Box, FormHelperText, InputAdornment } from '@linode/ui';
import * as React from 'react';
import { makeStyles } from 'tss-react/mui';
-import { Box } from 'src/components/Box';
import { CircleProgress } from 'src/components/CircleProgress';
import { TextField } from 'src/components/TextField';
import { Typography } from 'src/components/Typography';
diff --git a/packages/manager/src/features/Volumes/VolumeTableRow.tsx b/packages/manager/src/features/Volumes/VolumeTableRow.tsx
index c7e680cb990..d8558ac62fd 100644
--- a/packages/manager/src/features/Volumes/VolumeTableRow.tsx
+++ b/packages/manager/src/features/Volumes/VolumeTableRow.tsx
@@ -1,8 +1,8 @@
+import { Box } from '@linode/ui';
import * as React from 'react';
import { Link, useHistory } from 'react-router-dom';
import { makeStyles } from 'tss-react/mui';
-import { Box } from 'src/components/Box';
import { Chip } from 'src/components/Chip';
import { Hidden } from 'src/components/Hidden';
import { StatusIcon } from 'src/components/StatusIcon/StatusIcon';
diff --git a/packages/ui/.changeset/pr-11164-added-1729871599808.md b/packages/ui/.changeset/pr-11164-added-1729871599808.md
new file mode 100644
index 00000000000..bf250e40f84
--- /dev/null
+++ b/packages/ui/.changeset/pr-11164-added-1729871599808.md
@@ -0,0 +1,5 @@
+---
+"@linode/ui": Added
+---
+
+`Box` component from `manager` to `ui` package, part 2 ([#11164](https://github.com/linode/manager/pull/11164))
From 926fca5cc783d15313d79b53f47cd710c7541bfc Mon Sep 17 00:00:00 2001
From: Banks Nussman <115251059+bnussman-akamai@users.noreply.github.com>
Date: Wed, 30 Oct 2024 13:45:50 -0400
Subject: [PATCH 23/66] change: [M3-8807] - Improve Linode Create VPC user
experience (#11188)
* initial improvements
* fix logic and comment
* update the cypress test now that the UI has less friction
* add changeset
* reintroduce validation check @abailly-akamai
---------
Co-authored-by: Banks Nussman
---
.../pr-11188-added-1730298408749.md | 5 +
.../linodes/create-linode-with-vpc.spec.ts | 35 +-
.../features/Linodes/LinodeCreate/VPC/VPC.tsx | 23 +-
.../LinodeSettings/InterfaceSelect.tsx | 1 -
.../LinodeSettings/VPCPanel.test.tsx | 70 +--
.../LinodesDetail/LinodeSettings/VPCPanel.tsx | 443 ++++++------------
.../VPCCreateDrawer/VPCCreateDrawer.test.tsx | 2 +-
.../VPCs/VPCCreateDrawer/VPCCreateDrawer.tsx | 15 +-
packages/manager/src/hooks/useCreateVPC.ts | 9 +-
9 files changed, 225 insertions(+), 378 deletions(-)
create mode 100644 packages/manager/.changeset/pr-11188-added-1730298408749.md
diff --git a/packages/manager/.changeset/pr-11188-added-1730298408749.md b/packages/manager/.changeset/pr-11188-added-1730298408749.md
new file mode 100644
index 00000000000..94abffd9b01
--- /dev/null
+++ b/packages/manager/.changeset/pr-11188-added-1730298408749.md
@@ -0,0 +1,5 @@
+---
+"@linode/manager": Added
+---
+
+Pre-select a VPC subnet's on the Linode Create page when the VPC only has one subnet ([#11188](https://github.com/linode/manager/pull/11188))
diff --git a/packages/manager/cypress/e2e/core/linodes/create-linode-with-vpc.spec.ts b/packages/manager/cypress/e2e/core/linodes/create-linode-with-vpc.spec.ts
index 44041fc9dc6..f0746146d43 100644
--- a/packages/manager/cypress/e2e/core/linodes/create-linode-with-vpc.spec.ts
+++ b/packages/manager/cypress/e2e/core/linodes/create-linode-with-vpc.spec.ts
@@ -53,7 +53,6 @@ describe('Create Linode with VPCs', () => {
id: randomNumber(),
label: randomLabel(),
region: linodeRegion.id,
- //
});
mockGetVPCs([mockVPC]).as('getVPCs');
@@ -70,20 +69,18 @@ describe('Create Linode with VPCs', () => {
linodeCreatePage.setRootPassword(randomString(32));
// Confirm that mocked VPC is shown in the Autocomplete, and then select it.
- cy.findByText('Assign VPC').click().type(`${mockVPC.label}`);
+ cy.findByText('Assign VPC').click().type(mockVPC.label);
ui.autocompletePopper
.findByTitle(mockVPC.label)
.should('be.visible')
.click();
- // Confirm that Subnet selection appears and select mock subnet.
- cy.findByLabelText('Subnet').should('be.visible').type(mockSubnet.label);
-
- ui.autocompletePopper
- .findByTitle(`${mockSubnet.label} (${mockSubnet.ipv4})`)
- .should('be.visible')
- .click();
+ // Confirm that VPC's subnet gets selected
+ cy.findByLabelText('Subnet').should(
+ 'have.value',
+ `${mockSubnet.label} (${mockSubnet.ipv4})`
+ );
// Confirm VPC assignment indicator is shown in Linode summary.
cy.get('[data-qa-linode-create-summary]')
@@ -179,20 +176,34 @@ describe('Create Linode with VPCs', () => {
// Create VPC with successful API response mocked.
mockCreateVPC(mockVPC).as('createVpc');
+ mockGetVPCs([mockVPC]);
vpcCreateDrawer.submit();
});
- // Attempt to create Linode before selecting a VPC subnet, and confirm
- // that validation error appears.
+ // Verify the VPC field gets populated
+ cy.findByLabelText('Assign VPC').should('have.value', mockVPC.label);
+
+ // Verify the subnet gets populated
+ cy.findByLabelText('Subnet').should(
+ 'have.value',
+ `${mockSubnet.label} (${mockSubnet.ipv4})`
+ );
+
+ // Clear the subnet value
+ cy.get('[data-qa-autocomplete="Subnet"]').within(() => {
+ cy.findByLabelText('Clear').click();
+ });
+
+ // Try to submit the form without a subnet selected
ui.button
.findByTitle('Create Linode')
.should('be.visible')
.should('be.enabled')
.click();
+ // Verify a validation error shows
cy.findByText('Subnet is required.').should('be.visible');
- // Confirm that Subnet selection appears and select mock subnet.
cy.findByLabelText('Subnet').should('be.visible').type(mockSubnet.label);
ui.autocompletePopper
diff --git a/packages/manager/src/features/Linodes/LinodeCreate/VPC/VPC.tsx b/packages/manager/src/features/Linodes/LinodeCreate/VPC/VPC.tsx
index 74137759e13..ef9cfd9d07b 100644
--- a/packages/manager/src/features/Linodes/LinodeCreate/VPC/VPC.tsx
+++ b/packages/manager/src/features/Linodes/LinodeCreate/VPC/VPC.tsx
@@ -114,6 +114,19 @@ export const VPC = () => {
}
onChange={(e, vpc) => {
field.onChange(vpc?.id ?? null);
+
+ if (vpc && vpc.subnets.length === 1) {
+ // If the user selectes a VPC and the VPC only has one subnet,
+ // preselect that subnet for the user.
+ setValue('interfaces.0.subnet_id', vpc.subnets[0].id, {
+ shouldValidate: true,
+ });
+ } else {
+ // Otherwise, just clear the selected subnet
+ setValue('interfaces.0.subnet_id', null);
+ }
+
+ // Capture analytics
if (!vpc?.id) {
sendLinodeCreateFormInputEvent({
...vpcFormEventOptions,
@@ -306,7 +319,15 @@ export const VPC = () => {
setValue('interfaces.0.vpc_id', vpcId)}
+ onSuccess={(vpc) => {
+ setValue('interfaces.0.vpc_id', vpc.id);
+
+ if (vpc.subnets.length === 1) {
+ // If the user creates a VPC with just one subnet,
+ // preselect it for them
+ setValue('interfaces.0.subnet_id', vpc.subnets[0].id);
+ }
+ }}
onClose={() => setIsCreateDrawerOpen(false)}
open={isCreateDrawerOpen}
selectedRegion={regionId}
diff --git a/packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/InterfaceSelect.tsx b/packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/InterfaceSelect.tsx
index 23e5fb35631..2ef7b01e54b 100644
--- a/packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/InterfaceSelect.tsx
+++ b/packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/InterfaceSelect.tsx
@@ -395,7 +395,6 @@ export const InterfaceSelect = (props: InterfaceSelectProps) => {
additionalIPv4RangesForVPC={additionalIPv4RangesForVPC ?? []}
assignPublicIPv4Address={nattedIPv4Address !== undefined}
autoassignIPv4WithinVPC={vpcIPv4 === undefined}
- from="linodeConfig"
handleIPv4RangeChange={handleIPv4RangeChange}
handleSelectVPC={handleVPCLabelChange}
handleSubnetChange={handleSubnetChange}
diff --git a/packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/VPCPanel.test.tsx b/packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/VPCPanel.test.tsx
index 2255e3115ec..74e9117610c 100644
--- a/packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/VPCPanel.test.tsx
+++ b/packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/VPCPanel.test.tsx
@@ -3,10 +3,10 @@ import * as React from 'react';
import { accountFactory, regionFactory } from 'src/factories';
import { makeResourcePage } from 'src/mocks/serverHandlers';
-import { http, HttpResponse, server } from 'src/mocks/testServer';
+import { HttpResponse, http, server } from 'src/mocks/testServer';
import { mockMatchMedia, renderWithTheme } from 'src/utilities/testHelpers';
-import { VPCPanel, VPCPanelProps } from './VPCPanel';
+import { VPCPanel } from './VPCPanel';
beforeAll(() => mockMatchMedia());
@@ -14,7 +14,6 @@ const props = {
additionalIPv4RangesForVPC: [],
assignPublicIPv4Address: false,
autoassignIPv4WithinVPC: true,
- from: 'linodeCreate' as VPCPanelProps['from'],
handleIPv4RangeChange: vi.fn(),
handleSelectVPC: vi.fn(),
handleSubnetChange: vi.fn(),
@@ -100,7 +99,7 @@ describe('VPCPanel', () => {
});
});
- it('should display helper text if there are no vpcs in the selected region and "from" is "linodeCreate"', async () => {
+ it('should not display helper text if there are no vpcs in the selected region', async () => {
server.use(
http.get('*/regions', () => {
const usEast = regionFactory.build({
@@ -116,33 +115,6 @@ describe('VPCPanel', () => {
const wrapper = renderWithTheme( );
- await waitFor(() => {
- expect(
- wrapper.queryByText(
- 'No VPCs exist in the selected region. Click Create VPC to create one.'
- )
- ).toBeInTheDocument();
- });
- });
-
- it('should not display helper text if there are no vpcs in the selected region and "from" is "linodeConfig"', async () => {
- server.use(
- http.get('*/regions', () => {
- const usEast = regionFactory.build({
- capabilities: ['VPCs'],
- id: 'us-east',
- });
- return HttpResponse.json(makeResourcePage([usEast]));
- }),
- http.get('*/vpcs', () => {
- return HttpResponse.json(makeResourcePage([]));
- })
- );
-
- const wrapper = renderWithTheme(
-
- );
-
await waitFor(() => {
expect(
wrapper.queryByText(
@@ -151,42 +123,6 @@ describe('VPCPanel', () => {
).not.toBeInTheDocument();
});
});
- it('shows helper text for when "from" = "linodeCreate" if the selected region does not support VPCs', async () => {
- server.use(
- http.get('*/regions', () => {
- const usEast = regionFactory.build({
- capabilities: [],
- id: 'us-east',
- });
- return HttpResponse.json(makeResourcePage([usEast]));
- })
- );
-
- const wrapper = renderWithTheme( );
-
- await waitFor(() => {
- expect(
- wrapper.queryByText('VPC is not available in the selected region.')
- ).toBeInTheDocument();
- });
- });
- it('should show the "Create VPC" drawer link when from = "linodeCreate" and a region that supports VPCs is selected', async () => {
- server.use(
- http.get('*/regions', () => {
- const usEast = regionFactory.build({
- capabilities: ['VPCs'],
- id: 'us-east',
- });
- return HttpResponse.json(makeResourcePage([usEast]));
- })
- );
-
- const wrapper = renderWithTheme( );
-
- await waitFor(() => {
- expect(wrapper.queryByText('Create VPC')).toBeInTheDocument();
- });
- });
it('should display an unchecked VPC IPv4 auto-assign checkbox and display the VPC IPv4 input field if there is already a value', async () => {
const _props = {
...props,
diff --git a/packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/VPCPanel.tsx b/packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/VPCPanel.tsx
index 4ac18e72bfa..0220fb55d70 100644
--- a/packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/VPCPanel.tsx
+++ b/packages/manager/src/features/Linodes/LinodesDetail/LinodeSettings/VPCPanel.tsx
@@ -6,10 +6,7 @@ import * as React from 'react';
import { Autocomplete } from 'src/components/Autocomplete/Autocomplete';
import { Checkbox } from 'src/components/Checkbox';
import { FormControlLabel } from 'src/components/FormControlLabel';
-import { Link } from 'src/components/Link';
-import { LinkButton } from 'src/components/LinkButton';
import { Paper } from 'src/components/Paper';
-import { StyledLinkButtonBox } from 'src/components/SelectFirewallPanel/SelectFirewallPanel';
import { Stack } from 'src/components/Stack';
import { TextField } from 'src/components/TextField';
import { TooltipIcon } from 'src/components/TooltipIcon';
@@ -21,23 +18,16 @@ import {
import { AssignIPRanges } from 'src/features/VPCs/VPCDetail/AssignIPRanges';
import { useRegionsQuery } from 'src/queries/regions/regions';
import { useAllVPCsQuery } from 'src/queries/vpcs/vpcs';
-import { sendLinodeCreateFormInputEvent } from 'src/utilities/analytics/formEventAnalytics';
import { doesRegionSupportFeature } from 'src/utilities/doesRegionSupportFeature';
import { getAPIErrorOrDefault } from 'src/utilities/errorUtils';
-import { getQueryParamsFromQueryString } from 'src/utilities/queryParams';
import { scrollErrorIntoView } from 'src/utilities/scrollErrorIntoView';
-import { VPCCreateDrawer } from '../../../VPCs/VPCCreateDrawer/VPCCreateDrawer';
-
-import type { LinodeCreateQueryParams } from 'src/features/Linodes/types';
-import type { LinodeCreateFormEventOptions } from 'src/utilities/analytics/types';
import type { ExtendedIP } from 'src/utilities/ipUtils';
export interface VPCPanelProps {
additionalIPv4RangesForVPC: ExtendedIP[];
assignPublicIPv4Address: boolean;
autoassignIPv4WithinVPC: boolean;
- from: 'linodeConfig' | 'linodeCreate';
handleIPv4RangeChange: (ranges: ExtendedIP[]) => void;
handleSelectVPC: (vpcId: number) => void;
handleSubnetChange: (subnetId: number | undefined) => void;
@@ -62,7 +52,6 @@ export const VPCPanel = (props: VPCPanelProps) => {
additionalIPv4RangesForVPC,
assignPublicIPv4Address,
autoassignIPv4WithinVPC,
- from,
handleIPv4RangeChange,
handleSelectVPC,
handleSubnetChange,
@@ -92,10 +81,6 @@ export const VPCPanel = (props: VPCPanelProps) => {
'VPCs'
);
- const [isVPCCreateDrawerOpen, setIsVPCCreateDrawerOpen] = React.useState(
- false
- );
-
const { data: vpcsData, error, isLoading } = useAllVPCsQuery();
React.useEffect(() => {
@@ -104,38 +89,22 @@ export const VPCPanel = (props: VPCPanelProps) => {
}
}, [subnetError, vpcIPv4Error]);
- const params = getQueryParamsFromQueryString(
- location.search
- );
- const vpcFormEventOptions: LinodeCreateFormEventOptions = {
- createType: params.type ?? 'OS',
- headerName: 'VPC',
- interaction: 'click',
- label: 'VPC',
- };
-
const vpcs = vpcsData ?? [];
- const fromLinodeCreate = from === 'linodeCreate';
- const fromLinodeConfig = from === 'linodeConfig';
-
interface DropdownOption {
label: string;
value: number;
}
const vpcDropdownOptions: DropdownOption[] = React.useMemo(() => {
- return vpcs.reduce(
- (accumulator, vpc) => {
- return vpc.region === region
- ? [...accumulator, { label: vpc.label, value: vpc.id }]
- : accumulator;
- },
- fromLinodeCreate ? [{ label: 'None', value: -1 }] : []
- );
- }, [vpcs, region, fromLinodeCreate]);
+ return vpcs.reduce((accumulator, vpc) => {
+ return vpc.region === region
+ ? [...accumulator, { label: vpc.label, value: vpc.id }]
+ : accumulator;
+ }, []);
+ }, [vpcs, region]);
- const defaultVPCValue = fromLinodeConfig ? null : vpcDropdownOptions[0];
+ const defaultVPCValue = null;
const subnetDropdownOptions: DropdownOption[] =
vpcs
@@ -149,264 +118,160 @@ export const VPCPanel = (props: VPCPanelProps) => {
? getAPIErrorOrDefault(error, 'Unable to load VPCs')[0].reason
: undefined;
- const getMainCopyVPC = () => {
- if (fromLinodeConfig) {
- return null;
- }
- const copy =
- vpcDropdownOptions.length <= 1
- ? 'Allow Linode to communicate in an isolated environment.'
- : 'Assign this Linode to an existing VPC.';
-
- return (
- <>
- {copy}{' '}
-
- fromLinodeCreate &&
- sendLinodeCreateFormInputEvent({
- ...vpcFormEventOptions,
- label: 'Learn more',
- })
- }
- to="https://techdocs.akamai.com/cloud-computing/docs/assign-a-compute-instance-to-a-vpc"
- >
- Learn more
-
- .
- >
- );
- };
-
return (
- <>
- ({
- ...(fromLinodeCreate && {
- marginTop: theme.spacing(3),
- }),
- ...(fromLinodeConfig && {
- padding: 0,
- }),
- })}
- data-testid="vpc-panel"
- >
- {fromLinodeCreate && (
- ({ marginBottom: theme.spacing(2) })}
- variant="h2"
- >
- VPC
-
- )}
-
- {getMainCopyVPC()}
- {
- handleSelectVPC(selectedVPC?.value || -1);
- // Track clearing and changing the value once per page view, configured by inputValue in AA backend.
- if (selectedVPC?.label === 'None') {
- sendLinodeCreateFormInputEvent({
- ...vpcFormEventOptions,
- interaction: 'clear',
- subheaderName: 'Assign VPC',
- trackOnce: true,
- });
- } else {
- sendLinodeCreateFormInputEvent({
- ...vpcFormEventOptions,
- interaction: 'change',
- subheaderName: 'Assign VPC',
- trackOnce: true,
- });
+
+
+ {
+ handleSelectVPC(selectedVPC?.value || -1);
+ }}
+ textFieldProps={{
+ tooltipText: REGION_CAVEAT_HELPER_TEXT,
+ }}
+ value={
+ selectedVPCId && selectedVPCId !== -1
+ ? vpcDropdownOptions.find(
+ (option) => option.value === selectedVPCId
+ ) ?? null
+ : defaultVPCValue
+ }
+ autoHighlight
+ clearIcon={null}
+ disabled={!regionSupportsVPCs}
+ errorText={vpcIdError ?? vpcError}
+ label={'VPC'}
+ loading={isLoading}
+ noOptionsText="No VPCs exist in this Linode's region."
+ options={vpcDropdownOptions}
+ placeholder={'Select a VPC'}
+ />
+ {selectedVPCId !== -1 && regionSupportsVPCs && (
+
+ {
+ handleSubnetChange(selectedSubnet?.value);
+ }}
+ textFieldProps={{
+ errorGroup: ERROR_GROUP_STRING,
+ }}
+ value={
+ subnetDropdownOptions.find(
+ (option) => option.value === selectedSubnetId
+ ) ?? null
}
- }}
- textFieldProps={{
- tooltipText: REGION_CAVEAT_HELPER_TEXT,
- }}
- value={
- selectedVPCId && selectedVPCId !== -1
- ? vpcDropdownOptions.find(
- (option) => option.value === selectedVPCId
- ) ?? null
- : defaultVPCValue
- }
- autoHighlight
- clearIcon={null}
- disabled={!regionSupportsVPCs}
- errorText={vpcIdError ?? vpcError}
- label={from === 'linodeCreate' ? 'Assign VPC' : 'VPC'}
- loading={isLoading}
- noOptionsText="No VPCs exist in this Linode's region."
- options={vpcDropdownOptions}
- placeholder={'Select a VPC'}
- />
- {from === 'linodeCreate' &&
- vpcDropdownOptions.length <= 1 &&
- regionSupportsVPCs && (
- ({ paddingTop: theme.spacing(1.5) })}>
- No VPCs exist in the selected region. Click Create VPC to create
- one.
-
- )}
- {from === 'linodeCreate' &&
- (regionSupportsVPCs ? (
-
- {
- setIsVPCCreateDrawerOpen(true);
- sendLinodeCreateFormInputEvent({
- ...vpcFormEventOptions,
- label: 'Create VPC',
- });
- }}
+ autoHighlight
+ clearIcon={null}
+ errorText={subnetError}
+ label="Subnet"
+ options={subnetDropdownOptions}
+ placeholder="Select Subnet"
+ />
+ {selectedSubnetId && (
+ <>
+ ({
+ marginLeft: '2px',
+ paddingTop: theme.spacing(),
+ })}
+ alignItems="center"
+ display="flex"
+ flexDirection="row"
>
- Create VPC
-
-
- ) : (
- region && (
- ({ paddingTop: theme.spacing(1.5) })}
+
+ }
+ label={
+
+
+ Auto-assign a VPC IPv4 address for this Linode in the
+ VPC
+
+
+
+ }
+ data-testid="vpc-ipv4-checkbox"
+ />
+
+ {!autoassignIPv4WithinVPC && (
+ handleVPCIPv4Change(e.target.value)}
+ required={!autoassignIPv4WithinVPC}
+ value={vpcIPv4AddressOfLinode}
+ />
+ )}
+ ({
+ marginLeft: '2px',
+ marginTop: !autoassignIPv4WithinVPC ? theme.spacing() : 0,
+ })}
+ alignItems="center"
+ display="flex"
>
- VPC is not available in the selected region.
-
- )
- ))}
-
- {selectedVPCId !== -1 && regionSupportsVPCs && (
-
- {
- handleSubnetChange(selectedSubnet?.value);
- }}
- textFieldProps={{
- errorGroup: ERROR_GROUP_STRING,
- }}
- value={
- subnetDropdownOptions.find(
- (option) => option.value === selectedSubnetId
- ) ?? null
- }
- autoHighlight
- clearIcon={null}
- errorText={subnetError}
- label="Subnet"
- options={subnetDropdownOptions}
- placeholder="Select Subnet"
- />
- {selectedSubnetId && (
- <>
- ({
- marginLeft: '2px',
- paddingTop: theme.spacing(),
- })}
- alignItems="center"
- display="flex"
- flexDirection="row"
- >
-
+ }
+ label={
+
+
+ Assign a public IPv4 address for this Linode
+
+
- }
- label={
-
-
- Auto-assign a VPC IPv4 address for this Linode in
- the VPC
-
-
-
- }
- data-testid="vpc-ipv4-checkbox"
- />
-
- {!autoassignIPv4WithinVPC && (
- handleVPCIPv4Change(e.target.value)}
- required={!autoassignIPv4WithinVPC}
- value={vpcIPv4AddressOfLinode}
- />
- )}
-
+ }
+ />
+
+ {assignPublicIPv4Address && publicIPv4Error && (
+ ({
- marginLeft: '2px',
- marginTop: !autoassignIPv4WithinVPC ? theme.spacing() : 0,
+ color: theme.color.red,
})}
- alignItems="center"
- display="flex"
>
-
- }
- label={
-
-
- Assign a public IPv4 address for this Linode
-
-
-
- }
- />
-
- {assignPublicIPv4Address && publicIPv4Error && (
- ({
- color: theme.color.red,
- })}
- >
- {publicIPv4Error}
-
- )}
-
- >
- )}
-
- )}
-
-
- {isVPCCreateDrawerOpen && (
- handleSelectVPC(vpcId)}
- onClose={() => setIsVPCCreateDrawerOpen(false)}
- open={isVPCCreateDrawerOpen}
- selectedRegion={region}
- />
- )}
- >
+ {publicIPv4Error}
+
+ )}
+
+ >
+ )}
+
+ )}
+
+
);
};
diff --git a/packages/manager/src/features/VPCs/VPCCreateDrawer/VPCCreateDrawer.test.tsx b/packages/manager/src/features/VPCs/VPCCreateDrawer/VPCCreateDrawer.test.tsx
index 0f86ad99e04..434decf1b5b 100644
--- a/packages/manager/src/features/VPCs/VPCCreateDrawer/VPCCreateDrawer.test.tsx
+++ b/packages/manager/src/features/VPCs/VPCCreateDrawer/VPCCreateDrawer.test.tsx
@@ -6,8 +6,8 @@ import { renderWithTheme } from 'src/utilities/testHelpers';
import { VPCCreateDrawer } from './VPCCreateDrawer';
const props = {
- handleSelectVPC: vi.fn(),
onClose: vi.fn(),
+ onSuccess: vi.fn(),
open: true,
};
diff --git a/packages/manager/src/features/VPCs/VPCCreateDrawer/VPCCreateDrawer.tsx b/packages/manager/src/features/VPCs/VPCCreateDrawer/VPCCreateDrawer.tsx
index 44fa198a62a..f22abc2de96 100644
--- a/packages/manager/src/features/VPCs/VPCCreateDrawer/VPCCreateDrawer.tsx
+++ b/packages/manager/src/features/VPCs/VPCCreateDrawer/VPCCreateDrawer.tsx
@@ -11,16 +11,21 @@ import { SubnetContent } from 'src/features/VPCs/VPCCreate/FormComponents/Subnet
import { VPCTopSectionContent } from 'src/features/VPCs/VPCCreate/FormComponents/VPCTopSectionContent';
import { useCreateVPC } from 'src/hooks/useCreateVPC';
+import type { VPC } from '@linode/api-v4';
+
interface Props {
- handleSelectVPC: (vpcId: number) => void;
onClose: () => void;
+ /**
+ * A function that is called when a VPC is successfully created
+ */
+ onSuccess: (vpc: VPC) => void;
open: boolean;
selectedRegion?: string;
}
export const VPCCreateDrawer = (props: Props) => {
const theme = useTheme();
- const { handleSelectVPC, onClose, open, selectedRegion } = props;
+ const { onClose, onSuccess, open, selectedRegion } = props;
const {
formik,
@@ -33,7 +38,11 @@ export const VPCCreateDrawer = (props: Props) => {
setGeneralAPIError,
setGeneralSubnetErrorsFromAPI,
userCannotAddVPC,
- } = useCreateVPC({ handleSelectVPC, onDrawerClose: onClose, selectedRegion });
+ } = useCreateVPC({
+ handleSelectVPC: onSuccess,
+ onDrawerClose: onClose,
+ selectedRegion,
+ });
const { errors, handleSubmit, resetForm, setFieldValue, values } = formik;
diff --git a/packages/manager/src/hooks/useCreateVPC.ts b/packages/manager/src/hooks/useCreateVPC.ts
index f625cda34e4..becb96d697c 100644
--- a/packages/manager/src/hooks/useCreateVPC.ts
+++ b/packages/manager/src/hooks/useCreateVPC.ts
@@ -16,6 +16,7 @@ import type {
APIError,
CreateSubnetPayload,
CreateVPCPayload,
+ VPC,
} from '@linode/api-v4';
import type { LinodeCreateType } from 'src/features/Linodes/LinodeCreate/types';
import type { SubnetError } from 'src/utilities/formikErrorUtils';
@@ -31,7 +32,7 @@ export interface CreateVPCFieldState {
}
export interface UseCreateVPCInputs {
- handleSelectVPC?: (vpcId: number) => void;
+ handleSelectVPC?: (vpc: VPC) => void;
onDrawerClose?: () => void;
pushToVPCPage?: boolean;
selectedRegion?: string;
@@ -135,12 +136,12 @@ export const useCreateVPC = (inputs: UseCreateVPCInputs) => {
};
try {
- const response = await createVPC(createVPCPayload);
+ const vpc = await createVPC(createVPCPayload);
if (pushToVPCPage) {
- history.push(`/vpcs/${response.id}`);
+ history.push(`/vpcs/${vpc.id}`);
} else {
if (handleSelectVPC && onDrawerClose) {
- handleSelectVPC(response.id);
+ handleSelectVPC(vpc);
onDrawerClose();
}
}
From 6c80781ec82678842e85124ef465ad84e66380bb Mon Sep 17 00:00:00 2001
From: Hana Xu <115299789+hana-akamai@users.noreply.github.com>
Date: Wed, 30 Oct 2024 15:03:50 -0400
Subject: [PATCH 24/66] change: [M3-8659] - Incorporate Product Family Groups
in Side Nav (#11080)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## Description 📝
More products are getting added to Cloud Manager, so we need to make sure our side navigation menu can accommodate them.
This PR introduces collapsible Product families into the side nav to allow more products to be shown while also giving users the ability to hide/show relevant families. Additionally, individual product icons have been removed in favor of Product family icons
Note: The Monitor product family icon is still in discussion. Create menu dropdown will be updated in M3-8728.
## Changes 🔄
- Product nav links have been moved inside an accordion except for Managed
- The default state for the accordions is expanded
- Collapsed accordions are saved to preferences so state is maintained
- Individual product icons have been removed, only product families will have icons
- Empty state landing pages have been updated accordingly
- When the side menu is collapsed, only product family icons are displayed
- Hovering over the side menu while it is in the collapsed state will expand the menu with all the items
- The active product family icon will be green
Code clean up:
- Removed old unused prefetch code 🧹
- Migrated styles to Styled components
- Moved PrimaryLink to its own component
## How to test 🧪
### Verification steps
(How to verify changes)
- Pull this PR locally and check different states of the side nav menu
- To test Managed, you can use the MSW to set Managed to enabled
---
.../pr-11080-changed-1730138781683.md | 5 +
.../cloudpulse/cloudpulse-navigation.spec.ts | 4 +-
.../core/volumes/create-volume.smoke.spec.ts | 8 +-
packages/manager/src/assets/icons/more.svg | 8 +
.../src/components/PrimaryNav/PrimaryLink.tsx | 71 +++
.../PrimaryNav/PrimaryNav.styles.ts | 259 ++++----
.../components/PrimaryNav/PrimaryNav.test.tsx | 23 +-
.../src/components/PrimaryNav/PrimaryNav.tsx | 571 ++++++++----------
.../PrimaryNav/SideMenu.stories.tsx | 2 +-
.../src/components/PrimaryNav/SideMenu.tsx | 14 +-
.../Domains/DomainsEmptyLandingPage.tsx | 4 +-
.../FirewallLandingEmptyState.tsx | 6 +-
.../ImagesLanding/ImagesLandingEmptyState.tsx | 4 +-
.../CreateCluster/CreateCluster.tsx | 2 +-
.../KubernetesLandingEmptyState.tsx | 4 +-
.../NodeBalancersLandingEmptyState.tsx | 4 +-
.../PlacementGroupsLandingEmptyState.tsx | 4 +-
.../StackScriptsEmptyLandingPage.tsx | 4 +-
.../VPCs/VPCLanding/VPCEmptyState.tsx | 6 +-
.../VolumesLandingEmptyState.styles.ts | 9 -
.../Volumes/VolumesLandingEmptyState.tsx | 4 +-
packages/manager/src/hooks/usePreFetch.ts | 57 --
packages/ui/src/foundations/themes/light.ts | 2 +-
23 files changed, 516 insertions(+), 559 deletions(-)
create mode 100644 packages/manager/.changeset/pr-11080-changed-1730138781683.md
create mode 100644 packages/manager/src/assets/icons/more.svg
create mode 100644 packages/manager/src/components/PrimaryNav/PrimaryLink.tsx
delete mode 100644 packages/manager/src/features/Volumes/VolumesLandingEmptyState.styles.ts
delete mode 100644 packages/manager/src/hooks/usePreFetch.ts
diff --git a/packages/manager/.changeset/pr-11080-changed-1730138781683.md b/packages/manager/.changeset/pr-11080-changed-1730138781683.md
new file mode 100644
index 00000000000..b33939a9c8e
--- /dev/null
+++ b/packages/manager/.changeset/pr-11080-changed-1730138781683.md
@@ -0,0 +1,5 @@
+---
+"@linode/manager": Changed
+---
+
+Incorporate Product Family Groups in Side Nav ([#11080](https://github.com/linode/manager/pull/11080))
diff --git a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts
index 8196496aca3..e747af3f3bf 100644
--- a/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts
+++ b/packages/manager/cypress/e2e/core/cloudpulse/cloudpulse-navigation.spec.ts
@@ -29,7 +29,7 @@ describe('CloudPulse navigation', () => {
cy.visitWithLogin('/linodes');
cy.wait('@getFeatureFlags');
- ui.nav.findItemByTitle('Monitor').should('be.visible').click();
+ cy.get('[data-testid="menu-item-Monitor"]').should('be.visible').click();
cy.url().should('endWith', '/cloudpulse');
});
@@ -48,7 +48,7 @@ describe('CloudPulse navigation', () => {
cy.wait('@getFeatureFlags');
ui.nav.find().within(() => {
- cy.findByText('Monitor').should('not.exist');
+ cy.get('[data-testid="menu-item-Monitor"]').should('not.exist');
});
});
diff --git a/packages/manager/cypress/e2e/core/volumes/create-volume.smoke.spec.ts b/packages/manager/cypress/e2e/core/volumes/create-volume.smoke.spec.ts
index 0b44440546a..3c645ace145 100644
--- a/packages/manager/cypress/e2e/core/volumes/create-volume.smoke.spec.ts
+++ b/packages/manager/cypress/e2e/core/volumes/create-volume.smoke.spec.ts
@@ -152,7 +152,9 @@ describe('volumes', () => {
cy.wait('@getLinodeDetail');
// Create a new volume.
- cy.findByText('Storage').should('be.visible').click();
+ cy.get('main').within(() => {
+ cy.findByText('Storage').should('be.visible').click();
+ });
ui.button.findByTitle('Add Volume').should('be.visible').click();
@@ -285,7 +287,9 @@ describe('volumes', () => {
cy.wait(['@getVolumes', '@getLinodeDetail']);
// Open the Add Volume drawer.
- cy.findByText('Storage').should('be.visible').click();
+ cy.get('main').within(() => {
+ cy.findByText('Storage').should('be.visible').click();
+ });
ui.button.findByTitle('Add Volume').should('be.visible').click();
cy.wait(['@getVolumeTypesError']);
diff --git a/packages/manager/src/assets/icons/more.svg b/packages/manager/src/assets/icons/more.svg
new file mode 100644
index 00000000000..7b86cba0b77
--- /dev/null
+++ b/packages/manager/src/assets/icons/more.svg
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/packages/manager/src/components/PrimaryNav/PrimaryLink.tsx b/packages/manager/src/components/PrimaryNav/PrimaryLink.tsx
new file mode 100644
index 00000000000..788c0e4e6d0
--- /dev/null
+++ b/packages/manager/src/components/PrimaryNav/PrimaryLink.tsx
@@ -0,0 +1,71 @@
+import { BetaChip } from '@linode/ui';
+import * as React from 'react';
+
+import { StyledActiveLink, StyledPrimaryLinkBox } from './PrimaryNav.styles';
+
+import type { NavEntity } from './PrimaryNav';
+
+export interface PrimaryLink {
+ activeLinks?: Array;
+ attr?: { [key: string]: any };
+ betaChipClassName?: string;
+ display: NavEntity;
+ hide?: boolean;
+ href: string;
+ isBeta?: boolean;
+ onClick?: (e: React.ChangeEvent) => void;
+}
+
+interface PrimaryLinkProps extends PrimaryLink {
+ closeMenu: () => void;
+ isActiveLink: boolean;
+ isBeta?: boolean;
+ isCollapsed: boolean;
+}
+
+const PrimaryLink = React.memo((props: PrimaryLinkProps) => {
+ const {
+ attr,
+ betaChipClassName,
+ closeMenu,
+ display,
+ href,
+ isActiveLink,
+ isBeta,
+ isCollapsed,
+ onClick,
+ } = props;
+
+ return (
+ ) => {
+ closeMenu();
+ if (onClick) {
+ onClick(e);
+ }
+ }}
+ to={href}
+ {...attr}
+ aria-current={isActiveLink}
+ data-testid={`menu-item-${display}`}
+ isActiveLink={isActiveLink}
+ isCollapsed={isCollapsed}
+ >
+
+ {display}
+ {isBeta ? (
+
+ ) : null}
+
+
+ );
+});
+
+export default PrimaryLink;
diff --git a/packages/manager/src/components/PrimaryNav/PrimaryNav.styles.ts b/packages/manager/src/components/PrimaryNav/PrimaryNav.styles.ts
index df742cde809..5d7c0c33ece 100644
--- a/packages/manager/src/components/PrimaryNav/PrimaryNav.styles.ts
+++ b/packages/manager/src/components/PrimaryNav/PrimaryNav.styles.ts
@@ -1,140 +1,155 @@
-import { makeStyles } from 'tss-react/mui';
+import { Box } from '@linode/ui';
+import { styled } from '@mui/material/styles';
+import Grid from '@mui/material/Unstable_Grid2';
+import { Link } from 'react-router-dom';
+import AkamaiLogo from 'src/assets/logo/akamai-logo.svg';
+import { Accordion } from 'src/components/Accordion';
+import { Divider } from 'src/components/Divider';
import { SIDEBAR_WIDTH } from 'src/components/PrimaryNav/SideMenu';
+import { omittedProps } from 'src/utilities/omittedProps';
-import type { Theme } from '@mui/material/styles';
+export const StyledGrid = styled(Grid, {
+ label: 'StyledGrid',
+})(({ theme }) => ({
+ height: '100%',
+ margin: 0,
+ minHeight: 64,
+ padding: 0,
+ [theme.breakpoints.up('md')]: {
+ minHeight: 80,
+ },
+ [theme.breakpoints.up('sm')]: {
+ minHeight: 72,
+ },
+ width: '100%',
+}));
-const useStyles = makeStyles()(
- (theme: Theme, _params, classes) => ({
- active: {
- '& div.icon': {
- opacity: 1,
- },
- '& svg': {
- color: theme.palette.success.dark,
- },
- backgroundImage: 'linear-gradient(98deg, #38584B 1%, #3A5049 166%)',
- textDecoration: 'none',
- },
- chip: {
- marginTop: 2,
+export const StyledLogoBox = styled(Box, {
+ label: 'StyledLogoBox',
+ shouldForwardProp: omittedProps(['isCollapsed']),
+})<{ isCollapsed: boolean }>(({ theme, ...props }) => ({
+ alignItems: 'center',
+ backgroundColor: theme.name === 'dark' ? theme.bg.appBar : undefined,
+ display: 'flex',
+ height: 50,
+ paddingLeft: 13,
+ transition: 'padding-left .03s linear',
+ ...(props.isCollapsed && {
+ '& .akamai-logo-name': {
+ opacity: 0,
},
- divider: {
- backgroundColor: 'rgba(0, 0, 0, 0.12)',
- color: '#222',
- },
- linkItem: {
- '&.hiddenWhenCollapsed': {
- maxHeight: 36,
- opacity: 0,
- },
- alignItems: 'center',
- color: theme.tokens.color.Neutrals.White,
- display: 'flex',
- fontFamily: 'LatoWebBold',
- fontSize: '0.875rem',
- opacity: 1,
- position: 'relative',
- transition: theme.transitions.create(['color', 'opacity']),
- },
- listItem: {
- '& .icon': {
- '& svg': {
- '&:not(.wBorder) circle, & .circle': {
- display: 'none',
- },
- alignItems: 'center',
- display: 'flex',
- height: 20,
- width: 20,
- },
- color: '#CFD0D2',
- marginRight: theme.spacing(1.5),
- opacity: 0.5,
- transition: 'max-height 1s linear, width .1s linear',
- },
+ paddingLeft: 8,
+ }),
+}));
+
+export const StyledAkamaiLogo = styled(AkamaiLogo, {
+ label: 'StyledAkamaiLogo',
+})(({ theme }) => ({
+ '& .akamai-logo-name': {
+ transition: theme.transitions.create(['opacity']),
+ },
+ // give the svg a transition so it smoothly resizes
+ transition: 'width .1s linear',
+}));
+
+export const StyledDivider = styled(Divider, {
+ label: 'StyledDivider',
+})(({ theme }) => ({
+ borderColor:
+ theme.name === 'light'
+ ? theme.borderColors.dividerDark
+ : 'rgba(0, 0, 0, 0.19)',
+ margin: 0,
+}));
+
+export const StyledActiveLink = styled(Link, {
+ label: 'StyledActiveLink',
+ shouldForwardProp: omittedProps(['isActiveLink', 'isCollapsed']),
+})<{ isActiveLink: boolean; isCollapsed: boolean }>(({ ...props }) => ({
+ '&:hover': {
+ backgroundImage: 'linear-gradient(98deg, #38584B 1%, #3A5049 166%)',
+ },
+ '&:hover, &:focus': {
+ textDecoration: 'none',
+ },
+ alignItems: 'center',
+ cursor: 'pointer',
+ display: 'flex',
+ minWidth: SIDEBAR_WIDTH,
+ padding: '7px 16px',
+ position: 'relative',
+ ...(props.isActiveLink && {
+ backgroundImage: 'linear-gradient(98deg, #38584B 1%, #3A5049 166%)',
+ }),
+ ...(props.isCollapsed && {
+ backgroundImage: 'none',
+ }),
+}));
+
+export const StyledPrimaryLinkBox = styled(Box, {
+ label: 'StyledPrimaryLinkBox',
+ shouldForwardProp: omittedProps(['isCollapsed']),
+})<{ isCollapsed: boolean }>(({ theme, ...props }) => ({
+ alignItems: 'center',
+ color: theme.tokens.color.Neutrals.White,
+ display: 'flex',
+ fontFamily: 'LatoWebBold',
+ fontSize: '0.875rem',
+ justifyContent: 'space-between',
+ transition: theme.transitions.create(['color', 'opacity']),
+ width: '100%',
+ ...(props.isCollapsed && {
+ opacity: 0,
+ }),
+}));
+
+export const StyledAccordion = styled(Accordion, {
+ label: 'StyledAccordion',
+ shouldForwardProp: omittedProps(['isCollapsed', 'isActiveProductFamily']),
+})<{ isActiveProductFamily: boolean; isCollapsed: boolean }>(
+ ({ theme, ...props }) => ({
+ '& h3': {
'& p': {
- marginBottom: 0,
- marginTop: 0,
- },
- '&:focus': {
- textDecoration: 'none',
- },
- '&:hover': {
- '& .icon': {
- opacity: 1,
- },
- '& svg': {
- color: theme.palette.success.dark,
- fill: theme.palette.success.dark,
- },
- [`& .${classes.linkItem}`]: {
- color: theme.tokens.color.Neutrals.White,
- },
- backgroundImage: 'linear-gradient(98deg, #38584B 1%, #3A5049 166%)',
- border: 'red',
- textDecoration: 'none',
- },
- alignItems: 'center',
- cursor: 'pointer',
- display: 'flex',
- minWidth: SIDEBAR_WIDTH,
- padding: '8px 13px',
- position: 'relative',
- },
- logo: {
- '& .akamai-logo-name': {
+ color: '#B8B8B8',
transition: theme.transitions.create(['opacity']),
+ ...(props.isCollapsed && {
+ opacity: 0,
+ }),
},
- // give the svg a transition so it smoothly resizes
- transition: 'width .1s linear',
- },
- logoAkamaiCollapsed: {
- background: theme.bg.appBar,
- width: 83,
- },
- logoContainer: {
- lineHeight: 0,
- // when the nav is collapsed, but hovered by the user, make the logo full sized
- 'nav:hover & > svg ': {
- '& .akamai-logo-name': {
- opacity: 1,
- },
- width: 83,
+ // product family icon
+ '& svg': {
+ color: props.isActiveProductFamily ? '#00B159' : theme.color.grey4,
+ height: 20,
+ marginRight: 14,
+ transition: theme.transitions.create(['color']),
+ width: 20,
},
- },
- logoItemAkamai: {
alignItems: 'center',
- backgroundColor: theme.name === 'dark' ? theme.bg.appBar : undefined,
display: 'flex',
- height: 50,
- paddingLeft: 13,
- transition: 'padding-left .03s linear',
- },
- logoItemAkamaiCollapsed: {
- '& .akamai-logo-name': {
- opacity: 0,
- },
- paddingLeft: 8,
+ fontSize: '0.7rem',
+ letterSpacing: '1px',
+ lineheight: 20,
+ padding: '0 10px',
+ textTransform: 'uppercase',
},
- menuGrid: {
- height: '100%',
- margin: 0,
- minHeight: 64,
+ '.MuiAccordionDetails-root': {
padding: 0,
- [theme.breakpoints.up('md')]: {
- minHeight: 80,
+ },
+ '.MuiButtonBase-root, MuiAccordionSummary-root': {
+ '.Mui-expanded': {
+ alignItems: 'center',
+ maxHeight: '42px',
+ minHeight: '42px',
},
- [theme.breakpoints.up('sm')]: {
- minHeight: 72,
+ maxHeight: '42px',
+ minHeight: '42px',
+ paddingLeft: 4,
+ svg: {
+ fill: theme.tokens.color.Neutrals.White,
+ stroke: 'transparent',
},
- width: '100%',
- },
- navLinkItem: {
- lineHeight: 0,
},
+ backgroundColor: theme.name === 'dark' ? theme.bg.appBar : 'transparent',
})
);
-
-// TODO jss-to-tss-react codemod: usages of this hook outside of this file will not be converted.
-export default useStyles;
diff --git a/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx b/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx
index 80714ff7e42..3d7cec0d765 100644
--- a/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx
+++ b/packages/manager/src/components/PrimaryNav/PrimaryNav.test.tsx
@@ -74,14 +74,14 @@ describe('PrimaryNav', () => {
},
};
- const { findByText, queryByTestId } = renderWithTheme(
+ const { findByTestId, queryByTestId } = renderWithTheme(
,
{
flags,
}
);
- const databaseNavItem = await findByText('Databases');
+ const databaseNavItem = await findByTestId('menu-item-Databases');
expect(databaseNavItem).toBeVisible();
expect(queryByTestId('betaChip')).toBeNull();
@@ -105,14 +105,11 @@ describe('PrimaryNav', () => {
},
};
- const { findByTestId, findByText } = renderWithTheme(
- ,
- {
- flags,
- }
- );
+ const { findByTestId } = renderWithTheme( , {
+ flags,
+ });
- const databaseNavItem = await findByText('Databases');
+ const databaseNavItem = await findByTestId('menu-item-Databases');
const betaChip = await findByTestId('betaChip');
expect(databaseNavItem).toBeVisible();
@@ -137,14 +134,14 @@ describe('PrimaryNav', () => {
},
};
- const { findByText, queryByTestId } = renderWithTheme(
+ const { findByTestId, queryByTestId } = renderWithTheme(
,
{
flags,
}
);
- const databaseNavItem = await findByText('Databases');
+ const databaseNavItem = await findByTestId('menu-item-Databases');
expect(databaseNavItem).toBeVisible();
expect(queryByTestId('betaChip')).toBeNull();
@@ -168,11 +165,11 @@ describe('PrimaryNav', () => {
},
};
- const { findByText } = renderWithTheme( , {
+ const { findByTestId } = renderWithTheme( , {
flags,
});
- const databaseNavItem = await findByText('Databases');
+ const databaseNavItem = await findByTestId('menu-item-Databases');
expect(databaseNavItem).toBeVisible();
});
diff --git a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx
index 0c05da03365..fd6b10de5c5 100644
--- a/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx
+++ b/packages/manager/src/components/PrimaryNav/PrimaryNav.tsx
@@ -1,42 +1,38 @@
-import { BetaChip, Box } from '@linode/ui';
+import { Box } from '@linode/ui';
import Grid from '@mui/material/Unstable_Grid2';
import * as React from 'react';
-import { Link, useLocation } from 'react-router-dom';
+import { Link } from 'react-router-dom';
+import { useLocation } from 'react-router-dom';
-import Account from 'src/assets/icons/account.svg';
-import Beta from 'src/assets/icons/entityIcons/beta.svg';
import Storage from 'src/assets/icons/entityIcons/bucket.svg';
import Database from 'src/assets/icons/entityIcons/database.svg';
-import Domain from 'src/assets/icons/entityIcons/domain.svg';
-import Firewall from 'src/assets/icons/entityIcons/firewall.svg';
-import Image from 'src/assets/icons/entityIcons/image.svg';
-import Kubernetes from 'src/assets/icons/entityIcons/kubernetes.svg';
import Linode from 'src/assets/icons/entityIcons/linode.svg';
-import Managed from 'src/assets/icons/entityIcons/managed.svg';
-import CloudPulse from 'src/assets/icons/entityIcons/monitor.svg';
import NodeBalancer from 'src/assets/icons/entityIcons/nodebalancer.svg';
-import OCA from 'src/assets/icons/entityIcons/oneclick.svg';
-import PlacementGroups from 'src/assets/icons/entityIcons/placement-groups.svg';
-import StackScript from 'src/assets/icons/entityIcons/stackscript.svg';
-import Volume from 'src/assets/icons/entityIcons/volume.svg';
-import VPC from 'src/assets/icons/entityIcons/vpc.svg';
-import TooltipIcon from 'src/assets/icons/get_help.svg';
import Longview from 'src/assets/icons/longview.svg';
-import AkamaiLogo from 'src/assets/logo/akamai-logo.svg';
-import { Divider } from 'src/components/Divider';
+import More from 'src/assets/icons/more.svg';
import { useIsACLPEnabled } from 'src/features/CloudPulse/Utils/utils';
import { useIsDatabasesEnabled } from 'src/features/Databases/utilities';
import { useIsPlacementGroupsEnabled } from 'src/features/PlacementGroups/utils';
import { useFlags } from 'src/hooks/useFlags';
-import { usePrefetch } from 'src/hooks/usePreFetch';
import { useAccountSettings } from 'src/queries/account/settings';
+import {
+ useMutatePreferences,
+ usePreferences,
+} from 'src/queries/profile/preferences';
-import useStyles from './PrimaryNav.styles';
+import PrimaryLink from './PrimaryLink';
+import {
+ StyledAccordion,
+ StyledAkamaiLogo,
+ StyledDivider,
+ StyledGrid,
+ StyledLogoBox,
+} from './PrimaryNav.styles';
import { linkIsActive } from './utils';
-import type { LinkProps } from 'react-router-dom';
+import type { PrimaryLink as PrimaryLinkType } from './PrimaryLink';
-type NavEntity =
+export type NavEntity =
| 'Account'
| 'Account'
| 'Betas'
@@ -60,18 +56,10 @@ type NavEntity =
| 'VPC'
| 'Volumes';
-interface PrimaryLink {
- activeLinks?: Array;
- attr?: { [key: string]: any };
- betaChipClassName?: string;
- display: NavEntity;
- hide?: boolean;
- href: string;
- icon?: JSX.Element;
- isBeta?: boolean;
- onClick?: (e: React.ChangeEvent) => void;
- prefetchRequestCondition?: boolean;
- prefetchRequestFn?: () => void;
+interface PrimaryLinkGroup {
+ icon?: React.JSX.Element;
+ links: PrimaryLinkType[];
+ title?: string;
}
export interface PrimaryNavProps {
@@ -81,7 +69,6 @@ export interface PrimaryNavProps {
export const PrimaryNav = (props: PrimaryNavProps) => {
const { closeMenu, isCollapsed } = props;
- const { classes, cx } = useStyles();
const flags = useFlags();
const location = useLocation();
@@ -94,130 +81,146 @@ export const PrimaryNav = (props: PrimaryNavProps) => {
const { isPlacementGroupsEnabled } = useIsPlacementGroupsEnabled();
const { isDatabasesEnabled, isDatabasesV2Beta } = useIsDatabasesEnabled();
- const primaryLinkGroups: PrimaryLink[][] = React.useMemo(
+ const { data: preferences } = usePreferences();
+ const { mutateAsync: updatePreferences } = useMutatePreferences();
+
+ const primaryLinkGroups: PrimaryLinkGroup[] = React.useMemo(
() => [
- [
- {
- display: 'Managed',
- hide: !isManaged,
- href: '/managed',
- icon: ,
- },
- ],
- [
- {
- activeLinks: ['/linodes', '/linodes/create'],
- display: 'Linodes',
- href: '/linodes',
- icon: ,
- },
- {
- display: 'Volumes',
- href: '/volumes',
- icon: ,
- },
- {
- display: 'NodeBalancers',
- href: '/nodebalancers',
- icon: ,
- },
- {
- display: 'VPC',
- href: '/vpcs',
- icon: ,
- },
- {
- display: 'Firewalls',
- href: '/firewalls',
- icon: ,
- },
- {
- display: 'StackScripts',
- href: '/stackscripts',
- icon: ,
- },
- {
- activeLinks: [
- '/images/create/create-image',
- '/images/create/upload-image',
- ],
- display: 'Images',
- href: '/images',
- icon: ,
- },
- {
- betaChipClassName: 'beta-chip-placement-groups',
- display: 'Placement Groups',
- hide: !isPlacementGroupsEnabled,
- href: '/placement-groups',
- icon: ,
- },
- ],
- [
- {
- display: 'Domains',
- href: '/domains',
- icon: ,
- },
- {
- display: 'Databases',
- hide: !isDatabasesEnabled,
- href: '/databases',
- icon: ,
- isBeta: isDatabasesV2Beta,
- },
- {
- activeLinks: ['/kubernetes/create'],
- display: 'Kubernetes',
- href: '/kubernetes/clusters',
- icon: ,
- },
- {
- activeLinks: [
- '/object-storage/buckets',
- '/object-storage/access-keys',
- ],
- display: 'Object Storage',
- href: '/object-storage/buckets',
- icon: ,
- },
- {
- display: 'Longview',
- href: '/longview',
- icon: ,
- },
- {
- display: 'Monitor',
- hide: !isACLPEnabled,
- href: '/monitor/cloudpulse',
- icon: ,
- isBeta: flags.aclp?.beta,
- },
- {
- attr: { 'data-qa-one-click-nav-btn': true },
- display: 'Marketplace',
- href: '/linodes/create?type=One-Click',
- icon: ,
- },
- ],
- [
- {
- display: 'Account',
- href: '/account',
- icon: ,
- },
- {
- display: 'Betas',
- hide: !flags.selfServeBetas,
- href: '/betas',
- icon: ,
- },
- {
- display: 'Help & Support',
- href: '/support',
- icon: ,
- },
- ],
+ {
+ links: [
+ {
+ display: 'Managed',
+ hide: !isManaged,
+ href: '/managed',
+ },
+ ],
+ },
+ {
+ icon: ,
+ links: [
+ {
+ activeLinks: ['/linodes', '/linodes/create'],
+ display: 'Linodes',
+ href: '/linodes',
+ },
+ {
+ activeLinks: [
+ '/images/create/create-image',
+ '/images/create/upload-image',
+ ],
+ display: 'Images',
+ href: '/images',
+ },
+ {
+ activeLinks: ['/kubernetes/create'],
+ display: 'Kubernetes',
+ href: '/kubernetes/clusters',
+ },
+ {
+ display: 'StackScripts',
+ href: '/stackscripts',
+ },
+ {
+ betaChipClassName: 'beta-chip-placement-groups',
+ display: 'Placement Groups',
+ hide: !isPlacementGroupsEnabled,
+ href: '/placement-groups',
+ },
+ {
+ attr: { 'data-qa-one-click-nav-btn': true },
+ display: 'Marketplace',
+ href: '/linodes/create?type=One-Click',
+ },
+ ],
+ title: 'Compute',
+ },
+ {
+ icon: ,
+ links: [
+ {
+ activeLinks: [
+ '/object-storage/buckets',
+ '/object-storage/access-keys',
+ ],
+ display: 'Object Storage',
+ href: '/object-storage/buckets',
+ },
+ {
+ display: 'Volumes',
+ href: '/volumes',
+ },
+ ],
+ title: 'Storage',
+ },
+ {
+ icon: ,
+ links: [
+ {
+ display: 'VPC',
+ href: '/vpcs',
+ },
+ {
+ display: 'Firewalls',
+ href: '/firewalls',
+ },
+ {
+ display: 'NodeBalancers',
+ href: '/nodebalancers',
+ },
+ {
+ display: 'Domains',
+ href: '/domains',
+ },
+ ],
+ title: 'Networking',
+ },
+ {
+ icon: ,
+ links: [
+ {
+ display: 'Databases',
+ hide: !isDatabasesEnabled,
+ href: '/databases',
+ isBeta: isDatabasesV2Beta,
+ },
+ ],
+ title: 'Databases',
+ },
+ {
+ icon: ,
+ links: [
+ {
+ display: 'Longview',
+ href: '/longview',
+ },
+ {
+ display: 'Monitor',
+ hide: !isACLPEnabled,
+ href: '/monitor/cloudpulse',
+ isBeta: flags.aclp?.beta,
+ },
+ ],
+ title: 'Monitor',
+ },
+ {
+ icon: ,
+ links: [
+ {
+ display: 'Betas',
+ hide: !flags.selfServeBetas,
+ href: '/betas',
+ },
+ {
+ display: 'Account',
+ href: '/account',
+ },
+ {
+ display: 'Help & Support',
+ href: '/support',
+ },
+ ],
+ title: 'More',
+ },
],
// eslint-disable-next-line react-hooks/exhaustive-deps
[
@@ -229,11 +232,34 @@ export const PrimaryNav = (props: PrimaryNavProps) => {
]
);
+ const [collapsedAccordions, setCollapsedAccordions] = React.useState<
+ number[]
+ >(preferences?.collapsedSideNavProductFamilies ?? []);
+
+ const accordionClicked = (index: number) => {
+ let updatedCollapsedAccordions;
+ if (collapsedAccordions.includes(index)) {
+ updatedCollapsedAccordions = collapsedAccordions.filter(
+ (accIndex) => accIndex !== index
+ );
+ updatePreferences({
+ collapsedSideNavProductFamilies: updatedCollapsedAccordions,
+ });
+ setCollapsedAccordions(updatedCollapsedAccordions);
+ } else {
+ updatedCollapsedAccordions = [...collapsedAccordions, index];
+ updatePreferences({
+ collapsedSideNavProductFamilies: updatedCollapsedAccordions,
+ });
+ setCollapsedAccordions(updatedCollapsedAccordions);
+ }
+ };
+
+ let activeProductFamily = '';
+
return (
- {
wrap="nowrap"
>
-
+
-
+
-
+
+
-
- {primaryLinkGroups.map((thisGroup, idx) => {
- const filteredLinks = thisGroup.filter((thisLink) => !thisLink.hide);
+ {primaryLinkGroups.map((linkGroup, idx) => {
+ const filteredLinks = linkGroup.links.filter((link) => !link.hide);
if (filteredLinks.length === 0) {
return null;
}
- return (
-
-
({
- borderColor:
- theme.name === 'light'
- ? theme.borderColors.dividerDark
- : 'rgba(0, 0, 0, 0.19)',
- })}
- className={classes.divider}
- spacingBottom={11}
- spacingTop={isManaged ? (idx === 0 ? 0 : 11) : idx === 1 ? 0 : 11}
- />
- {filteredLinks.map((thisLink) => {
- const props = {
- closeMenu,
- isCollapsed,
- locationPathname: location.pathname,
- locationSearch: location.search,
- ...thisLink,
- };
- // PrefetchPrimaryLink and PrimaryLink are two separate components because invocation of
- // hooks cannot be conditional. is a wrapper around
- // that includes the usePrefetch hook.
- return thisLink.prefetchRequestFn &&
- thisLink.prefetchRequestCondition !== undefined ? (
-
- ) : (
-
- );
- })}
+ const PrimaryLinks = filteredLinks.map((link) => {
+ const isActiveLink = Boolean(
+ linkIsActive(
+ link.href,
+ location.search,
+ location.pathname,
+ link.activeLinks
+ )
+ );
+ if (isActiveLink) {
+ activeProductFamily = linkGroup.title ?? '';
+ }
+ const props = {
+ closeMenu,
+ isActiveLink,
+ isCollapsed,
+ ...link,
+ };
+ return ;
+ });
+
+ return (
+
+ {linkGroup.title ? ( // TODO: we can remove this conditional when Managed is removed
+ <>
+
+ {linkGroup.icon}
+ {linkGroup.title}
+ >
+ }
+ isActiveProductFamily={
+ activeProductFamily === linkGroup.title
+ }
+ expanded={!collapsedAccordions.includes(idx)}
+ isCollapsed={isCollapsed}
+ onChange={() => accordionClicked(idx)}
+ >
+ {PrimaryLinks}
+
+
+ >
+ ) : (
+
{PrimaryLinks}
+ )}
);
})}
-
+
);
};
export default React.memo(PrimaryNav);
-
-interface PrimaryLinkProps extends PrimaryLink {
- closeMenu: () => void;
- isBeta?: boolean;
- isCollapsed: boolean;
- locationPathname: string;
- locationSearch: string;
- prefetchProps?: {
- onBlur: LinkProps['onBlur'];
- onFocus: LinkProps['onFocus'];
- onMouseEnter: LinkProps['onMouseEnter'];
- onMouseLeave: LinkProps['onMouseLeave'];
- };
-}
-
-const PrimaryLink = React.memo((props: PrimaryLinkProps) => {
- const { classes, cx } = useStyles();
-
- const {
- activeLinks,
- attr,
- betaChipClassName,
- closeMenu,
- display,
- href,
- icon,
- isBeta,
- isCollapsed,
- locationPathname,
- locationSearch,
- onClick,
- prefetchProps,
- } = props;
-
- const isActiveLink = Boolean(
- linkIsActive(href, locationSearch, locationPathname, activeLinks)
- );
-
- return (
- ) => {
- closeMenu();
- if (onClick) {
- onClick(e);
- }
- }}
- to={href}
- {...prefetchProps}
- {...attr}
- className={cx({
- [classes.active]: isActiveLink,
- [classes.listItem]: true,
- })}
- aria-current={isActiveLink}
- data-testid={`menu-item-${display}`}
- >
- {icon && (
-
- {icon}
-
- )}
-
- {display}
- {isBeta ? (
-
- ) : null}
-
-
- );
-});
-
-interface PrefetchPrimaryLinkProps extends PrimaryLinkProps {
- prefetchRequestCondition: boolean;
- prefetchRequestFn: () => void;
-}
-
-// Wrapper around PrimaryLink that includes the usePrefetchHook.
-export const PrefetchPrimaryLink = React.memo(
- (props: PrefetchPrimaryLinkProps) => {
- const { cancelRequest, makeRequest } = usePrefetch(
- props.prefetchRequestFn,
- props.prefetchRequestCondition
- );
-
- const prefetchProps: PrimaryLinkProps['prefetchProps'] = {
- onBlur: cancelRequest,
- onFocus: makeRequest,
- onMouseEnter: makeRequest,
- onMouseLeave: cancelRequest,
- };
-
- return ;
- }
-);
diff --git a/packages/manager/src/components/PrimaryNav/SideMenu.stories.tsx b/packages/manager/src/components/PrimaryNav/SideMenu.stories.tsx
index 775c5afb96b..50a1041ab22 100644
--- a/packages/manager/src/components/PrimaryNav/SideMenu.stories.tsx
+++ b/packages/manager/src/components/PrimaryNav/SideMenu.stories.tsx
@@ -33,7 +33,7 @@ export const Default: StoryObj = {
open={args.open || open}
/>
-
+
diff --git a/packages/manager/src/features/Firewalls/FirewallLanding/FirewallLandingEmptyState.tsx b/packages/manager/src/features/Firewalls/FirewallLanding/FirewallLandingEmptyState.tsx
index 7822e9e81eb..aeef289110a 100644
--- a/packages/manager/src/features/Firewalls/FirewallLanding/FirewallLandingEmptyState.tsx
+++ b/packages/manager/src/features/Firewalls/FirewallLanding/FirewallLandingEmptyState.tsx
@@ -1,9 +1,9 @@
import * as React from 'react';
-import FirewallIcon from 'src/assets/icons/entityIcons/firewall.svg';
+import NodeBalancerIcon from 'src/assets/icons/entityIcons/nodebalancer.svg';
import { ResourcesSection } from 'src/components/EmptyLandingPageResources/ResourcesSection';
-import { useRestrictedGlobalGrantCheck } from 'src/hooks/useRestrictedGlobalGrantCheck';
import { getRestrictedResourceText } from 'src/features/Account/utils';
+import { useRestrictedGlobalGrantCheck } from 'src/hooks/useRestrictedGlobalGrantCheck';
import { sendEvent } from 'src/utilities/analytics/utils';
import {
@@ -47,7 +47,7 @@ export const FirewallLandingEmptyState = (props: Props) => {
]}
gettingStartedGuidesData={gettingStartedGuides}
headers={headers}
- icon={FirewallIcon}
+ icon={NodeBalancerIcon}
linkAnalyticsEvent={linkAnalyticsEvent}
youtubeLinkData={youtubeLinkData}
/>
diff --git a/packages/manager/src/features/Images/ImagesLanding/ImagesLandingEmptyState.tsx b/packages/manager/src/features/Images/ImagesLanding/ImagesLandingEmptyState.tsx
index e322c7d94c4..75d4c7fd744 100644
--- a/packages/manager/src/features/Images/ImagesLanding/ImagesLandingEmptyState.tsx
+++ b/packages/manager/src/features/Images/ImagesLanding/ImagesLandingEmptyState.tsx
@@ -1,7 +1,7 @@
import * as React from 'react';
import { useHistory } from 'react-router-dom';
-import ImageIcon from 'src/assets/icons/entityIcons/image.svg';
+import LinodeIcon from 'src/assets/icons/entityIcons/linode.svg';
import { ResourcesSection } from 'src/components/EmptyLandingPageResources/ResourcesSection';
import { getRestrictedResourceText } from 'src/features/Account/utils';
import { useRestrictedGlobalGrantCheck } from 'src/hooks/useRestrictedGlobalGrantCheck';
@@ -44,7 +44,7 @@ export const ImagesLandingEmptyState = () => {
]}
gettingStartedGuidesData={gettingStartedGuides}
headers={headers}
- icon={ImageIcon}
+ icon={LinodeIcon}
linkAnalyticsEvent={linkAnalyticsEvent}
youtubeLinkData={youtubeLinkData}
/>
diff --git a/packages/manager/src/features/Kubernetes/CreateCluster/CreateCluster.tsx b/packages/manager/src/features/Kubernetes/CreateCluster/CreateCluster.tsx
index c19f5a4664e..90b594b23e8 100644
--- a/packages/manager/src/features/Kubernetes/CreateCluster/CreateCluster.tsx
+++ b/packages/manager/src/features/Kubernetes/CreateCluster/CreateCluster.tsx
@@ -42,8 +42,8 @@ import { extendType } from 'src/utilities/extendType';
import { filterCurrentTypes } from 'src/utilities/filterCurrentLinodeTypes';
import { stringToExtendedIP } from 'src/utilities/ipUtils';
import { plansNoticesUtils } from 'src/utilities/planNotices';
-import { UNKNOWN_PRICE } from 'src/utilities/pricing/constants';
import { DOCS_LINK_LABEL_DC_PRICING } from 'src/utilities/pricing/constants';
+import { UNKNOWN_PRICE } from 'src/utilities/pricing/constants';
import { getDCSpecificPriceByType } from 'src/utilities/pricing/dynamicPricing';
import { scrollErrorIntoViewV2 } from 'src/utilities/scrollErrorIntoViewV2';
diff --git a/packages/manager/src/features/Kubernetes/KubernetesLanding/KubernetesLandingEmptyState.tsx b/packages/manager/src/features/Kubernetes/KubernetesLanding/KubernetesLandingEmptyState.tsx
index 915ac7726b0..2b0aeee2170 100644
--- a/packages/manager/src/features/Kubernetes/KubernetesLanding/KubernetesLandingEmptyState.tsx
+++ b/packages/manager/src/features/Kubernetes/KubernetesLanding/KubernetesLandingEmptyState.tsx
@@ -1,7 +1,7 @@
import * as React from 'react';
import { useHistory } from 'react-router-dom';
-import KubernetesSvg from 'src/assets/icons/entityIcons/kubernetes.svg';
+import LinodeIcon from 'src/assets/icons/entityIcons/linode.svg';
import { ResourcesSection } from 'src/components/EmptyLandingPageResources/ResourcesSection';
import { getRestrictedResourceText } from 'src/features/Account/utils';
import { sendEvent } from 'src/utilities/analytics/utils';
@@ -45,7 +45,7 @@ export const KubernetesEmptyState = (props: Props) => {
]}
gettingStartedGuidesData={gettingStartedGuides}
headers={headers}
- icon={KubernetesSvg}
+ icon={LinodeIcon}
linkAnalyticsEvent={linkAnalyticsEvent}
youtubeLinkData={youtubeLinkData}
/>
diff --git a/packages/manager/src/features/NodeBalancers/NodeBalancersLanding/NodeBalancersLandingEmptyState.tsx b/packages/manager/src/features/NodeBalancers/NodeBalancersLanding/NodeBalancersLandingEmptyState.tsx
index de40d0a7b84..ac34dd975cd 100644
--- a/packages/manager/src/features/NodeBalancers/NodeBalancersLanding/NodeBalancersLandingEmptyState.tsx
+++ b/packages/manager/src/features/NodeBalancers/NodeBalancersLanding/NodeBalancersLandingEmptyState.tsx
@@ -1,7 +1,7 @@
import * as React from 'react';
import { useHistory } from 'react-router-dom';
-import NodeBalancer from 'src/assets/icons/entityIcons/nodebalancer.svg';
+import NodeBalancerIcon from 'src/assets/icons/entityIcons/nodebalancer.svg';
import { DocumentTitleSegment } from 'src/components/DocumentTitle';
import { ResourcesSection } from 'src/components/EmptyLandingPageResources/ResourcesSection';
import { getRestrictedResourceText } from 'src/features/Account/utils';
@@ -47,7 +47,7 @@ export const NodeBalancerLandingEmptyState = () => {
]}
gettingStartedGuidesData={gettingStartedGuides}
headers={headers}
- icon={NodeBalancer}
+ icon={NodeBalancerIcon}
linkAnalyticsEvent={linkAnalyticsEvent}
youtubeLinkData={youtubeLinkData}
/>
diff --git a/packages/manager/src/features/PlacementGroups/PlacementGroupsLanding/PlacementGroupsLandingEmptyState.tsx b/packages/manager/src/features/PlacementGroups/PlacementGroupsLanding/PlacementGroupsLandingEmptyState.tsx
index 0c6c478ae93..cf0331b9095 100644
--- a/packages/manager/src/features/PlacementGroups/PlacementGroupsLanding/PlacementGroupsLandingEmptyState.tsx
+++ b/packages/manager/src/features/PlacementGroups/PlacementGroupsLanding/PlacementGroupsLandingEmptyState.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
-import PlacementGroups from 'src/assets/icons/entityIcons/placement-groups.svg';
+import LinodeIcon from 'src/assets/icons/entityIcons/linode.svg';
import { ResourcesSection } from 'src/components/EmptyLandingPageResources/ResourcesSection';
import { sendEvent } from 'src/utilities/analytics/utils';
@@ -37,7 +37,7 @@ export const PlacementGroupsLandingEmptyState = ({
]}
gettingStartedGuidesData={gettingStartedGuides}
headers={headers}
- icon={PlacementGroups}
+ icon={LinodeIcon}
linkAnalyticsEvent={linkAnalyticsEvent}
/>
);
diff --git a/packages/manager/src/features/StackScripts/StackScriptBase/StackScriptsEmptyLandingPage.tsx b/packages/manager/src/features/StackScripts/StackScriptBase/StackScriptsEmptyLandingPage.tsx
index 55bf8070ad9..b7145c0ea10 100644
--- a/packages/manager/src/features/StackScripts/StackScriptBase/StackScriptsEmptyLandingPage.tsx
+++ b/packages/manager/src/features/StackScripts/StackScriptBase/StackScriptsEmptyLandingPage.tsx
@@ -1,6 +1,6 @@
import * as React from 'react';
-import StackScriptsIcon from 'src/assets/icons/entityIcons/stackscript.svg';
+import LinodeIcon from 'src/assets/icons/entityIcons/linode.svg';
import { ResourcesSection } from 'src/components/EmptyLandingPageResources/ResourcesSection';
import { sendEvent } from 'src/utilities/analytics/utils';
@@ -35,7 +35,7 @@ export const StackScriptsEmptyLandingState = (props: Props) => {
]}
gettingStartedGuidesData={gettingStartedGuides}
headers={headers}
- icon={StackScriptsIcon}
+ icon={LinodeIcon}
linkAnalyticsEvent={linkAnalyticsEvent}
youtubeLinkData={youtubeLinkData}
/>
diff --git a/packages/manager/src/features/VPCs/VPCLanding/VPCEmptyState.tsx b/packages/manager/src/features/VPCs/VPCLanding/VPCEmptyState.tsx
index 721707b9b9f..c42c7695083 100644
--- a/packages/manager/src/features/VPCs/VPCLanding/VPCEmptyState.tsx
+++ b/packages/manager/src/features/VPCs/VPCLanding/VPCEmptyState.tsx
@@ -1,11 +1,11 @@
import * as React from 'react';
import { useHistory } from 'react-router-dom';
-import VPC from 'src/assets/icons/entityIcons/vpc.svg';
+import NodeBalancerIcon from 'src/assets/icons/entityIcons/nodebalancer.svg';
import { ResourcesSection } from 'src/components/EmptyLandingPageResources/ResourcesSection';
+import { getRestrictedResourceText } from 'src/features/Account/utils';
import { gettingStartedGuides } from 'src/features/VPCs/VPCLanding/VPCLandingEmptyStateData';
import { useRestrictedGlobalGrantCheck } from 'src/hooks/useRestrictedGlobalGrantCheck';
-import { getRestrictedResourceText } from 'src/features/Account/utils';
import { sendEvent } from 'src/utilities/analytics/utils';
import { headers, linkAnalyticsEvent } from './VPCEmptyStateData';
@@ -40,7 +40,7 @@ export const VPCEmptyState = () => {
]}
gettingStartedGuidesData={gettingStartedGuides}
headers={headers}
- icon={VPC}
+ icon={NodeBalancerIcon}
linkAnalyticsEvent={linkAnalyticsEvent}
/>
);
diff --git a/packages/manager/src/features/Volumes/VolumesLandingEmptyState.styles.ts b/packages/manager/src/features/Volumes/VolumesLandingEmptyState.styles.ts
deleted file mode 100644
index 4b876a36092..00000000000
--- a/packages/manager/src/features/Volumes/VolumesLandingEmptyState.styles.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { styled } from '@mui/material/styles';
-
-import VolumeIcon from 'src/assets/icons/entityIcons/volume.svg';
-
-const StyledVolumeIcon = styled(VolumeIcon)(() => ({
- transform: 'scale(0.75)',
-}));
-
-export { StyledVolumeIcon };
diff --git a/packages/manager/src/features/Volumes/VolumesLandingEmptyState.tsx b/packages/manager/src/features/Volumes/VolumesLandingEmptyState.tsx
index 560338843e0..a7cad37c634 100644
--- a/packages/manager/src/features/Volumes/VolumesLandingEmptyState.tsx
+++ b/packages/manager/src/features/Volumes/VolumesLandingEmptyState.tsx
@@ -4,10 +4,10 @@ import { useHistory } from 'react-router-dom';
import { DocumentTitleSegment } from 'src/components/DocumentTitle';
import { ResourcesSection } from 'src/components/EmptyLandingPageResources/ResourcesSection';
import { getRestrictedResourceText } from 'src/features/Account/utils';
+import { StyledBucketIcon } from 'src/features/ObjectStorage/BucketLanding/StylesBucketIcon';
import { useRestrictedGlobalGrantCheck } from 'src/hooks/useRestrictedGlobalGrantCheck';
import { sendEvent } from 'src/utilities/analytics/utils';
-import { StyledVolumeIcon } from './VolumesLandingEmptyState.styles';
import {
gettingStartedGuides,
headers,
@@ -47,7 +47,7 @@ export const VolumesLandingEmptyState = () => {
]}
gettingStartedGuidesData={gettingStartedGuides}
headers={headers}
- icon={StyledVolumeIcon}
+ icon={StyledBucketIcon}
linkAnalyticsEvent={linkAnalyticsEvent}
youtubeLinkData={youtubeLinkData}
/>
diff --git a/packages/manager/src/hooks/usePreFetch.ts b/packages/manager/src/hooks/usePreFetch.ts
deleted file mode 100644
index 086e6a1fd0b..00000000000
--- a/packages/manager/src/hooks/usePreFetch.ts
+++ /dev/null
@@ -1,57 +0,0 @@
-import * as React from 'react';
-
-export const PREFETCH_DELAY = 150;
-
-/**
- * usePrefetch() allows consumers to make a one-time, delayed, and cancellable request. It accepts
- * a request function, which will be executed according to the following lifecycle:
- *
- * 1. Consumer calls makeRequest()
- * 2. usePrefetch sets a timeout for the specified delay duration
- * 3. Once the timeout is complete, usePrefetch evaluates the specified condition
- * 4. If true, usePrefetch executes the given request function.
- *
- * Example usage:
- *
- * const { makeRequest, cancelRequest } = usePrefetch(requestDomains, !domainsLoading);
- * Domains
- */
-
-export const usePrefetch = (
- requestFn?: () => void,
- prefetchCondition = true,
- delay = PREFETCH_DELAY
-) => {
- const timeoutID = React.useRef(null);
-
- // We must store this in a ref so the handler inside setTimeout can "see" the current value.
- const prefetchConditionRef = React.useRef(prefetchCondition);
-
- // Update the ref when the values change.
- React.useEffect(() => {
- prefetchConditionRef.current = prefetchCondition;
- }, [prefetchCondition]);
-
- const makeRequest = () => {
- timeoutID.current = window.setTimeout(() => {
- if (prefetchConditionRef.current && requestFn) {
- requestFn();
- }
- }, delay);
- };
-
- const cancelRequest = React.useCallback(() => {
- if (timeoutID.current) {
- window.clearTimeout(timeoutID.current);
- }
- }, []);
-
- const handlers = {
- onBlur: cancelRequest,
- onFocus: makeRequest,
- onMouseEnter: makeRequest,
- onMouseLeave: cancelRequest,
- };
-
- return { cancelRequest, handlers, makeRequest };
-};
diff --git a/packages/ui/src/foundations/themes/light.ts b/packages/ui/src/foundations/themes/light.ts
index 6082f5c2eab..8f4f396640f 100644
--- a/packages/ui/src/foundations/themes/light.ts
+++ b/packages/ui/src/foundations/themes/light.ts
@@ -287,7 +287,7 @@ export const lightTheme: ThemeOptions = {
transform: 'rotate(0deg)',
},
margin: 0,
- minHeight: 48,
+ minHeight: 40,
},
'&:hover': {
'& h3': {
From 46d14e2a4dcf40f9703c6e7fa27bca7d97119d13 Mon Sep 17 00:00:00 2001
From: jdamore-linode <97627410+jdamore-linode@users.noreply.github.com>
Date: Wed, 30 Oct 2024 16:05:04 -0400
Subject: [PATCH 25/66] test: [M3-8810] - Fix DBaaS failures when v2 feature
flag is enabled (#11190)
* Mock DBaaS v2 feature flag to be disabled
* Remove feature flag mock, hourly price assertion
* Added changeset: Allow DBaaS resize test to pass when DBaaS v2 is enabled
---------
Co-authored-by: Joe D'Amore
---
packages/manager/.changeset/pr-11190-tests-1730312266172.md | 5 +++++
.../cypress/e2e/core/databases/resize-database.spec.ts | 3 ---
2 files changed, 5 insertions(+), 3 deletions(-)
create mode 100644 packages/manager/.changeset/pr-11190-tests-1730312266172.md
diff --git a/packages/manager/.changeset/pr-11190-tests-1730312266172.md b/packages/manager/.changeset/pr-11190-tests-1730312266172.md
new file mode 100644
index 00000000000..7ca92a9978c
--- /dev/null
+++ b/packages/manager/.changeset/pr-11190-tests-1730312266172.md
@@ -0,0 +1,5 @@
+---
+"@linode/manager": Tests
+---
+
+Allow DBaaS resize test to pass when DBaaS v2 is enabled ([#11190](https://github.com/linode/manager/pull/11190))
diff --git a/packages/manager/cypress/e2e/core/databases/resize-database.spec.ts b/packages/manager/cypress/e2e/core/databases/resize-database.spec.ts
index fb2d9123c87..efeb39df9a9 100644
--- a/packages/manager/cypress/e2e/core/databases/resize-database.spec.ts
+++ b/packages/manager/cypress/e2e/core/databases/resize-database.spec.ts
@@ -154,9 +154,6 @@ describe('Resizing existing clusters', () => {
cy.contains(`$${desiredPlanPrice.monthly}/month`).should(
'be.visible'
);
- cy.contains(`$${desiredPlanPrice.hourly}/hour`).should(
- 'be.visible'
- );
});
});
});
From 5bb78393ad56273c687b5b0c32b4a3e9bd0e299e Mon Sep 17 00:00:00 2001
From: smans-akamai
Date: Thu, 31 Oct 2024 10:27:59 -0400
Subject: [PATCH 26/66] change: [UIE-8220] - Settings text update (#11166)
* change: [UIE-8220] - Settings text update
* change: [UIE-8220] - fix tests, update text
* change: [UIE-8220] - fix e2e tests
---------
Co-authored-by: mpolotsk
---
.../.changeset/pr-11166-changed-1729892043474.md | 5 +++++
.../e2e/core/databases/update-database.spec.ts | 2 +-
.../DatabaseDetail/AccessControls.test.tsx | 4 ++--
.../Databases/DatabaseDetail/AccessControls.tsx | 5 +++--
.../AddAccessControlDrawer.test.tsx | 15 ++++++++-------
.../DatabaseSettings/DatabaseSettings.test.tsx | 10 +++++-----
.../DatabaseSettings/DatabaseSettings.tsx | 4 ++--
.../DatabaseSettings/MaintenanceWindow.tsx | 14 +++++++-------
.../DatabaseSummary/DatabaseSummary.test.tsx | 14 ++++++++------
9 files changed, 41 insertions(+), 32 deletions(-)
create mode 100644 packages/manager/.changeset/pr-11166-changed-1729892043474.md
diff --git a/packages/manager/.changeset/pr-11166-changed-1729892043474.md b/packages/manager/.changeset/pr-11166-changed-1729892043474.md
new file mode 100644
index 00000000000..e177811b75a
--- /dev/null
+++ b/packages/manager/.changeset/pr-11166-changed-1729892043474.md
@@ -0,0 +1,5 @@
+---
+"@linode/manager": Changed
+---
+
+Database settings text and labels ([#11166](https://github.com/linode/manager/pull/11166))
diff --git a/packages/manager/cypress/e2e/core/databases/update-database.spec.ts b/packages/manager/cypress/e2e/core/databases/update-database.spec.ts
index f99436412a1..9c05905c5c3 100644
--- a/packages/manager/cypress/e2e/core/databases/update-database.spec.ts
+++ b/packages/manager/cypress/e2e/core/databases/update-database.spec.ts
@@ -94,7 +94,7 @@ const removeAllowedIp = (allowedIp: string) => {
* @param existingIps - The number of existing IPs. Optional, default is `0`.
*/
const manageAccessControl = (allowedIps: string[], existingIps: number = 0) => {
- cy.findByText('Manage Access Controls').closest('button').click();
+ cy.findByTestId('button-access-control').click();
ui.drawer
.findByTitle('Manage Access Controls')
diff --git a/packages/manager/src/features/Databases/DatabaseDetail/AccessControls.test.tsx b/packages/manager/src/features/Databases/DatabaseDetail/AccessControls.test.tsx
index 5d551ca4253..b8e8128dd7b 100644
--- a/packages/manager/src/features/Databases/DatabaseDetail/AccessControls.test.tsx
+++ b/packages/manager/src/features/Databases/DatabaseDetail/AccessControls.test.tsx
@@ -35,13 +35,13 @@ describe('Access Controls', () => {
['disable', true],
['enable', false],
])(
- 'should %s "Manage Access Control" button when disabled is %s',
+ 'should %s "Manage Access" button when disabled is %s',
(_, isDisabled) => {
const database = databaseFactory.build();
const { getByRole } = renderWithTheme(
);
- const button = getByRole('button', { name: 'Manage Access Controls' });
+ const button = getByRole('button', { name: 'Manage Access' });
if (isDisabled) {
expect(button).toBeDisabled();
diff --git a/packages/manager/src/features/Databases/DatabaseDetail/AccessControls.tsx b/packages/manager/src/features/Databases/DatabaseDetail/AccessControls.tsx
index a1b7f157ec9..ebbd3edbfe9 100644
--- a/packages/manager/src/features/Databases/DatabaseDetail/AccessControls.tsx
+++ b/packages/manager/src/features/Databases/DatabaseDetail/AccessControls.tsx
@@ -175,17 +175,18 @@ export const AccessControls = (props: Props) => {
- Access Controls
+ Manage Access
{description ?? null}
setAddAccessControlDrawerOpen(true)}
>
- Manage Access Controls
+ Manage Access
{ipTable(database.allow_list)}
diff --git a/packages/manager/src/features/Databases/DatabaseDetail/AddAccessControlDrawer.test.tsx b/packages/manager/src/features/Databases/DatabaseDetail/AddAccessControlDrawer.test.tsx
index c41e81f6cc2..e0a9abac2b5 100644
--- a/packages/manager/src/features/Databases/DatabaseDetail/AddAccessControlDrawer.test.tsx
+++ b/packages/manager/src/features/Databases/DatabaseDetail/AddAccessControlDrawer.test.tsx
@@ -5,19 +5,20 @@ import { databaseFactory } from 'src/factories';
import { IPv4List } from 'src/factories/databases';
import { mockMatchMedia, renderWithTheme } from 'src/utilities/testHelpers';
-import { DatabaseInstance } from '@linode/api-v4';
import AccessControls from './AccessControls';
import AddAccessControlDrawer from './AddAccessControlDrawer';
+import type { DatabaseInstance } from '@linode/api-v4';
+
beforeAll(() => mockMatchMedia());
describe('Add Access Controls drawer', () => {
const database = databaseFactory.build();
- const { getByTestId, getByText } = renderWithTheme(
+ const { getByTestId } = renderWithTheme(
);
- const button = getByText('Manage Access Controls');
+ const button = getByTestId('button-access-control');
fireEvent.click(button);
it('Should open when a user clicks the Add Access Controls button', () => {
@@ -28,9 +29,9 @@ describe('Add Access Controls drawer', () => {
it('Should open with a full list of current inbound sources that are allow listed', async () => {
const IPv4ListWithMasks = IPv4List.map((ip) => `${ip}/32`);
const db = {
- id: 123,
- engine: 'postgresql',
allow_list: IPv4ListWithMasks,
+ engine: 'postgresql',
+ id: 123,
} as DatabaseInstance;
const { getAllByTestId } = renderWithTheme(
null} open={true} />
@@ -47,9 +48,9 @@ describe('Add Access Controls drawer', () => {
it('Should have a disabled Add Inbound Sources button until an inbound source field is touched', () => {
const db = {
- id: 123,
- engine: 'postgresql',
allow_list: IPv4List,
+ engine: 'postgresql',
+ id: 123,
} as DatabaseInstance;
const { getByText } = renderWithTheme(
null} open={true} />
diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSettings/DatabaseSettings.test.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSettings/DatabaseSettings.test.tsx
index 3778dcf9e07..6148b7cff14 100644
--- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSettings/DatabaseSettings.test.tsx
+++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSettings/DatabaseSettings.test.tsx
@@ -12,16 +12,16 @@ describe('DatabaseSettings Component', () => {
renderWithTheme( );
});
- it('Should render a Paper component with headers for Access Controls, Reseting the Root password, and Deleting the Cluster', () => {
+ it('Should render a Paper component with headers for Manage Access, Reseting the Root password, and Deleting the Cluster', () => {
const { container, getAllByRole } = renderWithTheme(
);
const paper = container.querySelector('.MuiPaper-root');
expect(paper).not.toBeNull();
const headings = getAllByRole('heading');
- expect(headings[0].textContent).toBe('Access Controls');
- expect(headings[1].textContent).toBe('Reset Root Password');
- expect(headings[2].textContent).toBe('Delete Cluster');
+ expect(headings[0].textContent).toBe('Manage Access');
+ expect(headings[1].textContent).toBe('Reset the Root Password');
+ expect(headings[2].textContent).toBe('Delete the Cluster');
});
it.each([
@@ -33,7 +33,7 @@ describe('DatabaseSettings Component', () => {
);
const button1 = getByTitle('Reset Root Password');
const button2 = getByTitle('Save Changes');
- const button3 = getByRole('button', { name: 'Manage Access Controls' });
+ const button3 = getByRole('button', { name: 'Manage Access' });
if (isDisabled) {
expect(button1).toBeDisabled();
diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSettings/DatabaseSettings.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSettings/DatabaseSettings.tsx
index a10f1c39b15..5b72c88a7e4 100644
--- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSettings/DatabaseSettings.tsx
+++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSettings/DatabaseSettings.tsx
@@ -75,7 +75,7 @@ export const DatabaseSettings: React.FC = (props) => {
descriptiveText={resetRootPasswordCopy}
disabled={disabled}
onClick={onResetRootPassword}
- sectionTitle="Reset Root Password"
+ sectionTitle="Reset the Root Password"
/>
= (props) => {
descriptiveText={deleteClusterCopy}
disabled={Boolean(profile?.restricted)}
onClick={onDeleteCluster}
- sectionTitle="Delete Cluster"
+ sectionTitle="Delete the Cluster"
/>
{
const isLegacy = database.platform === 'rdbms-legacy';
- const typographyDatabase =
- 'Select when you want the required OS and DB engine updates to take place. The maintenance may cause downtime on clusters with less than 3 nodes (non high-availability clusters).';
-
const typographyLegacyDatabase =
- "OS and DB engine updates will be performed on the schedule below. Select the frequency, day, and time you'd prefer maintenance to occur.";
+ 'Select when you want the required OS and database engine updates to take place. The maintenance may cause downtime on clusters with less than 3 nodes (non high-availability clusters).';
+
+ const typographyDatabase =
+ "OS and database engine updates will be performed on the schedule below. Select the frequency, day, and time you'd prefer maintenance to occur.";
return (