Add sync settings
This commit is contained in:
@@ -30,6 +30,7 @@ import {
|
||||
} from '@/lib/graphql/generated/graphql-base.types.ts';
|
||||
import { ThemeMode } from '@/features/theme/AppTheme.types.ts';
|
||||
import { getPreferredISOLanguageCodes } from '@/lib/ISOLanguageUtil.ts';
|
||||
import type { BackupFlag } from '@/features/backup/Backup.types.ts';
|
||||
|
||||
export const MANGA_GRID_WIDTH = {
|
||||
min: 100,
|
||||
@@ -317,3 +318,45 @@ export const IMAGE_PROCESSING_TYPE_TO_SETTING: Record<
|
||||
[ImageProcessingType.DOWNLOAD]: 'downloadConversions',
|
||||
[ImageProcessingType.SERVE]: 'serveConversions',
|
||||
};
|
||||
|
||||
const SYNC_INTERVAL_TO_TRANSLATION: Record<string, SelectSettingValueDisplayInfo> = {
|
||||
[d(0).seconds.asWholeMinutes.toISOString()]: {
|
||||
text: msg`Disabled`,
|
||||
},
|
||||
[d(30).minutes.asWholeMinutes.toISOString()]: {
|
||||
text: msg`Every 30 minutes`,
|
||||
},
|
||||
[d(1).hours.asWholeMinutes.toISOString()]: {
|
||||
text: msg`Every hour`,
|
||||
},
|
||||
[d(3).hours.asWholeMinutes.toISOString()]: {
|
||||
text: msg`Every 3 hours`,
|
||||
},
|
||||
[d(6).hours.asWholeMinutes.toISOString()]: {
|
||||
text: msg`Every 6 hours`,
|
||||
},
|
||||
[d(12).hours.asWholeMinutes.toISOString()]: {
|
||||
text: msg`Every 12 hours`,
|
||||
},
|
||||
[d(1).days.asWholeMinutes.toISOString()]: {
|
||||
text: msg`Daily`,
|
||||
},
|
||||
[d(7).days.asWholeMinutes.toISOString()]: {
|
||||
text: msg`Weekly`,
|
||||
},
|
||||
};
|
||||
export const SYNC_INTERVAL_CUSTOM_VALUE = d(10).days.asWholeMinutes.toISOString();
|
||||
export const SYNC_INTERVAL_VALUES = Object.keys(SYNC_INTERVAL_TO_TRANSLATION);
|
||||
export const SYNC_INTERVAL_SELECT_VALUES: SelectSettingValue<string>[] = SYNC_INTERVAL_VALUES.map((value) => [
|
||||
value,
|
||||
SYNC_INTERVAL_TO_TRANSLATION[value],
|
||||
]);
|
||||
export const SYNC_INTERVAL_SELECT_VALUES_WITH_CUSTOM: SelectSettingValue<string>[] = [
|
||||
...SYNC_INTERVAL_SELECT_VALUES,
|
||||
[SYNC_INTERVAL_CUSTOM_VALUE, { text: msg`Custom` }],
|
||||
];
|
||||
|
||||
export const SYNC_SETTINGS_HIDDEN_BACKUP_FLAGS = [
|
||||
'includeServerSettings',
|
||||
'includeClientData',
|
||||
] as const satisfies BackupFlag[];
|
||||
|
||||
@@ -31,17 +31,46 @@ import { makeToast } from '@/base/utils/Toast.ts';
|
||||
import type { MetadataUpdateSettings } from '@/features/app-updates/AppUpdateChecker.types.ts';
|
||||
import { getErrorMessage } from '@/lib/HelperFunctions.ts';
|
||||
import { useAppTitle } from '@/features/navigation-bar/hooks/useAppTitle.ts';
|
||||
import type { PartialSettingsTypeInput } from '@/lib/graphql/generated/graphql-base.types.ts';
|
||||
import { AuthMode, CbzMediaType, DatabaseType, SortOrder } from '@/lib/graphql/generated/graphql-base.types.ts';
|
||||
import {
|
||||
AUTH_MODES_SELECT_VALUES,
|
||||
JWT_ACCESS_TOKEN_EXPIRY,
|
||||
JWT_REFRESH_TOKEN_EXPIRY,
|
||||
SYNC_INTERVAL_CUSTOM_VALUE,
|
||||
SYNC_INTERVAL_SELECT_VALUES,
|
||||
SYNC_INTERVAL_SELECT_VALUES_WITH_CUSTOM,
|
||||
SYNC_INTERVAL_VALUES,
|
||||
SYNC_SETTINGS_HIDDEN_BACKUP_FLAGS,
|
||||
} from '@/features/settings/Settings.constants.ts';
|
||||
import { ServerAddressSetting } from '@/features/settings/components/ServerAddressSetting.tsx';
|
||||
import { AuthManager } from '@/features/authentication/AuthManager.ts';
|
||||
import type { ServerSettings as ServerSettingsType } from '@/features/settings/Settings.types.ts';
|
||||
import { KoreaderSyncSettings } from '@/features/settings/components/koreaderSync/KoreaderSyncSettings.tsx';
|
||||
import { Confirmation } from '@/base/AppAwaitableComponent.ts';
|
||||
import { BackupFlagInclusionDialog } from '@/features/backup/component/BackupFlagInclusionDialog.tsx';
|
||||
import ListItemButton from '@mui/material/ListItemButton';
|
||||
import { AwaitableComponent } from 'awaitable-component';
|
||||
import { getAutoBackupFlagsInfo } from '@/features/backup/Backup.utils.ts';
|
||||
import type { BackupFlagInclusionState } from '@/features/backup/Backup.types.ts';
|
||||
|
||||
const convertSyncDataToBackupFlags = (settings: ServerSettingsType): BackupFlagInclusionState => ({
|
||||
includeManga: settings.syncDataManga,
|
||||
includeChapters: settings.syncDataChapters,
|
||||
includeCategories: settings.syncDataCategories,
|
||||
includeHistory: settings.syncDataHistory,
|
||||
includeTracking: settings.syncDataTracking,
|
||||
includeClientData: false,
|
||||
includeServerSettings: false,
|
||||
});
|
||||
|
||||
const convertBackupFlagsToSyncData = (flags: BackupFlagInclusionState): PartialSettingsTypeInput => ({
|
||||
syncDataManga: flags.includeManga,
|
||||
syncDataChapters: flags.includeChapters,
|
||||
syncDataCategories: flags.includeCategories,
|
||||
syncDataHistory: flags.includeHistory,
|
||||
syncDataTracking: flags.includeTracking,
|
||||
});
|
||||
|
||||
const getLogFilesCleanupDisplayValue = (ttl: number): string => {
|
||||
if (ttl === 0) {
|
||||
@@ -91,6 +120,15 @@ export const ServerSettings = () => {
|
||||
onCompletion?.(false);
|
||||
}
|
||||
};
|
||||
const updateSettings = async (settings: PartialSettingsTypeInput, onCompletion?: (success: boolean) => void) => {
|
||||
try {
|
||||
await mutateSettings({ variables: { input: { settings } } });
|
||||
onCompletion?.(true);
|
||||
} catch (e) {
|
||||
makeToast(t`Failed to save changes`, 'error', getErrorMessage(e));
|
||||
onCompletion?.(false);
|
||||
}
|
||||
};
|
||||
|
||||
const localSettings = useMemo(
|
||||
() => (
|
||||
@@ -176,6 +214,13 @@ export const ServerSettings = () => {
|
||||
const authModeDisabled = !serverSettings.authUsername?.trim() || !serverSettings.authPassword?.trim();
|
||||
const isH2Database = serverSettings.databaseType === DatabaseType.H2;
|
||||
|
||||
const isCustomSyncInterval = !SYNC_INTERVAL_VALUES.includes(
|
||||
d(serverSettings.syncInterval).minutes.asWholeMinutes.toISOString(),
|
||||
);
|
||||
const syncDataFlagsInfo = getAutoBackupFlagsInfo(serverSettings);
|
||||
const includedSyncDataText = syncDataFlagsInfo.true;
|
||||
const excludedSyncDataText = syncDataFlagsInfo.false;
|
||||
|
||||
return (
|
||||
<List sx={{ pt: 0 }}>
|
||||
{localSettings}
|
||||
@@ -669,6 +714,81 @@ export const ServerSettings = () => {
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
<List
|
||||
subheader={
|
||||
<ListSubheader component="div" id="server-settings-sync">
|
||||
{t`Sync`}
|
||||
</ListSubheader>
|
||||
}
|
||||
>
|
||||
<ListItemButton
|
||||
onClick={async () => {
|
||||
try {
|
||||
const flags = await AwaitableComponent.show(BackupFlagInclusionDialog, {
|
||||
title: t`Sync data`,
|
||||
flags: convertSyncDataToBackupFlags(serverSettings),
|
||||
hiddenFlags: SYNC_SETTINGS_HIDDEN_BACKUP_FLAGS,
|
||||
});
|
||||
|
||||
await updateSettings(convertBackupFlagsToSyncData(flags));
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ListItemText
|
||||
primary={t`Backup data`}
|
||||
secondary={
|
||||
<>
|
||||
<span>{t`Include: ${includedSyncDataText}`}</span>
|
||||
<span>{t`Exclude: ${excludedSyncDataText}`}</span>
|
||||
</>
|
||||
}
|
||||
slotProps={{
|
||||
secondary: { sx: { display: 'flex', flexDirection: 'column' } },
|
||||
}}
|
||||
/>
|
||||
</ListItemButton>
|
||||
<SelectSetting
|
||||
settingName={t`Sync interval`}
|
||||
value={
|
||||
isCustomSyncInterval
|
||||
? SYNC_INTERVAL_CUSTOM_VALUE
|
||||
: d(serverSettings.syncInterval).minutes.asWholeMinutes.toISOString()
|
||||
}
|
||||
values={
|
||||
isCustomSyncInterval ? SYNC_INTERVAL_SELECT_VALUES_WITH_CUSTOM : SYNC_INTERVAL_SELECT_VALUES
|
||||
}
|
||||
handleChange={(syncInterval) => updateSetting('syncInterval', syncInterval)}
|
||||
/>
|
||||
<List
|
||||
subheader={
|
||||
<ListSubheader component="div" id="server-settings-sync-syncyomi">
|
||||
{t`SyncYomi`}
|
||||
</ListSubheader>
|
||||
}
|
||||
>
|
||||
<ListItem>
|
||||
<ListItemText primary={t`SyncYomi enabled`} />
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={serverSettings.syncYomiEnabled}
|
||||
onChange={(e) => updateSetting('syncYomiEnabled', e.target.checked)}
|
||||
/>
|
||||
</ListItem>
|
||||
<TextSetting
|
||||
settingName={t`SyncYomi host`}
|
||||
value={serverSettings.syncYomiHost}
|
||||
handleChange={(host) => updateSetting('syncYomiHost', host)}
|
||||
/>
|
||||
<TextSetting
|
||||
settingName={t`SyncYomi API key`}
|
||||
value={serverSettings.syncYomiApiKey}
|
||||
handleChange={(apiKey) => updateSetting('syncYomiApiKey', apiKey)}
|
||||
isPassword
|
||||
/>
|
||||
</List>
|
||||
</List>
|
||||
<List
|
||||
subheader={
|
||||
<ListSubheader component="div" id="server-settings-misc">
|
||||
|
||||
Reference in New Issue
Block a user