diff --git a/managed/RUNTIME-FLAGS.md b/managed/RUNTIME-FLAGS.md index 443e3905fdf9..9b47f257233a 100644 --- a/managed/RUNTIME-FLAGS.md +++ b/managed/RUNTIME-FLAGS.md @@ -11,6 +11,7 @@ | "Use Redesigned Provider UI" | "yb.ui.feature_flags.provider_redesign" | "CUSTOMER" | "The redesigned provider UI adds a provider list view, a provider details view and improves the provider creation form for AWS, AZU, GCP, and K8s" | "Boolean" | | "Enable partial editing of in use providers" | "yb.ui.feature_flags.edit_in_use_provider" | "CUSTOMER" | "A subset of fields from in use providers can be edited. Users can edit in use providers directly through the YBA API. This config is used to enable this functionality through YBA UI as well." | "Boolean" | | "Show underlying xCluster configs from DR setup" | "yb.ui.xcluster.dr.show_xcluster_config" | "CUSTOMER" | "YBA creates an underlying transactional xCluster config when setting up an active-active single-master disaster recovery (DR) config. During regular operation you should manage the DR config through the DR UI instead of the xCluster UI. This feature flag serves as a way to expose the underlying xCluster config for troubleshooting." | "Boolean" | +| "Enable the option to skip creating a full copy for xCluster operations" | "yb.ui.xcluster.enable_skip_bootstrapping" | "CUSTOMER" | "Enabling this runtime config will expose an option in the create xCluster modal and select tables modal to skip creating a full copy for xCluster replication configs." | "Boolean" | | "Enforce User Tags" | "yb.universe.user_tags.is_enforced" | "CUSTOMER" | "Prevents universe creation when the enforced tags are not provided." | "Boolean" | | "Enforced User Tags List" | "yb.universe.user_tags.enforced_tags" | "CUSTOMER" | "A list of enforced user tag and accepted value pairs during universe creation. Pass '*' to accept all values for a tag. Ex: [\"yb_task:dev\",\"yb_task:test\",\"yb_owner:*\",\"yb_dept:eng\",\"yb_dept:qa\", \"yb_dept:product\", \"yb_dept:sales\"]" | "Key Value SetMultimap" | | "Enable IMDSv2" | "yb.aws.enable_imdsv2_support" | "CUSTOMER" | "Enable IMDSv2 support for AWS providers" | "Boolean" | diff --git a/managed/src/main/java/com/yugabyte/yw/common/config/CustomerConfKeys.java b/managed/src/main/java/com/yugabyte/yw/common/config/CustomerConfKeys.java index 527ca26a5e53..cce6bf50d10a 100644 --- a/managed/src/main/java/com/yugabyte/yw/common/config/CustomerConfKeys.java +++ b/managed/src/main/java/com/yugabyte/yw/common/config/CustomerConfKeys.java @@ -143,6 +143,17 @@ public class CustomerConfKeys extends RuntimeConfigKeysModule { ConfDataType.BooleanType, ImmutableList.of(ConfKeyTags.PUBLIC)); + public static final ConfKeyInfo enableSkipBootstrapping = + new ConfKeyInfo<>( + "yb.ui.xcluster.enable_skip_bootstrapping", + ScopeType.CUSTOMER, + "Enable the option to skip creating a full copy for xCluster operations", + "Enabling this runtime config will expose an option in the create xCluster modal and" + + " select tables modal to skip creating a full copy for xCluster replication" + + " configs.", + ConfDataType.BooleanType, + ImmutableList.of(ConfKeyTags.PUBLIC)); + public static final ConfKeyInfo enforceUserTags = new ConfKeyInfo<>( "yb.universe.user_tags.is_enforced", diff --git a/managed/src/main/resources/reference.conf b/managed/src/main/resources/reference.conf index 524748fd6b44..e19106cab4d5 100644 --- a/managed/src/main/resources/reference.conf +++ b/managed/src/main/resources/reference.conf @@ -181,6 +181,7 @@ yb { } xcluster { + enable_skip_bootstrapping=false dr: { # Show underlying xCluster configs used in DR on the xCluster config tab # Relevant xCluster operations can and should be done through the DR UI instead. diff --git a/managed/ui/src/actions/xClusterReplication.ts b/managed/ui/src/actions/xClusterReplication.ts index c8f23e471808..8a5d936eb573 100644 --- a/managed/ui/src/actions/xClusterReplication.ts +++ b/managed/ui/src/actions/xClusterReplication.ts @@ -37,28 +37,42 @@ export function fetchTablesInUniverse( } return Promise.reject('Querying universe tables failed: No universe UUID provided.'); } +export interface CreateXClusterConfigRequest { + name: string; + sourceUniverseUUID: string; + targetUniverseUUID: string; + configType: XClusterConfigType; + tables: string[]; -export function createXClusterReplication( - targetUniverseUUID: string, - sourceUniverseUUID: string, - name: string, - configType: XClusterConfigType, - tables: string[], - bootstrapParams: { + bootstrapParams?: { tables: string[]; - backupRequestParams: any; - } | null -) { + allowBootstrapping: boolean; + backupRequestParams: { + storageConfigUUID: string; + }; + }; +} + +export interface EditXClusterConfigTablesRequest { + tables: string[]; + + autoIncludeIndexTables?: boolean; + bootstrapParams?: { + tables: string[]; + allowBootstrapping: boolean; + backupRequestParams: { + storageConfigUUID: string; + }; + }; +} + +export function createXClusterConfig(createxClusterConfigRequest: CreateXClusterConfigRequest) { const customerId = localStorage.getItem('customerId'); return axios - .post(`${ROOT_URL}/customers/${customerId}/xcluster_configs`, { - sourceUniverseUUID, - targetUniverseUUID, - name, - configType, - tables, - ...(bootstrapParams && { bootstrapParams }) - }) + .post( + `${ROOT_URL}/customers/${customerId}/xcluster_configs`, + createxClusterConfigRequest + ) .then((response) => response.data); } @@ -135,15 +149,6 @@ export function editXclusterName(replication: XClusterConfig) { }); } -interface EditXClusterConfigTablesRequest { - tables: string[]; - autoIncludeIndexTables?: boolean; - bootstrapParams?: { - tables: string[]; - backupRequestParams: any; - }; -} - export function editXClusterConfigTables( xClusterUUID: string, { tables, autoIncludeIndexTables, bootstrapParams }: EditXClusterConfigTablesRequest diff --git a/managed/ui/src/components/xcluster/createConfig/CreateConfigModal.tsx b/managed/ui/src/components/xcluster/createConfig/CreateConfigModal.tsx index a5cc2e47d0de..0cf39401043a 100644 --- a/managed/ui/src/components/xcluster/createConfig/CreateConfigModal.tsx +++ b/managed/ui/src/components/xcluster/createConfig/CreateConfigModal.tsx @@ -1,13 +1,14 @@ import { useState } from 'react'; import { AxiosError } from 'axios'; -import { Box, Typography, useTheme } from '@material-ui/core'; +import { Box, makeStyles, Typography, useTheme } from '@material-ui/core'; import { toast } from 'react-toastify'; import { useMutation, useQuery, useQueryClient } from 'react-query'; import { useTranslation } from 'react-i18next'; import { FormProvider, SubmitHandler, useForm } from 'react-hook-form'; import { - createXClusterReplication, + createXClusterConfig, + CreateXClusterConfigRequest, fetchTablesInUniverse, fetchTaskUntilItCompletes, fetchUniverseDiskUsageMetric @@ -19,7 +20,12 @@ import { parseFloatIfDefined } from '../ReplicationUtils'; import { assertUnreachableCase, handleServerError } from '../../../utils/errorHandlingUtils'; -import { api, drConfigQueryKey, universeQueryKey } from '../../../redesign/helpers/api'; +import { + api, + drConfigQueryKey, + runtimeConfigQueryKey, + universeQueryKey +} from '../../../redesign/helpers/api'; import { YBButton, YBModal, YBModalProps } from '../../../redesign/components'; import { StorageConfigOption } from '../sharedComponents/ReactSelectStorageConfig'; import { CurrentFormStep } from './CurrentFormStep'; @@ -29,6 +35,7 @@ import { XClusterConfigType, XCLUSTER_UNIVERSE_TABLE_FILTERS } from '../constants'; +import { RuntimeConfigKey } from '../../../redesign/helpers/constants'; import { XClusterTableType } from '../XClusterTypes'; import { TableType, TableTypeLabel, Universe, YBTable } from '../../../redesign/helpers/dtos'; @@ -72,6 +79,12 @@ export const FormStep = { } as const; export type FormStep = typeof FormStep[keyof typeof FormStep]; +const useStyles = makeStyles(() => ({ + secondarySubmitButton: { + marginLeft: 'auto' + } +})); + const MODAL_NAME = 'CreateConfigModal'; const FIRST_FORM_STEP = FormStep.SELECT_TARGET_UNIVERSE; const TRANSLATION_KEY_PREFIX = 'clusterDetail.xCluster.createConfigModal'; @@ -89,7 +102,7 @@ export const CreateConfigModal = ({ modalProps, sourceUniverseUuid }: CreateConf } | null>(null); const [bootstrapRequiredTableUUIDs, setBootstrapRequiredTableUUIDs] = useState([]); const [isTableSelectionValidated, setIsTableSelectionValidated] = useState(false); - + const [skipBootstrapping, setSkipBootStrapping] = useState(false); // The purpose of committedTargetUniverse is to store the targetUniverse field value prior // to the user submitting their target universe step. // This value updates whenever the user submits SelectTargetUniverseStep with a new @@ -100,24 +113,32 @@ export const CreateConfigModal = ({ modalProps, sourceUniverseUuid }: CreateConf const { t } = useTranslation('translation', { keyPrefix: TRANSLATION_KEY_PREFIX }); const queryClient = useQueryClient(); const theme = useTheme(); + const classes = useStyles(); const xClusterConfigMutation = useMutation( (formValues: CreateXClusterConfigFormValues) => { - return createXClusterReplication( - formValues.targetUniverse.value.universeUUID, - sourceUniverseUuid, - formValues.configName, - formValues.isTransactionalConfig ? XClusterConfigType.TXN : XClusterConfigType.BASIC, - formValues.tableUuids.map(formatUuidForXCluster), - bootstrapRequiredTableUUIDs.length > 0 - ? { + const createXClusterConfigRequest: CreateXClusterConfigRequest = { + name: formValues.configName, + sourceUniverseUUID: sourceUniverseUuid, + targetUniverseUUID: formValues.targetUniverse.value.universeUUID, + configType: formValues.isTransactionalConfig + ? XClusterConfigType.TXN + : XClusterConfigType.BASIC, + tables: formValues.tableUuids.map(formatUuidForXCluster), + + ...(!skipBootstrapping && + bootstrapRequiredTableUUIDs.length > 0 && { + bootstrapParams: { tables: bootstrapRequiredTableUUIDs, + allowBootstrapping: true, + backupRequestParams: { storageConfigUUID: formValues.storageConfig.value.uuid } } - : null - ); + }) + }; + return createXClusterConfig(createXClusterConfigRequest); }, { onSuccess: async (response, values) => { @@ -182,6 +203,11 @@ export const CreateConfigModal = ({ modalProps, sourceUniverseUuid }: CreateConf api.fetchUniverse(sourceUniverseUuid) ); + const customerUuid = localStorage.getItem('customerId') ?? ''; + const runtimeConfigQuery = useQuery(runtimeConfigQueryKey.customerScope(customerUuid), () => + api.fetchRuntimeConfigs(sourceUniverseUuid, true) + ); + const formMethods = useForm({ defaultValues: { namespaceUuids: [], @@ -195,19 +221,18 @@ export const CreateConfigModal = ({ modalProps, sourceUniverseUuid }: CreateConf }); const modalTitle = t('title'); - const cancelLabel = t('cancel', { keyPrefix: 'common' }); if ( sourceUniverseTablesQuery.isLoading || sourceUniverseTablesQuery.isIdle || sourceUniverseQuery.isLoading || - sourceUniverseQuery.isIdle + sourceUniverseQuery.isIdle || + runtimeConfigQuery.isLoading || + runtimeConfigQuery.isIdle ) { return ( - + ); } @@ -278,7 +306,11 @@ export const CreateConfigModal = ({ modalProps, sourceUniverseUuid }: CreateConf }; const sourceUniverseTables = sourceUniverseTablesQuery.data; - const onSubmit: SubmitHandler = async (formValues) => { + + const onSubmit = async ( + formValues: CreateXClusterConfigFormValues, + skipBootstrapping: boolean + ) => { // When the user changes target universe or table type, the old table selection is no longer valid. const isTableSelectionInvalidated = formValues.targetUniverse.value.universeUUID !== committedTargetUniverseUuid || @@ -319,6 +351,12 @@ export const CreateConfigModal = ({ modalProps, sourceUniverseUuid }: CreateConf return; } + setSkipBootStrapping(skipBootstrapping); + if (skipBootstrapping) { + setCurrentFormStep(FormStep.CONFIRM_ALERT); + return; + } + if (!isTableSelectionValidated) { let bootstrapTableUuids: string[] | null = null; const hasSelectionError = false; @@ -411,7 +449,11 @@ export const CreateConfigModal = ({ modalProps, sourceUniverseUuid }: CreateConf return assertUnreachableCase(currentFormStep); } }; - + const onFormSubmit: SubmitHandler = async (formValues) => + onSubmit(formValues, false); + const onSkipBootstrapAndSubmit: SubmitHandler = async ( + formValues + ) => onSubmit(formValues, true); const handleBackNavigation = () => { // We can clear errors here because prior steps have already been validated // and future steps will be revalidated when the user clicks the next page button. @@ -427,7 +469,7 @@ export const CreateConfigModal = ({ modalProps, sourceUniverseUuid }: CreateConf setCurrentFormStep(FormStep.SELECT_TABLES); return; case FormStep.CONFIRM_ALERT: - if (bootstrapRequiredTableUUIDs.length > 0) { + if (bootstrapRequiredTableUUIDs.length > 0 && !skipBootstrapping) { setCurrentFormStep(FormStep.CONFIGURE_BOOTSTRAP); } else { setCurrentFormStep(FormStep.SELECT_TABLES); @@ -481,16 +523,20 @@ export const CreateConfigModal = ({ modalProps, sourceUniverseUuid }: CreateConf const isTransactionalConfig = formMethods.watch('isTransactionalConfig'); const isFormDisabled = formMethods.formState.isSubmitting; + const runtimeConfigEntries = runtimeConfigQuery.data.configEntries ?? []; + const isSkipBootstrappingEnabled = runtimeConfigEntries.some( + (config: any) => + config.key === RuntimeConfigKey.ENABLE_XCLUSTER_SKIP_BOOTSTRAPPING && config.value === 'true' + ); return ( - {t('back', { keyPrefix: 'common' })} - - ) + <> + {currentFormStep !== FIRST_FORM_STEP && ( + + {t('back', { keyPrefix: 'common' })} + + )} + {currentFormStep === FormStep.SELECT_TABLES && + isBootstrapStepRequired && + isSkipBootstrappingEnabled && ( + + {t('step.selectTables.submitButton.skipBootstrapping')} + + )} + } {...modalProps} > diff --git a/managed/ui/src/components/xcluster/createConfig/SelectTargetUniverseStep.tsx b/managed/ui/src/components/xcluster/createConfig/SelectTargetUniverseStep.tsx index ae8d982469c9..fa1d21953737 100644 --- a/managed/ui/src/components/xcluster/createConfig/SelectTargetUniverseStep.tsx +++ b/managed/ui/src/components/xcluster/createConfig/SelectTargetUniverseStep.tsx @@ -278,7 +278,8 @@ export const SelectTargetUniverseStep = ({ - {!isTransactionalConfig && ( + {/* Txn xCluster is only available for YSQL. We don't warn for YCQL as we don't offer an alternative. */} + {!isTransactionalConfig && tableType === TableType.PGSQL_TABLE_TYPE && ( {t('warning.nonTxnXCluster')} diff --git a/managed/ui/src/components/xcluster/disasterRecovery/createConfig/CreateConfigModal.tsx b/managed/ui/src/components/xcluster/disasterRecovery/createConfig/CreateConfigModal.tsx index 7f434fe28a76..3778731667ff 100644 --- a/managed/ui/src/components/xcluster/disasterRecovery/createConfig/CreateConfigModal.tsx +++ b/managed/ui/src/components/xcluster/disasterRecovery/createConfig/CreateConfigModal.tsx @@ -334,11 +334,9 @@ export const CreateConfigModal = ({ modalProps, sourceUniverseUuid }: CreateConf ({ + secondarySubmitButton: { + marginLeft: 'auto' + } +})); + const MODAL_NAME = 'EditTablesModal'; const TRANSLATION_KEY_PREFIX = 'clusterDetail.disasterRecovery.config.editTablesModal'; const TRANSLATION_KEY_PREFIX_SELECT_TABLE = 'clusterDetail.xCluster.selectTable'; @@ -85,7 +93,9 @@ export const EditTablesModal = (props: EditTablesModalProps) => { } | null>(null); const [bootstrapRequiredTableUUIDs, setBootstrapRequiredTableUUIDs] = useState([]); const [isTableSelectionValidated, setIsTableSelectionValidated] = useState(false); + const [skipBootstrapping, setSkipBootStrapping] = useState(false); + const classes = useStyles(); const theme = useTheme(); const queryClient = useQueryClient(); const { t } = useTranslation('translation', { keyPrefix: TRANSLATION_KEY_PREFIX }); @@ -110,17 +120,13 @@ export const EditTablesModal = (props: EditTablesModalProps) => { universeQueryKey.namespaces(xClusterConfig.sourceUniverseUUID), () => api.fetchUniverseNamespaces(xClusterConfig.sourceUniverseUUID) ); + const customerUuid = localStorage.getItem('customerId') ?? ''; + const runtimeConfigQuery = useQuery(runtimeConfigQueryKey.customerScope(customerUuid), () => + api.fetchRuntimeConfigs(customerUuid, true) + ); + const editTableMutation = useMutation( (formValues: EditTablesFormValues) => { - const bootstrapParams = - bootstrapRequiredTableUUIDs.length > 0 - ? { - tables: bootstrapRequiredTableUUIDs, - backupRequestParams: { - storageConfigUUID: formValues.storageConfig?.value.uuid - } - } - : undefined; return props.isDrInterface ? api.updateTablesInDr(props.drConfigUuid, { tables: formValues.tableUuids @@ -128,7 +134,16 @@ export const EditTablesModal = (props: EditTablesModalProps) => { : editXClusterConfigTables(xClusterConfig.uuid, { tables: formValues.tableUuids, autoIncludeIndexTables: shouldAutoIncludeIndexTables(xClusterConfig), - bootstrapParams: bootstrapParams + ...(!skipBootstrapping && + bootstrapRequiredTableUUIDs.length > 0 && { + bootstrapParams: { + tables: bootstrapRequiredTableUUIDs, + allowBootstrapping: true, + backupRequestParams: { + storageConfigUUID: formValues.storageConfig.value.uuid + } + } + }) }); }, { @@ -175,23 +190,18 @@ export const EditTablesModal = (props: EditTablesModalProps) => { } ); const modalTitle = t('title'); - const cancelLabel = t('cancel', { keyPrefix: 'common' }); if ( sourceUniverseQuery.isLoading || sourceUniverseQuery.isIdle || sourceUniverseTablesQuery.isLoading || sourceUniverseTablesQuery.isIdle || sourceUniverseNamespacesQuery.isLoading || - sourceUniverseNamespacesQuery.isIdle + sourceUniverseNamespacesQuery.isIdle || + runtimeConfigQuery.isLoading || + runtimeConfigQuery.isIdle ) { return ( - + ); @@ -209,7 +219,8 @@ export const EditTablesModal = (props: EditTablesModalProps) => { sourceUniverseQuery.isError || sourceUniverseTablesQuery.isError || sourceUniverseNamespacesQuery.isError || - !xClusterConfigTableType + !xClusterConfigTableType || + runtimeConfigQuery.isError ) { const errorMessage = !xClusterConfig.sourceUniverseUUID ? t('error.undefinedSourceUniverseUuid') @@ -217,15 +228,11 @@ export const EditTablesModal = (props: EditTablesModalProps) => { ? t('error.undefinedTargetUniverseUuid') : !xClusterConfigTableType ? t('error.undefinedXClusterTableType', { keyPrefix: TRANSLATION_KEY_PREFIX_XCLUSTER }) + : runtimeConfigQuery.isError + ? t('failedToFetchCustomerRuntimeConfig', { keyPrefix: 'queryError' }) : t('error.fetchSourceUniverseDetailsFailure'); return ( - + ); @@ -281,7 +288,7 @@ export const EditTablesModal = (props: EditTablesModalProps) => { }; const sourceUniverse = sourceUniverseQuery.data; - const onSubmit: SubmitHandler = async (formValues) => { + const onSubmit = async (formValues: EditTablesFormValues, skipBootstrapping: boolean) => { switch (currentFormStep) { case FormStep.SELECT_TABLES: { setSelectionError(null); @@ -306,6 +313,11 @@ export const EditTablesModal = (props: EditTablesModalProps) => { return; } + setSkipBootStrapping(skipBootstrapping); + if (skipBootstrapping) { + return editTableMutation.mutateAsync(formValues); + } + if (!isTableSelectionValidated) { let bootstrapTableUuids: string[] | null = null; const hasSelectionError = false; @@ -399,6 +411,10 @@ export const EditTablesModal = (props: EditTablesModalProps) => { return assertUnreachableCase(currentFormStep); } }; + const onFormSubmit: SubmitHandler = async (formValues) => + onSubmit(formValues, false); + const onSkipBootstrapAndSubmit: SubmitHandler = async (formValues) => + onSubmit(formValues, true); const handleBackNavigation = () => { switch (currentFormStep) { @@ -417,9 +433,13 @@ export const EditTablesModal = (props: EditTablesModalProps) => { case FormStep.SELECT_TABLES: return isTableSelectionValidated ? bootstrapRequiredTableUUIDs.length > 0 - ? t('step.selectTables.nextButton') + ? t( + `step.selectTables.submitButton.configureBootstrap.${ + props.isDrInterface ? 'dr' : 'xCluster' + }` + ) : t('applyChanges', { keyPrefix: 'common' }) - : t('submitButton.validate'); + : t('step.selectTables.submitButton.validateSelection'); case FormStep.CONFIGURE_BOOTSTRAP: return t('applyChanges', { keyPrefix: 'common' }); default: @@ -431,25 +451,44 @@ export const EditTablesModal = (props: EditTablesModalProps) => { const selectedTableUuids = formMethods.watch('tableUuids'); const selectedNamespaceUuids = formMethods.watch('namespaceUuids'); const isFormDisabled = formMethods.formState.isSubmitting; + const runtimeConfigEntries = runtimeConfigQuery.data.configEntries ?? []; + const isSkipBootstrappingEnabled = runtimeConfigEntries.some( + (config: any) => + config.key === RuntimeConfigKey.ENABLE_XCLUSTER_SKIP_BOOTSTRAPPING && config.value === 'true' + ); return ( - {t('back', { keyPrefix: 'common' })} - - ) + <> + {currentFormStep !== FIRST_FORM_STEP && ( + + {t('back', { keyPrefix: 'common' })} + + )} + {currentFormStep === FormStep.SELECT_TABLES && + !props.isDrInterface && + isSkipBootstrappingEnabled && ( + + {t('step.selectTables.submitButton.skipBootstrapping')} + + )} + } {...modalProps} > diff --git a/managed/ui/src/components/xcluster/sharedComponents/tableSelect/TableSelect.tsx b/managed/ui/src/components/xcluster/sharedComponents/tableSelect/TableSelect.tsx index 9a7d274627bb..233fdb3b80e9 100644 --- a/managed/ui/src/components/xcluster/sharedComponents/tableSelect/TableSelect.tsx +++ b/managed/ui/src/components/xcluster/sharedComponents/tableSelect/TableSelect.tsx @@ -13,12 +13,7 @@ import { fetchTablesInUniverse, fetchXClusterConfig } from '../../../../actions/xClusterReplication'; -import { - api, - runtimeConfigQueryKey, - universeQueryKey, - xClusterQueryKey -} from '../../../../redesign/helpers/api'; +import { api, universeQueryKey, xClusterQueryKey } from '../../../../redesign/helpers/api'; import { YBControlledSelect, YBInputField } from '../../../common/forms/fields'; import { YBErrorIndicator, YBLoading } from '../../../common/indicators'; import { hasSubstringMatch } from '../../../queries/helpers/queriesHelper'; @@ -41,7 +36,6 @@ import { ExpandedTableSelect } from './ExpandedTableSelect'; import { XClusterTableEligibility } from '../../constants'; import { assertUnreachableCase } from '../../../../utils/errorHandlingUtils'; import { SortOrder, YBTableRelationType } from '../../../../redesign/helpers/constants'; -import { DEFAULT_RUNTIME_GLOBAL_SCOPE } from '../../../../actions/customers'; import { ExpandColumnComponent } from './ExpandColumnComponent'; import { getTableUuid } from '../../../../utils/tableUtils'; import { YBBanner, YBBannerVariant } from '../../../common/descriptors'; @@ -216,10 +210,6 @@ export const TableSelect = (props: TableSelectProps) => { // Upgrading react-query to v3.28 may solve this issue: https://github.com/TanStack/query/issues/1675 ) as UseQueryResult[]; - const globalRuntimeConfigQuery = useQuery(runtimeConfigQueryKey.globalScope(), () => - api.fetchRuntimeConfigs(DEFAULT_RUNTIME_GLOBAL_SCOPE, true) - ); - if ( sourceUniverseNamespaceQuery.isLoading || sourceUniverseNamespaceQuery.isIdle || @@ -230,9 +220,7 @@ export const TableSelect = (props: TableSelectProps) => { sourceUniverseQuery.isLoading || sourceUniverseQuery.isIdle || targetUniverseQuery.isLoading || - targetUniverseQuery.isIdle || - globalRuntimeConfigQuery.isLoading || - globalRuntimeConfigQuery.isIdle + targetUniverseQuery.isIdle ) { return ; } @@ -253,9 +241,6 @@ export const TableSelect = (props: TableSelectProps) => { ); } - if (globalRuntimeConfigQuery.isError) { - return ; - } const toggleTableGroup = ( isSelected: boolean, diff --git a/managed/ui/src/redesign/components/YBModal/YBModal.tsx b/managed/ui/src/redesign/components/YBModal/YBModal.tsx index 474892d484eb..d74b0a27bfce 100644 --- a/managed/ui/src/redesign/components/YBModal/YBModal.tsx +++ b/managed/ui/src/redesign/components/YBModal/YBModal.tsx @@ -45,6 +45,7 @@ export interface YBModalProps extends DialogProps { dialogContentProps?: DialogContentProps; titleContentProps?: string; isSubmitting?: boolean; + showSubmitSpinner?: boolean; } export const SlideTransition = React.forwardRef( @@ -115,7 +116,9 @@ const useStyles = makeStyles>((theme) => ({ lineHeight: '26px' }, footerAccessory: { - marginRight: 'auto' + display: 'flex', + flexShrink: 1, + width: '100%' }, title: { display: 'flex' @@ -130,6 +133,9 @@ const useStyles = makeStyles>((theme) => ({ text: { marginLeft: theme.spacing(1), whiteSpace: 'nowrap' + }, + submitButton: { + flexShrink: 0 } })); @@ -155,6 +161,7 @@ export const YBModal: FC = (props: YBModalProps) => { submitButtonTooltip, cancelButtonTooltip, isSubmitting, + showSubmitSpinner = true, dialogContentProps = { dividers: true }, titleContentProps, ...dialogProps @@ -246,10 +253,11 @@ export const YBModal: FC = (props: YBModalProps) => { {submitLabel} diff --git a/managed/ui/src/redesign/helpers/constants.ts b/managed/ui/src/redesign/helpers/constants.ts index 51fb28ebfc91..a85efc419458 100644 --- a/managed/ui/src/redesign/helpers/constants.ts +++ b/managed/ui/src/redesign/helpers/constants.ts @@ -38,6 +38,7 @@ export const RuntimeConfigKey = { PROVIDER_REDESIGN_UI_FEATURE_FLAG: 'yb.ui.feature_flags.provider_redesign', EDIT_IN_USE_PORIVDER_UI_FEATURE_FLAG: 'yb.ui.feature_flags.edit_in_use_provider', XCLUSTER_TRANSACTIONAL_ATOMICITY_FEATURE_FLAG: 'yb.xcluster.transactional.enabled', + ENABLE_XCLUSTER_SKIP_BOOTSTRAPPING: 'yb.ui.xcluster.enable_skip_bootstrapping', DISASTER_RECOVERY_FEATURE_FLAG: 'yb.xcluster.dr.enabled', PERFOMANCE_ADVISOR_UI_FEATURE_FLAG: 'yb.ui.feature_flags.perf_advisor', GRANULAR_METRICS_FEATURE_FLAG: 'yb.ui.feature_flags.granular_metrics', diff --git a/managed/ui/src/translations/en.json b/managed/ui/src/translations/en.json index 4cd46ba7e823..85ffb7b7fb3e 100644 --- a/managed/ui/src/translations/en.json +++ b/managed/ui/src/translations/en.json @@ -962,7 +962,14 @@ "dr": "Select the tables to enable disaster recovery for", "xCluster": "Select the tables to enable xCluster replication for" }, - "nextButton": "Next: Confirm Full Copy" + "submitButton": { + "skipBootstrapping": "Skip Creating Full Copy", + "validateSelection": "Validate Table Selection", + "configureBootstrap": { + "dr": "Next: Confirm Full Copy", + "xCluster": "Next: Configure Full Copy" + } + } }, "configureBootstrap": { "infoText": { @@ -977,10 +984,6 @@ } } }, - "submitButton": { - "validate": "Validate Selection", - "applyChanges": "Apply Changes" - }, "error": { "requestFailureLabel": "Edit tables request failed", "taskFailure": "Edit tables task failed.", @@ -1053,11 +1056,11 @@ "ysql": "Select the databases to enable xCluster replication for", "ycql": "Select the tables to enable xCluster replication for" }, - "validateButton": "Validate Table Selection", "submitButton": { - "validateSelection": "Validate Selection", + "validateSelection": "Validate Table Selection", "configureBootstrap": "Next: Configure Full Copy", - "confirmAlert": "Next: Confirm Alert Threshold" + "confirmAlert": "Next: Confirm Alert Threshold", + "skipBootstrapping": "Skip Creating Full Copy" } }, "configureBootstrap": {