Add sync state to settings
This commit is contained in:
@@ -199,6 +199,7 @@ const BackgroundSubscriptions = () => {
|
||||
requestManager.useDownloadSubscription({ skip: skipConnection });
|
||||
requestManager.useUpdaterSubscription({ skip: skipConnection });
|
||||
requestManager.useWebUIUpdateSubscription({ skip: skipConnection });
|
||||
requestManager.useSyncSubscription({ skip: skipConnection });
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
@@ -48,7 +48,7 @@ export const isSameDay = (first: Dayjs, second: Dayjs): boolean => first.isSame(
|
||||
* @param date
|
||||
* @param withTime
|
||||
*/
|
||||
export const getDateString = (date: Dayjs | number, withTime: boolean = false) => {
|
||||
export const getDateString = (date: Dayjs | number, withTime: boolean = false, dateTime: boolean = false) => {
|
||||
const actualDate = date instanceof dayjs ? date : dayjs(date);
|
||||
const timeString = timeFormatter.format(actualDate.toDate());
|
||||
|
||||
@@ -68,5 +68,9 @@ export const getDateString = (date: Dayjs | number, withTime: boolean = false) =
|
||||
return t`Yesterday`;
|
||||
}
|
||||
|
||||
if (dateTime) {
|
||||
return dateTimeFormatter.format(actualDate.toDate());
|
||||
}
|
||||
|
||||
return dateFormatter.format(actualDate.toDate());
|
||||
};
|
||||
|
||||
@@ -24,6 +24,8 @@ import {
|
||||
AuthMode,
|
||||
KoreaderSyncChecksumMethod,
|
||||
KoreaderSyncConflictStrategy,
|
||||
StartSyncResult,
|
||||
SyncState,
|
||||
WebUiChannel,
|
||||
WebUiFlavor,
|
||||
WebUiInterface,
|
||||
@@ -360,3 +362,20 @@ export const SYNC_SETTINGS_HIDDEN_BACKUP_FLAGS = [
|
||||
'includeServerSettings',
|
||||
'includeClientData',
|
||||
] as const satisfies BackupFlag[];
|
||||
|
||||
export const SYNC_START_RESULT_TRANSLATION: Record<StartSyncResult, MessageDescriptor> = {
|
||||
[StartSyncResult.Success]: msg`Sync started`,
|
||||
[StartSyncResult.SyncDisabled]: msg`Sync disabled`,
|
||||
[StartSyncResult.SyncInProgress]: msg`Sync in progress`,
|
||||
};
|
||||
|
||||
export const SYNC_STATE_TRANSLATION: Record<SyncState, MessageDescriptor> = {
|
||||
[SyncState.CreatingBackup]: msg`Creating backup`,
|
||||
[SyncState.Downloading]: msg`Downloading`,
|
||||
[SyncState.Error]: msg`Error`,
|
||||
[SyncState.Merging]: msg`Merging`,
|
||||
[SyncState.Restoring]: msg`Restoring`,
|
||||
[SyncState.Started]: msg`Started`,
|
||||
[SyncState.Success]: msg`Success`,
|
||||
[SyncState.Uploading]: msg`Uploading`,
|
||||
};
|
||||
|
||||
@@ -32,7 +32,14 @@ import type { MetadataUpdateSettings } from '@/features/app-updates/AppUpdateChe
|
||||
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 {
|
||||
AuthMode,
|
||||
CbzMediaType,
|
||||
DatabaseType,
|
||||
SortOrder,
|
||||
StartSyncResult,
|
||||
SyncState,
|
||||
} from '@/lib/graphql/generated/graphql-base.types.ts';
|
||||
import {
|
||||
AUTH_MODES_SELECT_VALUES,
|
||||
JWT_ACCESS_TOKEN_EXPIRY,
|
||||
@@ -42,6 +49,8 @@ import {
|
||||
SYNC_INTERVAL_SELECT_VALUES_WITH_CUSTOM,
|
||||
SYNC_INTERVAL_VALUES,
|
||||
SYNC_SETTINGS_HIDDEN_BACKUP_FLAGS,
|
||||
SYNC_START_RESULT_TRANSLATION,
|
||||
SYNC_STATE_TRANSLATION,
|
||||
} from '@/features/settings/Settings.constants.ts';
|
||||
import { ServerAddressSetting } from '@/features/settings/components/ServerAddressSetting.tsx';
|
||||
import { AuthManager } from '@/features/authentication/AuthManager.ts';
|
||||
@@ -53,6 +62,7 @@ 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';
|
||||
import { epochToDate, getDateString } from '@/base/utils/DateHelper.ts';
|
||||
|
||||
const convertSyncDataToBackupFlags = (settings: ServerSettingsType): BackupFlagInclusionState => ({
|
||||
includeManga: settings.syncDataManga,
|
||||
@@ -88,6 +98,7 @@ export const ServerSettings = () => {
|
||||
|
||||
useAppTitle(t`Server`);
|
||||
|
||||
const syncStatusRequest = requestManager.useGetSyncStatus();
|
||||
const {
|
||||
settings: { serverInformAvailableUpdate, serverInformVersionUpdated },
|
||||
loading: areMetadataServerSettingsLoading,
|
||||
@@ -221,6 +232,11 @@ export const ServerSettings = () => {
|
||||
const includedSyncDataText = syncDataFlagsInfo.true;
|
||||
const excludedSyncDataText = syncDataFlagsInfo.false;
|
||||
|
||||
const syncStatus = syncStatusRequest.data?.lastSyncStatus;
|
||||
const syncDate = syncStatus?.endDate ?? syncStatus?.startDate;
|
||||
const syncState = syncStatus?.state;
|
||||
const isSyncing = !!syncState && ![SyncState.Success, SyncState.Error].includes(syncState);
|
||||
|
||||
return (
|
||||
<List sx={{ pt: 0 }}>
|
||||
{localSettings}
|
||||
@@ -732,6 +748,33 @@ export const ServerSettings = () => {
|
||||
</ListSubheader>
|
||||
}
|
||||
>
|
||||
<ListItemButton
|
||||
disabled={isSyncing}
|
||||
onClick={() =>
|
||||
requestManager
|
||||
.startSync()
|
||||
.response.then((response) => {
|
||||
const startResult = response.data?.startSync.result;
|
||||
|
||||
makeToast(
|
||||
t(SYNC_START_RESULT_TRANSLATION[startResult!]),
|
||||
startResult === StartSyncResult.Success ? 'success' : 'error',
|
||||
);
|
||||
})
|
||||
.catch((e) => makeToast(t`Could not start sync`, 'error', getErrorMessage(e)))
|
||||
}
|
||||
>
|
||||
<ListItemText
|
||||
primary={isSyncing ? t`Sync status` : t`Start sync`}
|
||||
secondary={
|
||||
<>
|
||||
{syncDate && t`Last sync: ${getDateString(epochToDate(Number(syncDate)), true, true)}`}{' '}
|
||||
{syncState && t`- State: ${t(SYNC_STATE_TRANSLATION[syncState])}`}
|
||||
{!!syncStatus?.errorMessage && `\nError: ${syncStatus.errorMessage}`}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</ListItemButton>
|
||||
<ListItemButton
|
||||
onClick={async () => {
|
||||
try {
|
||||
@@ -748,7 +791,7 @@ export const ServerSettings = () => {
|
||||
}}
|
||||
>
|
||||
<ListItemText
|
||||
primary={t`Backup data`}
|
||||
primary={t`Sync data`}
|
||||
secondary={
|
||||
<>
|
||||
<span>{t`Include: ${includedSyncDataText}`}</span>
|
||||
|
||||
@@ -14,6 +14,11 @@ msgstr ""
|
||||
"Plural-Forms: \n"
|
||||
"X-Message-Format: ICU\n"
|
||||
|
||||
#. placeholder {0}: t(SYNC_STATE_TRANSLATION[syncState])
|
||||
#: src/features/settings/screens/ServerSettings.tsx
|
||||
msgid "- State: {0}"
|
||||
msgstr "- State: {0}"
|
||||
|
||||
#. placeholder {0}: selectedChapters.length
|
||||
#. placeholder {0}: visibleChapters.length
|
||||
#: src/features/chapter/components/ChapterList.tsx
|
||||
@@ -574,7 +579,6 @@ msgid "Backup cleanup"
|
||||
msgstr "Backup cleanup"
|
||||
|
||||
#: src/features/backup/screens/Backup.tsx
|
||||
#: src/features/settings/screens/ServerSettings.tsx
|
||||
msgid "Backup data"
|
||||
msgstr "Backup data"
|
||||
|
||||
@@ -1152,6 +1156,10 @@ msgstr "Could not save theme changes"
|
||||
msgid "Could not search source"
|
||||
msgstr "Could not search source"
|
||||
|
||||
#: src/features/settings/screens/ServerSettings.tsx
|
||||
msgid "Could not start sync"
|
||||
msgstr "Could not start sync"
|
||||
|
||||
#: src/features/updates/components/UpdateChecker.tsx
|
||||
msgid "Could not stop global update"
|
||||
msgstr "Could not stop global update"
|
||||
@@ -1192,6 +1200,10 @@ msgstr "Create theme"
|
||||
msgid "Created theme"
|
||||
msgstr "Created theme"
|
||||
|
||||
#: src/features/settings/Settings.constants.ts
|
||||
msgid "Creating backup"
|
||||
msgstr "Creating backup"
|
||||
|
||||
#: src/features/backup/screens/Backup.tsx
|
||||
msgid "Creating backup…"
|
||||
msgstr "Creating backup…"
|
||||
@@ -1488,6 +1500,7 @@ msgid "Downloaded"
|
||||
msgstr "Downloaded"
|
||||
|
||||
#: src/base/components/downloads/DownloadStateIndicator.tsx
|
||||
#: src/features/settings/Settings.constants.ts
|
||||
msgid "Downloading"
|
||||
msgstr "Downloading"
|
||||
|
||||
@@ -1587,6 +1600,7 @@ msgstr "Entry \"{id}\" not found"
|
||||
|
||||
#: src/base/components/downloads/DownloadStateIndicator.tsx
|
||||
#: src/base/components/feedback/SnackbarWithDescription.tsx
|
||||
#: src/features/settings/Settings.constants.ts
|
||||
msgid "Error"
|
||||
msgstr "Error"
|
||||
|
||||
@@ -2168,6 +2182,11 @@ msgstr "Large"
|
||||
msgid "Last read chapter"
|
||||
msgstr "Last read chapter"
|
||||
|
||||
#. placeholder {0}: getDateString(epochToDate(Number(syncDate)), true, true)
|
||||
#: src/features/settings/screens/ServerSettings.tsx
|
||||
msgid "Last sync: {0}"
|
||||
msgstr "Last sync: {0}"
|
||||
|
||||
#: src/features/updates/screens/Updates.tsx
|
||||
msgid "Last update: {date}"
|
||||
msgstr "Last update: {date}"
|
||||
@@ -2420,6 +2439,10 @@ msgstr "Medium"
|
||||
msgid "Menu"
|
||||
msgstr "Menu"
|
||||
|
||||
#: src/features/settings/Settings.constants.ts
|
||||
msgid "Merging"
|
||||
msgstr "Merging"
|
||||
|
||||
#: src/features/browse/screens/Browse.tsx
|
||||
#: src/features/manga/components/MangaToolbarMenu.tsx
|
||||
#: src/features/manga/Manga.constants.ts
|
||||
@@ -3008,6 +3031,10 @@ msgstr "Restore"
|
||||
msgid "Restore Backup"
|
||||
msgstr "Restore Backup"
|
||||
|
||||
#: src/features/settings/Settings.constants.ts
|
||||
msgid "Restoring"
|
||||
msgstr "Restoring"
|
||||
|
||||
#: src/features/backup/screens/Backup.tsx
|
||||
msgid "Restoring backup…"
|
||||
msgstr "Restoring backup…"
|
||||
@@ -3496,7 +3523,12 @@ msgstr ""
|
||||
msgid "Start Search"
|
||||
msgstr "Start Search"
|
||||
|
||||
#: src/features/settings/screens/ServerSettings.tsx
|
||||
msgid "Start sync"
|
||||
msgstr "Start sync"
|
||||
|
||||
#: src/features/library/components/LibraryOptionsPanel.tsx
|
||||
#: src/features/settings/Settings.constants.ts
|
||||
#: src/features/tracker/components/cards/TrackerMangaCard.tsx
|
||||
msgid "Started"
|
||||
msgstr "Started"
|
||||
@@ -3531,6 +3563,7 @@ msgid "Submit"
|
||||
msgstr "Submit"
|
||||
|
||||
#: src/base/components/feedback/SnackbarWithDescription.tsx
|
||||
#: src/features/settings/Settings.constants.ts
|
||||
msgid "Success"
|
||||
msgstr "Success"
|
||||
|
||||
@@ -3550,11 +3583,24 @@ msgstr "Sync"
|
||||
msgid "Sync data"
|
||||
msgstr "Sync data"
|
||||
|
||||
#: src/features/settings/Settings.constants.ts
|
||||
msgid "Sync disabled"
|
||||
msgstr "Sync disabled"
|
||||
|
||||
#: src/features/settings/Settings.constants.ts
|
||||
msgid "Sync in progress"
|
||||
msgstr "Sync in progress"
|
||||
|
||||
#: src/features/settings/screens/ServerSettings.tsx
|
||||
msgid "Sync interval"
|
||||
msgstr "Sync interval"
|
||||
|
||||
#: src/features/settings/Settings.constants.ts
|
||||
msgid "Sync started"
|
||||
msgstr "Sync started"
|
||||
|
||||
#: src/features/settings/components/koreaderSync/KoreaderSyncSettings.tsx
|
||||
#: src/features/settings/screens/ServerSettings.tsx
|
||||
msgid "Sync status"
|
||||
msgstr "Sync status"
|
||||
|
||||
@@ -3966,6 +4012,10 @@ msgstr "Updates"
|
||||
msgid "Updating"
|
||||
msgstr "Updating"
|
||||
|
||||
#: src/features/settings/Settings.constants.ts
|
||||
msgid "Uploading"
|
||||
msgstr "Uploading"
|
||||
|
||||
#: src/features/settings/Settings.constants.ts
|
||||
msgid "URL"
|
||||
msgstr "URL"
|
||||
|
||||
@@ -102,6 +102,8 @@ import type {
|
||||
GetSourceMangasFetchMutationVariables,
|
||||
GetSourcesListQuery,
|
||||
GetSourcesListQueryVariables,
|
||||
GetSyncStatusQuery,
|
||||
GetSyncStatusQueryVariables,
|
||||
GetUpdateStatusQuery,
|
||||
GetUpdateStatusQueryVariables,
|
||||
GetWebuiUpdateStatusQuery,
|
||||
@@ -124,10 +126,14 @@ import type {
|
||||
RestoreBackupMutationVariables,
|
||||
StartDownloaderMutation,
|
||||
StartDownloaderMutationVariables,
|
||||
StartSyncMutation,
|
||||
StartSyncMutationVariables,
|
||||
StopDownloaderMutation,
|
||||
StopDownloaderMutationVariables,
|
||||
StopUpdaterMutation,
|
||||
StopUpdaterMutationVariables,
|
||||
SyncSubscription,
|
||||
SyncSubscriptionVariables,
|
||||
TrackerBindMutation,
|
||||
TrackerBindMutationVariables,
|
||||
TrackerBindTrackRecordMutation,
|
||||
@@ -193,6 +199,7 @@ import type {
|
||||
ValidateBackupQuery,
|
||||
ValidateBackupQueryVariables,
|
||||
WebuiUpdateSubscription,
|
||||
WebuiUpdateSubscriptionVariables,
|
||||
} from '@/lib/graphql/generated/graphql.ts';
|
||||
import type {
|
||||
CreateBackupInput,
|
||||
@@ -345,6 +352,9 @@ import { EXTENSION_STORE_FIELDS } from '@/lib/graphql/extension/store/ExtensionS
|
||||
import { ADD_EXTENSION_STORE, REMOVE_EXTENSION_STORE } from '@/lib/graphql/extension/store/ExtensionStoreMutation.ts';
|
||||
import { assertIsDefined } from '@/base/Asserts.ts';
|
||||
import { GET_EXTENSION_STORE, GET_EXTENSION_STORES } from '@/lib/graphql/extension/store/ExtensionStoreQuery.ts';
|
||||
import { SYNC_SUBSCRIPTION } from '@/lib/graphql/sync/SyncSubscription.ts';
|
||||
import { START_SYNC } from '@/lib/graphql/sync/SyncMutation.ts';
|
||||
import { GET_SYNC_STATUS } from '@/lib/graphql/sync/SyncQuery.ts';
|
||||
|
||||
enum GQLMethod {
|
||||
QUERY = 'QUERY',
|
||||
@@ -3717,7 +3727,7 @@ export class RequestManager {
|
||||
}
|
||||
|
||||
public useWebUIUpdateSubscription(
|
||||
options?: SubscriptionHookOptions<WebuiUpdateSubscription, WebuiUpdateSubscription>,
|
||||
options?: SubscriptionHookOptions<WebuiUpdateSubscription, WebuiUpdateSubscriptionVariables>,
|
||||
): useSubscription.Result<WebuiUpdateSubscription> {
|
||||
return this.doRequest(GQLMethod.USE_SUBSCRIPTION, WEBUI_UPDATE_SUBSCRIPTION, undefined, options);
|
||||
}
|
||||
@@ -3860,6 +3870,29 @@ export class RequestManager {
|
||||
return this.doRequest(GQLMethod.USE_MUTATION, USER_LOGIN, undefined, options);
|
||||
}
|
||||
|
||||
public startSync(
|
||||
options?: MutationOptions<StartSyncMutation, StartSyncMutationVariables>,
|
||||
): AbortableApolloMutationResponse<StartSyncMutation> {
|
||||
return this.doRequest<StartSyncMutation, StartSyncMutationVariables>(
|
||||
GQLMethod.MUTATION,
|
||||
START_SYNC,
|
||||
{},
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
public useGetSyncStatus(
|
||||
options?: QueryHookOptions<GetSyncStatusQuery, GetSyncStatusQueryVariables>,
|
||||
): AbortableApolloUseQueryResponse<GetSyncStatusQuery, GetSyncStatusQueryVariables> {
|
||||
return this.doRequest(GQLMethod.USE_QUERY, GET_SYNC_STATUS, {}, options);
|
||||
}
|
||||
|
||||
public useSyncSubscription(
|
||||
options?: SubscriptionHookOptions<SyncSubscription, SyncSubscriptionVariables>,
|
||||
): useSubscription.Result<SyncSubscription> {
|
||||
return this.doRequest(GQLMethod.USE_SUBSCRIPTION, SYNC_SUBSCRIPTION, undefined, options);
|
||||
}
|
||||
|
||||
public useKoSyncStatus(
|
||||
options?: QueryHookOptions<GetKoSyncStatusQuery, GetKoSyncStatusQueryVariables>,
|
||||
): AbortableApolloUseQueryResponse<GetKoSyncStatusQuery, GetKoSyncStatusQueryVariables> {
|
||||
|
||||
@@ -74,6 +74,7 @@ const typePolicies: TypedTypePolicies = {
|
||||
WebUIUpdateStatus: { keyFields: [] },
|
||||
UpdateStatus: { keyFields: [] },
|
||||
KoSyncStatusPayload: { keyFields: [] },
|
||||
SyncStatus: { keyFields: [] },
|
||||
Query: {
|
||||
fields: {
|
||||
manga(_, { args, toReference }) {
|
||||
@@ -132,6 +133,9 @@ const typePolicies: TypedTypePolicies = {
|
||||
updateStatus(_, { toReference }) {
|
||||
return toReference({ __typename: 'UpdateStatus', key: {} });
|
||||
},
|
||||
lastSyncStatus(_, { toReference }) {
|
||||
return toReference({ __typename: 'SyncStatus', key: {} });
|
||||
},
|
||||
chapters: {
|
||||
keyArgs: ['condition', 'filter', 'orderBy', 'orderByType', 'order'],
|
||||
merge(existing, incoming) {
|
||||
|
||||
Reference in New Issue
Block a user