From b32222d73d2641c360d37ae05a6a31eb28b44da7 Mon Sep 17 00:00:00 2001 From: Lingeshwar S Date: Thu, 19 Sep 2024 07:54:25 +0530 Subject: [PATCH] [PLAT-15280][PLAT-14753] - Pg parity improvements and other ui fixes Summary: **[PLAT-15280]** Show Reminder modal for **ANALYZE** statement whenever pg toggle is enabled both in create and edit flow. **[PLAT-14753]** Access keys getting overwritten on edit universe page. This is because old code was not handling multiple access keys for a provider. **Others** - Changes label Internal YSQL Port - Do not show empty tooltip for connection pooling Test Plan: Tested manually **Screenshot** {F287332} Reviewers: kkannan Reviewed By: kkannan Subscribers: ui, yugaware Differential Revision: https://phorge.dev.yugabyte.com/D38191 --- managed/ui/src/redesign/assets/reminder.svg | 4 + .../edit-pg-compatibility/AnalyzeDialog.tsx | 75 +++++++++++++++++++ .../EditPGCompatibilityModal.tsx | 34 +++++++-- .../AccessKeysField/AccessKeysField.tsx | 25 ++++--- .../ConnectionPoolingField.tsx | 21 ++++-- .../PGCompatibilityField.tsx | 10 ++- .../advanced/AdvancedConfiguration.tsx | 2 +- managed/ui/src/translations/en.json | 25 ++++--- 8 files changed, 158 insertions(+), 38 deletions(-) create mode 100644 managed/ui/src/redesign/assets/reminder.svg create mode 100644 managed/ui/src/redesign/features/universe/universe-actions/edit-pg-compatibility/AnalyzeDialog.tsx diff --git a/managed/ui/src/redesign/assets/reminder.svg b/managed/ui/src/redesign/assets/reminder.svg new file mode 100644 index 000000000000..0a53776f2bd8 --- /dev/null +++ b/managed/ui/src/redesign/assets/reminder.svg @@ -0,0 +1,4 @@ + + + + diff --git a/managed/ui/src/redesign/features/universe/universe-actions/edit-pg-compatibility/AnalyzeDialog.tsx b/managed/ui/src/redesign/features/universe/universe-actions/edit-pg-compatibility/AnalyzeDialog.tsx new file mode 100644 index 000000000000..bd93a8ef4a4d --- /dev/null +++ b/managed/ui/src/redesign/features/universe/universe-actions/edit-pg-compatibility/AnalyzeDialog.tsx @@ -0,0 +1,75 @@ +import { FC } from 'react'; +import { useTranslation, Trans } from 'react-i18next'; +import { Box, makeStyles, Typography, Chip, Link } from '@material-ui/core'; +import { YBModal } from '../../../../components'; + +//icons +import { ReactComponent as ReminderIcon } from '../../../../assets/reminder.svg'; + +interface AnalyzeDialogProps { + open: boolean; + onClose: () => void; +} + +const useStyles = makeStyles((theme) => ({ + innerContainer: { + height: 'auto', + display: 'flex', + flexDirection: 'column', + padding: theme.spacing(2), + backgroundColor: '#FCFCFC', + border: '1px solid #D7DEE4', + borderRadius: '8px' + }, + chip: { + height: 24, + width: 'fit-content', + padding: '4px 6px', + borderRadius: '6px', + backgroundColor: '#FFFFFF', + border: '1px solid #D7DEE4', + fontFamily: 'Menio', + color: '#0B1117', + fontSize: '13px', + fontWeight: 400 + } +})); + +export const AnalyzeDialog: FC = ({ open, onClose }) => { + const classes = useStyles(); + const { t } = useTranslation(); + return ( + } + onClose={onClose} + cancelLabel={t('common.close')} + cancelTestId="AnalyzeDialog-Cancel" + overrideHeight={'auto'} + overrideWidth={'600px'} + dialogContentProps={{ style: { padding: '32px 16px 32px 24px' }, dividers: true }} + > + + + +
+
+ {t('universeActions.pgCompatibility.analyzeModal.msg2')}  + +   + {t('universeActions.pgCompatibility.analyzeModal.msg3')} +
+
+ + {t('universeActions.pgCompatibility.analyzeModal.learnLink')} + +
+
+
+ ); +}; diff --git a/managed/ui/src/redesign/features/universe/universe-actions/edit-pg-compatibility/EditPGCompatibilityModal.tsx b/managed/ui/src/redesign/features/universe/universe-actions/edit-pg-compatibility/EditPGCompatibilityModal.tsx index 740696265bcf..3a36903df7f4 100644 --- a/managed/ui/src/redesign/features/universe/universe-actions/edit-pg-compatibility/EditPGCompatibilityModal.tsx +++ b/managed/ui/src/redesign/features/universe/universe-actions/edit-pg-compatibility/EditPGCompatibilityModal.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react'; +import { FC, useState } from 'react'; import { get, cloneDeep } from 'lodash'; import { toast } from 'react-toastify'; import { useForm } from 'react-hook-form'; @@ -6,6 +6,7 @@ import { useMutation } from 'react-query'; import { useTranslation, Trans } from 'react-i18next'; import { Box, makeStyles, Typography, Link } from '@material-ui/core'; import { YBModal, YBToggleField } from '../../../../components'; +import { AnalyzeDialog } from './AnalyzeDialog'; import { getPrimaryCluster, createErrorMessage, @@ -108,13 +109,17 @@ export const EditPGCompatibilityModal: FC = ({ const universeName = get(primaryCluster, 'userIntent.universeName'); const currentRF = get(primaryCluster, 'userIntent.replicationFactor'); const isPGEnabled = primaryCluster ? isPGEnabledFromIntent(primaryCluster?.userIntent) : false; + const [openAnalyzeModal, setAnalyzeModal] = useState(false); - const { control, handleSubmit, watch } = useForm({ + const { control, watch, getValues } = useForm({ defaultValues: { enablePGCompatibitilty: isPGEnabled ? true : false } }); + //watchers + const pgToggleValue = watch('enablePGCompatibitilty'); + const upgradePGCompatibility = useMutation( (values: EditGflagPayload) => { return api.upgradeGflags(values, universeUUID); @@ -129,10 +134,7 @@ export const EditPGCompatibilityModal: FC = ({ } ); - //watchers - const pgToggleValue = watch('enablePGCompatibitilty'); - - const handleFormSubmit = handleSubmit(async (formValues) => { + const handleFormSubmit = async (formValues: PGFormValues) => { try { const payload: EditGflagPayload = { nodePrefix, @@ -169,7 +171,15 @@ export const EditPGCompatibilityModal: FC = ({ } catch (e) { console.error(createErrorMessage(e)); } - }); + }; + + const onFormSubmit = () => { + if (pgToggleValue) setAnalyzeModal(true); + else { + const formValues = getValues(); + handleFormSubmit(formValues); + } + }; const canEditGFlags = hasNecessaryPerm({ onResource: universeUUID, @@ -183,7 +193,7 @@ export const EditPGCompatibilityModal: FC = ({ submitLabel={t('common.applyChanges')} cancelLabel={t('common.cancel')} onClose={onClose} - onSubmit={handleFormSubmit} + onSubmit={onFormSubmit} overrideHeight={'420px'} overrideWidth={'600px'} submitTestId="EditPGCompatibilityModal-Submit" @@ -277,6 +287,14 @@ export const EditPGCompatibilityModal: FC = ({ )} )} + { + setAnalyzeModal(false); + const formValues = getValues(); + handleFormSubmit(formValues); + }} + /> ); diff --git a/managed/ui/src/redesign/features/universe/universe-form/form/fields/AccessKeysField/AccessKeysField.tsx b/managed/ui/src/redesign/features/universe/universe-form/form/fields/AccessKeysField/AccessKeysField.tsx index 00c116528a1f..5ea221baec23 100644 --- a/managed/ui/src/redesign/features/universe/universe-form/form/fields/AccessKeysField/AccessKeysField.tsx +++ b/managed/ui/src/redesign/features/universe/universe-form/form/fields/AccessKeysField/AccessKeysField.tsx @@ -8,8 +8,6 @@ import { YBLabel, YBSelectField } from '../../../../../../components'; import { AccessKey, UniverseFormData } from '../../../utils/dto'; import { ACCESS_KEY_FIELD, PROVIDER_FIELD } from '../../../utils/constants'; import { useFormFieldStyles } from '../../../universeMainStyle'; -import { YBProvider } from '../../../../../../../components/configRedesign/providerRedesign/types'; -import { ProviderCode } from '../../../../../../../components/configRedesign/providerRedesign/constants'; const useStyles = makeStyles((theme) => ({ overrideMuiSelectMenu: { @@ -21,9 +19,10 @@ const useStyles = makeStyles((theme) => ({ interface AccessKeysFieldProps { disabled?: boolean; + isEditMode?: boolean; } -export const AccessKeysField = ({ disabled }: AccessKeysFieldProps): ReactElement => { +export const AccessKeysField = ({ disabled, isEditMode }: AccessKeysFieldProps): ReactElement => { const { control, setValue } = useFormContext(); const { t } = useTranslation(); const classes = useFormFieldStyles(); @@ -45,19 +44,23 @@ export const AccessKeysField = ({ disabled }: AccessKeysFieldProps): ReactElemen const accessKeys = allAccessKeys.data.filter( (item: AccessKey) => item?.idKey?.providerUUID === provider?.uuid ); - if (accessKeys?.length) { - setValue(ACCESS_KEY_FIELD, accessKeys[0]?.idKey.keyCode, { shouldValidate: true }); - } else { - setValue(ACCESS_KEY_FIELD, null, { shouldValidate: true }); + if (!isEditMode) { + if (accessKeys?.length) { + setValue(ACCESS_KEY_FIELD, accessKeys[0]?.idKey.keyCode, { shouldValidate: true }); + } else { + setValue(ACCESS_KEY_FIELD, null, { shouldValidate: true }); + } } }, [provider]); //only first time useEffectOnce(() => { - if (accessKeysList?.length && provider?.uuid) { - setValue(ACCESS_KEY_FIELD, accessKeysList[0]?.idKey.keyCode, { shouldValidate: true }); - } else { - setValue(ACCESS_KEY_FIELD, null, { shouldValidate: true }); + if (!isEditMode) { + if (accessKeysList?.length && provider?.uuid) { + setValue(ACCESS_KEY_FIELD, accessKeysList[0]?.idKey.keyCode, { shouldValidate: true }); + } else { + setValue(ACCESS_KEY_FIELD, null, { shouldValidate: true }); + } } }); diff --git a/managed/ui/src/redesign/features/universe/universe-form/form/fields/ConnectionPoolingField/ConnectionPoolingField.tsx b/managed/ui/src/redesign/features/universe/universe-form/form/fields/ConnectionPoolingField/ConnectionPoolingField.tsx index fdcb09b5e30d..3f93d20cf612 100644 --- a/managed/ui/src/redesign/features/universe/universe-form/form/fields/ConnectionPoolingField/ConnectionPoolingField.tsx +++ b/managed/ui/src/redesign/features/universe/universe-form/form/fields/ConnectionPoolingField/ConnectionPoolingField.tsx @@ -51,15 +51,20 @@ export const ConnectionPoolingField: FC = ({ disabled return ( - {isYSQLEnabled - ? isConnectionPoolSupported - ? '' - : t('universeForm.advancedConfig.conPoolVersionTooltip') - : t('universeForm.advancedConfig.conPoolYSQLWarn')} - + isYSQLEnabled ? ( + isConnectionPoolSupported ? ( + '' + ) : ( + + {t('universeForm.advancedConfig.conPoolVersionTooltip')} + + ) + ) : ( + + {t('universeForm.advancedConfig.conPoolYSQLWarn')} + + ) } >
diff --git a/managed/ui/src/redesign/features/universe/universe-form/form/fields/PGCompatibilityField/PGCompatibilityField.tsx b/managed/ui/src/redesign/features/universe/universe-form/form/fields/PGCompatibilityField/PGCompatibilityField.tsx index 8b55e9a4b53a..158fc86224ed 100644 --- a/managed/ui/src/redesign/features/universe/universe-form/form/fields/PGCompatibilityField/PGCompatibilityField.tsx +++ b/managed/ui/src/redesign/features/universe/universe-form/form/fields/PGCompatibilityField/PGCompatibilityField.tsx @@ -1,9 +1,10 @@ -import { FC } from 'react'; +import { FC, useState } from 'react'; import { useUpdateEffect } from 'react-use'; import { useTranslation, Trans } from 'react-i18next'; import { Box, makeStyles, Typography, Link } from '@material-ui/core'; import { useFormContext, useWatch } from 'react-hook-form'; import { YBToggleField, YBLabel, YBTooltip } from '../../../../../../components'; +import { AnalyzeDialog } from '../../../../universe-actions/edit-pg-compatibility/AnalyzeDialog'; import { isVersionPGSupported } from '../../../utils/helpers'; import { UniverseFormData } from '../../../utils/dto'; import { PG_COMPATIBILITY_FIELD, SOFTWARE_VERSION_FIELD } from '../../../utils/constants'; @@ -41,11 +42,13 @@ const useStyles = makeStyles((theme) => ({ export const PGCompatibiltyField: FC = ({ disabled }) => { const { control, setValue } = useFormContext(); + const [openAnalyzeModal, setAnalyzeModal] = useState(false); const classes = useStyles(); const { t } = useTranslation(); //watchers const dbVersionValue = useWatch({ name: SOFTWARE_VERSION_FIELD }); + const pgValue = useWatch({ name: PG_COMPATIBILITY_FIELD }); const isPGSupported = isVersionPGSupported(dbVersionValue); @@ -54,6 +57,10 @@ export const PGCompatibiltyField: FC = ({ disabled }) if (!isVersionPGSupported(dbVersionValue)) setValue(PG_COMPATIBILITY_FIELD, false); }, [dbVersionValue]); + useUpdateEffect(() => { + if (pgValue) setAnalyzeModal(true); + }, [pgValue]); + return ( = ({ disabled }) + setAnalyzeModal(false)} /> ); }; diff --git a/managed/ui/src/redesign/features/universe/universe-form/form/sections/advanced/AdvancedConfiguration.tsx b/managed/ui/src/redesign/features/universe/universe-form/form/sections/advanced/AdvancedConfiguration.tsx index 4b09d1a21b58..5fae4d92efde 100644 --- a/managed/ui/src/redesign/features/universe/universe-form/form/sections/advanced/AdvancedConfiguration.tsx +++ b/managed/ui/src/redesign/features/universe/universe-form/form/sections/advanced/AdvancedConfiguration.tsx @@ -65,7 +65,7 @@ export const AdvancedConfiguration = ({ runtimeConfigs }: UniverseFormConfigurat {provider.code !== CloudType.kubernetes && ( - + )} {provider.code === CloudType.aws && ( diff --git a/managed/ui/src/translations/en.json b/managed/ui/src/translations/en.json index 657cd41b8742..e766f8f844d4 100644 --- a/managed/ui/src/translations/en.json +++ b/managed/ui/src/translations/en.json @@ -41,6 +41,7 @@ "and": "and", "learnMore": "Learn more", "clear": "Clear", + "reminder": "Reminder", "duration": { "seconds": "Seconds", "minutes": "Minutes", @@ -250,7 +251,13 @@ "disableWarning2": "Requires a rolling restart of {{universeName}}. The universe will remain online and available throughout.", "disableWarning3": "May impact performance.", "disableWarning1RF1": "Note! Disabling enhanced Postgres compatibility requires a restart of {{universeName}} and may impact performance.", - "disableWarning2RF1": "The universe won't be available for reads and writes during the restart." + "disableWarning2RF1": "The universe won't be available for reads and writes during the restart.", + "analyzeModal": { + "msg1": "Enabling Enhanced Postgres Compatibility also enables the Cost Based Optimizer (CBO).", + "msg2": "You must run", + "msg3": "on user tables after data load for the CBO to create optimal execution plans.", + "learnLink": "Learn more about ANALYZE" + } }, "connectionPooling": { "modalTitle": "Edit Connection Pooling", @@ -326,7 +333,7 @@ "yqlServerRpcPort": "YCQL RPC Port", "ysqlServerHttpPort": "YSQL HTTP Port", "ysqlServerRpcPort": "YSQL RPC Port", - "internalYsqlServerRpcPort": "YSQL Database Port", + "internalYsqlServerRpcPort": "Internal YSQL Port", "enhancePGCompatibility": "Enhanced Postgres Compatibility", "earlyAccess": "Early Access", "pgSubText": "Configure YSQL for maximum Postgres compatibility by enabling
early access features. <1>Learn more", @@ -2704,16 +2711,16 @@ "deleteMsg": "scheduled backup policy is being deleted", "editModal": { "title": "Edit Scheduled Backup Policy", - "backupStrategy":"Backup Strategy", + "backupStrategy": "Backup Strategy", "success": "Scheduled backup policy is being updated" }, "deleteModal": { - "deleteMsg":"Are you sure you want to delete this schedule policy?" + "deleteMsg": "Are you sure you want to delete this schedule policy?" }, "showIntervalModal": { "title": "Backup Intervals", - "fullBackup":"Full Backup", - "incrementalBackup":"Incremental Backup" + "fullBackup": "Full Backup", + "incrementalBackup": "Incremental Backup" }, "backupTables": "Backup Tables" } @@ -2769,11 +2776,11 @@ "parallelThreads": "Parallel threads (Optional)" }, "validationErrMsg": { - "keyspacesAlreadyExists":"Keyspace already exists in the target Universe", + "keyspacesAlreadyExists": "Keyspace already exists in the target Universe", "pitrMillisOptions.secs": "Secs must be between 0 to 59", "kmsConfigRequired": "KMS Config is required", - "invalidKeyspaceName":"Invalid keyspace name", - "duplicateKeyspaceName":"Duplicate keyspace name given" + "invalidKeyspaceName": "Invalid keyspace name", + "duplicateKeyspaceName": "Duplicate keyspace name given" } } },