mirror of
https://github.com/ChatGPTNextWeb/ChatGPT-Next-Web.git
synced 2025-10-01 15:46:39 +08:00
Merge 7c1a7653ac
into 6ded4e96e7
This commit is contained in:
commit
36cfebdadd
@ -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 (
|
||||||
|
@ -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>
|
||||||
);
|
);
|
||||||
|
@ -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> & {
|
||||||
|
@ -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: "本地数据",
|
||||||
|
@ -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",
|
||||||
|
@ -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;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user