diff --git a/packages/api-v4/.changeset/pr-10262-added-1709742032135.md b/packages/api-v4/.changeset/pr-10262-added-1709742032135.md new file mode 100644 index 00000000000..045f50335b8 --- /dev/null +++ b/packages/api-v4/.changeset/pr-10262-added-1709742032135.md @@ -0,0 +1,5 @@ +--- +"@linode/api-v4": Added +--- + +Added event type for database resize create ([#10262](https://github.com/linode/manager/pull/10262)) diff --git a/packages/api-v4/src/account/types.ts b/packages/api-v4/src/account/types.ts index f35c3e804e5..955ec311566 100644 --- a/packages/api-v4/src/account/types.ts +++ b/packages/api-v4/src/account/types.ts @@ -288,6 +288,7 @@ export type EventAction = | 'credit_card_updated' | 'database_low_disk_space' | 'database_resize' + | 'database_resize_create' | 'database_backup_restore' | 'database_create' | 'database_credentials_reset' diff --git a/packages/api-v4/src/databases/types.ts b/packages/api-v4/src/databases/types.ts index 3dd34f63984..1e079d38c8d 100644 --- a/packages/api-v4/src/databases/types.ts +++ b/packages/api-v4/src/databases/types.ts @@ -35,7 +35,8 @@ export type DatabaseStatus = | 'resuming' | 'restoring' | 'failed' - | 'degraded'; + | 'degraded' + | 'resizing'; export type DatabaseBackupType = 'snapshot' | 'auto'; diff --git a/packages/manager/.changeset/pr-10262-changed-1709742412767.md b/packages/manager/.changeset/pr-10262-changed-1709742412767.md new file mode 100644 index 00000000000..f6dcacb6887 --- /dev/null +++ b/packages/manager/.changeset/pr-10262-changed-1709742412767.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Changed +--- + +Notifications for database resize events ([#10262](https://github.com/linode/manager/pull/10262)) diff --git a/packages/manager/src/components/TypeToConfirmDialog/TypeToConfirmDialog.tsx b/packages/manager/src/components/TypeToConfirmDialog/TypeToConfirmDialog.tsx index 6bf1f6eb4f5..c4e6e3ae8bb 100644 --- a/packages/manager/src/components/TypeToConfirmDialog/TypeToConfirmDialog.tsx +++ b/packages/manager/src/components/TypeToConfirmDialog/TypeToConfirmDialog.tsx @@ -13,7 +13,12 @@ import { import { usePreferences } from 'src/queries/preferences'; interface EntityInfo { - action?: 'cancellation' | 'deletion' | 'detachment' | 'restoration'; + action?: + | 'cancellation' + | 'deletion' + | 'detachment' + | 'restoration' + | 'resizing'; name?: string | undefined; primaryBtnText: string; subType?: 'CloseAccount' | 'Cluster' | 'ObjectStorage'; diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResize.test.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResize.test.tsx index d37d71ea695..a339b426de0 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResize.test.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResize.test.tsx @@ -118,7 +118,7 @@ describe('database resize', () => { 'false' ); fireEvent.click(resizeButton); - getByText(`Resize ${database.label}?`); + getByText(`Resize Database Cluster ${database.label}?`); }); }); }); diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResize.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResize.tsx index 1957bec5b23..baa3d42d498 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResize.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResize.tsx @@ -1,28 +1,25 @@ -import { LinodeTypeClass } from '@linode/api-v4'; import { Database, DatabaseClusterSizeObject, DatabasePriceObject, + DatabaseType, Engine, } from '@linode/api-v4/lib/databases/types'; import { useSnackbar } from 'notistack'; import * as React from 'react'; import { useHistory } from 'react-router-dom'; - -import { ActionsPanel } from 'src/components/ActionsPanel/ActionsPanel'; import { Box } from 'src/components/Box'; import { CircleProgress } from 'src/components/CircleProgress'; -import { ConfirmationDialog } from 'src/components/ConfirmationDialog/ConfirmationDialog'; import { ErrorState } from 'src/components/ErrorState/ErrorState'; import { Notice } from 'src/components/Notice/Notice'; import { Paper } from 'src/components/Paper'; import { Typography } from 'src/components/Typography'; import { typeLabelDetails } from 'src/features/Linodes/presentation'; import { PlanSelectionType } from 'src/features/components/PlansPanel/types'; -import { getPlanSelectionsByPlanType } from 'src/features/components/PlansPanel/utils'; import { useDatabaseTypesQuery } from 'src/queries/databases'; import { useDatabaseMutation } from 'src/queries/databases'; import { formatStorageUnits } from 'src/utilities/formatStorageUnits'; +import { TypeToConfirmDialog } from 'src/components/TypeToConfirmDialog/TypeToConfirmDialog'; import { StyledGrid, @@ -75,12 +72,9 @@ export const DatabaseResize = ({ database }: Props) => { updateDatabase({ type: planSelected, }).then(() => { - enqueueSnackbar( - `Your database cluster ${database.label} is being resized.`, - { - variant: 'info', - } - ); + enqueueSnackbar(`Database cluster ${database.label} is being resized.`, { + variant: 'info', + }); history.push(`/databases/${database.engine}/${database.id}`); }); }; @@ -117,22 +111,6 @@ export const DatabaseResize = ({ database }: Props) => { ); - const confirmationDialogActions = ( - setIsResizeConfirmationDialogOpen(false), - }} - /> - ); - const costSummary = ( {`The cost of the resized database is ${summaryText?.price}.`} @@ -160,7 +138,9 @@ export const DatabaseResize = ({ database }: Props) => { return; } - const selectedPlanType = dbTypes.find((type) => type.id === planSelected); + const selectedPlanType = dbTypes.find( + (type: DatabaseType) => type.id === planSelected + ); if (!selectedPlanType) { setPlanSelected(undefined); setSummaryText(undefined); @@ -195,11 +175,12 @@ export const DatabaseResize = ({ database }: Props) => { if (!dbTypes) { return []; } - return dbTypes.map((type) => { + return dbTypes.map((type: DatabaseType) => { const { label } = type; const formattedLabel = formatStorageUnits(label); const nodePricing = type.engines[selectedEngine].find( - (cluster) => cluster.quantity === database.cluster_size + (cluster: DatabaseClusterSizeObject) => + cluster.quantity === database.cluster_size ); const price = nodePricing?.price ?? { hourly: null, @@ -220,18 +201,12 @@ export const DatabaseResize = ({ database }: Props) => { }, [database.cluster_size, dbTypes, selectedEngine]); const currentPlan = displayTypes?.find((type) => type.id === database.type); - // create an array of different class of types. - const typeClasses: LinodeTypeClass[] = Object.keys( - getPlanSelectionsByPlanType(displayTypes) - ).map((plan) => (plan === 'shared' ? 'standard' : (plan as LinodeTypeClass))); - const currentPlanClass = currentPlan?.class ?? 'dedicated'; - // We don't have a "Nanodes" tab anymore, so use `shared` - const selectedTypeClass = - currentPlanClass === 'nanode' ? 'standard' : currentPlanClass; - // User cannot switch to different plan type apart from current plan while resizing a DB cluster. So disable rest of the tabs. - const tabsToBeDisabled = typeClasses - .filter((typeClass) => typeClass !== selectedTypeClass) - .map((plan) => (plan === 'standard' ? 'shared' : plan)); + + const disabledPlans = displayTypes?.filter( + (type) => + type.disk < (currentPlan ? currentPlan.disk : 0) || + (currentPlan?.class === 'dedicated' && type.disk === currentPlan?.disk) + ); if (typesLoading) { return ; } @@ -249,15 +224,12 @@ export const DatabaseResize = ({ database }: Props) => { setPlanSelected(selected)} - selectedDiskSize={currentPlan?.disk} selectedId={planSelected} types={displayTypes} /> @@ -275,15 +247,26 @@ export const DatabaseResize = ({ database }: Props) => { Resize Database Cluster - setIsResizeConfirmationDialogOpen(false)} open={isResizeConfirmationDialogOpen} - title={`Resize ${database.label}?`} + title={`Resize Database Cluster ${database.label}?`} > + {resizeError ? ( + + ) : null} {confirmationPopUpMessage} - + ); }; diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResizeCurrentConfiguration.style.ts b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResizeCurrentConfiguration.style.ts index 0cda918f77e..a3689e4e874 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResizeCurrentConfiguration.style.ts +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResizeCurrentConfiguration.style.ts @@ -47,8 +47,11 @@ export const StyledTitleTypography = styled(Typography, { marginBottom: theme.spacing(2), })); -export const StyledStatusSpan = styled('span', { label: 'StyledStatusSpan' })( - () => ({ - textTransform: 'capitalize', - }) -); +export const StyledStatusBox = styled(Box, { + label: 'StyledStatusBox', +})(() => ({ + alignItems: 'center', + display: 'inline-flex', + textTransform: 'capitalize', + verticalAlign: 'sub', +})); diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResizeCurrentConfiguration.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResizeCurrentConfiguration.tsx index ba01bb75260..1206cb415d2 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResizeCurrentConfiguration.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResizeCurrentConfiguration.tsx @@ -1,28 +1,29 @@ -import { Database, DatabaseInstance } from '@linode/api-v4/lib/databases/types'; +import { + Database, + DatabaseInstance, + DatabaseType, +} from '@linode/api-v4/lib/databases/types'; import { useTheme } from '@mui/material/styles'; import * as React from 'react'; - import { Box } from 'src/components/Box'; import { CircleProgress } from 'src/components/CircleProgress'; import { ErrorState } from 'src/components/ErrorState/ErrorState'; -import { StatusIcon } from 'src/components/StatusIcon/StatusIcon'; import { TooltipIcon } from 'src/components/TooltipIcon'; import { useDatabaseTypesQuery } from 'src/queries/databases'; import { useRegionsQuery } from 'src/queries/regions'; +import { useInProgressEvents } from 'src/queries/events/events'; import { formatStorageUnits } from 'src/utilities/formatStorageUnits'; import { convertMegabytesTo } from 'src/utilities/unitConversions'; - -import { - databaseEngineMap, - databaseStatusMap, -} from '../../DatabaseLanding/DatabaseRow'; +import { databaseEngineMap } from '../../DatabaseLanding/DatabaseRow'; import { - StyledStatusSpan, StyledSummaryBox, StyledSummaryTextBox, StyledSummaryTextTypography, StyledTitleTypography, + StyledStatusBox, } from './DatabaseResizeCurrentConfiguration.style'; +import { Region } from '@linode/api-v4'; +import { DatabaseStatusDisplay } from '../DatabaseStatusDisplay'; interface Props { database: Database; @@ -41,10 +42,11 @@ export const DatabaseResizeCurrentConfiguration = ({ database }: Props) => { const theme = useTheme(); const { data: regions } = useRegionsQuery(); - const region = regions?.find((r) => r.id === database.region); + const region = regions?.find((r: Region) => r.id === database.region); - const type = types?.find((type) => type.id === database?.type); + const type = types?.find((type: DatabaseType) => type.id === database?.type); + const { data: events } = useInProgressEvents(); if (typesLoading) { return ; } @@ -68,7 +70,7 @@ export const DatabaseResizeCurrentConfiguration = ({ database }: Props) => { }; const STORAGE_COPY = - 'The total disk size is smaller than the selected plan capacity due to the OS overhead.'; + 'The total disk size is smaller than the selected plan capacity due to overhead from the OS.'; return ( <> @@ -83,13 +85,9 @@ export const DatabaseResizeCurrentConfiguration = ({ database }: Props) => { Status{' '} - - - {database.status} - + + + Version{' '} diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseStatusDisplay.test.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseStatusDisplay.test.tsx new file mode 100644 index 00000000000..feb25df224d --- /dev/null +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseStatusDisplay.test.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { DatabaseStatusDisplay } from '../DatabaseDetail/DatabaseStatusDisplay'; +import { mockMatchMedia, renderWithTheme } from 'src/utilities/testHelpers'; +import { databaseFactory } from 'src/factories'; +import { entityFactory, eventFactory } from 'src/factories/events'; +beforeAll(() => mockMatchMedia()); + +describe('DatabaseStatusDisplay component', () => { + it(`renders status 'resizing' with percentage when recent event status is 'started' or 'scheduled'`, () => { + const mockEvent = eventFactory.build({ + action: 'database_resize', + percent_complete: 50, + entity: entityFactory.build({ id: 1, type: 'database' }), + }); + const database = databaseFactory.build({ id: 1, status: 'resizing' }); + + const { getByText } = renderWithTheme( + + ); + expect(getByText('Resizing (50%)')).toBeInTheDocument(); + }); + + it(`renders status 'active' when recent event status is 'finished' `, () => { + const mockEvent = eventFactory.build({ + action: 'database_resize', + status: 'finished', + entity: entityFactory.build({ id: 1, type: 'database' }), + }); + const database = databaseFactory.build({ id: 1, status: 'active' }); + + const { getByText } = renderWithTheme( + + ); + + expect(getByText('Active')).toBeInTheDocument(); + }); +}); diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseStatusDisplay.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseStatusDisplay.tsx new file mode 100644 index 00000000000..968c2f4d2cb --- /dev/null +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseStatusDisplay.tsx @@ -0,0 +1,62 @@ +import React from 'react'; +import { Typography } from 'src/components/Typography'; +import { capitalize } from 'src/utilities/capitalize'; +import { Event } from '@linode/api-v4'; +import { + Database, + DatabaseInstance, + DatabaseStatus, +} from '@linode/api-v4/lib/databases/types'; +import { Status, StatusIcon } from 'src/components/StatusIcon/StatusIcon'; + +export const databaseStatusMap: Record = { + active: 'active', + degraded: 'inactive', + failed: 'error', + provisioning: 'other', + restoring: 'other', + resuming: 'other', + suspended: 'error', + suspending: 'other', + resizing: 'other', +}; +interface Props { + events: Event[] | undefined; + database: Database | DatabaseInstance; +} +export const DatabaseStatusDisplay = (props: Props) => { + const { events, database } = props; + const recentEvent = events?.find( + (event: Event) => + event.entity?.id === database.id && event.entity?.type === 'database' + ); + + let progress: number | undefined; + if (recentEvent?.action === 'database_resize') { + progress = recentEvent?.percent_complete ?? 0; + } + + let displayedStatus; + if ( + recentEvent?.status === 'started' || + recentEvent?.status === 'scheduled' + ) { + displayedStatus = ( + <> + + + {`Resizing ${progress ? `(${progress}%)` : '(0%)'}`} + + + ); + } else { + displayedStatus = ( + <> + + {capitalize(database.status)} + + ); + } + + return displayedStatus; +}; diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSummary/DatabaseSummaryClusterConfiguration.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSummary/DatabaseSummaryClusterConfiguration.tsx index 2d5125724e2..23ce46f0ade 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSummary/DatabaseSummaryClusterConfiguration.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSummary/DatabaseSummaryClusterConfiguration.tsx @@ -1,21 +1,22 @@ -import { Database, DatabaseInstance } from '@linode/api-v4/lib/databases/types'; +import { + Database, + DatabaseInstance, + DatabaseType, +} from '@linode/api-v4/lib/databases/types'; import { Theme } from '@mui/material/styles'; import * as React from 'react'; import { makeStyles } from 'tss-react/mui'; - import { Box } from 'src/components/Box'; -import { StatusIcon } from 'src/components/StatusIcon/StatusIcon'; import { TooltipIcon } from 'src/components/TooltipIcon'; import { Typography } from 'src/components/Typography'; import { useDatabaseTypesQuery } from 'src/queries/databases'; import { useRegionsQuery } from 'src/queries/regions'; +import { useInProgressEvents } from 'src/queries/events/events'; import { formatStorageUnits } from 'src/utilities/formatStorageUnits'; import { convertMegabytesTo } from 'src/utilities/unitConversions'; - -import { - databaseEngineMap, - databaseStatusMap, -} from '../../DatabaseLanding/DatabaseRow'; +import { DatabaseStatusDisplay } from '../DatabaseStatusDisplay'; +import { databaseEngineMap } from '../../DatabaseLanding/DatabaseRow'; +import { Region } from '@linode/api-v4'; const useStyles = makeStyles()((theme: Theme) => ({ configs: { @@ -53,9 +54,11 @@ export const DatabaseSummaryClusterConfiguration = (props: Props) => { const { data: types } = useDatabaseTypesQuery(); const { data: regions } = useRegionsQuery(); - const region = regions?.find((r) => r.id === database.region); + const region = regions?.find((r: Region) => r.id === database.region); + + const type = types?.find((type: DatabaseType) => type.id === database?.type); - const type = types?.find((type) => type.id === database?.type); + const { data: events } = useInProgressEvents(); if (!database || !type) { return null; @@ -72,7 +75,7 @@ export const DatabaseSummaryClusterConfiguration = (props: Props) => { }; const STORAGE_COPY = - 'The total disk size is smaller than the selected plan capacity due to the OS overhead.'; + 'The total disk size is smaller than the selected plan capacity due to overhead from the OS.'; return ( <> @@ -82,10 +85,9 @@ export const DatabaseSummaryClusterConfiguration = (props: Props) => {
Status - - - {database.status} - +
+ +
Version diff --git a/packages/manager/src/features/Databases/DatabaseDetail/index.tsx b/packages/manager/src/features/Databases/DatabaseDetail/index.tsx index 77300fc74ce..3abdb75747e 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/index.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/index.tsx @@ -78,19 +78,16 @@ export const DatabaseDetail = () => { routeName: `/databases/${engine}/${id}/backups`, title: 'Backups', }, + { + routeName: `/databases/${engine}/${id}/resize`, + title: 'Resize', + }, { routeName: `/databases/${engine}/${id}/settings`, title: 'Settings', }, ]; - if (flags.databaseResize) { - tabs.push({ - routeName: `/databases/${engine}/${id}/resize`, - title: 'Resize', - }); - } - const getTabIndex = () => { const tabChoice = tabs.findIndex((tab) => Boolean(matchPath(tab.routeName, { path: location.pathname })) @@ -161,14 +158,14 @@ export const DatabaseDetail = () => { - - - {flags.databaseResize ? ( - + ) : null} + + + diff --git a/packages/manager/src/features/Databases/DatabaseLanding/DatabaseLanding.tsx b/packages/manager/src/features/Databases/DatabaseLanding/DatabaseLanding.tsx index 447d0f189d7..da631d133c3 100644 --- a/packages/manager/src/features/Databases/DatabaseLanding/DatabaseLanding.tsx +++ b/packages/manager/src/features/Databases/DatabaseLanding/DatabaseLanding.tsx @@ -16,8 +16,8 @@ import { TableSortCell } from 'src/components/TableSortCell'; import { useOrder } from 'src/hooks/useOrder'; import { usePagination } from 'src/hooks/usePagination'; import { useDatabasesQuery } from 'src/queries/databases'; +import { useInProgressEvents } from 'src/queries/events/events'; import { getAPIErrorOrDefault } from 'src/utilities/errorUtils'; - import { DatabaseEmptyState } from './DatabaseEmptyState'; import { DatabaseRow } from './DatabaseRow'; @@ -27,6 +27,8 @@ const DatabaseLanding = () => { const history = useHistory(); const pagination = usePagination(1, preferenceKey); + const { data: events } = useInProgressEvents(); + const { handleOrderChange, order, orderBy } = useOrder( { order: 'desc', @@ -129,7 +131,11 @@ const DatabaseLanding = () => { {data?.data.map((database: DatabaseInstance) => ( - + ))} diff --git a/packages/manager/src/features/Databases/DatabaseLanding/DatabaseRow.tsx b/packages/manager/src/features/Databases/DatabaseLanding/DatabaseRow.tsx index c197e839549..8f15a606507 100644 --- a/packages/manager/src/features/Databases/DatabaseLanding/DatabaseRow.tsx +++ b/packages/manager/src/features/Databases/DatabaseLanding/DatabaseRow.tsx @@ -1,32 +1,20 @@ import { + Database, DatabaseInstance, - DatabaseStatus, Engine, } from '@linode/api-v4/lib/databases/types'; import * as React from 'react'; import { Link } from 'react-router-dom'; - import { Chip } from 'src/components/Chip'; import { Hidden } from 'src/components/Hidden'; -import { Status, StatusIcon } from 'src/components/StatusIcon/StatusIcon'; import { TableCell } from 'src/components/TableCell'; import { TableRow } from 'src/components/TableRow'; import { useProfile } from 'src/queries/profile'; import { useRegionsQuery } from 'src/queries/regions'; -import { capitalize } from 'src/utilities/capitalize'; import { isWithinDays, parseAPIDate } from 'src/utilities/date'; import { formatDate } from 'src/utilities/formatDate'; - -export const databaseStatusMap: Record = { - active: 'active', - degraded: 'inactive', - failed: 'error', - provisioning: 'other', - restoring: 'other', - resuming: 'other', - suspended: 'error', - suspending: 'other', -}; +import { Event } from '@linode/api-v4'; +import { DatabaseStatusDisplay } from '../DatabaseDetail/DatabaseStatusDisplay'; export const databaseEngineMap: Record = { mongodb: 'MongoDB', @@ -36,10 +24,11 @@ export const databaseEngineMap: Record = { }; interface Props { - database: DatabaseInstance; + database: DatabaseInstance | Database; + events?: Event[]; } -export const DatabaseRow = ({ database }: Props) => { +export const DatabaseRow = ({ database, events }: Props) => { const { cluster_size, created, @@ -47,7 +36,6 @@ export const DatabaseRow = ({ database }: Props) => { id, label, region, - status, version, } = database; @@ -81,8 +69,7 @@ export const DatabaseRow = ({ database }: Props) => { {label} - - {capitalize(status)} + {configuration} diff --git a/packages/manager/src/features/Events/constants.ts b/packages/manager/src/features/Events/constants.ts index 4fd19cdef94..edc64d05c45 100644 --- a/packages/manager/src/features/Events/constants.ts +++ b/packages/manager/src/features/Events/constants.ts @@ -17,6 +17,7 @@ export const EVENT_ACTIONS: Event['action'][] = [ 'database_update_failed', 'database_update', 'database_resize', + 'database_resize_create', 'disk_create', 'disk_delete', 'disk_duplicate', diff --git a/packages/manager/src/features/Events/eventMessageGenerator.ts b/packages/manager/src/features/Events/eventMessageGenerator.ts index 6bef2809fee..1d514c1f486 100644 --- a/packages/manager/src/features/Events/eventMessageGenerator.ts +++ b/packages/manager/src/features/Events/eventMessageGenerator.ts @@ -128,6 +128,15 @@ export const eventMessageCreators: { [index: string]: CreatorsForStatus } = { scheduled: (e) => `Database ${e.entity!.label} is scheduled for resizing.`, started: (e) => `Database ${e.entity!.label} is resizing.`, }, + database_resize_create: { + notification: (e) => `Database ${e.entity!.label} scheduled to be resized.`, + }, + database_scale: { + failed: (e) => `Database ${e.entity!.label} could not be resized.`, + finished: (e) => `Database ${e.entity!.label} has been resized.`, + scheduled: (e) => `Database ${e.entity!.label} is scheduled for resizing.`, + started: (e) => `Database ${e.entity!.label} is resizing.`, + }, database_update: { finished: (e) => `Database ${e.entity!.label} has been updated.`, }, diff --git a/packages/manager/src/features/Events/eventMessageGenerator_CMR.tsx b/packages/manager/src/features/Events/eventMessageGenerator_CMR.tsx index 77620db876d..e50fae1b63e 100644 --- a/packages/manager/src/features/Events/eventMessageGenerator_CMR.tsx +++ b/packages/manager/src/features/Events/eventMessageGenerator_CMR.tsx @@ -80,6 +80,8 @@ export const eventMessageGenerator = ( return 'image uploading'; case 'volume_migrate': return `Volume ${e.entity?.label} is being upgraded to NVMe.`; + case 'database_resize': + return 'resizing'; default: // If we haven't handled it explicitly here, it doesn't count as @@ -92,5 +94,9 @@ export const eventLabelGenerator = (e: Event) => { if (['disk_imagize'].includes(e.action)) { return e.secondary_entity?.label; } + + if (e.action == 'database_resize') { + return `Database ${e.entity!.label}`; + } return e.entity?.label; }; diff --git a/packages/manager/src/features/NotificationCenter/NotificationData/RenderProgressEvent.tsx b/packages/manager/src/features/NotificationCenter/NotificationData/RenderProgressEvent.tsx index 9a6c9c5aecd..f265cc41834 100644 --- a/packages/manager/src/features/NotificationCenter/NotificationData/RenderProgressEvent.tsx +++ b/packages/manager/src/features/NotificationCenter/NotificationData/RenderProgressEvent.tsx @@ -59,7 +59,10 @@ export const RenderProgressEvent = (props: Props) => { <> - + {eventMessage} void; @@ -55,6 +57,8 @@ export const PlanContainer = (props: Props) => { disabled, disabledClasses, hideDisabledHelpIcons, + disabledPlanTypes, + disabledPlanTypesToolTipText, isCreate, linodeID, onSelect, @@ -85,20 +89,25 @@ export const PlanContainer = (props: Props) => { const renderPlanSelection = React.useCallback(() => { return plans.map((plan, id) => { + const planIsDisabled = + disabledPlanTypes?.find((element) => element.id === plan.id) !== + undefined; return ( void; + planIsDisabled?: boolean; selectedDiskSize?: number; selectedId?: string; selectedRegionId?: Region['id']; @@ -54,17 +56,37 @@ const getDisabledClass = ( return disabledClasses.includes(typeClass); }; +const getToolTip = ({ + sizeTooSmall, + planIsDisabled, + disabledToolTip, +}: { + sizeTooSmall: boolean; + planIsDisabled?: boolean; + disabledToolTip?: string; +}) => { + if (planIsDisabled) { + return disabledToolTip; + } + if (sizeTooSmall) { + return 'This plan is too small for the selected image.'; + } + return undefined; +}; + export const PlanSelection = (props: PlanSelectionProps) => { const { currentPlanHeading, disabled, disabledClasses, hideDisabledHelpIcons, + disabledToolTip, idx, isCreate, isLimitedAvailabilityPlan, linodeID, onSelect, + planIsDisabled, selectedDiskSize, selectedId, selectedRegionId, @@ -84,9 +106,11 @@ export const PlanSelection = (props: PlanSelectionProps) => { const diskSize = selectedDiskSize ? selectedDiskSize : 0; const planTooSmall = diskSize > type.disk; - const tooltip = planTooSmall - ? 'This plan is too small for the selected image.' - : undefined; + const tooltip = getToolTip({ + sizeTooSmall: planTooSmall, + planIsDisabled: planIsDisabled, + disabledToolTip: disabledToolTip, + }); const isSamePlan = type.heading === currentPlanHeading; const isGPU = type.class === 'gpu'; const isDisabledClass = getDisabledClass(type.class, disabledClasses ?? []); @@ -115,20 +139,23 @@ export const PlanSelection = (props: PlanSelectionProps) => { price?.monthly )}/mo ($${price?.hourly ?? UNKNOWN_PRICE}/hr)`; + const rowAriaDisabled = + isSamePlan || planTooSmall || isDisabledClass || planIsDisabled; + return ( {/* Displays Table Row for larger screens */} !isSamePlan && !isDisabled && !isDisabledClass && !planTooSmall ? onSelect(type.id) : undefined } - aria-disabled={isSamePlan || planTooSmall || isDisabled || disabled} aria-label={rowAriaLabel} data-qa-plan-row={type.formattedLabel} - disabled={isSamePlan || planTooSmall || isDisabled || disabled} key={type.id} > diff --git a/packages/manager/src/features/components/PlansPanel/PlansPanel.tsx b/packages/manager/src/features/components/PlansPanel/PlansPanel.tsx index 6b93da07f6f..af024bb1c78 100644 --- a/packages/manager/src/features/components/PlansPanel/PlansPanel.tsx +++ b/packages/manager/src/features/components/PlansPanel/PlansPanel.tsx @@ -47,6 +47,8 @@ interface Props { tabDisabledMessage?: string; tabbedPanelInnerClass?: string; types: PlanSelectionType[]; + disabledPlanTypes?: PlanSelectionType[]; + disabledPlanTypesToolTipText?: string; } export const PlansPanel = (props: Props) => { @@ -66,6 +68,8 @@ export const PlansPanel = (props: Props) => { selectedRegionID, showTransfer, types, + disabledPlanTypes, + disabledPlanTypesToolTipText, } = props; const flags = useFlags(); @@ -188,6 +192,8 @@ export const PlansPanel = (props: Props) => { selectedId={selectedId} selectedRegionId={selectedRegionID} showTransfer={showTransfer} + disabledPlanTypes={disabledPlanTypes} + disabledPlanTypesToolTipText={disabledPlanTypesToolTipText} /> );