Feature/settings backup (#453)
* Show loading indicator for "NumberSetting" * [i18n] Add lowercase interpolation format * Add required dependencies for time settings * Dynamically import dayjs locales for languages * Add backup settings
This commit is contained in:
@@ -13,12 +13,39 @@ import { fromEvent } from 'file-selector';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ListItemButton } from '@mui/material';
|
||||
import ListItemIcon from '@mui/material/ListItemIcon';
|
||||
import ListSubheader from '@mui/material/ListSubheader';
|
||||
import { t as translate } from 'i18next';
|
||||
import { requestManager } from '@/lib/requests/RequestManager.ts';
|
||||
import { makeToast } from '@/components/util/Toast';
|
||||
import { ListItemLink } from '@/components/util/ListItemLink';
|
||||
import { NavBarContext, useSetDefaultBackTo } from '@/components/context/NavbarContext';
|
||||
import { BackupRestoreState } from '@/lib/graphql/generated/graphql.ts';
|
||||
import { Progress } from '@/components/util/Progress.tsx';
|
||||
import { ServerDirSetting } from '@/components/settings/ServerDirSetting.tsx';
|
||||
import { NumberSetting } from '@/components/settings/NumberSetting.tsx';
|
||||
import { TimeSetting } from '@/components/settings/TimeSetting.tsx';
|
||||
import { ServerSettings } from '@/typings.ts';
|
||||
|
||||
type BackupSettingsType = Pick<ServerSettings, 'backupPath' | 'backupTime' | 'backupInterval' | 'backupTTL'>;
|
||||
|
||||
const extractBackupSettings = (settings: ServerSettings): BackupSettingsType => ({
|
||||
backupPath: settings.backupPath,
|
||||
backupTime: settings.backupTime,
|
||||
backupInterval: settings.backupInterval,
|
||||
backupTTL: settings.backupTTL,
|
||||
});
|
||||
|
||||
const getBackupCleanupDisplayValue = (ttl?: number) => {
|
||||
if (ttl === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (ttl === 0) {
|
||||
return translate('global.label.never');
|
||||
}
|
||||
|
||||
return translate('settings.backup.automated.cleanup.label.value', { days: ttl, count: ttl });
|
||||
};
|
||||
|
||||
let backupRestoreId: string | undefined;
|
||||
|
||||
@@ -32,6 +59,11 @@ export function Backup() {
|
||||
|
||||
useSetDefaultBackTo('settings');
|
||||
|
||||
const { data: settingsData } = requestManager.useGetServerSettings();
|
||||
const [mutateSettings] = requestManager.useUpdateServerSettings();
|
||||
|
||||
const backupSettings = settingsData ? extractBackupSettings(settingsData.settings) : undefined;
|
||||
|
||||
const { data } = requestManager.useGetBackupRestoreStatus(backupRestoreId ?? '', {
|
||||
skip: !backupRestoreId,
|
||||
pollInterval: 1000,
|
||||
@@ -48,6 +80,13 @@ export function Backup() {
|
||||
return Number.isNaN(progress) ? 0 : progress;
|
||||
})();
|
||||
|
||||
const updateSetting = <Setting extends keyof BackupSettingsType>(
|
||||
setting: Setting,
|
||||
value: BackupSettingsType[Setting],
|
||||
) => {
|
||||
mutateSettings({ variables: { input: { settings: { [setting]: value } } } });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!data?.restoreStatus) {
|
||||
return;
|
||||
@@ -142,6 +181,59 @@ export function Backup() {
|
||||
</ListItemIcon>
|
||||
) : null}
|
||||
</ListItemButton>
|
||||
<List
|
||||
subheader={
|
||||
<ListSubheader component="div" id="backup-settings">
|
||||
Automated backup
|
||||
</ListSubheader>
|
||||
}
|
||||
>
|
||||
<ServerDirSetting
|
||||
settingName={t('settings.backup.automated.location.label.title')}
|
||||
dialogDescription={t('settings.backup.automated.location.label.description')}
|
||||
dirPath={backupSettings?.backupPath}
|
||||
handlePathChange={(path) => updateSetting('backupPath', path)}
|
||||
/>
|
||||
<TimeSetting
|
||||
settingName={t('settings.backup.automated.label.time')}
|
||||
value={backupSettings?.backupTime}
|
||||
defaultValue="00:00"
|
||||
handleChange={(time: string) => updateSetting('backupTime', time)}
|
||||
/>
|
||||
<NumberSetting
|
||||
settingTitle={t('settings.backup.automated.label.interval')}
|
||||
settingValue={
|
||||
backupSettings?.backupInterval
|
||||
? t('global.date.value.label.day', {
|
||||
days: backupSettings.backupInterval,
|
||||
count: backupSettings.backupInterval,
|
||||
})
|
||||
: undefined
|
||||
}
|
||||
value={backupSettings?.backupInterval ?? 1}
|
||||
defaultValue={1}
|
||||
minValue={1}
|
||||
maxValue={31}
|
||||
stepSize={1}
|
||||
dialogTitle="Interval"
|
||||
valueUnit="Day"
|
||||
showSlider
|
||||
handleUpdate={(interval: number) => updateSetting('backupInterval', interval)}
|
||||
/>
|
||||
<NumberSetting
|
||||
settingTitle={t('settings.backup.automated.cleanup.label.title')}
|
||||
settingValue={getBackupCleanupDisplayValue(backupSettings?.backupTTL)}
|
||||
value={backupSettings?.backupTTL ?? 14}
|
||||
defaultValue={14}
|
||||
minValue={0}
|
||||
maxValue={1000}
|
||||
stepSize={1}
|
||||
dialogTitle="Cleanup"
|
||||
valueUnit="Day"
|
||||
showSlider
|
||||
handleUpdate={(ttl: number) => updateSetting('backupTTL', ttl)}
|
||||
/>
|
||||
</List>
|
||||
</List>
|
||||
<input type="file" id="backup-file" style={{ display: 'none' }} />
|
||||
</>
|
||||
|
||||
Reference in New Issue
Block a user