This commit is contained in:
Wang Guan 2024-11-06 21:01:36 +11:00 committed by GitHub
commit 36cfebdadd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 90 additions and 6 deletions

View File

@ -29,6 +29,9 @@ import { AuthPage } from "./auth";
import { getClientConfig } from "../config/client"; import { getClientConfig } from "../config/client";
import { type ClientApi, getClientApi } from "../client/api"; import { type ClientApi, getClientApi } from "../client/api";
import { useAccessStore } from "../store"; import { useAccessStore } from "../store";
import { useSyncStore } from "../store/sync";
import { showToast } from "./ui-lib";
import Locale from "@/app/locales";
export function Loading(props: { noLogo?: boolean }) { export function Loading(props: { noLogo?: boolean }) {
return ( return (
@ -149,6 +152,40 @@ export function WindowContent(props: { children: React.ReactNode }) {
); );
} }
function useSyncOnStart() {
const syncStore = useSyncStore();
const storeHasHydrated = useSyncStore((s) => s._hasHydrated);
useEffect(() => {
let running = true;
setTimeout(async () => {
if (
!(
storeHasHydrated &&
running &&
syncStore.cloudSync() &&
syncStore.autoSync.onStart
)
) {
return;
}
const dismissSyncingToast = showToast(Locale.Settings.Sync.IsSyncing);
try {
await syncStore.sync();
dismissSyncingToast();
showToast(Locale.Settings.Sync.Success);
} catch (e: unknown) {
dismissSyncingToast();
showToast(Locale.Settings.Sync.Fail);
console.error("[Sync]", e);
}
});
return () => {
running = false;
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [storeHasHydrated]);
}
function Screen() { function Screen() {
const config = useAppConfig(); const config = useAppConfig();
const location = useLocation(); const location = useLocation();
@ -165,6 +202,7 @@ function Screen() {
useEffect(() => { useEffect(() => {
loadAsyncGoogleFont(); loadAsyncGoogleFont();
}, []); }, []);
useSyncOnStart();
if (isArtifact) { if (isArtifact) {
return ( return (

View File

@ -477,6 +477,21 @@ function SyncConfigModal(props: { onClose?: () => void }) {
</ListItem> </ListItem>
</List> </List>
)} )}
<List>
<ListItem title={Locale.Settings.Sync.Config.AutoSync.OnStartup}>
<input
type="checkbox"
checked={syncStore.autoSync.onStart}
onChange={(e) => {
syncStore.update(
(config) =>
(config.autoSync.onStart = e.currentTarget.checked),
);
}}
/>
</ListItem>
</List>
</Modal> </Modal>
</div> </div>
); );

View File

@ -229,13 +229,19 @@ export function showToast(
content: string, content: string,
action?: ToastProps["action"], action?: ToastProps["action"],
delay = 3000, delay = 3000,
) { ): () => void {
const div = document.createElement("div"); const div = document.createElement("div");
div.className = styles.show; div.className = styles.show;
document.body.appendChild(div); document.body.appendChild(div);
const root = createRoot(div); const root = createRoot(div);
let closeCalled = false;
const close = () => { const close = () => {
if (closeCalled) {
return;
} else {
closeCalled = true;
}
div.classList.add(styles.hide); div.classList.add(styles.hide);
setTimeout(() => { setTimeout(() => {
@ -249,6 +255,8 @@ export function showToast(
}, delay); }, delay);
root.render(<Toast content={content} action={action} onClose={close} />); root.render(<Toast content={content} action={action} onClose={close} />);
return close;
} }
export type InputProps = React.HTMLProps<HTMLTextAreaElement> & { export type InputProps = React.HTMLProps<HTMLTextAreaElement> & {

View File

@ -223,6 +223,7 @@ const cn = {
CloudState: "云端数据", CloudState: "云端数据",
NotSyncYet: "还没有进行过同步", NotSyncYet: "还没有进行过同步",
Success: "同步成功", Success: "同步成功",
IsSyncing: "正在同步...",
Fail: "同步失败", Fail: "同步失败",
Config: { Config: {
@ -254,6 +255,10 @@ const cn = {
UserName: "备份名称", UserName: "备份名称",
Password: "UpStash Redis REST Token", Password: "UpStash Redis REST Token",
}, },
AutoSync: {
OnStartup: "启动时自动同步",
},
}, },
LocalState: "本地数据", LocalState: "本地数据",

View File

@ -225,6 +225,7 @@ const en: LocaleType = {
CloudState: "Last Update", CloudState: "Last Update",
NotSyncYet: "Not sync yet", NotSyncYet: "Not sync yet",
Success: "Sync Success", Success: "Sync Success",
IsSyncing: "Sync in progress...",
Fail: "Sync Fail", Fail: "Sync Fail",
Config: { Config: {
@ -257,6 +258,10 @@ const en: LocaleType = {
UserName: "Backup Name", UserName: "Backup Name",
Password: "UpStash Redis REST Token", Password: "UpStash Redis REST Token",
}, },
AutoSync: {
OnStartup: "Sync on startup",
},
}, },
LocalState: "Local Data", LocalState: "Local Data",

View File

@ -27,18 +27,22 @@ const DEFAULT_SYNC_STATE = {
useProxy: true, useProxy: true,
proxyUrl: ApiPath.Cors as string, proxyUrl: ApiPath.Cors as string,
webdav: { [ProviderType.WebDAV]: {
endpoint: "", endpoint: "",
username: "", username: "",
password: "", password: "",
}, },
upstash: { [ProviderType.UpStash]: {
endpoint: "", endpoint: "",
username: STORAGE_KEY, username: STORAGE_KEY,
apiKey: "", apiKey: "",
}, },
autoSync: {
onStart: false,
},
lastSyncTime: 0, lastSyncTime: 0,
lastProvider: "", lastProvider: "",
}; };
@ -46,9 +50,14 @@ const DEFAULT_SYNC_STATE = {
export const useSyncStore = createPersistStore( export const useSyncStore = createPersistStore(
DEFAULT_SYNC_STATE, DEFAULT_SYNC_STATE,
(set, get) => ({ (set, get) => ({
cloudSync() { cloudSync(): boolean {
const config = get()[get().provider]; const config = get()[get().provider];
return Object.values(config).every((c) => c.toString().length > 0); if (!config) {
return false;
}
return Object.values(config).every(
(c) => c != null && c.toString().length > 0,
);
}, },
markSyncTime() { markSyncTime() {
@ -126,7 +135,7 @@ export const useSyncStore = createPersistStore(
}), }),
{ {
name: StoreKey.Sync, name: StoreKey.Sync,
version: 1.2, version: 1.3,
migrate(persistedState, version) { migrate(persistedState, version) {
const newState = persistedState as typeof DEFAULT_SYNC_STATE; const newState = persistedState as typeof DEFAULT_SYNC_STATE;
@ -144,6 +153,10 @@ export const useSyncStore = createPersistStore(
} }
} }
if (version < 1.3) {
newState.autoSync = { ...DEFAULT_SYNC_STATE.autoSync };
}
return newState as any; return newState as any;
}, },
}, },