diff --git a/src/api/api.ts b/src/api/api.ts
index 4c9e6b6..6b51824 100644
--- a/src/api/api.ts
+++ b/src/api/api.ts
@@ -25,7 +25,7 @@ let lastestRefreshTokenAt = 0
export async function fetcher(method: FetcherMethod, path: string, data?: any): Promise {
let response
- if (method === FetcherMethod.GET || method === FetcherMethod.DELETE) {
+ if (method === FetcherMethod.GET || method === FetcherMethod.DELETE) {
response = await fetch(buildUrl(path, data), {
method: "GET",
})
diff --git a/src/api/oauth2.ts b/src/api/oauth2.ts
index 6289b39..89dedc8 100644
--- a/src/api/oauth2.ts
+++ b/src/api/oauth2.ts
@@ -7,27 +7,45 @@ export enum Oauth2RequestType {
BIND = 2,
}
-export const getOauth2RedirectURL = async (provider: string, rType: Oauth2RequestType): Promise => {
+export const getOauth2RedirectURL = async (
+ provider: string,
+ rType: Oauth2RequestType,
+): Promise => {
+ const sType = "type"
return fetcher(FetcherMethod.GET, `/api/v1/oauth2/${provider}`, {
- "type": rType,
+ sType: rType,
})
}
-
-export const bindOauth2 = async (provider: string, state: string, code: string): Promise => {
- return fetcher(FetcherMethod.POST, `/api/v1/oauth2/${provider}/bind`, {
- "state": state,
- "code": code,
- })
+export const bindOauth2 = async (
+ provider: string,
+ state: string,
+ code: string,
+): Promise => {
+ return fetcher(
+ FetcherMethod.POST,
+ `/api/v1/oauth2/${provider}/bind`,
+ {
+ state: state,
+ code: code,
+ },
+ )
}
export const unbindOauth2 = async (provider: string): Promise => {
- return fetcher(FetcherMethod.POST, `/api/v1/oauth2/${provider}/unbind`)
+ return fetcher(
+ FetcherMethod.POST,
+ `/api/v1/oauth2/${provider}/unbind`,
+ )
}
-
-export const oauth2callback = async (provider: string, state: string, code: string): Promise => {
+export const oauth2callback = async (
+ provider: string,
+ state: string,
+ code: string,
+): Promise => {
return fetcher(FetcherMethod.POST, `/api/v1/oauth2/${provider}/callback`, {
- state, code
+ state,
+ code,
})
}
diff --git a/src/components/fm.tsx b/src/components/fm.tsx
index 4b3e7a8..bdb02c0 100644
--- a/src/components/fm.tsx
+++ b/src/components/fm.tsx
@@ -41,6 +41,7 @@ import { HTMLAttributes, useEffect, useRef, useState } from "react"
import { useTranslation } from "react-i18next"
import { toast } from "sonner"
+import { Button } from "./ui/button"
import { TableCell, TableRow } from "./ui/table"
import { Filepath } from "./xui/filepath"
import { IconButton } from "./xui/icon-button"
@@ -102,7 +103,7 @@ const FMComponent: React.FC = ({ wsUrl,
header: () => {t("Actions")},
id: "download",
cell: ({ row }) => {
- return (
+ return row.original.type == 0 ? (
= ({ wsUrl,
downloadFile(row.original.name)
}}
/>
+ ) : (
+
)
},
},
@@ -157,42 +160,6 @@ const FMComponent: React.FC = ({ wsUrl,
}
}
- worker.onmessage = async (event: MessageEvent) => {
- switch (event.data.type) {
- case FMWorkerOpcode.Error: {
- console.error("Error from worker", event.data.error)
- break
- }
- case FMWorkerOpcode.Progress: {
- handleReady.current = true
- break
- }
- case FMWorkerOpcode.Result: {
- handleReady.current = false
-
- if (event.data.blob && event.data.fileName) {
- const url = URL.createObjectURL(event.data.blob)
- const anchor = document.createElement("a")
- anchor.href = url
- anchor.download = event.data.fileName
- anchor.click()
- URL.revokeObjectURL(url)
- }
-
- firstChunk.current = true
- if (dOpen) setdOpen(false)
- break
- }
- }
- }
-
- const [currentPath, setPath] = useState("")
- useEffect(() => {
- if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
- listFile()
- }
- }, [wsRef.current, currentPath])
-
useEffect(() => {
const ws = new WebSocket(wsUrl)
wsRef.current = ws
@@ -209,27 +176,27 @@ const FMComponent: React.FC = ({ wsUrl,
description: t("Results.UnExpectedError"),
})
}
- ws.onmessage = async (e) => {
+ ws.onmessage = async (e: MessageEvent) => {
try {
- const buf: ArrayBufferLike = e.data
+ const identifier = new Uint8Array(e.data, 0, 4)
+ if (arraysEqual(identifier, FMIdentifier.error)) {
+ const errBytes = e.data.slice(4)
+ const errMsg = new TextDecoder("utf-8").decode(errBytes)
+ throw new Error(errMsg)
+ }
if (firstChunk.current) {
- const identifier = new Uint8Array(buf, 0, 4)
if (arraysEqual(identifier, FMIdentifier.file)) {
worker.postMessage({
operation: 1,
- arrayBuffer: buf,
+ arrayBuffer: e.data,
fileName: currentBasename.current,
})
firstChunk.current = false
} else if (arraysEqual(identifier, FMIdentifier.fileName)) {
- const { path, fmList } = await fm.parseFMList(buf)
+ const { path, fmList } = await fm.parseFMList(e.data)
setPath(path)
setFMEntries(fmList)
- } else if (arraysEqual(identifier, FMIdentifier.error)) {
- const errBytes = buf.slice(4)
- const errMsg = new TextDecoder("utf-8").decode(errBytes)
- throw new Error(errMsg)
} else if (arraysEqual(identifier, FMIdentifier.complete)) {
// Upload completed
if (uOpen) setuOpen(false)
@@ -241,7 +208,7 @@ const FMComponent: React.FC = ({ wsUrl,
await waitForHandleReady()
worker.postMessage({
operation: 2,
- arrayBuffer: buf,
+ arrayBuffer: e.data,
fileName: currentBasename.current,
})
}
@@ -250,12 +217,61 @@ const FMComponent: React.FC = ({ wsUrl,
toast("FM" + " " + t("Error"), {
description: t("Results.UnExpectedError"),
})
- if (dOpen) setdOpen(false)
- if (uOpen) setuOpen(false)
+ setdOpen(false)
+ setuOpen(false)
}
}
}, [wsUrl])
+ useEffect(() => {
+ worker.onmessage = async (event: MessageEvent) => {
+ switch (event.data.type) {
+ case FMWorkerOpcode.Error: {
+ console.error("Error from worker", event.data.error)
+ break
+ }
+ case FMWorkerOpcode.Progress: {
+ handleReady.current = true
+ break
+ }
+ case FMWorkerOpcode.Result: {
+ handleReady.current = false
+
+ if (event.data.blob && event.data.fileName) {
+ const url = URL.createObjectURL(event.data.blob)
+ const anchor = document.createElement("a")
+ anchor.href = url
+ anchor.download = event.data.fileName
+ anchor.click()
+ URL.revokeObjectURL(url)
+ }
+
+ firstChunk.current = true
+ if (dOpen) setdOpen(false)
+ break
+ }
+ }
+ }
+
+ const handleBeforeUnload = () => {
+ worker.postMessage({
+ operation: 3,
+ })
+ }
+
+ window.addEventListener("beforeunload", handleBeforeUnload)
+ return () => {
+ window.removeEventListener("beforeunload", handleBeforeUnload)
+ }
+ }, [worker, dOpen])
+
+ const [currentPath, setPath] = useState("")
+ useEffect(() => {
+ if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
+ listFile()
+ }
+ }, [wsRef.current, currentPath])
+
const listFile = () => {
const prefix = new Int8Array([FMOpcode.List])
const pathMsg = new TextEncoder().encode(currentPath)
@@ -317,7 +333,7 @@ const FMComponent: React.FC = ({ wsUrl,
toast("FM" + " " + t("Error"), {
description: error.message,
})
- console.log("copy error: ", error)
+ console.error("copy error: ", error)
}
}}
>
diff --git a/src/components/install-commands.tsx b/src/components/install-commands.tsx
index 86ac9df..012a189 100644
--- a/src/components/install-commands.tsx
+++ b/src/components/install-commands.tsx
@@ -8,7 +8,7 @@ import {
import { useAuth } from "@/hooks/useAuth"
import useSettings from "@/hooks/useSetting"
import { copyToClipboard } from "@/lib/utils"
-import { ModelProfile, ModelConfig } from "@/types"
+import { ModelConfig, ModelProfile } from "@/types"
import i18next from "i18next"
import { Check, Clipboard } from "lucide-react"
import { forwardRef, useState } from "react"
diff --git a/src/components/xui/filepath.tsx b/src/components/xui/filepath.tsx
index 4c49424..cdf2ef6 100644
--- a/src/components/xui/filepath.tsx
+++ b/src/components/xui/filepath.tsx
@@ -52,7 +52,7 @@ export const Filepath: React.FC = ({ path, setPath }) => {
setPath("/")
}}
>
- {"/"}
+ /
diff --git a/src/hooks/useAuth.tsx b/src/hooks/useAuth.tsx
index 3c3429f..8ffb374 100644
--- a/src/hooks/useAuth.tsx
+++ b/src/hooks/useAuth.tsx
@@ -1,3 +1,4 @@
+import { oauth2callback } from "@/api/oauth2"
import { getProfile, login as loginRequest } from "@/api/user"
import { AuthContextProps } from "@/types"
import { createContext, useContext, useEffect, useMemo } from "react"
@@ -5,13 +6,12 @@ import { useNavigate } from "react-router-dom"
import { toast } from "sonner"
import { useMainStore } from "./useMainStore"
-import { oauth2callback } from "@/api/oauth2"
const AuthContext = createContext({
profile: undefined,
- login: () => { },
- loginOauth2: () => { },
- logout: () => { },
+ login: () => {},
+ loginOauth2: () => {},
+ logout: () => {},
})
export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
@@ -19,7 +19,7 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
const setProfile = useMainStore((store) => store.setProfile)
useEffect(() => {
- ; (async () => {
+ ;(async () => {
try {
const user = await getProfile()
user.role = user.role || 0
diff --git a/src/hooks/useSetting.tsx b/src/hooks/useSetting.tsx
index 3f433e4..6a2001e 100644
--- a/src/hooks/useSetting.tsx
+++ b/src/hooks/useSetting.tsx
@@ -3,6 +3,8 @@ import { GithubComNezhahqNezhaModelSettingResponseModelConfig } from "@/types"
import useSWR from "swr"
export default function useSetting() {
- return useSWR("/api/v1/setting", swrFetcher)
+ return useSWR(
+ "/api/v1/setting",
+ swrFetcher,
+ )
}
-
diff --git a/src/lib/fm.ts b/src/lib/fm.ts
index 5448ff8..11a13eb 100644
--- a/src/lib/fm.ts
+++ b/src/lib/fm.ts
@@ -38,9 +38,8 @@ onmessage = async function (event) {
throw new Error("accessHandle is undefined")
}
- const dataChunk = arrayBuffer
- accessHandle.write(dataChunk, { at: receivedLength })
- receivedLength += dataChunk.byteLength
+ accessHandle.write(arrayBuffer, { at: receivedLength })
+ receivedLength += arrayBuffer.byteLength
if (receivedLength === expectedLength) {
accessHandle.flush()
diff --git a/src/routes/login.tsx b/src/routes/login.tsx
index 5b20924..5e97578 100644
--- a/src/routes/login.tsx
+++ b/src/routes/login.tsx
@@ -1,4 +1,4 @@
-import { getOauth2RedirectURL, Oauth2RequestType } from "@/api/oauth2"
+import { Oauth2RequestType, getOauth2RedirectURL } from "@/api/oauth2"
import { Button } from "@/components/ui/button"
import {
Form,
@@ -59,7 +59,7 @@ function Login() {
window.location.href = redirectUrl.redirect!
} catch (error: any) {
toast.error(error.message)
- }
+ }
}
const { t } = useTranslation()
@@ -103,9 +103,9 @@ function Login() {
- {settingData?.config?.oauth2_providers?.map((p: string) =>
+ {settingData?.config?.oauth2_providers?.map((p: string) => (
- )}
+ ))}
)
diff --git a/src/routes/profile.tsx b/src/routes/profile.tsx
index f8936e3..6d62616 100644
--- a/src/routes/profile.tsx
+++ b/src/routes/profile.tsx
@@ -1,4 +1,4 @@
-import { bindOauth2, getOauth2RedirectURL, Oauth2RequestType, unbindOauth2 } from "@/api/oauth2"
+import { Oauth2RequestType, bindOauth2, getOauth2RedirectURL, unbindOauth2 } from "@/api/oauth2"
import { getProfile } from "@/api/user"
import { ProfileCard } from "@/components/profile"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
@@ -31,7 +31,8 @@ export default function ProfilePage() {
getProfile().then((profile) => {
setProfile(profile)
})
- }).finally(() => {
+ })
+ .finally(() => {
window.history.replaceState({}, document.title, window.location.pathname)
})
}
@@ -116,12 +117,20 @@ export default function ProfilePage() {
- {settingData?.config?.oauth2_providers?.map((provider) =>
- {provider}: {profile.oauth2_bind?.[provider.toLowerCase()]} {profile.oauth2_bind?.[provider.toLowerCase()] ?
-
- :
- }
-
)}
+ {settingData?.config?.oauth2_providers?.map((provider) => (
+
+ {provider}: {profile.oauth2_bind?.[provider.toLowerCase()]}{" "}
+ {profile.oauth2_bind?.[provider.toLowerCase()] ? (
+
+ ) : (
+
+ )}
+
+ ))}
diff --git a/src/routes/settings.tsx b/src/routes/settings.tsx
index 8d27ca3..50e3a34 100644
--- a/src/routes/settings.tsx
+++ b/src/routes/settings.tsx
@@ -67,21 +67,21 @@ export default function SettingsPage() {
resolver: zodResolver(settingFormSchema),
defaultValues: config
? {
- ...config,
- language: config?.config?.language,
- site_name: config.config?.site_name || "",
- user_template:
- config.config?.user_template ||
- Object.keys(config.frontend_templates?.filter((t) => !t.is_admin) || {})[0] ||
- "user-dist",
- }
+ ...config,
+ language: config?.config?.language,
+ site_name: config.config?.site_name || "",
+ user_template:
+ config.config?.user_template ||
+ Object.keys(config.frontend_templates?.filter((t) => !t.is_admin) || {})[0] ||
+ "user-dist",
+ }
: {
- ip_change_notification_group_id: 0,
- cover: 1,
- site_name: "",
- language: "",
- user_template: "user-dist",
- },
+ ip_change_notification_group_id: 0,
+ cover: 1,
+ site_name: "",
+ language: "",
+ user_template: "user-dist",
+ },
resetOptions: {
keepDefaultValues: false,
},
@@ -229,15 +229,15 @@ export default function SettingsPage() {
{!config?.frontend_templates?.find(
(t) => t.path === field.value,
)?.is_official && (
-
-
- {t("CommunityThemeWarning")}
-
-
- {t("CommunityThemeDescription")}
-
+
+
+ {t("CommunityThemeWarning")}
- )}
+
+ {t("CommunityThemeDescription")}
+
+
+ )}
)}
/>
diff --git a/src/types/api.ts b/src/types/api.ts
index 2899ec1..16359d5 100644
--- a/src/types/api.ts
+++ b/src/types/api.ts
@@ -1,14 +1,14 @@
-/* eslint-disable */
-/* tslint:disable */
-/*
- * ---------------------------------------------------------------
- * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
- * ## ##
- * ## AUTHOR: acacode ##
- * ## SOURCE: https://github.com/acacode/swagger-typescript-api ##
- * ---------------------------------------------------------------
- */
-
+/* eslint-disable */
+/* tslint:disable */
+/*
+ * ---------------------------------------------------------------
+ * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ##
+ * ## ##
+ * ## AUTHOR: acacode ##
+ * ## SOURCE: https://github.com/acacode/swagger-typescript-api ##
+ * ---------------------------------------------------------------
+ */
+
export interface GithubComNezhahqNezhaModelCommonResponseAny {
data?: any
error?: string