diff --git a/ui/apps/everest/.e2e/pr/db-cluster/db-wizard/create-db-cluster/create-db-cluster.e2e.ts b/ui/apps/everest/.e2e/pr/db-cluster/db-wizard/create-db-cluster/create-db-cluster.e2e.ts index 857d8d0de..71cc73f6d 100644 --- a/ui/apps/everest/.e2e/pr/db-cluster/db-wizard/create-db-cluster/create-db-cluster.e2e.ts +++ b/ui/apps/everest/.e2e/pr/db-cluster/db-wizard/create-db-cluster/create-db-cluster.e2e.ts @@ -20,7 +20,6 @@ import { } from '@e2e/utils/database-engines'; import { deleteDbClusterFn } from '@e2e/utils/db-cluster'; import { getTokenFromLocalStorage } from '@e2e/utils/localStorage'; -import { getClusterDetailedInfo } from '@e2e/utils/storage-class'; import { advancedConfigurationStepCheck } from './steps/advanced-configuration-step'; import { backupsStepCheck } from './steps/backups-step'; import { basicInformationStepCheck } from './steps/basic-information-step'; @@ -55,19 +54,12 @@ test.describe('DB Cluster creation', () => { psmdb: [], postgresql: [], }; - let storageClasses = []; // let monitoringInstancesList = []; const namespace = EVEREST_CI_NAMESPACES.EVEREST_UI; test.beforeAll(async ({ request }) => { const token = await getTokenFromLocalStorage(); engineVersions = await getEnginesVersions(token, namespace, request); - - const { storageClassNames = [] } = await getClusterDetailedInfo( - token, - request - ); - storageClasses = storageClassNames; }); test.beforeEach(async ({ page }) => { @@ -120,14 +112,12 @@ test.describe('DB Cluster creation', () => { request ); - expect(storageClasses.length).toBeGreaterThan(0); await selectDbEngine(page, 'psmdb'); await basicInformationStepCheck( page, engineVersions, recommendedEngineVersions, - storageClasses, clusterName ); @@ -240,7 +230,6 @@ test.describe('DB Cluster creation', () => { // '192.168.1.1/24', // '192.168.1.0', // ]); - expect(addedCluster?.spec.engine.storage.class).toBe(storageClasses[0]); expect(addedCluster?.spec.backup.schedules[0].retentionCopies).toBe(1); // Verify timezone conversion was applied to the schedule cron // Day 10, 1h05 in IST timezone is day 9, 19h35 UTC @@ -250,8 +239,6 @@ test.describe('DB Cluster creation', () => { test('PITR should be disabled when backups has no schedules checked', async ({ page, }) => { - expect(storageClasses.length).toBeGreaterThan(0); - await selectDbEngine(page, 'pxc'); // go to resources page await moveForward(page); @@ -278,7 +265,6 @@ test.describe('DB Cluster creation', () => { test.skip('Cancel wizard', async ({ page }) => { await page.getByTestId('mongodb-toggle-button').click(); await page.getByTestId('text-input-db-name').fill('new-cluster'); - await page.getByTestId('text-input-storage-class').click(); await page.getByRole('option').first().click(); await moveForward(page); @@ -332,7 +318,6 @@ test.describe('DB Cluster creation', () => { page, engineVersions, recommendedEngineVersions, - storageClasses, clusterName ); await moveForward(page); @@ -374,10 +359,9 @@ test.describe('DB Cluster creation', () => { await deleteDbClusterFn(request, clusterName, namespace); }); - test('Warning should appears for schedule with the same date and storage', async ({ + test('Warning should appears for schedule with the same date', async ({ page, }) => { - expect(storageClasses.length).toBeGreaterThan(0); await selectDbEngine(page, 'psmdb'); // Resources Step @@ -395,9 +379,7 @@ test.describe('DB Cluster creation', () => { test('Reset schedules, PITR and monitoring when changing namespace', async ({ page, }) => { - expect(storageClasses.length).toBeGreaterThan(0); await selectDbEngine(page, 'psmdb'); - await expect(page.getByText(storageClasses[0])).toBeVisible(); await moveForward(page); await moveForward(page); await addFirstScheduleInDBWizard(page); diff --git a/ui/apps/everest/.e2e/pr/db-cluster/db-wizard/create-db-cluster/steps/basic-information-step.ts b/ui/apps/everest/.e2e/pr/db-cluster/db-wizard/create-db-cluster/steps/basic-information-step.ts index b9767470f..dd45773bc 100644 --- a/ui/apps/everest/.e2e/pr/db-cluster/db-wizard/create-db-cluster/steps/basic-information-step.ts +++ b/ui/apps/everest/.e2e/pr/db-cluster/db-wizard/create-db-cluster/steps/basic-information-step.ts @@ -19,7 +19,6 @@ export const basicInformationStepCheck = async ( page: Page, engineVersions, recommendedEngineVersions, - storageClasses, clusterName ) => { expect( @@ -29,12 +28,11 @@ export const basicInformationStepCheck = async ( const dbVersionOptions = page.getByRole('option'); - engineVersions.psmdb.forEach( - async (version) => - await expect( - dbVersionOptions.filter({ hasText: new RegExp(`^${version}$`) }) - ).toBeVisible() - ); + for (const version of engineVersions.psmdb) { + await expect( + dbVersionOptions.filter({ hasText: new RegExp(`^${version}$`) }) + ).toBeVisible(); + } const defaultOption = await page.getByRole('option', { selected: true }); expect(await defaultOption.textContent()).toBe( @@ -43,19 +41,7 @@ export const basicInformationStepCheck = async ( await page.getByRole('option').filter({ hasText: '6.0.9-7' }).click(); await page.getByTestId('text-input-db-name').fill(clusterName); - await page.getByTestId('text-input-storage-class').click(); expect( await page.getByTestId('switch-input-sharding').getByRole('checkbox') ).not.toBeDisabled(); - - const storageClassOptions = page.getByRole('option'); - - storageClasses.forEach( - async (className) => - await expect( - storageClassOptions.filter({ hasText: new RegExp(`^${className}$`) }) - ).toBeVisible() - ); - - await page.getByRole('option').first().click(); }; diff --git a/ui/apps/everest/src/components/advanced-card/advanced-card.tsx b/ui/apps/everest/src/components/advanced-card/advanced-card.tsx new file mode 100644 index 000000000..5375e79b7 --- /dev/null +++ b/ui/apps/everest/src/components/advanced-card/advanced-card.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { Card, CardContent, Typography, Box } from '@mui/material'; + +type AdvancedCardProps = { + title: string; + description: string | React.ReactNode; + controlComponent: React.ReactNode; + gapFromText?: number; +}; + +const AdvancedCard: React.FC = ({ + title, + description, + controlComponent, + gapFromText = 48, +}) => { + return ( + + + + + {title} + + {controlComponent} + + {typeof description === 'string' ? ( + + {description} + + ) : ( + {description} + )} + + + ); +}; + +export default AdvancedCard; diff --git a/ui/apps/everest/src/components/advanced-card/index.ts b/ui/apps/everest/src/components/advanced-card/index.ts new file mode 100644 index 000000000..44cb1e769 --- /dev/null +++ b/ui/apps/everest/src/components/advanced-card/index.ts @@ -0,0 +1 @@ +export { default } from './advanced-card'; diff --git a/ui/apps/everest/src/components/cluster-form/advanced-configuration/advanced-configuration-schema.ts b/ui/apps/everest/src/components/cluster-form/advanced-configuration/advanced-configuration-schema.ts index e5ad8b92c..b44e392ee 100644 --- a/ui/apps/everest/src/components/cluster-form/advanced-configuration/advanced-configuration-schema.ts +++ b/ui/apps/everest/src/components/cluster-form/advanced-configuration/advanced-configuration-schema.ts @@ -21,6 +21,17 @@ import { Messages } from './messages'; export const advancedConfigurationsSchema = () => z .object({ + [AdvancedConfigurationFields.storageClass]: z + .string() + .nullable() + .superRefine((input, ctx) => { + if (!input) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: Messages.errors.storageClass.invalid, + }); + } + }), [AdvancedConfigurationFields.externalAccess]: z.boolean(), [AdvancedConfigurationFields.sourceRanges]: z.array( z.object({ sourceRange: z.string().optional() }) diff --git a/ui/apps/everest/src/components/cluster-form/advanced-configuration/advanced-configuration.tsx b/ui/apps/everest/src/components/cluster-form/advanced-configuration/advanced-configuration.tsx index 5bc4a815c..a31f136ea 100644 --- a/ui/apps/everest/src/components/cluster-form/advanced-configuration/advanced-configuration.tsx +++ b/ui/apps/everest/src/components/cluster-form/advanced-configuration/advanced-configuration.tsx @@ -13,29 +13,80 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { SwitchInput, TextArray, TextInput } from '@percona/ui-lib'; +import { + AutoCompleteInput, + SwitchInput, + TextArray, + TextInput, +} from '@percona/ui-lib'; import { Messages } from './messages'; import { AdvancedConfigurationFields } from './advanced-configuration.types'; import { useFormContext } from 'react-hook-form'; import { DbType } from '@percona/types'; import { getParamsPlaceholderFromDbType } from './advanced-configuration.utils'; import { Stack } from '@mui/material'; +import { useKubernetesClusterInfo } from 'hooks/api/kubernetesClusters/useKubernetesClusterInfo'; +import { useEffect } from 'react'; +import { DbWizardFormFields } from 'consts'; +import { useDatabasePageMode } from 'pages/database-form/useDatabasePageMode'; +import AdvancedCard from 'components/advanced-card'; interface AdvancedConfigurationFormProps { dbType: DbType; + loadingDefaultsForEdition?: boolean; } export const AdvancedConfigurationForm = ({ dbType, + loadingDefaultsForEdition, }: AdvancedConfigurationFormProps) => { - const { watch } = useFormContext(); + const { watch, setValue, getFieldState } = useFormContext(); + const mode = useDatabasePageMode(); const [externalAccess, engineParametersEnabled] = watch([ AdvancedConfigurationFields.externalAccess, AdvancedConfigurationFields.engineParametersEnabled, + AdvancedConfigurationFields.storageClass, ]); + const { data: clusterInfo, isLoading: clusterInfoLoading } = + useKubernetesClusterInfo(['wizard-k8-info']); + // setting the storage class default value + useEffect(() => { + const { isTouched: storageClassTouched } = getFieldState( + DbWizardFormFields.storageClass + ); + + if ( + !storageClassTouched && + mode === 'new' && + clusterInfo?.storageClassNames && + clusterInfo.storageClassNames.length > 0 + ) { + setValue( + DbWizardFormFields.storageClass, + clusterInfo?.storageClassNames[0] + ); + } + }, [clusterInfo]); return ( <> + + } + /> { const methods = useForm({ @@ -25,7 +28,12 @@ describe('FourthStep', () => { render( - + + + ); @@ -45,7 +53,12 @@ describe('FourthStep', () => { render( - + + + ); diff --git a/ui/apps/everest/src/pages/database-form/database-form-body/steps/advanced-configurations/advanced-configurations.tsx b/ui/apps/everest/src/pages/database-form/database-form-body/steps/advanced-configurations/advanced-configurations.tsx index 6cc2a15be..69c43ccc6 100644 --- a/ui/apps/everest/src/pages/database-form/database-form-body/steps/advanced-configurations/advanced-configurations.tsx +++ b/ui/apps/everest/src/pages/database-form/database-form-body/steps/advanced-configurations/advanced-configurations.tsx @@ -20,8 +20,11 @@ import { DbWizardFormFields } from 'consts.ts'; import { StepHeader } from '../step-header/step-header.tsx'; import AdvancedConfigurationForm from 'components/cluster-form/advanced-configuration/advanced-configuration.tsx'; import { FormGroup } from '@mui/material'; +import { StepProps } from 'pages/database-form/database-form.types.ts'; -export const AdvancedConfigurations = () => { +export const AdvancedConfigurations = ({ + loadingDefaultsForEdition, +}: StepProps) => { const { watch } = useFormContext(); const dbType = watch(DbWizardFormFields.dbType); @@ -29,7 +32,10 @@ export const AdvancedConfigurations = () => { <> - + ); diff --git a/ui/apps/everest/src/pages/database-form/database-form-body/steps/first/first-step.messages.ts b/ui/apps/everest/src/pages/database-form/database-form-body/steps/first/first-step.messages.ts index 536ceade4..7791e4f50 100644 --- a/ui/apps/everest/src/pages/database-form/database-form-body/steps/first/first-step.messages.ts +++ b/ui/apps/everest/src/pages/database-form/database-form-body/steps/first/first-step.messages.ts @@ -21,7 +21,6 @@ export const Messages = { k8sNamespace: 'Namespace', dbEnvironment: 'Database environment', dbVersion: 'Database version', - storageClass: 'Storage class', shardedCluster: 'Sharded Cluster', }, placeholders: { diff --git a/ui/apps/everest/src/pages/database-form/database-form-body/steps/first/first-step.test.tsx b/ui/apps/everest/src/pages/database-form/database-form-body/steps/first/first-step.test.tsx index 90c3f9143..37305d7f5 100644 --- a/ui/apps/everest/src/pages/database-form/database-form-body/steps/first/first-step.test.tsx +++ b/ui/apps/everest/src/pages/database-form/database-form-body/steps/first/first-step.test.tsx @@ -66,7 +66,6 @@ vi.mock('api/kubernetesClusterApi', () => ({ getKubernetesClusterInfoFn: vi.fn(() => Promise.resolve({ clusterType: 'generic', - storageClassNames: ['local-path'], }) ), })); diff --git a/ui/apps/everest/src/pages/database-form/database-form-body/steps/first/first-step.tsx b/ui/apps/everest/src/pages/database-form/database-form-body/steps/first/first-step.tsx index 29635f7c6..775aa6a00 100644 --- a/ui/apps/everest/src/pages/database-form/database-form-body/steps/first/first-step.tsx +++ b/ui/apps/everest/src/pages/database-form/database-form-body/steps/first/first-step.tsx @@ -25,7 +25,6 @@ import { TextInput, } from '@percona/ui-lib'; import { dbTypeToDbEngine } from '@percona/utils'; -import { useKubernetesClusterInfo } from 'hooks/api/kubernetesClusters/useKubernetesClusterInfo'; import { useFormContext } from 'react-hook-form'; import { DbEngineToolStatus } from 'shared-types/dbEngines.types'; import { @@ -57,9 +56,6 @@ export const FirstStep = ({ loadingDefaultsForEdition }: StepProps) => { const { watch, setValue, getFieldState, resetField, trigger } = useFormContext(); - const { data: clusterInfo, isLoading: clusterInfoLoading } = - useKubernetesClusterInfo(['wizard-k8-info']); - const dbType: DbType = watch(DbWizardFormFields.dbType); const dbVersion: DbType = watch(DbWizardFormFields.dbVersion); const dbNamespace = watch(DbWizardFormFields.k8sNamespace); @@ -102,25 +98,6 @@ export const FirstStep = ({ loadingDefaultsForEdition }: StepProps) => { const disableSharding = mode !== 'new' || notSupportedMongoOperatorVersionForSharding; - // setting the storage class default value - useEffect(() => { - const { isTouched: storageClassTouched } = getFieldState( - DbWizardFormFields.storageClass - ); - - if ( - !storageClassTouched && - mode === 'new' && - clusterInfo?.storageClassNames && - clusterInfo.storageClassNames.length > 0 - ) { - setValue( - DbWizardFormFields.storageClass, - clusterInfo?.storageClassNames[0] - ); - } - }, [clusterInfo]); - const { canCreate, isLoading } = useNamespacePermissionsForResource('database-clusters'); @@ -258,16 +235,6 @@ export const FirstStep = ({ loadingDefaultsForEdition }: StepProps) => { availableVersions={dbEngineData?.availableVersions.engine} loading={dbEnginesFoDbEngineTypesFetching || isLoading} /> - {dbType === DbType.Mongo && ( .nonempty(), [DbWizardFormFields.k8sNamespace]: z.string().nullable(), ...dbVersionSchemaObject, - [DbWizardFormFields.storageClass]: z - .string() - .nullable() - .superRefine((input, ctx) => { - if (!input) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: Messages.errors.storageClass.invalid, - }); - } - }), [DbWizardFormFields.sharding]: z.boolean(), }) .passthrough(); diff --git a/ui/apps/everest/src/pages/database-form/database-form.messages.ts b/ui/apps/everest/src/pages/database-form/database-form.messages.ts index 56f795ae7..ce54be3d5 100644 --- a/ui/apps/everest/src/pages/database-form/database-form.messages.ts +++ b/ui/apps/everest/src/pages/database-form/database-form.messages.ts @@ -35,9 +35,6 @@ export const Messages = { dbName: { tooLong: errorMessages.tooLong('database'), }, - storageClass: { - invalid: 'Invalid storage class', - }, monitoringEndpoint: { invalidOption: 'Invalid option. Please make sure you added a monitoring endpoint and select it from the dropdown', diff --git a/ui/apps/everest/src/pages/database-form/database-form.utils.ts b/ui/apps/everest/src/pages/database-form/database-form.utils.ts index c6e735ca7..fcd496d99 100644 --- a/ui/apps/everest/src/pages/database-form/database-form.utils.ts +++ b/ui/apps/everest/src/pages/database-form/database-form.utils.ts @@ -130,9 +130,6 @@ export const DbClusterPayloadToFormValues = ( ).toString(), 'G' ).value, - [DbWizardFormFields.storageClass]: - dbCluster?.spec?.engine?.storage?.class || null, - //backups [DbWizardFormFields.backupsEnabled]: (backup?.schedules || []).length > 0, diff --git a/ui/apps/everest/src/pages/database-form/database-preview/sections/advanced-configurations-section.tsx b/ui/apps/everest/src/pages/database-form/database-preview/sections/advanced-configurations-section.tsx index 685cc4e53..e7ade3b0d 100644 --- a/ui/apps/everest/src/pages/database-form/database-preview/sections/advanced-configurations-section.tsx +++ b/ui/apps/everest/src/pages/database-form/database-preview/sections/advanced-configurations-section.tsx @@ -5,8 +5,10 @@ export const AdvancedConfigurationsPreviewSection = ({ externalAccess, engineParametersEnabled, engineParameters, + storageClass, }: AdvancedConfigurationType) => ( <> + diff --git a/ui/apps/everest/src/pages/database-form/database-preview/sections/section-one.tsx b/ui/apps/everest/src/pages/database-form/database-preview/sections/section-one.tsx index c16d9b428..9d99d2c04 100644 --- a/ui/apps/everest/src/pages/database-form/database-preview/sections/section-one.tsx +++ b/ui/apps/everest/src/pages/database-form/database-preview/sections/section-one.tsx @@ -7,7 +7,6 @@ export const PreviewSectionOne = ({ dbName, dbVersion, dbType, - storageClass, k8sNamespace, sharding, }: SectionProps) => ( @@ -16,7 +15,6 @@ export const PreviewSectionOne = ({ - {dbType === DbType.Mongo && ( { handleSubmitModal({ externalAccess, engineParametersEnabled, engineParameters, sourceRanges, + storageClass, }); };