mirror of
https://github.com/coaidev/coai.git
synced 2025-05-21 22:10:12 +09:00
update code struct
This commit is contained in:
parent
435308de41
commit
f9949a86f7
@ -25,6 +25,7 @@
|
||||
"@radix-ui/react-tooltip": "^1.0.6",
|
||||
"@reduxjs/toolkit": "^1.9.5",
|
||||
"axios": "^1.5.0",
|
||||
"chart.js": "^4.4.0",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.0.0",
|
||||
"i18next": "^23.4.6",
|
||||
@ -32,11 +33,12 @@
|
||||
"lucide-react": "^0.274.0",
|
||||
"match-sorter": "^6.3.1",
|
||||
"react": "^18.2.0",
|
||||
"react-chartjs-2": "^5.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-i18next": "^13.2.2",
|
||||
"react-markdown": "^8.0.7",
|
||||
"react-redux": "^8.1.2",
|
||||
"react-router-dom": "^6.15.0",
|
||||
"react-router-dom": "^5.1.2",
|
||||
"react-syntax-highlighter": "^15.5.0",
|
||||
"rehype-katex": "^6.0.3",
|
||||
"remark-gfm": "^3.0.1",
|
||||
|
27
app/pnpm-lock.yaml
generated
27
app/pnpm-lock.yaml
generated
@ -47,6 +47,9 @@ dependencies:
|
||||
axios:
|
||||
specifier: ^1.5.0
|
||||
version: 1.5.0
|
||||
chart.js:
|
||||
specifier: ^4.4.0
|
||||
version: 4.4.0
|
||||
class-variance-authority:
|
||||
specifier: ^0.7.0
|
||||
version: 0.7.0
|
||||
@ -68,6 +71,9 @@ dependencies:
|
||||
react:
|
||||
specifier: ^18.2.0
|
||||
version: 18.2.0
|
||||
react-chartjs-2:
|
||||
specifier: ^5.2.0
|
||||
version: 5.2.0(chart.js@4.4.0)(react@18.2.0)
|
||||
react-dom:
|
||||
specifier: ^18.2.0
|
||||
version: 18.2.0(react@18.2.0)
|
||||
@ -1669,6 +1675,10 @@ packages:
|
||||
'@jridgewell/resolve-uri': 3.1.1
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
|
||||
/@kurkle/color@0.3.2:
|
||||
resolution: {integrity: sha512-fuscdXJ9G1qb7W8VdHi+IwRqij3lBkosAm4ydQtEmbY58OzHXqQhvlxqEkoz0yssNVn38bcpRWgA9PP+OGoisw==}
|
||||
dev: false
|
||||
|
||||
/@nodelib/fs.scandir@2.1.5:
|
||||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
|
||||
engines: {node: '>= 8'}
|
||||
@ -3375,6 +3385,13 @@ packages:
|
||||
resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==}
|
||||
dev: false
|
||||
|
||||
/chart.js@4.4.0:
|
||||
resolution: {integrity: sha512-vQEj6d+z0dcsKLlQvbKIMYFHd3t8W/7L2vfJIbYcfyPcRx92CsHqECpueN8qVGNlKyDcr5wBrYAYKnfu/9Q1hQ==}
|
||||
engines: {pnpm: '>=7'}
|
||||
dependencies:
|
||||
'@kurkle/color': 0.3.2
|
||||
dev: false
|
||||
|
||||
/chokidar@3.5.3:
|
||||
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
|
||||
engines: {node: '>= 8.10.0'}
|
||||
@ -5742,6 +5759,16 @@ packages:
|
||||
safe-buffer: 5.2.1
|
||||
dev: true
|
||||
|
||||
/react-chartjs-2@5.2.0(chart.js@4.4.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==}
|
||||
peerDependencies:
|
||||
chart.js: ^4.1.1
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
chart.js: 4.4.0
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/react-dom@18.2.0(react@18.2.0):
|
||||
resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
|
||||
peerDependencies:
|
||||
|
159
app/src/App.tsx
159
app/src/App.tsx
@ -1,162 +1,13 @@
|
||||
import { RouterProvider } from "react-router-dom";
|
||||
import "./assets/navbar.less";
|
||||
import ModeToggle, { ThemeProvider } from "./components/ThemeProvider.tsx";
|
||||
import { Button } from "./components/ui/button.tsx";
|
||||
import router from "./router.ts";
|
||||
import I18nProvider from "./components/I18nProvider.tsx";
|
||||
import ProjectLink from "./components/ProjectLink.tsx";
|
||||
import {
|
||||
BadgeCent,
|
||||
Boxes,
|
||||
CalendarPlus,
|
||||
Cloud,
|
||||
ListStart,
|
||||
Menu,
|
||||
Plug,
|
||||
} from "lucide-react";
|
||||
import { Provider, useDispatch, useSelector } from "react-redux";
|
||||
import { toggleMenu } from "./store/menu.ts";
|
||||
import { Provider } from "react-redux";
|
||||
import store from "./store/index.ts";
|
||||
import {
|
||||
logout,
|
||||
selectAuthenticated,
|
||||
selectUsername,
|
||||
validateToken,
|
||||
} from "./store/auth.ts";
|
||||
import { useEffect } from "react";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "./components/ui/dropdown-menu.tsx";
|
||||
import { Toaster } from "./components/ui/toaster.tsx";
|
||||
import { login, tokenField } from "./conf.ts";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Quota from "./routes/Quota.tsx";
|
||||
import { openDialog as openQuotaDialog, quotaSelector } from "./store/quota.ts";
|
||||
import { openDialog as openPackageDialog } from "./store/package.ts";
|
||||
import { openDialog as openSub } from "./store/subscription.ts";
|
||||
import { openDialog as openApiDialog } from "./store/api.ts";
|
||||
import { openDialog as openSharingDialog } from "./store/sharing.ts";
|
||||
import Package from "./routes/Package.tsx";
|
||||
import Subscription from "./routes/Subscription.tsx";
|
||||
import ApiKey from "./routes/ApiKey.tsx";
|
||||
import ShareManagement from "./routes/ShareManagement.tsx";
|
||||
|
||||
function Settings() {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
const username = useSelector(selectUsername);
|
||||
const quota = useSelector(quotaSelector);
|
||||
|
||||
return (
|
||||
<div className={`avatar`}>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant={`ghost`} size={`icon`}>
|
||||
<img src={`https://api.deeptrain.net/avatar/${username}`} alt="" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align={`end`}>
|
||||
<DropdownMenuLabel className={`username`}>
|
||||
{username}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={() => dispatch(openQuotaDialog())}>
|
||||
<Cloud className={`h-4 w-4 mr-1`} />
|
||||
{quota}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => dispatch(openQuotaDialog())}>
|
||||
<BadgeCent className={`h-4 w-4 mr-1`} />
|
||||
{t("quota")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => dispatch(openSub())}>
|
||||
<CalendarPlus className={`h-4 w-4 mr-1`} />
|
||||
{t("sub.title")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => dispatch(openPackageDialog())}>
|
||||
<Boxes className={`h-4 w-4 mr-1`} />
|
||||
{t("pkg.title")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => dispatch(openSharingDialog())}>
|
||||
<ListStart className={`h-4 w-4 mr-1`} />
|
||||
{t("share.manage")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => dispatch(openApiDialog())}>
|
||||
<Plug className={`h-4 w-4 mr-1`} />
|
||||
{t("api.title")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem asChild>
|
||||
<Button
|
||||
size={`sm`}
|
||||
className={`action-button`}
|
||||
onClick={() => dispatch(logout())}
|
||||
>
|
||||
{t("logout")}
|
||||
</Button>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function NavBar() {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
useEffect(() => {
|
||||
validateToken(dispatch, localStorage.getItem(tokenField) ?? "");
|
||||
}, []);
|
||||
const auth = useSelector(selectAuthenticated);
|
||||
|
||||
return (
|
||||
<nav className={`navbar`}>
|
||||
<div className={`items`}>
|
||||
<Button
|
||||
size={`icon`}
|
||||
variant={`ghost`}
|
||||
onClick={() => dispatch(toggleMenu())}
|
||||
>
|
||||
<Menu />
|
||||
</Button>
|
||||
<img
|
||||
className={`logo`}
|
||||
src="/favicon.ico"
|
||||
alt=""
|
||||
onClick={() => router.navigate("/")}
|
||||
/>
|
||||
<div className={`grow`} />
|
||||
<ProjectLink />
|
||||
<ModeToggle />
|
||||
<I18nProvider />
|
||||
{auth ? (
|
||||
<Settings />
|
||||
) : (
|
||||
<Button size={`sm`} onClick={login}>
|
||||
{t("login")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
import AppProvider from "./components/app/AppProvider.tsx";
|
||||
import { AppRouter } from "./router.tsx";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<Provider store={store}>
|
||||
<NavBar />
|
||||
<ThemeProvider />
|
||||
<RouterProvider router={router} />
|
||||
<Toaster />
|
||||
<Quota />
|
||||
<ApiKey />
|
||||
<Package />
|
||||
<Subscription />
|
||||
<ShareManagement />
|
||||
<AppProvider />
|
||||
<AppRouter />
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
|
15
app/src/components/app/AppProvider.tsx
Normal file
15
app/src/components/app/AppProvider.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
import NavBar from "./NavBar.tsx";
|
||||
import { ThemeProvider } from "../ThemeProvider.tsx";
|
||||
import DialogManager from "../../dialogs";
|
||||
|
||||
function AppProvider() {
|
||||
return (
|
||||
<>
|
||||
<NavBar />
|
||||
<ThemeProvider />
|
||||
<DialogManager />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default AppProvider;
|
142
app/src/components/app/NavBar.tsx
Normal file
142
app/src/components/app/NavBar.tsx
Normal file
@ -0,0 +1,142 @@
|
||||
import "@/assets/navbar.less";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
logout,
|
||||
selectAuthenticated,
|
||||
selectUsername,
|
||||
validateToken,
|
||||
} from "../../store/auth.ts";
|
||||
import {
|
||||
openDialog as openQuotaDialog,
|
||||
quotaSelector,
|
||||
} from "../../store/quota.ts";
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "../ui/dropdown-menu.tsx";
|
||||
import { Button } from "../ui/button.tsx";
|
||||
import {
|
||||
BadgeCent,
|
||||
Boxes,
|
||||
CalendarPlus,
|
||||
Cloud,
|
||||
ListStart,
|
||||
Plug,
|
||||
} from "lucide-react";
|
||||
import { openDialog as openSub } from "../../store/subscription.ts";
|
||||
import { openDialog as openPackageDialog } from "../../store/package.ts";
|
||||
import { openDialog as openSharingDialog } from "../../store/sharing.ts";
|
||||
import { openDialog as openApiDialog } from "../../store/api.ts";
|
||||
import { useEffect } from "react";
|
||||
import { login, tokenField } from "../../conf.ts";
|
||||
import { toggleMenu } from "../../store/menu.ts";
|
||||
import ProjectLink from "../ProjectLink.tsx";
|
||||
import ModeToggle from "../ThemeProvider.tsx";
|
||||
import I18nProvider from "../I18nProvider.tsx";
|
||||
import router from "../../router.tsx";
|
||||
|
||||
function Menu() {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
const username = useSelector(selectUsername);
|
||||
const quota = useSelector(quotaSelector);
|
||||
|
||||
return (
|
||||
<div className={`avatar`}>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant={`ghost`} size={`icon`}>
|
||||
<img src={`https://api.deeptrain.net/avatar/${username}`} alt="" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align={`end`}>
|
||||
<DropdownMenuLabel className={`username`}>
|
||||
{username}
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={() => dispatch(openQuotaDialog())}>
|
||||
<Cloud className={`h-4 w-4 mr-1`} />
|
||||
{quota}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => dispatch(openQuotaDialog())}>
|
||||
<BadgeCent className={`h-4 w-4 mr-1`} />
|
||||
{t("quota")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => dispatch(openSub())}>
|
||||
<CalendarPlus className={`h-4 w-4 mr-1`} />
|
||||
{t("sub.title")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => dispatch(openPackageDialog())}>
|
||||
<Boxes className={`h-4 w-4 mr-1`} />
|
||||
{t("pkg.title")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => dispatch(openSharingDialog())}>
|
||||
<ListStart className={`h-4 w-4 mr-1`} />
|
||||
{t("share.manage")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => dispatch(openApiDialog())}>
|
||||
<Plug className={`h-4 w-4 mr-1`} />
|
||||
{t("api.title")}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem asChild>
|
||||
<Button
|
||||
size={`sm`}
|
||||
className={`action-button`}
|
||||
onClick={() => dispatch(logout())}
|
||||
>
|
||||
{t("logout")}
|
||||
</Button>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function NavBar() {
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useDispatch();
|
||||
useEffect(() => {
|
||||
validateToken(dispatch, localStorage.getItem(tokenField) ?? "");
|
||||
}, []);
|
||||
const auth = useSelector(selectAuthenticated);
|
||||
|
||||
return (
|
||||
<nav className={`navbar`}>
|
||||
<div className={`items`}>
|
||||
<Button
|
||||
size={`icon`}
|
||||
variant={`ghost`}
|
||||
onClick={() => dispatch(toggleMenu())}
|
||||
>
|
||||
<Menu />
|
||||
</Button>
|
||||
<img
|
||||
className={`logo`}
|
||||
src="/favicon.ico"
|
||||
alt=""
|
||||
onClick={() => router.navigate("/")}
|
||||
/>
|
||||
<div className={`grow`} />
|
||||
<ProjectLink />
|
||||
<ModeToggle />
|
||||
<I18nProvider />
|
||||
{auth ? (
|
||||
<Menu />
|
||||
) : (
|
||||
<Button size={`sm`} onClick={login}>
|
||||
{t("login")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
|
||||
export default NavBar;
|
@ -13,7 +13,7 @@ import { manager } from "../../conversation/manager.ts";
|
||||
import { formatMessage } from "../../utils.ts";
|
||||
import ChatInterface from "./ChatInterface.tsx";
|
||||
import { Button } from "../ui/button.tsx";
|
||||
import router from "../../router.ts";
|
||||
import router from "../../router.tsx";
|
||||
import { BookMarked, ChevronRight, FolderKanban, Globe } from "lucide-react";
|
||||
import {
|
||||
Tooltip,
|
||||
|
@ -1,7 +1,7 @@
|
||||
import axios from "axios";
|
||||
import { Model } from "./conversation/types.ts";
|
||||
|
||||
export const version = "3.5.0";
|
||||
export const version = "3.5.1";
|
||||
export const dev: boolean = window.location.hostname === "localhost";
|
||||
export const deploy: boolean = true;
|
||||
export let rest_api: string = "http://localhost:8094";
|
||||
|
21
app/src/dialogs/index.tsx
Normal file
21
app/src/dialogs/index.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import { Toaster } from "../components/ui/toaster.tsx";
|
||||
import Quota from "./Quota.tsx";
|
||||
import ApiKey from "./ApiKey.tsx";
|
||||
import Package from "./Package.tsx";
|
||||
import Subscription from "./Subscription.tsx";
|
||||
import ShareManagement from "./ShareManagement.tsx";
|
||||
|
||||
function DialogManager() {
|
||||
return (
|
||||
<>
|
||||
<Toaster />
|
||||
<Quota />
|
||||
<ApiKey />
|
||||
<Package />
|
||||
<Subscription />
|
||||
<ShareManagement />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default DialogManager;
|
@ -1,4 +1,4 @@
|
||||
import { createBrowserRouter } from "react-router-dom";
|
||||
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||
import Home from "./routes/Home.tsx";
|
||||
import NotFound from "./routes/NotFound.tsx";
|
||||
import Auth from "./routes/Auth.tsx";
|
||||
@ -30,4 +30,8 @@ const router = createBrowserRouter([
|
||||
},
|
||||
]);
|
||||
|
||||
export function AppRouter() {
|
||||
return <RouterProvider router={router} />;
|
||||
}
|
||||
|
||||
export default router;
|
@ -8,7 +8,7 @@ import "../assets/auth.less";
|
||||
import axios from "axios";
|
||||
import { validateToken } from "../store/auth.ts";
|
||||
import { useDispatch } from "react-redux";
|
||||
import router from "../router.ts";
|
||||
import router from "../router.tsx";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
function Auth() {
|
||||
|
@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { Button } from "../components/ui/button.tsx";
|
||||
import { ChevronLeft, Cloud, FileDown, Send } from "lucide-react";
|
||||
import { rest_api } from "../conf.ts";
|
||||
import router from "../router.ts";
|
||||
import router from "../router.tsx";
|
||||
import { Input } from "../components/ui/input.tsx";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { manager } from "../conversation/generation.ts";
|
||||
|
@ -1,7 +1,7 @@
|
||||
import "../assets/404.less";
|
||||
import { Button } from "../components/ui/button.tsx";
|
||||
import { HelpCircle } from "lucide-react";
|
||||
import router from "../router.ts";
|
||||
import router from "../router.tsx";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
function NotFound() {
|
||||
|
@ -11,7 +11,7 @@ import { Copy, File, HelpCircle, Loader2, MessagesSquare } from "lucide-react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import MessageSegment from "../components/Message.tsx";
|
||||
import { Button } from "../components/ui/button.tsx";
|
||||
import router from "../router.ts";
|
||||
import router from "../router.tsx";
|
||||
import { useToast } from "../components/ui/use-toast.ts";
|
||||
import { sharingEvent } from "../events/sharing.ts";
|
||||
import { Message } from "../conversation/types.ts";
|
||||
|
Loading…
Reference in New Issue
Block a user