Skip to content

Commit

Permalink
[PLAT-13605][PLAT-13609]: Edit Volume controls and storage type in FU…
Browse files Browse the repository at this point in the history
…LL_MOVE but not in case of UPDATE

Summary:
1. In non K8 universe, all fields such as Volume Size, volume count, num nodes, instance type, storage type and placement info should be editable
2. In case of GCP, when we change storage type to SCRATCH, we disable volume size, this is the default behavior today, this limitation comes not from full_move/smart resize logic.
3. All the fields will be disabled in VIEW mode though

Test Plan:
Please refer to screenshot and videos
{F172044}

{F172046}

{F261513}

Reviewers: yshchetinin

Reviewed By: yshchetinin

Subscribers: yugaware

Differential Revision: https://phorge.dev.yugabyte.com/D35675
  • Loading branch information
rajmaddy89 committed Jun 27, 2024
1 parent 0a1406d commit 70a87f9
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 61 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { FC } from 'react';
import { FC, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { useFormContext, useWatch } from 'react-hook-form';
import { useQuery } from 'react-query';
import { useUpdateEffect } from 'react-use';
import { Box, Grid, MenuItem, makeStyles } from '@material-ui/core';
import { YBLabel, YBSelect } from '../../../../../../components';
import { UniverseFormContext } from '../../../UniverseFormContainer';
import { api, QUERY_KEY } from '../../../utils/api';
import {
getThroughputByStorageType,
getStorageTypeOptions,
getIopsByStorageType
getIopsByStorageType,
useVolumeControls
} from './VolumeInfoFieldHelper';
import { StorageType, UniverseFormData, CloudType } from '../../../utils/dto';
import { IsOsPatchingEnabled } from '../../../../../../../components/configRedesign/providerRedesign/components/linuxVersionCatalog/LinuxVersionUtils';
Expand All @@ -33,20 +35,25 @@ const useStyles = makeStyles((theme) => ({
}));

interface StorageTypeFieldProps {
disableStorageType: boolean;
isViewMode: boolean;
isEditMode: boolean;
}

export const StorageTypeField: FC<StorageTypeFieldProps> = ({ disableStorageType }) => {
export const StorageTypeField: FC<StorageTypeFieldProps> = ({ isViewMode, isEditMode }) => {
const { t } = useTranslation();
const classes = useStyles();

const { universeConfigureTemplate } = useContext(UniverseFormContext)[0];
const updateOptions = universeConfigureTemplate?.updateOptions;

// watchers
const fieldValue = useWatch({ name: DEVICE_INFO_FIELD });
const masterFieldValue = useWatch({ name: MASTER_DEVICE_INFO_FIELD });
const provider = useWatch({ name: PROVIDER_FIELD });
const instanceType = useWatch({ name: INSTANCE_TYPE_FIELD });
const cpuArch = useWatch({ name: CPU_ARCHITECTURE_FIELD });
const { setValue } = useFormContext<UniverseFormData>();
const { disableStorageType } = useVolumeControls(isEditMode, updateOptions);

//field actions
const onStorageTypeChanged = (storageType: StorageType) => {
Expand Down Expand Up @@ -120,14 +127,14 @@ export const StorageTypeField: FC<StorageTypeFieldProps> = ({ disableStorageType
<YBSelect
className={classes.storageTypeSelectField}
fullWidth
disabled={disableStorageType}
disabled={isViewMode || disableStorageType}
value={storageType}
inputProps={{
min: 1,
'data-testid': 'VolumeInfoFieldDedicated-Common-StorageTypeSelect'
}}
onChange={(event) =>
onStorageTypeChanged(event?.target.value as unknown as StorageType)
onStorageTypeChanged((event?.target.value as unknown) as StorageType)
}
>
{getStorageTypeOptions(provider?.code).map((item) => (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ import {
MasterPlacementMode,
StorageType,
UniverseFormData,
UpdateActions,
VolumeType
} from '../../../utils/dto';
import { IsOsPatchingEnabled } from '../../../../../../../components/configRedesign/providerRedesign/components/linuxVersionCatalog/LinuxVersionUtils';

import { isNonEmptyArray } from '../../../../../../../utils/ObjectUtils';
import {
PROVIDER_FIELD,
DEVICE_INFO_FIELD,
Expand All @@ -40,11 +41,7 @@ import WarningIcon from '../../../../../../assets/info-message.svg';
interface VolumeInfoFieldProps {
isEditMode: boolean;
isPrimary: boolean;
disableIops: boolean;
disableThroughput: boolean;
disableStorageType: boolean;
disableVolumeSize: boolean;
disableNumVolumes: boolean;
isViewMode: boolean;
isDedicatedMasterField?: boolean;
maxVolumeCount: number;
updateOptions: string[];
Expand Down Expand Up @@ -81,11 +78,7 @@ const useStyles = makeStyles((theme) => ({
export const VolumeInfoField: FC<VolumeInfoFieldProps> = ({
isEditMode,
isPrimary,
disableIops,
disableThroughput,
disableStorageType,
disableVolumeSize,
disableNumVolumes,
isViewMode,
isDedicatedMasterField,
maxVolumeCount,
updateOptions,
Expand All @@ -97,11 +90,6 @@ export const VolumeInfoField: FC<VolumeInfoFieldProps> = ({
const { t } = useTranslation();
const instanceTypeChanged = useRef(false);
const dataTag = isDedicatedMasterField ? 'Master' : 'TServer';
const { numVolumesDisable, volumeSizeDisable, minVolumeSize } = useVolumeControls(
isEditMode,
updateOptions
);
const isAwsNodeCoolingDown = diffInHours !== null && diffInHours < AwsCoolDownPeriod;

//watchers
const fieldValue = isDedicatedMasterField
Expand All @@ -114,6 +102,16 @@ export const VolumeInfoField: FC<VolumeInfoFieldProps> = ({
const masterPlacement = useWatch({ name: MASTER_PLACEMENT_FIELD });
const provider = useWatch({ name: PROVIDER_FIELD });

const {
numVolumesDisable,
volumeSizeDisable,
minVolumeSize,
disableIops,
disableThroughput,
disableStorageType
} = useVolumeControls(isEditMode, updateOptions);
const isAwsNodeCoolingDown = diffInHours !== null && diffInHours < AwsCoolDownPeriod;

//fetch run time configs
const {
data: providerRuntimeConfigs,
Expand All @@ -140,7 +138,7 @@ export const VolumeInfoField: FC<VolumeInfoFieldProps> = ({
if (!instance) return;
const getProviderRuntimeConfigs = async () => {
const providerRuntimeConfigsRefetch = await providerConfigsRefetch();
let deviceInfo = getDeviceInfoFromInstance(
const deviceInfo = getDeviceInfoFromInstance(
instance,
providerRuntimeConfigsRefetch.isError
? providerRuntimeConfigs
Expand Down Expand Up @@ -236,7 +234,10 @@ export const VolumeInfoField: FC<VolumeInfoFieldProps> = ({

const renderVolumeInfo = () => {
const isAWSProvider = provider?.code === CloudType.aws;
const isAwsNodeDisabled = isAWSProvider && isAwsNodeCoolingDown;
const isSmartResize =
isNonEmptyArray(updateOptions) &&
(updateOptions.includes(UpdateActions.SMART_RESIZE) ||
updateOptions.includes(UpdateActions.SMART_RESIZE_NON_RESTART));
const fixedVolumeSize =
[VolumeType.SSD, VolumeType.NVME].includes(volumeType) &&
fieldValue?.storageType === StorageType.Scratch &&
Expand Down Expand Up @@ -268,7 +269,7 @@ export const VolumeInfoField: FC<VolumeInfoFieldProps> = ({
<YBInput
type="number"
fullWidth
disabled={fixedNumVolumes || disableNumVolumes || numVolumesDisable}
disabled={fixedNumVolumes || isViewMode || numVolumesDisable}
inputProps={{ min: 1, 'data-testid': `VolumeInfoField-${dataTag}-VolumeInput` }}
value={convertToString(fieldValue.numVolumes)}
onChange={(event) => onNumVolumesChanged(event.target.value)}
Expand All @@ -286,13 +287,12 @@ export const VolumeInfoField: FC<VolumeInfoFieldProps> = ({
fullWidth
disabled={
fixedVolumeSize ||
disableVolumeSize ||
isViewMode ||
(provider?.code !== CloudType.kubernetes &&
!smartResizePossible &&
isEditMode &&
!instanceTypeChanged.current) ||
volumeSizeDisable ||
isAwsNodeDisabled
volumeSizeDisable
}
inputProps={{
min: 1,
Expand All @@ -310,7 +310,7 @@ export const VolumeInfoField: FC<VolumeInfoFieldProps> = ({
? t('universeForm.instanceConfig.k8VolumeSizeUnit')
: t('universeForm.instanceConfig.volumeSizeUnit')}
</span>
{isAwsNodeDisabled && (
{isAWSProvider && isAwsNodeCoolingDown && !isSmartResize && (
<Box className={classes.coolDownTooltip}>
<Tooltip
title={t('universeForm.instanceConfig.cooldownHours')}
Expand Down Expand Up @@ -350,7 +350,7 @@ export const VolumeInfoField: FC<VolumeInfoFieldProps> = ({
<Box flex={1}>
<YBSelect
className={classes.storageTypeSelectField}
disabled={disableStorageType}
disabled={disableStorageType || isViewMode}
value={fieldValue.storageType}
inputProps={{
min: 1,
Expand Down Expand Up @@ -393,7 +393,7 @@ export const VolumeInfoField: FC<VolumeInfoFieldProps> = ({
<YBInput
type="number"
fullWidth
disabled={disableIops}
disabled={disableIops || isViewMode}
inputProps={{ min: 1, 'data-testid': `VolumeInfoField-${dataTag}-DiskIopsInput` }}
value={convertToString(fieldValue.diskIops)}
onChange={(event) => onDiskIopsChanged(event.target.value)}
Expand All @@ -420,7 +420,7 @@ export const VolumeInfoField: FC<VolumeInfoFieldProps> = ({
<YBInput
type="number"
fullWidth
disabled={disableThroughput}
disabled={disableThroughput || isViewMode}
inputProps={{ min: 1, 'data-testid': `VolumeInfoField-${dataTag}-ThroughputInput` }}
value={convertToString(fieldValue.throughput)}
onChange={(event) => onThroughputChange(event.target.value)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,10 @@ export const useVolumeControls = (isEditMode: boolean, updateOptions: string[])
const [numVolumesDisable, setNumVolumesDisable] = useState(false);
const [volumeSizeDisable, setVolumeSizeDisable] = useState(false);
const [userTagsDisable, setUserTagsDisable] = useState(false);
const [disableIops, setDisableIops] = useState(false);
const [disableThroughput, setDisableThroughput] = useState(false);
const [disableStorageType, setDisableStorageType] = useState(false);
const [minVolumeSize, setMinVolumeSize] = useState(1);
const { setValue } = useFormContext<UniverseFormData>();

//watchers
const provider = useWatch({ name: PROVIDER_FIELD });
Expand All @@ -227,28 +229,16 @@ export const useVolumeControls = (isEditMode: boolean, updateOptions: string[])
const instanceType = useWatch({ name: INSTANCE_TYPE_FIELD });
const deviceInfo = useWatch({ name: DEVICE_INFO_FIELD });

const initialCombination = useRef({
totalNodes: Number(totalNodes),
placements,
instanceType,
deviceInfo
});

useUpdateEffect(() => {
if (isEditMode && provider.code !== CloudType.kubernetes) {
if (isNonEmptyArray(updateOptions) && updateOptions.includes(UpdateActions.UPDATE)) {
setNumVolumesDisable(true);
setVolumeSizeDisable(true);
setUserTagsDisable(true);
setValue(DEVICE_INFO_FIELD, initialCombination.current.deviceInfo);
// Volume Size Increase, Other device Info changes (Count, Storage type, provisioned IOPS) , Instance Type Change
} else {
setNumVolumesDisable(false);
setVolumeSizeDisable(false);
setUserTagsDisable(false);
}
setNumVolumesDisable(false);
setVolumeSizeDisable(false);
setUserTagsDisable(false);
setDisableIops(false);
setDisableThroughput(false);
setDisableStorageType(false);
}
}, [totalNodes, placements, instanceType, deviceInfo?.volumeSize]);

return { numVolumesDisable, volumeSizeDisable, userTagsDisable, minVolumeSize };
return { numVolumesDisable, volumeSizeDisable, userTagsDisable, minVolumeSize, disableIops, disableThroughput, disableStorageType };
};
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ export const InstanceConfiguration = ({ runtimeConfigs }: UniverseFormConfigurat
const isCreateMode = mode === ClusterModes.CREATE; //Form is in edit mode
const isCreatePrimary = isCreateMode && isPrimary; //Creating Primary Cluster
const isCreateRR = !newUniverse && isCreateMode && !isPrimary; //Adding Async Cluster to an existing Universe
const isNodeResizable = true;
//field data
const provider = useWatch({ name: PROVIDER_FIELD });
const deviceInfo = useWatch({ name: DEVICE_INFO_FIELD });
Expand Down Expand Up @@ -125,7 +124,7 @@ export const InstanceConfiguration = ({ runtimeConfigs }: UniverseFormConfigurat
<K8VolumeInfoField
isEditMode={!isCreateMode}
isDedicatedMasterField={isDedicatedMasterField}
disableVolumeSize={!isNodeResizable || isViewMode}
disableVolumeSize={isViewMode}
disableNumVolumes={!isCreateMode && provider?.code === CloudType.kubernetes}
maxVolumeCount={maxVolumeCount}
/>
Expand All @@ -140,11 +139,7 @@ export const InstanceConfiguration = ({ runtimeConfigs }: UniverseFormConfigurat
<VolumeInfoField
isEditMode={!isCreateMode}
isPrimary={isPrimary}
disableVolumeSize={!isNodeResizable || isViewMode}
disableNumVolumes={isViewMode}
disableStorageType={!isCreatePrimary && !isCreateRR}
disableIops={!isCreatePrimary && !isCreateRR}
disableThroughput={!isCreatePrimary && !isCreateRR}
isViewMode={isViewMode}
isDedicatedMasterField={isDedicatedMasterField}
maxVolumeCount={maxVolumeCount}
updateOptions={updateOptions}
Expand Down Expand Up @@ -203,7 +198,7 @@ export const InstanceConfiguration = ({ runtimeConfigs }: UniverseFormConfigurat
provider?.code === CloudType.gcp &&
masterPlacement === MasterPlacementMode.DEDICATED && (
<Box width="50%">
<StorageTypeField disableStorageType={!isCreatePrimary && !isCreateRR} />
<StorageTypeField isViewMode={isViewMode} isEditMode={!isCreateMode} />
</Box>
)}
</Box>
Expand Down
2 changes: 1 addition & 1 deletion managed/ui/src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@
"aarch64": "AArch6 (ARM)",
"linuxVersion": "Linux Version",
"showRetired": "Show retired recommendations",
"cooldownHours": "Disk can be resized after a cooldown period of 6 hours"
"cooldownHours": "Resizing device within cooldown period of 6 hours causes resize to happen only by moving to different nodes"
},
"securityConfig": {
"title": "Security Configurations",
Expand Down

0 comments on commit 70a87f9

Please sign in to comment.