forked from XiaoMo/ChatGPT-Next-Web
feat: [WIP] support webdav
This commit is contained in:
parent
6caf79121b
commit
1dd75b63de
@ -46,6 +46,7 @@ import { InputRange } from "./input-range";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Avatar, AvatarPicker } from "./emoji";
|
||||
import { getClientConfig } from "../config/client";
|
||||
import { useSyncStore } from "../store/sync";
|
||||
|
||||
function EditPromptModal(props: { id: number; onClose: () => void }) {
|
||||
const promptStore = usePromptStore();
|
||||
@ -198,6 +199,78 @@ function UserPromptModal(props: { onClose?: () => void }) {
|
||||
);
|
||||
}
|
||||
|
||||
function SyncItems() {
|
||||
const syncStore = useSyncStore();
|
||||
const webdav = syncStore.webDavConfig;
|
||||
|
||||
// not ready: https://github.com/Yidadaa/ChatGPT-Next-Web/issues/920#issuecomment-1609866332
|
||||
return null;
|
||||
|
||||
return (
|
||||
<List>
|
||||
<ListItem
|
||||
title={"上次同步:" + new Date().toLocaleString()}
|
||||
subTitle={"20 次对话,100 条消息,200 提示词,20 面具"}
|
||||
>
|
||||
<IconButton
|
||||
icon={<ResetIcon />}
|
||||
text="同步"
|
||||
onClick={() => {
|
||||
syncStore.check().then(console.log);
|
||||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem
|
||||
title={"本地备份"}
|
||||
subTitle={"20 次对话,100 条消息,200 提示词,20 面具"}
|
||||
></ListItem>
|
||||
|
||||
<ListItem
|
||||
title={"Web Dav Server"}
|
||||
subTitle={Locale.Settings.AccessCode.SubTitle}
|
||||
>
|
||||
<input
|
||||
value={webdav.server}
|
||||
type="text"
|
||||
placeholder={"https://example.com"}
|
||||
onChange={(e) => {
|
||||
syncStore.update(
|
||||
(config) => (config.server = e.currentTarget.value),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem title="Web Dav User Name" subTitle="user name here">
|
||||
<input
|
||||
value={webdav.username}
|
||||
type="text"
|
||||
placeholder={"username"}
|
||||
onChange={(e) => {
|
||||
syncStore.update(
|
||||
(config) => (config.username = e.currentTarget.value),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem title="Web Dav Password" subTitle="password here">
|
||||
<input
|
||||
value={webdav.password}
|
||||
type="text"
|
||||
placeholder={"password"}
|
||||
onChange={(e) => {
|
||||
syncStore.update(
|
||||
(config) => (config.password = e.currentTarget.value),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
);
|
||||
}
|
||||
|
||||
function formatVersionDate(t: string) {
|
||||
const d = new Date(+t);
|
||||
const year = d.getUTCFullYear();
|
||||
@ -556,6 +629,7 @@ export function Settings() {
|
||||
<input
|
||||
type="text"
|
||||
value={accessStore.openaiUrl}
|
||||
placeholder="https://api.openai.com/"
|
||||
onChange={(e) =>
|
||||
accessStore.updateOpenAiUrl(e.currentTarget.value)
|
||||
}
|
||||
@ -596,6 +670,8 @@ export function Settings() {
|
||||
</ListItem>
|
||||
</List>
|
||||
|
||||
<SyncItems />
|
||||
|
||||
<List>
|
||||
<ModelConfigList
|
||||
modelConfig={config.modelConfig}
|
||||
|
@ -33,6 +33,7 @@ export enum StoreKey {
|
||||
Mask = "mask-store",
|
||||
Prompt = "prompt-store",
|
||||
Update = "chat-update",
|
||||
Sync = "sync",
|
||||
}
|
||||
|
||||
export const MAX_SIDEBAR_WIDTH = 500;
|
||||
|
87
app/store/sync.ts
Normal file
87
app/store/sync.ts
Normal file
@ -0,0 +1,87 @@
|
||||
import { Updater } from "../typing";
|
||||
import { create } from "zustand";
|
||||
import { persist } from "zustand/middleware";
|
||||
import { StoreKey } from "../constant";
|
||||
|
||||
export interface WebDavConfig {
|
||||
server: string;
|
||||
username: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface SyncStore {
|
||||
webDavConfig: WebDavConfig;
|
||||
lastSyncTime: number;
|
||||
|
||||
update: Updater<WebDavConfig>;
|
||||
check: () => Promise<boolean>;
|
||||
|
||||
path: (path: string) => string;
|
||||
headers: () => { Authorization: string };
|
||||
}
|
||||
|
||||
const FILE = {
|
||||
root: "/chatgpt-next-web/",
|
||||
};
|
||||
|
||||
export const useSyncStore = create<SyncStore>()(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
webDavConfig: {
|
||||
server: "",
|
||||
username: "",
|
||||
password: "",
|
||||
},
|
||||
|
||||
lastSyncTime: 0,
|
||||
|
||||
update(updater) {
|
||||
const config = { ...get().webDavConfig };
|
||||
updater(config);
|
||||
set({ webDavConfig: config });
|
||||
},
|
||||
|
||||
async check() {
|
||||
try {
|
||||
const res = await fetch(this.path(""), {
|
||||
method: "PROFIND",
|
||||
headers: this.headers(),
|
||||
});
|
||||
console.log(res);
|
||||
return res.status === 207;
|
||||
} catch (e) {
|
||||
console.error("[Sync] ", e);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
path(path: string) {
|
||||
let url = get().webDavConfig.server;
|
||||
|
||||
if (!url.endsWith("/")) {
|
||||
url += "/";
|
||||
}
|
||||
|
||||
if (path.startsWith("/")) {
|
||||
path = path.slice(1);
|
||||
}
|
||||
|
||||
return url + path;
|
||||
},
|
||||
|
||||
headers() {
|
||||
const auth = btoa(
|
||||
[get().webDavConfig.username, get().webDavConfig.password].join(":"),
|
||||
);
|
||||
|
||||
return {
|
||||
Authorization: `Basic ${auth}`,
|
||||
};
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: StoreKey.Sync,
|
||||
version: 1,
|
||||
},
|
||||
),
|
||||
);
|
Loading…
Reference in New Issue
Block a user