Skip to content

Commit

Permalink
feat: [UIE-8009] - Review fix: replace Time Picker, refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
mpolotsk-akamai committed Sep 19, 2024
1 parent ba8948a commit 5854ae3
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ describe('Database Backups', () => {
const { findByText } = renderWithTheme(
<DatabaseBackups disabled={false} />
);
const timePickerLabel = await findByText('Time(UTC)');
const timePickerLabel = await findByText('Time (UTC)');
expect(timePickerLabel).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
import { FormControl } from '@mui/material';
import Grid from '@mui/material/Grid';
import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon';
Expand All @@ -9,6 +9,7 @@ import { useParams } from 'react-router-dom';
import { Box } from 'src/components/Box';
import { Button } from 'src/components/Button/Button';
import { Divider } from 'src/components/Divider';
import Select from 'src/components/EnhancedSelect/Select';
import { Paper } from 'src/components/Paper';
import { Table } from 'src/components/Table';
import { TableBody } from 'src/components/TableBody';
Expand All @@ -22,11 +23,11 @@ import { TableSortCell } from 'src/components/TableSortCell';
import { Typography } from 'src/components/Typography';
import {
StyledDateCalendar,
StyledTimePicker,
StyledTypography,
} from 'src/features/Databases/DatabaseDetail/DatabaseBackups/DatabaseBackups.style';
import RestoreLegacyFromBackupDialog from 'src/features/Databases/DatabaseDetail/DatabaseBackups/RestoreLegacyFromBackupDialog';
import RestoreNewFromBackupDialog from 'src/features/Databases/DatabaseDetail/DatabaseBackups/RestoreNewFromBackupDialog';
import { isOutsideBackupTimeframe } from 'src/features/Databases/utilities';
import { useOrder } from 'src/hooks/useOrder';
import {
useDatabaseBackupsQuery,
Expand Down Expand Up @@ -131,20 +132,6 @@ export const DatabaseBackups = (props: Props) => {
? DateTime.fromISO(database.oldest_restore_time)
: null;

const isWithinBackupTimeframe = (
date: DateTime,
oldestBackup: DateTime | null
) => {
const today = DateTime.now().startOf('day');
if (!oldestBackup) {
return false;
}
const backupStart = oldestBackup.startOf('day');
const dateStart = date.startOf('day');

return dateStart < backupStart || dateStart > today;
};

const onRestoreNewDatabase = (selectedDate: DateTime | null) => {
const day = selectedDate?.toISODate();
const time = selectedTime?.toISOTime({ includeOffset: false });
Expand Down Expand Up @@ -202,7 +189,7 @@ export const DatabaseBackups = (props: Props) => {
<LocalizationProvider dateAdapter={AdapterLuxon}>
<StyledDateCalendar
shouldDisableDate={(date) =>
isWithinBackupTimeframe(date, oldestBackup)
isOutsideBackupTimeframe(date, oldestBackup)
}
onChange={(newDate) => setSelectedDate(newDate)}
value={selectedDate}
Expand All @@ -211,35 +198,41 @@ export const DatabaseBackups = (props: Props) => {
</Grid>
<Grid item lg={3} md={4} xs={12}>
<Typography variant="h3">Time (UTC)</Typography>
<LocalizationProvider dateAdapter={AdapterLuxon}>
<StyledTimePicker
slotProps={{
desktopPaper: {
sx: {
'.MuiPickersLayout-contentWrapper': {
display: 'flex',
},
marginLeft: '-17px',
},
<FormControl style={{ marginTop: 0 }}>
{/* TODO: Replace Time Select to the own custom date-time picker component when it's ready */}
<Select
defaultValue={hourSelectionMap.find(
(option) => option.value === selectedTime?.hour
)}
onChange={(time) =>
setSelectedTime(
DateTime.now().set({ hour: time.value, minute: 0 })
)
}
textFieldProps={{
dataAttrs: {
'data-qa-time-select': true,
},
}}
ampm={false}
value={hourSelectionMap.find(
(thisOption) => thisOption.value === selectedTime?.hour
)}
disabled={!selectedDate}
label=""
onChange={(time) => setSelectedTime(time)}
slots={{ openPickerIcon: KeyboardArrowDownIcon }}
timeSteps={{ hours: 1, minutes: 1 }}
value={selectedTime}
isClearable={false}
name="Time"
noMarginTop
options={hourSelectionMap}
placeholder="Choose a time"
/>
</LocalizationProvider>
</FormControl>
</Grid>
</Grid>
<Grid item xs={12}>
<Box display="flex" justifyContent="flex-end">
<Button
buttonType="primary"
data-qa-settings-button="restore"
disabled={selectedDate ? false : true}
disabled={!selectedDate}
onClick={() => onRestoreNewDatabase(selectedDate)}
>
Restore
Expand Down Expand Up @@ -294,4 +287,31 @@ export const DatabaseBackups = (props: Props) => {
);
};

const hourSelectionMap = [
{ label: '00:00', value: 0 },
{ label: '01:00', value: 1 },
{ label: '02:00', value: 2 },
{ label: '03:00', value: 3 },
{ label: '04:00', value: 4 },
{ label: '05:00', value: 5 },
{ label: '06:00', value: 6 },
{ label: '07:00', value: 7 },
{ label: '08:00', value: 8 },
{ label: '09:00', value: 9 },
{ label: '10:00', value: 10 },
{ label: '11:00', value: 11 },
{ label: '12:00', value: 12 },
{ label: '13:00', value: 13 },
{ label: '14:00', value: 14 },
{ label: '15:00', value: 15 },
{ label: '16:00', value: 16 },
{ label: '17:00', value: 17 },
{ label: '18:00', value: 18 },
{ label: '19:00', value: 19 },
{ label: '20:00', value: 20 },
{ label: '21:00', value: 21 },
{ label: '22:00', value: 22 },
{ label: '23:00', value: 23 },
];

export default DatabaseBackups;
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ export const RestoreNewFromBackupDialog = (props: Props) => {
const history = useHistory();
const { enqueueSnackbar } = useSnackbar();

const formatedDate = `${restoreTime?.split('T')[0]} ${restoreTime
?.split('T')[1]
.slice(0, 5)}`;
const formatedDate =
restoreTime &&
`${restoreTime?.split('T')[0]} ${restoreTime?.split('T')[1].slice(0, 5)}`;

const { error, mutateAsync: restore } = useNewRestoreFromBackupMutation(
database.engine,
Expand All @@ -51,7 +51,7 @@ export const RestoreNewFromBackupDialog = (props: Props) => {
<Dialog
onClose={onClose}
open={open}
subtitle={`From ${formatedDate} (UTC)`}
subtitle={formatedDate && `From ${formatedDate} (UTC)`}
title={`Restore ${database.label}`}
>
<Typography sx={(theme) => ({ marginBottom: theme.spacing(4) })}>
Expand Down
32 changes: 30 additions & 2 deletions packages/manager/src/features/Databases/utilities.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { renderHook, waitFor } from '@testing-library/react';
import { DateTime } from 'luxon';

import { accountFactory } from 'src/factories';
import {
isOutsideBackupTimeframe,
useIsDatabasesEnabled,
} from 'src/features/Databases/utilities';
import { makeResourcePage } from 'src/mocks/serverHandlers';
import { HttpResponse, http, server } from 'src/mocks/testServer';
import { wrapWithTheme } from 'src/utilities/testHelpers';

import { useIsDatabasesEnabled } from './utilities';

describe('useIsDatabasesEnabled', () => {
it('should return true for an unrestricted user with the account capability V1', async () => {
const account = accountFactory.build({
Expand Down Expand Up @@ -112,3 +115,28 @@ describe('useIsDatabasesEnabled', () => {
await waitFor(() => expect(result.current.isDatabasesEnabled).toBe(false));
});
});

describe('isOutsideBackupTimeframe', () => {
it('should return true if date is before the oldest backup', () => {
const date = DateTime.now().minus({ days: 10 });
const oldestBackup = DateTime.now().minus({ days: 5 });
expect(isOutsideBackupTimeframe(date, oldestBackup)).toBe(true);
});

it('should return true if date is after today', () => {
const date = DateTime.now().plus({ days: 1 });
const oldestBackup = DateTime.now().minus({ days: 5 });
expect(isOutsideBackupTimeframe(date, oldestBackup)).toBe(true);
});

it('should return false if date is between the oldest backup and today', () => {
const date = DateTime.now().minus({ days: 3 });
const oldestBackup = DateTime.now().minus({ days: 5 });
expect(isOutsideBackupTimeframe(date, oldestBackup)).toBe(false);
});

it('should return false if there is no oldest backup', () => {
const date = DateTime.now().minus({ days: 3 });
expect(isOutsideBackupTimeframe(date, null)).toBe(false);
});
});
25 changes: 25 additions & 0 deletions packages/manager/src/features/Databases/utilities.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { DateTime } from 'luxon';

import { useFlags } from 'src/hooks/useFlags';
import { useAccount } from 'src/queries/account/account';
import { useDatabaseEnginesQuery } from 'src/queries/databases/databases';
Expand Down Expand Up @@ -50,3 +52,26 @@ export const useIsDatabasesEnabled = () => {
isDatabasesEnabled: userCouldLoadDatabaseEngines,
};
};

/**
* Checks if a given date is outside the timeframe between the oldest backup and today.
*
* @param {DateTime} date - The date you want to check.
* @param {DateTime | null} oldestBackup - The date of the oldest backup. If there are no backups (i.e., `null`), the function will return `false`.
* @returns {boolean}
* - `true` if the date is before the oldest backup or after today.
* - `false` if the date is within the range between the oldest backup and today.
*/
export const isOutsideBackupTimeframe = (
date: DateTime,
oldestBackup: DateTime | null
) => {
const today = DateTime.now().startOf('day');
if (!oldestBackup) {
return false;
}
const backupStart = oldestBackup.startOf('day');
const dateStart = date.startOf('day');

return dateStart < backupStart || dateStart > today;
};

0 comments on commit 5854ae3

Please sign in to comment.