From 93ad218d688a6c2131b70bd4801693ac627fb016 Mon Sep 17 00:00:00 2001 From: Wang Guan Date: Sat, 19 Oct 2024 18:58:35 +0900 Subject: [PATCH 01/10] run cloud sync on startup --- app/components/home.tsx | 26 ++++++++++++++++++++++++-- app/store/sync.ts | 10 +++++++--- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/app/components/home.tsx b/app/components/home.tsx index 465ad0f1ed1..54cb1ea058e 100644 --- a/app/components/home.tsx +++ b/app/components/home.tsx @@ -28,7 +28,9 @@ import { useAppConfig } from "../store/config"; import { AuthPage } from "./auth"; import { getClientConfig } from "../config/client"; import { type ClientApi, getClientApi } from "../client/api"; -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 }) { return ( @@ -224,12 +226,32 @@ export function Home() { useSwitchTheme(); useLoadData(); useHtmlLang(); + const syncStore = useSyncStore(); useEffect(() => { console.log("[Config] got config from build time", getClientConfig()); - useAccessStore.getState().fetch(); }, []); + useEffect(() => { + let running = true; + + setTimeout(async () => { + if (running && syncStore.cloudSync()) { + try { + await syncStore.sync(); + showToast(Locale.Settings.Sync.Success); + } catch (e: unknown) { + showToast(Locale.Settings.Sync.Fail); + console.error("[Sync]", e); + } + } + }); + + return () => { + running = false; + }; + }, [syncStore]); + if (!useHasHydrated()) { return ; } diff --git a/app/store/sync.ts b/app/store/sync.ts index 8477c1e4ba7..bbde212c0e2 100644 --- a/app/store/sync.ts +++ b/app/store/sync.ts @@ -27,18 +27,22 @@ const DEFAULT_SYNC_STATE = { useProxy: true, proxyUrl: ApiPath.Cors as string, - webdav: { + [ProviderType.WebDAV]: { endpoint: "", username: "", password: "", }, - upstash: { + [ProviderType.UpStash]: { endpoint: "", username: STORAGE_KEY, apiKey: "", }, + autoSync: { + onStart: true, + }, + lastSyncTime: 0, lastProvider: "", }; @@ -46,7 +50,7 @@ const DEFAULT_SYNC_STATE = { export const useSyncStore = createPersistStore( DEFAULT_SYNC_STATE, (set, get) => ({ - cloudSync() { + cloudSync(): boolean { const config = get()[get().provider]; return Object.values(config).every((c) => c.toString().length > 0); }, From df7edbd7d0f031852e8a61ded90eb9a2b86d194f Mon Sep 17 00:00:00 2001 From: Wang Guan Date: Sat, 19 Oct 2024 19:31:18 +0900 Subject: [PATCH 02/10] add setting UI --- app/components/home.tsx | 2 +- app/components/settings.tsx | 15 +++++++++++++++ app/locales/cn.ts | 4 ++++ app/locales/en.ts | 4 ++++ app/store/sync.ts | 2 +- 5 files changed, 25 insertions(+), 2 deletions(-) diff --git a/app/components/home.tsx b/app/components/home.tsx index 54cb1ea058e..ae7bf901c4b 100644 --- a/app/components/home.tsx +++ b/app/components/home.tsx @@ -236,7 +236,7 @@ export function Home() { let running = true; setTimeout(async () => { - if (running && syncStore.cloudSync()) { + if (running && syncStore.cloudSync() && syncStore.autoSync.onStart) { try { await syncStore.sync(); showToast(Locale.Settings.Sync.Success); diff --git a/app/components/settings.tsx b/app/components/settings.tsx index 82ce70e5a18..4eff5d78922 100644 --- a/app/components/settings.tsx +++ b/app/components/settings.tsx @@ -475,6 +475,21 @@ function SyncConfigModal(props: { onClose?: () => void }) { )} + + + + { + syncStore.update( + (config) => + (config.autoSync.onStart = e.currentTarget.checked), + ); + }} + /> + + ); diff --git a/app/locales/cn.ts b/app/locales/cn.ts index e514eb4fe65..ea545918d21 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -254,6 +254,10 @@ const cn = { UserName: "备份名称", Password: "UpStash Redis REST Token", }, + + AutoSync: { + OnStartup: "启动时自动同步", + }, }, LocalState: "本地数据", diff --git a/app/locales/en.ts b/app/locales/en.ts index c86cc08f039..fada08193db 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -257,6 +257,10 @@ const en: LocaleType = { UserName: "Backup Name", Password: "UpStash Redis REST Token", }, + + AutoSync: { + OnStartup: "Sync on startup", + }, }, LocalState: "Local Data", diff --git a/app/store/sync.ts b/app/store/sync.ts index bbde212c0e2..4db38f40d3a 100644 --- a/app/store/sync.ts +++ b/app/store/sync.ts @@ -40,7 +40,7 @@ const DEFAULT_SYNC_STATE = { }, autoSync: { - onStart: true, + onStart: false, }, lastSyncTime: 0, From a73a4c6dd61c0d6f2c797cf70309f66569ddce60 Mon Sep 17 00:00:00 2001 From: Wang Guan Date: Sat, 19 Oct 2024 19:49:16 +0900 Subject: [PATCH 03/10] only sync on startup --- app/components/home.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/components/home.tsx b/app/components/home.tsx index ae7bf901c4b..d4a7065fc8e 100644 --- a/app/components/home.tsx +++ b/app/components/home.tsx @@ -250,7 +250,8 @@ export function Home() { return () => { running = false; }; - }, [syncStore]); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); if (!useHasHydrated()) { return ; From 903d00bd89423a3d21af5f50e65c85b70d2c14f1 Mon Sep 17 00:00:00 2001 From: Wang Guan Date: Tue, 22 Oct 2024 01:50:23 +0900 Subject: [PATCH 04/10] showToast(): return a dismiss callback --- app/components/ui-lib.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/components/ui-lib.tsx b/app/components/ui-lib.tsx index 4af37dbba1c..5d52bef59be 100644 --- a/app/components/ui-lib.tsx +++ b/app/components/ui-lib.tsx @@ -229,13 +229,19 @@ export function showToast( content: string, action?: ToastProps["action"], delay = 3000, -) { +): () => void { const div = document.createElement("div"); div.className = styles.show; document.body.appendChild(div); const root = createRoot(div); + let closeCalled = false; const close = () => { + if (closeCalled) { + return; + } else { + closeCalled = true; + } div.classList.add(styles.hide); setTimeout(() => { @@ -249,6 +255,8 @@ export function showToast( }, delay); root.render(); + + return close; } export type InputProps = React.HTMLProps & { From f123ffc74ba1b9110f090792720c964b1c84f8b7 Mon Sep 17 00:00:00 2001 From: Wang Guan Date: Tue, 22 Oct 2024 01:51:30 +0900 Subject: [PATCH 05/10] change useSyncOnStart() to a hook --- app/components/home.tsx | 51 ++++++++++++++++++++++------------------- app/locales/cn.ts | 1 + app/locales/en.ts | 1 + 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/app/components/home.tsx b/app/components/home.tsx index d4a7065fc8e..4b731c63420 100644 --- a/app/components/home.tsx +++ b/app/components/home.tsx @@ -151,6 +151,33 @@ export function WindowContent(props: { children: React.ReactNode }) { ); } +function useSyncOnStart() { + const syncStore = useSyncStore(); + useEffect(() => { + let running = true; + setTimeout(async () => { + if (!(running && syncStore.cloudSync() && syncStore.autoSync.onStart)) { + return; + } + console.debug("wtf", syncStore.autoSync, syncStore.cloudSync()); + 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 + }, []); +} + function Screen() { const config = useAppConfig(); const location = useLocation(); @@ -167,6 +194,7 @@ function Screen() { useEffect(() => { loadAsyncGoogleFont(); }, []); + useSyncOnStart(); if (isArtifact) { return ( @@ -226,33 +254,10 @@ export function Home() { useSwitchTheme(); useLoadData(); useHtmlLang(); - const syncStore = useSyncStore(); - useEffect(() => { console.log("[Config] got config from build time", getClientConfig()); }, []); - useEffect(() => { - let running = true; - - setTimeout(async () => { - if (running && syncStore.cloudSync() && syncStore.autoSync.onStart) { - try { - await syncStore.sync(); - showToast(Locale.Settings.Sync.Success); - } catch (e: unknown) { - showToast(Locale.Settings.Sync.Fail); - console.error("[Sync]", e); - } - } - }); - - return () => { - running = false; - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - if (!useHasHydrated()) { return ; } diff --git a/app/locales/cn.ts b/app/locales/cn.ts index ea545918d21..4ae8f8fd717 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -223,6 +223,7 @@ const cn = { CloudState: "云端数据", NotSyncYet: "还没有进行过同步", Success: "同步成功", + IsSyncing: "正在同步...", Fail: "同步失败", Config: { diff --git a/app/locales/en.ts b/app/locales/en.ts index fada08193db..c1be15c8c23 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -225,6 +225,7 @@ const en: LocaleType = { CloudState: "Last Update", NotSyncYet: "Not sync yet", Success: "Sync Success", + IsSyncing: "Sync in progress...", Fail: "Sync Fail", Config: { From 7fac17f189c5dc3d73028aa81b8a83f71c689111 Mon Sep 17 00:00:00 2001 From: Wang Guan Date: Tue, 22 Oct 2024 20:57:58 +0900 Subject: [PATCH 06/10] fix --- app/components/home.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/components/home.tsx b/app/components/home.tsx index 4b731c63420..92ee35b7e62 100644 --- a/app/components/home.tsx +++ b/app/components/home.tsx @@ -28,6 +28,7 @@ import { useAppConfig } from "../store/config"; import { AuthPage } from "./auth"; import { getClientConfig } from "../config/client"; import { type ClientApi, getClientApi } from "../client/api"; +import { useAccessStore } from "../store"; import { useSyncStore } from "../store/sync"; import { showToast } from "./ui-lib"; import Locale from "@/app/locales"; @@ -159,7 +160,6 @@ function useSyncOnStart() { if (!(running && syncStore.cloudSync() && syncStore.autoSync.onStart)) { return; } - console.debug("wtf", syncStore.autoSync, syncStore.cloudSync()); const dismissSyncingToast = showToast(Locale.Settings.Sync.IsSyncing); try { await syncStore.sync(); @@ -254,8 +254,10 @@ export function Home() { useSwitchTheme(); useLoadData(); useHtmlLang(); + useEffect(() => { console.log("[Config] got config from build time", getClientConfig()); + useAccessStore.getState().fetch(); }, []); if (!useHasHydrated()) { From 53156abf1bfd446f88314504b1c162dd2f75c466 Mon Sep 17 00:00:00 2001 From: Wang Guan Date: Tue, 22 Oct 2024 21:35:13 +0900 Subject: [PATCH 07/10] make coderabbit happy --- app/store/sync.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/store/sync.ts b/app/store/sync.ts index 4db38f40d3a..c17385b0b6b 100644 --- a/app/store/sync.ts +++ b/app/store/sync.ts @@ -130,7 +130,7 @@ export const useSyncStore = createPersistStore( }), { name: StoreKey.Sync, - version: 1.2, + version: 1.3, migrate(persistedState, version) { const newState = persistedState as typeof DEFAULT_SYNC_STATE; @@ -148,6 +148,10 @@ export const useSyncStore = createPersistStore( } } + if (version < 1.3) { + newState.autoSync = { ...DEFAULT_SYNC_STATE.autoSync }; + } + return newState as any; }, }, From 7869f7cc5f7437a8885917233d82bae249783b27 Mon Sep 17 00:00:00 2001 From: Wang Guan Date: Tue, 22 Oct 2024 12:35:58 +0000 Subject: [PATCH 08/10] Update app/store/sync.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- app/store/sync.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/store/sync.ts b/app/store/sync.ts index c17385b0b6b..40ab64168c9 100644 --- a/app/store/sync.ts +++ b/app/store/sync.ts @@ -52,7 +52,11 @@ export const useSyncStore = createPersistStore( (set, get) => ({ cloudSync(): boolean { 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() { From 02ce9681ff19fa760e291f8c76a373a1b60459a1 Mon Sep 17 00:00:00 2001 From: Wang Guan Date: Tue, 22 Oct 2024 23:37:57 +0900 Subject: [PATCH 09/10] wait for store hydration --- app/components/home.tsx | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/components/home.tsx b/app/components/home.tsx index 92ee35b7e62..f069b1fc46e 100644 --- a/app/components/home.tsx +++ b/app/components/home.tsx @@ -154,10 +154,18 @@ 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 (!(running && syncStore.cloudSync() && syncStore.autoSync.onStart)) { + if ( + !( + storeHasHydrated && + running && + syncStore.cloudSync() && + syncStore.autoSync.onStart + ) + ) { return; } const dismissSyncingToast = showToast(Locale.Settings.Sync.IsSyncing); @@ -175,7 +183,7 @@ function useSyncOnStart() { running = false; }; // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + }, [storeHasHydrated]); } function Screen() { From 7c1a7653acc22559eace606ee1937876562cb398 Mon Sep 17 00:00:00 2001 From: Wang Guan Date: Tue, 22 Oct 2024 23:41:16 +0900 Subject: [PATCH 10/10] fix syntax error --- app/store/sync.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/store/sync.ts b/app/store/sync.ts index 40ab64168c9..c297699df5f 100644 --- a/app/store/sync.ts +++ b/app/store/sync.ts @@ -55,8 +55,9 @@ export const useSyncStore = createPersistStore( if (!config) { return false; } - return Object.values(config).every((c) => c != null && c.toString().length > 0); - } + return Object.values(config).every( + (c) => c != null && c.toString().length > 0, + ); }, markSyncTime() {