From ae81c260e6cd8135a848331ee389aecee3a83468 Mon Sep 17 00:00:00 2001 From: Conal Ryan Date: Thu, 31 Oct 2024 15:03:09 -0400 Subject: [PATCH] feat: [UIE-8194] - DBaaS major and minor upgrades - 4 --- ...r-11199-upcoming-features-1730465428837.md | 5 + .../Databases/DatabaseCreate/utilities.tsx | 10 +- .../DatabaseResizeCurrentConfiguration.tsx | 15 +- .../DatabaseSettings.test.tsx | 148 +++++++++++++++++- .../DatabaseSettings/DatabaseSettings.tsx | 74 ++++++++- .../DatabaseSummaryClusterConfiguration.tsx | 10 +- ...abaseSummaryClusterConfigurationLegacy.tsx | 10 +- .../Databases/DatabaseLanding/DatabaseRow.tsx | 21 +-- 8 files changed, 256 insertions(+), 37 deletions(-) create mode 100644 packages/manager/.changeset/pr-11199-upcoming-features-1730465428837.md diff --git a/packages/manager/.changeset/pr-11199-upcoming-features-1730465428837.md b/packages/manager/.changeset/pr-11199-upcoming-features-1730465428837.md new file mode 100644 index 00000000000..d971b6407b5 --- /dev/null +++ b/packages/manager/.changeset/pr-11199-upcoming-features-1730465428837.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Upcoming Features +--- + +DBaaS major minor updates integration ([#11199](https://github.com/linode/manager/pull/11199)) diff --git a/packages/manager/src/features/Databases/DatabaseCreate/utilities.tsx b/packages/manager/src/features/Databases/DatabaseCreate/utilities.tsx index ec405a84c58..f7d560d2ced 100644 --- a/packages/manager/src/features/Databases/DatabaseCreate/utilities.tsx +++ b/packages/manager/src/features/Databases/DatabaseCreate/utilities.tsx @@ -4,8 +4,7 @@ import React from 'react'; import MongoDBIcon from 'src/assets/icons/mongodb.svg'; import MySQLIcon from 'src/assets/icons/mysql.svg'; import PostgreSQLIcon from 'src/assets/icons/postgresql.svg'; - -import { databaseEngineMap } from '../DatabaseLanding/DatabaseRow'; +import { getDatabasesDescription } from 'src/features/Databases/utilities'; import type { DatabaseEngine } from '@linode/api-v4'; @@ -101,9 +100,10 @@ export const getEngineOptions = (engines: DatabaseEngine[]) => { .map((engineObject) => ({ ...engineObject, flag: engineIcons[engineObject.engine], - label: `${databaseEngineMap[engineObject.engine]} v${ - engineObject.version - }`, + label: getDatabasesDescription({ + engine: engineObject.engine, + version: engineObject.version, + }), value: `${engineObject.engine}/${engineObject.version}`, })) .sort((a, b) => (a.version > b.version ? -1 : 1)), diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResizeCurrentConfiguration.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResizeCurrentConfiguration.tsx index eba42f15ce6..a45c1814922 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResizeCurrentConfiguration.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseResize/DatabaseResizeCurrentConfiguration.tsx @@ -5,13 +5,13 @@ import * as React from 'react'; import { CircleProgress } from 'src/components/CircleProgress'; import { ErrorState } from 'src/components/ErrorState/ErrorState'; import { TooltipIcon } from 'src/components/TooltipIcon'; +import { DatabaseEngineVersion } from 'src/features/Databases/DatabaseEngineVersion'; import { useDatabaseTypesQuery } from 'src/queries/databases/databases'; import { useInProgressEvents } from 'src/queries/events/events'; import { useRegionsQuery } from 'src/queries/regions/regions'; import { formatStorageUnits } from 'src/utilities/formatStorageUnits'; import { convertMegabytesTo } from 'src/utilities/unitConversions'; -import { databaseEngineMap } from '../../DatabaseLanding/DatabaseRow'; import { DatabaseStatusDisplay } from '../DatabaseStatusDisplay'; import { StyledStatusBox, @@ -24,7 +24,6 @@ import { import type { Region } from '@linode/api-v4'; import type { Database, - DatabaseInstance, DatabaseType, } from '@linode/api-v4/lib/databases/types'; @@ -32,10 +31,6 @@ interface Props { database: Database; } -export const getDatabaseVersionNumber = ( - version: DatabaseInstance['version'] -) => version.split('/')[1]; - export const DatabaseResizeCurrentConfiguration = ({ database }: Props) => { const { data: types, @@ -94,7 +89,13 @@ export const DatabaseResizeCurrentConfiguration = ({ database }: Props) => { Version{' '} - {databaseEngineMap[database.engine]} v{database.version} + Nodes{' '} 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 6148b7cff14..2bf0c733400 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSettings/DatabaseSettings.test.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSettings/DatabaseSettings.test.tsx @@ -3,8 +3,46 @@ import * as React from 'react'; import { databaseFactory } from 'src/factories/databases'; import { renderWithTheme } from 'src/utilities/testHelpers'; +import * as utils from '../../utilities'; import DatabaseSettings from './DatabaseSettings'; +const v1 = () => { + return { + isDatabasesEnabled: true, + isDatabasesV1Enabled: true, + isDatabasesV2Beta: false, + isDatabasesV2Enabled: false, + isDatabasesV2GA: false, + isUserExistingBeta: false, + isUserNewBeta: false, + }; +}; + +const v2Beta = () => { + return { + isDatabasesEnabled: true, + isDatabasesV1Enabled: true, + isDatabasesV2Beta: true, + isDatabasesV2Enabled: true, + isDatabasesV2GA: false, + isUserExistingBeta: false, + isUserNewBeta: true, + }; +}; + +const v2GA = () => ({ + isDatabasesEnabled: true, + isDatabasesV1Enabled: true, + isDatabasesV2Beta: false, + isDatabasesV2Enabled: true, + isDatabasesV2GA: true, + isUserExistingBeta: false, + isUserNewBeta: false, +}); + +const spy = vi.spyOn(utils, 'useIsDatabasesEnabled'); +spy.mockReturnValue(v2GA()); + describe('DatabaseSettings Component', () => { const database = databaseFactory.build(); it('Should exist and be renderable', () => { @@ -12,16 +50,16 @@ describe('DatabaseSettings Component', () => { renderWithTheme(); }); - it('Should render a Paper component with headers for Manage Access, Reseting the Root password, and Deleting the Cluster', () => { + it('Should render a Paper component with headers for Access Controls, 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('Manage Access'); - expect(headings[1].textContent).toBe('Reset the Root Password'); - expect(headings[2].textContent).toBe('Delete the Cluster'); + expect(headings[0].textContent).toBe('Access Controls'); + expect(headings[1].textContent).toBe('Reset Root Password'); + expect(headings[2].textContent).toBe('Delete Cluster'); }); it.each([ @@ -33,7 +71,7 @@ describe('DatabaseSettings Component', () => { ); const button1 = getByTitle('Reset Root Password'); const button2 = getByTitle('Save Changes'); - const button3 = getByRole('button', { name: 'Manage Access' }); + const button3 = getByRole('button', { name: 'Manage Access Controls' }); if (isDisabled) { expect(button1).toBeDisabled(); @@ -45,6 +83,106 @@ describe('DatabaseSettings Component', () => { } }); + it('should not render Maintenance for V1 view legacy db', async () => { + spy.mockReturnValue(v1()); + + const database = databaseFactory.build({ + engine: 'postgresql', + platform: 'rdbms-legacy', + version: '14.6', + }); + + const { container } = renderWithTheme( + + ); + + const maintenance = container.querySelector( + '[data-qa-settings-section="Maintenance"]' + ); + + expect(maintenance).not.toBeInTheDocument(); + }); + + it('should not render Maintenance for V2 beta view legacy db', async () => { + spy.mockReturnValue(v2Beta()); + + const database = databaseFactory.build({ + engine: 'postgresql', + platform: 'rdbms-legacy', + version: '14.6', + }); + + const { container } = renderWithTheme( + + ); + + const maintenance = container.querySelector( + '[data-qa-settings-section="Maintenance"]' + ); + + expect(maintenance).not.toBeInTheDocument(); + }); + + it('should not render Maintenance for V2 beta view default db', async () => { + spy.mockReturnValue(v2Beta()); + + const database = databaseFactory.build({ + engine: 'postgresql', + platform: 'rdbms-default', + version: '14.6', + }); + + const { container } = renderWithTheme( + + ); + + const maintenance = container.querySelector( + '[data-qa-settings-section="Maintenance"]' + ); + + expect(maintenance).not.toBeInTheDocument(); + }); + + it('should not render Maintenance for V2 GA view legacy db', async () => { + spy.mockReturnValue(v2GA()); + + const database = databaseFactory.build({ + engine: 'postgresql', + platform: 'rdbms-legacy', + version: '14.6', + }); + + const { container } = renderWithTheme( + + ); + + const maintenance = container.querySelector( + '[data-qa-settings-section="Maintenance"]' + ); + + expect(maintenance).not.toBeInTheDocument(); + }); + + it('should render Maintenance for V2 GA view default db', async () => { + spy.mockReturnValue(v2GA()); + + const database = databaseFactory.build({ + engine: 'postgresql', + platform: 'rdbms-default', + version: '14.6', + }); + + const { container } = renderWithTheme( + + ); + + const maintenance = container.querySelector( + '[data-qa-settings-section="Maintenance"]' + ); + + expect(maintenance).toBeInTheDocument(); + }); + it('Should render Maintenance Window with radio buttons', () => { const database = databaseFactory.build({ platform: 'rdbms-legacy', diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSettings/DatabaseSettings.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSettings/DatabaseSettings.tsx index 2c7f4bcc22c..bddc3a1a680 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSettings/DatabaseSettings.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSettings/DatabaseSettings.tsx @@ -1,12 +1,19 @@ +import { Paper } from '@linode/ui'; import * as React from 'react'; import { Divider } from 'src/components/Divider'; -import { Paper } from '@linode/ui'; import { Typography } from 'src/components/Typography'; +import { DatabaseSettingsReviewUpdatesDialog } from 'src/features/Databases/DatabaseDetail/DatabaseSettings/DatabaseSettingsReviewUpdatesDialog'; +import { DatabaseSettingsUpgradeVersionDialog } from 'src/features/Databases/DatabaseDetail/DatabaseSettings/DatabaseSettingsUpgradeVersionDialog'; +import { + isDefaultDatabase, + useIsDatabasesEnabled, +} from 'src/features/Databases/utilities'; import { useProfile } from 'src/queries/profile/profile'; import AccessControls from '../AccessControls'; import DatabaseSettingsDeleteClusterDialog from './DatabaseSettingsDeleteClusterDialog'; +import { DatabaseSettingsMaintenance } from './DatabaseSettingsMaintenance'; import DatabaseSettingsMenuItem from './DatabaseSettingsMenuItem'; import DatabaseSettingsResetPasswordDialog from './DatabaseSettingsResetPasswordDialog'; import MaintenanceWindow from './MaintenanceWindow'; @@ -21,6 +28,8 @@ interface Props { export const DatabaseSettings: React.FC = (props) => { const { database, disabled } = props; const { data: profile } = useProfile(); + const { isDatabasesV2GA } = useIsDatabasesEnabled(); + const isDefaultDB = isDefaultDatabase(database); const accessControlCopy = ( @@ -29,13 +38,11 @@ export const DatabaseSettings: React.FC = (props) => { ); - const isLegacy = database.platform === 'rdbms-legacy'; - - const resetRootPasswordCopy = isLegacy + const resetRootPasswordCopy = !isDefaultDB ? 'Resetting your root password will automatically generate a new password. You can view the updated password on your database cluster summary page. ' : 'Reset your root password if someone should no longer have access to the root user or if you believe your password may have been compromised. This will automatically generate a new password that you’ll be able to see on your database cluster summary page.'; - const deleteClusterCopy = isLegacy + const deleteClusterCopy = !isDefaultDB ? 'Deleting a database cluster is permanent and cannot be undone.' : 'Permanently remove an unused database cluster.'; @@ -45,6 +52,16 @@ export const DatabaseSettings: React.FC = (props) => { setIsResetRootPasswordDialogOpen, ] = React.useState(false); + const [ + isUpgradeVersionDialogOpen, + setIsUpgradeVersionDialogOpen, + ] = React.useState(false); + + const [ + isReviewUpdatesDialogOpen, + setIsReviewUpdatesDialogOpen, + ] = React.useState(false); + const onResetRootPassword = () => { setIsResetRootPasswordDialogOpen(true); }; @@ -61,6 +78,22 @@ export const DatabaseSettings: React.FC = (props) => { setIsResetRootPasswordDialogOpen(false); }; + const onUpgradeVersion = () => { + setIsUpgradeVersionDialogOpen(true); + }; + + const onUpgradeVersionClose = () => { + setIsUpgradeVersionDialogOpen(false); + }; + + const onReviewUpdates = () => { + setIsReviewUpdatesDialogOpen(true); + }; + + const onReviewUpdatesClose = () => { + setIsReviewUpdatesDialogOpen(false); + }; + return ( <> @@ -75,7 +108,7 @@ export const DatabaseSettings: React.FC = (props) => { descriptiveText={resetRootPasswordCopy} disabled={disabled} onClick={onResetRootPassword} - sectionTitle="Reset the Root Password" + sectionTitle="Reset Root Password" /> = (props) => { descriptiveText={deleteClusterCopy} disabled={Boolean(profile?.restricted)} onClick={onDeleteCluster} - sectionTitle="Delete the Cluster" + sectionTitle="Delete Cluster" /> + {isDatabasesV2GA && isDefaultDB && ( + <> + + + + )} = (props) => { onClose={onResetRootPasswordClose} open={isResetRootPasswordDialogOpen} /> + + ); }; diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSummary/DatabaseSummaryClusterConfiguration.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSummary/DatabaseSummaryClusterConfiguration.tsx index f619078acab..54b733ed209 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSummary/DatabaseSummaryClusterConfiguration.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSummary/DatabaseSummaryClusterConfiguration.tsx @@ -10,7 +10,7 @@ import { StyledLabelTypography, StyledValueGrid, } from 'src/features/Databases/DatabaseDetail/DatabaseSummary/DatabaseSummaryClusterConfiguration.style'; -import { databaseEngineMap } from 'src/features/Databases/DatabaseLanding/DatabaseRow'; +import { DatabaseEngineVersion } from 'src/features/Databases/DatabaseEngineVersion'; import { useDatabaseTypesQuery } from 'src/queries/databases/databases'; import { useInProgressEvents } from 'src/queries/events/events'; import { useRegionsQuery } from 'src/queries/regions/regions'; @@ -101,7 +101,13 @@ export const DatabaseSummaryClusterConfiguration = (props: Props) => { Engine - {databaseEngineMap[database.engine]} v{database.version} + Region diff --git a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSummary/legacy/DatabaseSummaryClusterConfigurationLegacy.tsx b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSummary/legacy/DatabaseSummaryClusterConfigurationLegacy.tsx index 8b018175505..dedbefe5070 100644 --- a/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSummary/legacy/DatabaseSummaryClusterConfigurationLegacy.tsx +++ b/packages/manager/src/features/Databases/DatabaseDetail/DatabaseSummary/legacy/DatabaseSummaryClusterConfigurationLegacy.tsx @@ -5,7 +5,7 @@ import { makeStyles } from 'tss-react/mui'; import { TooltipIcon } from 'src/components/TooltipIcon'; import { Typography } from 'src/components/Typography'; import { DatabaseStatusDisplay } from 'src/features/Databases/DatabaseDetail/DatabaseStatusDisplay'; -import { databaseEngineMap } from 'src/features/Databases/DatabaseLanding/DatabaseRow'; +import { DatabaseEngineVersion } from 'src/features/Databases/DatabaseEngineVersion'; import { useDatabaseTypesQuery } from 'src/queries/databases/databases'; import { useInProgressEvents } from 'src/queries/events/events'; import { useRegionsQuery } from 'src/queries/regions/regions'; @@ -94,7 +94,13 @@ export const DatabaseSummaryClusterConfigurationLegacy = (props: Props) => { Version - {databaseEngineMap[database.engine]} v{database.version} + Nodes diff --git a/packages/manager/src/features/Databases/DatabaseLanding/DatabaseRow.tsx b/packages/manager/src/features/Databases/DatabaseLanding/DatabaseRow.tsx index 031bf088fb4..e44a5321518 100644 --- a/packages/manager/src/features/Databases/DatabaseLanding/DatabaseRow.tsx +++ b/packages/manager/src/features/Databases/DatabaseLanding/DatabaseRow.tsx @@ -6,6 +6,7 @@ import { Hidden } from 'src/components/Hidden'; import { TableCell } from 'src/components/TableCell'; import { TableRow } from 'src/components/TableRow'; import { DatabaseStatusDisplay } from 'src/features/Databases/DatabaseDetail/DatabaseStatusDisplay'; +import { DatabaseEngineVersion } from 'src/features/Databases/DatabaseEngineVersion'; import { DatabaseActionMenu } from 'src/features/Databases/DatabaseLanding/DatabaseActionMenu'; import { useIsDatabasesEnabled } from 'src/features/Databases/utilities'; import { useDatabaseTypesQuery } from 'src/queries/databases/databases'; @@ -19,17 +20,9 @@ import type { Event } from '@linode/api-v4'; import type { DatabaseInstance, DatabaseType, - Engine, } from '@linode/api-v4/lib/databases/types'; import type { ActionHandlers } from 'src/features/Databases/DatabaseLanding/DatabaseActionMenu'; -export const databaseEngineMap: Record = { - mongodb: 'MongoDB', - mysql: 'MySQL', - postgresql: 'PostgreSQL', - redis: 'Redis', -}; - interface Props { database: DatabaseInstance; events?: Event[]; @@ -53,8 +46,10 @@ export const DatabaseRow = ({ engine, id, label, + platform, region, type, + updates, version, } = database; @@ -94,7 +89,15 @@ export const DatabaseRow = ({ {configuration} - {`${databaseEngineMap[engine]} v${version}`} + + + {actualRegion?.label ?? region}