Skip to content

Commit

Permalink
[PLAT-15821]Restore button in backup details doesn't allow restore to…
Browse files Browse the repository at this point in the history
… particular time - [PLAT-15807] - [PLAT-PLAT-15832]

Summary:
[[ https://yugabyte.atlassian.net/browse/PLAT-15821 | PLAT-15821 ]] - Restore button in backup details doesn't allow restore to particular time - **We forgot to pass the restoreTimeWindow to the restore window. Fixed it by passing the prop.**
[[ https://yugabyte.atlassian.net/browse/PLAT-15832 | PLAT-15832 ]] - When you disable policy in new UI, actions and metadata also looks disabled - **Instead of setting opacity, we changed the text color from black to grey. Because , the child elements cannot override the parent opacity**
[[ https://yugabyte.atlassian.net/browse/PLAT-15807 | PLAT-15807 ]] - Do not need to create edit schedule task if nothing changed - **Now we compare the changes with default values, If changed then we send the req, else we display the toast "No values changed"**.

Test Plan:
Tested manually
{F303433}

Reviewers: lsangappa

Reviewed By: lsangappa

Subscribers: yugaware

Differential Revision: https://phorge.dev.yugabyte.com/D39347
  • Loading branch information
haikarthikssk committed Oct 24, 2024
1 parent 2d36243 commit 6786953
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export const YSQLTableList: FC<YSQLTableProps> = ({
keyspace: table.keyspace,
storageLocation: table.storageLocation,
defaultLocation: table.defaultLocation,
backupPointInTimeRestoreWindow: table.backupPointInTimeRestoreWindow,
index
};
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,23 +101,25 @@ export const prepareScheduledBackupPayload = (

const keyspaceGroups = groupBy(backupObjects.selectedTables, 'keySpace');

payload['keyspaceTableList'] = Object.keys(keyspaceGroups).map((keyspace) => {
if (backupObjects.keyspace?.tableType === BACKUP_API_TYPES.YSQL) {
if (backupObjects.keyspace?.tableType === BACKUP_API_TYPES.YSQL) {
payload['keyspaceTableList'] = backupObjects.keyspace.isDefaultOption
? []
: [{ keyspace: backupObjects.keyspace.value }];
} else {
payload['keyspaceTableList'] = Object.keys(keyspaceGroups).map((keyspace) => {
return {
keyspace
keyspace,
tableNameList:
backupObjects.tableBackupType === Backup_Options_Type.ALL
? []
: keyspaceGroups[keyspace].map((t: ITable) => t.tableName),
tableUUIDList:
backupObjects.tableBackupType === Backup_Options_Type.ALL
? []
: keyspaceGroups[keyspace].map((t: ITable) => t.tableUUID)
};
}
return {
keyspace,
tableNameList:
backupObjects.tableBackupType === Backup_Options_Type.ALL
? []
: keyspaceGroups[keyspace].map((t: ITable) => t.tableName),
tableUUIDList:
backupObjects.tableBackupType === Backup_Options_Type.ALL
? []
: keyspaceGroups[keyspace].map((t: ITable) => t.tableUUID)
};
});
});
}

return payload;
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
* http://github.com/YugaByte/yugabyte-db/blob/master/licenses/POLYFORM-FREE-TRIAL-LICENSE-1.0.0.txt
*/

import { FC } from 'react';
import { FC, useCallback, useEffect } from 'react';
import { Control, useForm } from 'react-hook-form';
import { useMutation, useQueryClient } from 'react-query';
import { Trans, useTranslation } from 'react-i18next';
Expand Down Expand Up @@ -70,7 +70,7 @@ const EditScheduledPolicyModal: FC<EditScheduledPolicyModalProps> = ({
const backupFrequencyKeyPrefix = 'backup.scheduled.create.backupFrequency';
const classes = useStyles();
const queryClient = useQueryClient();
const { control, handleSubmit } = useForm<EditScheduledPolicyModalFormProps>({
const { control, handleSubmit, formState: { defaultValues }, reset, watch, setValue } = useForm<EditScheduledPolicyModalFormProps>({
defaultValues: {
scheduledBackupType: schedule.backupInfo.pointInTimeRestoreEnabled
? BackupStrategyType.POINT_IN_TIME
Expand All @@ -84,7 +84,7 @@ const EditScheduledPolicyModal: FC<EditScheduledPolicyModalProps> = ({
useIncrementalBackup: !!schedule.incrementalBackupFrequency,
incrementalBackupFrequency: schedule.incrementalBackupFrequency
? schedule.incrementalBackupFrequency /
(MILLISECONDS_IN as any)[schedule.incrementalBackupFrequencyTimeUnit]
(MILLISECONDS_IN as any)[schedule.incrementalBackupFrequencyTimeUnit]
: 0,
incrementalBackupFrequencyTimeUnit: capitalize(
schedule.incrementalBackupFrequencyTimeUnit
Expand All @@ -98,6 +98,7 @@ const EditScheduledPolicyModal: FC<EditScheduledPolicyModalProps> = ({
onSuccess: () => {
toast.success(t('success'));
queryClient.invalidateQueries('scheduled_backup_list');
reset();
onHide();
},
onError: (error) => {
Expand All @@ -106,6 +107,17 @@ const EditScheduledPolicyModal: FC<EditScheduledPolicyModalProps> = ({
}
);

const useCronExpression = watch('useCronExpression');

useEffect(() => {
if (!useCronExpression) {
setValue('cronExpression', defaultValues!.cronExpression!);
}
}, [useCronExpression]);

const shallowCompare = useCallback((obj1: EditScheduledPolicyModalFormProps, obj2: EditScheduledPolicyModalFormProps) =>
(Object.keys(obj1) as (keyof EditScheduledPolicyModalFormProps)[]).every(key => obj1[key] + "" === obj2[key] + ""), []);

if (!visible) return null;

const backupTypeOptions = [
Expand Down Expand Up @@ -140,7 +152,7 @@ const EditScheduledPolicyModal: FC<EditScheduledPolicyModalProps> = ({
return (
<YBModal
open={true}
onClose={onHide}
onClose={() => { reset(); onHide(); }}
title={t('title')}
overrideWidth={'1000px'}
overrideHeight={'650px'}
Expand All @@ -153,6 +165,11 @@ const EditScheduledPolicyModal: FC<EditScheduledPolicyModalProps> = ({
cancelLabel={t('cancel', { keyPrefix: 'common' })}
onSubmit={() => {
handleSubmit((data) => {
if (shallowCompare(defaultValues as any, data)) {
toast.error(t('noFieldsChanged'));
return;
}

const payload: Record<string, any> = {};
if (data.useCronExpression) {
payload['cronExpression'] = data.cronExpression;
Expand All @@ -166,7 +183,7 @@ const EditScheduledPolicyModal: FC<EditScheduledPolicyModalProps> = ({
if (data.useIncrementalBackup) {
payload['incrementalBackupFrequency'] =
(MILLISECONDS_IN as Record<string, any>)[
data.incrementalBackupFrequencyTimeUnit.toUpperCase()
data.incrementalBackupFrequencyTimeUnit.toUpperCase()
] * data.incrementalBackupFrequency;
payload[
'incrementalBackupFrequencyTimeUnit'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,10 @@ const useStyles = makeStyles((theme) => ({
cursor: 'pointer'
},
inactive: {
opacity: 0.5
color: theme.palette.grey[500],
'&:hover': {
color: theme.palette.grey[500],
}
}
}));

Expand Down Expand Up @@ -195,7 +198,7 @@ export const ScheduledCard: FC<ScheduledCardProps> = ({
}
return (
<span
className={classes.link}
className={clsx(classes.link, !isScheduleEnabled && classes.inactive)}
onClick={() => {
setShowTablesModal(true);
}}
Expand Down Expand Up @@ -276,7 +279,7 @@ export const ScheduledCard: FC<ScheduledCardProps> = ({
</div>
<div className={classes.content}>
<div className={classes.details}>
<div className={classes.attribute}>
<div className={clsx(classes.attribute, !isScheduleEnabled && classes.inactive)}>
<span>{t('scope')}</span>
<span>{t('keyspace')}</span>
<span>{t('tables')}</span>
Expand All @@ -294,31 +297,31 @@ export const ScheduledCard: FC<ScheduledCardProps> = ({
</div>
<div className={classes.nextScheduledDates}>
<div>
<div className={classes.attribute}>{t('lastBackup')}</div>
<div className={classes.value}>
<div className={clsx(classes.attribute, !isScheduleEnabled && classes.inactive)}>{t('lastBackup')}</div>
<div className={clsx(classes.value, !isScheduleEnabled && classes.inactive)}>
{schedule.prevCompletedTask ? ybFormatDate(schedule.prevCompletedTask) : '-'}
</div>
</div>
<div>
<div className={classes.attribute}>{t('nextBackup')}</div>
<div className={classes.value}>
<div className={clsx(classes.attribute, !isScheduleEnabled && classes.inactive)}>{t('nextBackup')}</div>
<div className={clsx(classes.value, !isScheduleEnabled && classes.inactive)}>
{schedule.nextExpectedTask ? ybFormatDate(schedule.nextExpectedTask) : '-'}
</div>
</div>
</div>
</div>
<div className={classes.footer}>
<div>
<div className={classes.attribute}>{t('backupIntervals')}</div>
<div className={classes.value}>
<div className={clsx(classes.attribute, !isScheduleEnabled && classes.inactive)}>{t('backupIntervals')}</div>
<div className={clsx(classes.value, !isScheduleEnabled && classes.inactive)}>
{backupInterval} -{' '}
<Trans
t={t}
i18nKey="details"
components={{
a: (
<a
className={classes.link}
className={clsx(classes.link, !isScheduleEnabled && classes.inactive)}
onClick={() => {
setShowIntervalsModal(true);
}}
Expand All @@ -329,20 +332,20 @@ export const ScheduledCard: FC<ScheduledCardProps> = ({
</div>
</div>
<div>
<div className={classes.attribute}>{t('incrementalBackup')}</div>
<div className={classes.value}>
<div className={clsx(classes.attribute, !isScheduleEnabled && classes.inactive)}>{t('incrementalBackup')}</div>
<div className={clsx(classes.value, !isScheduleEnabled && classes.inactive)}>
{schedule.incrementalBackupFrequency === 0 ? t('disabled') : t('enabled')}
</div>
</div>
<div>
<div className={classes.attribute}>{t('pitr')}</div>
<div className={classes.value}>
<div className={clsx(classes.attribute, !isScheduleEnabled && classes.inactive)}>{t('pitr')}</div>
<div className={clsx(classes.value, !isScheduleEnabled && classes.inactive)}>
{schedule.backupInfo.pointInTimeRestoreEnabled ? t('enabled') : t('disabled')}
</div>
</div>
<div>
<div className={classes.attribute}>{t('retentionPeriod')}</div>
<div className={classes.value}>
<div className={clsx(classes.attribute, !isScheduleEnabled && classes.inactive)}>{t('retentionPeriod')}</div>
<div className={clsx(classes.value, !isScheduleEnabled && classes.inactive)}>
{schedule.backupInfo?.timeBeforeDelete
? convertMsecToTimeFrame(
schedule.backupInfo.timeBeforeDelete,
Expand All @@ -352,12 +355,12 @@ export const ScheduledCard: FC<ScheduledCardProps> = ({
</div>
</div>
<div>
<div className={classes.attribute}>{t('storageConfig')}</div>
<div className={classes.value}>
<div className={clsx(classes.attribute, !isScheduleEnabled && classes.inactive)}>{t('storageConfig')}</div>
<div className={clsx(classes.value, !isScheduleEnabled && classes.inactive)}>
{storageConfig ? (
<a
target="_blank"
className={classes.link}
className={clsx(classes.link, !isScheduleEnabled && classes.inactive)}
href={`/config/backup/${storageConfig ? storageConfig.name.toLowerCase() : ''}`}
rel="noreferrer"
>
Expand Down
3 changes: 2 additions & 1 deletion managed/ui/src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2744,7 +2744,8 @@
"editModal": {
"title": "Edit Scheduled Backup Policy",
"backupStrategy": "Backup Strategy",
"success": "Scheduled backup policy is being updated"
"success": "Scheduled backup policy is being updated",
"noFieldsChanged": "No values changed"
},
"deleteModal": {
"deleteMsg": "Are you sure you want to delete this schedule policy?"
Expand Down

0 comments on commit 6786953

Please sign in to comment.