From 90414a69b690da6e9f79eb257cc55a8a13e9c162 Mon Sep 17 00:00:00 2001 From: Semesse Date: Mon, 22 Jan 2024 00:44:18 +0800 Subject: [PATCH] chore: prettify frontend code --- www/.prettierignore | 2 + www/.prettierrc.js | 41 + www/api/auth.ts | 19 +- www/api/client.ts | 38 +- www/api/frp.ts | 36 +- www/api/http.ts | 36 +- www/api/platform.ts | 19 +- www/api/server.ts | 38 +- www/api/user.ts | 18 +- www/components.json | 2 +- www/components/apitest.tsx | 323 ++- www/components/client_create_dialog.tsx | 122 +- www/components/client_item.tsx | 443 +-- www/components/client_list.tsx | 154 +- www/components/column_header.tsx | 114 +- www/components/data_table.tsx | 166 +- www/components/data_table_pagination.tsx | 162 +- www/components/frpc_card.tsx | 255 +- www/components/frpc_editor.tsx | 146 +- www/components/frpc_form.tsx | 337 +-- www/components/frps_card.tsx | 178 +- www/components/frps_editor.tsx | 168 +- www/components/frps_form.tsx | 287 +- www/components/header.tsx | 127 +- www/components/layout.tsx | 41 +- www/components/login.tsx | 185 +- www/components/platforminfo.tsx | 192 +- www/components/providers.tsx | 16 +- www/components/proxy_form.tsx | 625 ++--- www/components/register.tsx | 221 +- www/components/server_create_dialog.tsx | 135 +- www/components/server_item.tsx | 493 ++-- www/components/server_list.tsx | 156 +- www/components/sidebar.tsx | 103 +- www/components/ui/accordion.tsx | 22 +- www/components/ui/alert.tsx | 60 +- www/components/ui/avatar.tsx | 22 +- www/components/ui/button.tsx | 54 +- www/components/ui/card.tsx | 99 +- www/components/ui/dialog.tsx | 57 +- www/components/ui/dropdown-menu.tsx | 77 +- www/components/ui/form.tsx | 180 +- www/components/ui/hover-card.tsx | 12 +- www/components/ui/icon.tsx | 15 +- www/components/ui/input.tsx | 37 +- www/components/ui/label.tsx | 21 +- www/components/ui/popover.tsx | 12 +- www/components/ui/select.tsx | 62 +- www/components/ui/separator.tsx | 33 +- www/components/ui/sonner.tsx | 18 +- www/components/ui/switch.tsx | 12 +- www/components/ui/table.tsx | 178 +- www/components/ui/textarea.tsx | 35 +- www/components/ui/toast.tsx | 56 +- www/components/ui/toaster.tsx | 15 +- www/components/ui/tooltip.tsx | 10 +- www/components/ui/use-toast.ts | 53 +- www/lib/consts.ts | 62 +- www/lib/utils.ts | 4 +- www/package.json | 2 +- www/pages/clientedit.tsx | 32 +- www/pages/clients.tsx | 40 +- www/pages/index.tsx | 14 +- www/pages/login.tsx | 55 +- www/pages/register.tsx | 107 +- www/pages/serveredit.tsx | 32 +- www/pages/servers.tsx | 41 +- www/pages/test.tsx | 43 +- www/pnpm-lock.yaml | 3172 ++++++++++------------ www/store/proxy.ts | 6 +- www/store/user.ts | 2 +- www/styles/globals.css | 38 +- www/tailwind.config.js | 79 +- www/tailwind.config.ts | 3 +- www/tsconfig.json | 6 +- www/types/api.ts | 10 +- www/types/client.ts | 120 +- www/types/common.ts | 72 +- www/types/plugin.ts | 66 +- www/types/proxy.ts | 126 +- www/types/server.ts | 96 +- www/types/visitor.ts | 44 +- 82 files changed, 5224 insertions(+), 5586 deletions(-) create mode 100644 www/.prettierignore create mode 100644 www/.prettierrc.js diff --git a/www/.prettierignore b/www/.prettierignore new file mode 100644 index 0000000..65e433a --- /dev/null +++ b/www/.prettierignore @@ -0,0 +1,2 @@ +lib/pb +out \ No newline at end of file diff --git a/www/.prettierrc.js b/www/.prettierrc.js new file mode 100644 index 0000000..136167c --- /dev/null +++ b/www/.prettierrc.js @@ -0,0 +1,41 @@ +module.exports = { + // max 120 characters per line + printWidth: 120, + // use 2 spaces for indentation + tabWidth: 2, + // use spaces instead of indentations + useTabs: false, + // semicolon at the end of the line + semi: false, + // use single quotes + singleQuote: true, + // object's key is quoted only when necessary + quoteProps: 'as-needed', + // use double quotes instead of single quotes in jsx + jsxSingleQuote: false, + // no comma at the end + trailingComma: 'all', + // spaces are required at the beginning and end of the braces + bracketSpacing: true, + // end tag of jsx need to wrap + bracketSameLine: false, + // brackets are required for arrow function parameter, even when there is only one parameter + arrowParens: 'always', + // format the entire contents of the file + rangeStart: 0, + rangeEnd: Infinity, + // no need to write the beginning @prettier of the file + requirePragma: false, + // No need to automatically insert @prettier at the beginning of the file + insertPragma: false, + // use default break criteria + proseWrap: 'preserve', + // decide whether to break the html according to the display style + htmlWhitespaceSensitivity: 'css', + // vue files script and style tags indentation + vueIndentScriptAndStyle: false, + // lf for newline + endOfLine: 'lf', + // formats quoted code embedded + embeddedLanguageFormatting: 'auto', +} diff --git a/www/api/auth.ts b/www/api/auth.ts index 6f0fcf8..b4d304e 100644 --- a/www/api/auth.ts +++ b/www/api/auth.ts @@ -1,23 +1,20 @@ import http from '@/api/http' import { API_PATH } from '@/lib/consts' -import { - LoginRequest, LoginResponse, - RegisterRequest, RegisterResponse -} from '@/lib/pb/api_auth' +import { LoginRequest, LoginResponse, RegisterRequest, RegisterResponse } from '@/lib/pb/api_auth' import { CommonResponse } from '@/lib/pb/common' import { BaseResponse } from '@/types/api' export const login = async (req: LoginRequest) => { - const res = await http.post(API_PATH + '/auth/login', LoginRequest.toJson(req)) - return LoginResponse.fromJson((res.data as BaseResponse).body) + const res = await http.post(API_PATH + '/auth/login', LoginRequest.toJson(req)) + return LoginResponse.fromJson((res.data as BaseResponse).body) } export const register = async (req: RegisterRequest) => { - const res = await http.post(API_PATH + '/auth/register', RegisterRequest.toJson(req)) - return RegisterResponse.fromJson((res.data as BaseResponse).body) + const res = await http.post(API_PATH + '/auth/register', RegisterRequest.toJson(req)) + return RegisterResponse.fromJson((res.data as BaseResponse).body) } export const logout = async () => { - const res = await http.get(API_PATH + '/auth/logout') - return CommonResponse.fromJson((res.data as BaseResponse).body) -} \ No newline at end of file + const res = await http.get(API_PATH + '/auth/logout') + return CommonResponse.fromJson((res.data as BaseResponse).body) +} diff --git a/www/api/client.ts b/www/api/client.ts index cd9e14a..626d22a 100644 --- a/www/api/client.ts +++ b/www/api/client.ts @@ -1,30 +1,34 @@ import http from '@/api/http' -import { API_PATH } from "@/lib/consts"; +import { API_PATH } from '@/lib/consts' import { - DeleteClientRequest, DeleteClientResponse, - GetClientRequest, GetClientResponse, - InitClientRequest, InitClientResponse, - ListClientsRequest, ListClientsResponse -} from '@/lib/pb/api_client'; -import { BaseResponse } from "@/types/api"; + DeleteClientRequest, + DeleteClientResponse, + GetClientRequest, + GetClientResponse, + InitClientRequest, + InitClientResponse, + ListClientsRequest, + ListClientsResponse, +} from '@/lib/pb/api_client' +import { BaseResponse } from '@/types/api' export const getClient = async (req: GetClientRequest) => { - const res = await http.post(API_PATH + '/client/get', GetClientRequest.toJson(req)) - return GetClientResponse.fromJson((res.data as BaseResponse).body) + const res = await http.post(API_PATH + '/client/get', GetClientRequest.toJson(req)) + return GetClientResponse.fromJson((res.data as BaseResponse).body) } export const listClient = async (req: ListClientsRequest) => { - const res = await http.post(API_PATH + '/client/list', ListClientsRequest.toJson(req)) - return ListClientsResponse.fromJson((res.data as BaseResponse).body) + const res = await http.post(API_PATH + '/client/list', ListClientsRequest.toJson(req)) + return ListClientsResponse.fromJson((res.data as BaseResponse).body) } export const deleteClient = async (req: DeleteClientRequest) => { - const res = await http.post(API_PATH + '/client/delete', DeleteClientRequest.toJson(req)) - return DeleteClientResponse.fromJson((res.data as BaseResponse).body) + const res = await http.post(API_PATH + '/client/delete', DeleteClientRequest.toJson(req)) + return DeleteClientResponse.fromJson((res.data as BaseResponse).body) } export const initClient = async (req: InitClientRequest) => { - console.log("attempting init client:", InitClientRequest.toJsonString(req)) - const res = await http.post(API_PATH + '/client/init', InitClientRequest.toJson(req)) - return InitClientResponse.fromJson((res.data as BaseResponse).body) -} \ No newline at end of file + console.log('attempting init client:', InitClientRequest.toJsonString(req)) + const res = await http.post(API_PATH + '/client/init', InitClientRequest.toJson(req)) + return InitClientResponse.fromJson((res.data as BaseResponse).body) +} diff --git a/www/api/frp.ts b/www/api/frp.ts index 087a2ec..2312b55 100644 --- a/www/api/frp.ts +++ b/www/api/frp.ts @@ -1,35 +1,25 @@ import http from '@/api/http' -import { API_PATH } from "@/lib/consts"; -import { - RemoveFRPCRequest, - RemoveFRPCResponse, - UpdateFRPCRequest, - UpdateFRPCResponse -} from '@/lib/pb/api_client'; -import { - RemoveFRPSRequest, - RemoveFRPSResponse, - UpdateFRPSRequest, - UpdateFRPSResponse -} from '@/lib/pb/api_server'; -import { BaseResponse } from "@/types/api"; +import { API_PATH } from '@/lib/consts' +import { RemoveFRPCRequest, RemoveFRPCResponse, UpdateFRPCRequest, UpdateFRPCResponse } from '@/lib/pb/api_client' +import { RemoveFRPSRequest, RemoveFRPSResponse, UpdateFRPSRequest, UpdateFRPSResponse } from '@/lib/pb/api_server' +import { BaseResponse } from '@/types/api' export const updateFRPS = async (req: UpdateFRPSRequest) => { - const res = await http.post(API_PATH + '/frps/update', UpdateFRPSRequest.toJson(req)) - return UpdateFRPSResponse.fromJson((res.data as BaseResponse).body) + const res = await http.post(API_PATH + '/frps/update', UpdateFRPSRequest.toJson(req)) + return UpdateFRPSResponse.fromJson((res.data as BaseResponse).body) } export const removeFRPS = async (req: RemoveFRPSRequest) => { - const res = await http.post(API_PATH + '/frps/remove', RemoveFRPSRequest.toJson(req)) - return RemoveFRPSResponse.fromJson((res.data as BaseResponse).body) + const res = await http.post(API_PATH + '/frps/remove', RemoveFRPSRequest.toJson(req)) + return RemoveFRPSResponse.fromJson((res.data as BaseResponse).body) } export const updateFRPC = async (req: UpdateFRPCRequest) => { - const res = await http.post(API_PATH + '/frpc/update', UpdateFRPCRequest.toJson(req)) - return UpdateFRPCResponse.fromJson((res.data as BaseResponse).body) + const res = await http.post(API_PATH + '/frpc/update', UpdateFRPCRequest.toJson(req)) + return UpdateFRPCResponse.fromJson((res.data as BaseResponse).body) } export const removeFRPC = async (req: RemoveFRPCRequest) => { - const res = await http.post(API_PATH + '/frpc/remove', RemoveFRPCRequest.toJson(req)) - return RemoveFRPCResponse.fromJson((res.data as BaseResponse).body) -} \ No newline at end of file + const res = await http.post(API_PATH + '/frpc/remove', RemoveFRPCRequest.toJson(req)) + return RemoveFRPCResponse.fromJson((res.data as BaseResponse).body) +} diff --git a/www/api/http.ts b/www/api/http.ts index 322cb1f..58da775 100644 --- a/www/api/http.ts +++ b/www/api/http.ts @@ -1,29 +1,29 @@ -import { LOCAL_STORAGE_TOKEN_KEY, SET_TOKEN_HEADER, X_CLIENT_REQUEST_ID } from '@/lib/consts'; -import { $token } from '@/store/user'; +import { LOCAL_STORAGE_TOKEN_KEY, SET_TOKEN_HEADER, X_CLIENT_REQUEST_ID } from '@/lib/consts' +import { $token } from '@/store/user' import axios from 'axios' -import { v4 as uuidv4 } from 'uuid'; +import { v4 as uuidv4 } from 'uuid' const instance = axios.create({}) instance.interceptors.request.use((request) => { - let token = 'Bearer ' + localStorage.getItem(LOCAL_STORAGE_TOKEN_KEY) - if (token) { - request.headers.Authorization = token - $token.set(token) - } - request.headers[X_CLIENT_REQUEST_ID] = uuidv4(); - return request + let token = 'Bearer ' + localStorage.getItem(LOCAL_STORAGE_TOKEN_KEY) + if (token) { + request.headers.Authorization = token + $token.set(token) + } + request.headers[X_CLIENT_REQUEST_ID] = uuidv4() + return request }) instance.interceptors.response.use((response) => { - if (response.headers?.[SET_TOKEN_HEADER]) { - localStorage.setItem(LOCAL_STORAGE_TOKEN_KEY, response.headers[SET_TOKEN_HEADER]) - $token.set(response.headers[SET_TOKEN_HEADER]) - } - if (response.data.code != 200) { - throw response.data.msg - } - return response + if (response.headers?.[SET_TOKEN_HEADER]) { + localStorage.setItem(LOCAL_STORAGE_TOKEN_KEY, response.headers[SET_TOKEN_HEADER]) + $token.set(response.headers[SET_TOKEN_HEADER]) + } + if (response.data.code != 200) { + throw response.data.msg + } + return response }) export default instance diff --git a/www/api/platform.ts b/www/api/platform.ts index 572fea9..9cbd68e 100644 --- a/www/api/platform.ts +++ b/www/api/platform.ts @@ -1,20 +1,15 @@ import http from '@/api/http' import { API_PATH } from '@/lib/consts' -import { - GetClientsStatusRequest, - GetClientsStatusResponse -} from '@/lib/pb/api_master' -import { - GetPlatformInfoResponse, -} from '@/lib/pb/api_user' +import { GetClientsStatusRequest, GetClientsStatusResponse } from '@/lib/pb/api_master' +import { GetPlatformInfoResponse } from '@/lib/pb/api_user' import { BaseResponse } from '@/types/api' export const getPlatformInfo = async () => { - const res = await http.get(API_PATH + '/platform/baseinfo') - return GetPlatformInfoResponse.fromJson((res.data as BaseResponse).body) + const res = await http.get(API_PATH + '/platform/baseinfo') + return GetPlatformInfoResponse.fromJson((res.data as BaseResponse).body) } export const getClientsStatus = async (req: GetClientsStatusRequest) => { - const res = await http.post(API_PATH + '/platform/clientsstatus', GetClientsStatusRequest.toJson(req)) - return GetClientsStatusResponse.fromJson((res.data as BaseResponse).body) -} \ No newline at end of file + const res = await http.post(API_PATH + '/platform/clientsstatus', GetClientsStatusRequest.toJson(req)) + return GetClientsStatusResponse.fromJson((res.data as BaseResponse).body) +} diff --git a/www/api/server.ts b/www/api/server.ts index 8901790..152dae5 100644 --- a/www/api/server.ts +++ b/www/api/server.ts @@ -1,31 +1,33 @@ import http from '@/api/http' -import { API_PATH } from "@/lib/consts"; +import { API_PATH } from '@/lib/consts' import { - DeleteServerRequest, - DeleteServerResponse, - GetServerRequest, GetServerResponse, - InitServerRequest, - InitServerResponse, - ListServersRequest, ListServersResponse -} from "@/lib/pb/api_server"; -import { BaseResponse } from "@/types/api"; + DeleteServerRequest, + DeleteServerResponse, + GetServerRequest, + GetServerResponse, + InitServerRequest, + InitServerResponse, + ListServersRequest, + ListServersResponse, +} from '@/lib/pb/api_server' +import { BaseResponse } from '@/types/api' export const getServer = async (req: GetServerRequest) => { - const res = await http.post(API_PATH + '/server/get', GetServerRequest.toJson(req)) - return GetServerResponse.fromJson((res.data as BaseResponse).body) + const res = await http.post(API_PATH + '/server/get', GetServerRequest.toJson(req)) + return GetServerResponse.fromJson((res.data as BaseResponse).body) } export const listServer = async (req: ListServersRequest) => { - const res = await http.post(API_PATH + '/server/list', ListServersRequest.toJson(req)) - return ListServersResponse.fromJson((res.data as BaseResponse).body) + const res = await http.post(API_PATH + '/server/list', ListServersRequest.toJson(req)) + return ListServersResponse.fromJson((res.data as BaseResponse).body) } export const deleteServer = async (req: DeleteServerRequest) => { - const res = await http.post(API_PATH + '/server/delete', DeleteServerRequest.toJson(req)) - return DeleteServerResponse.fromJson((res.data as BaseResponse).body) + const res = await http.post(API_PATH + '/server/delete', DeleteServerRequest.toJson(req)) + return DeleteServerResponse.fromJson((res.data as BaseResponse).body) } export const initServer = async (req: InitServerRequest) => { - const res = await http.post(API_PATH + '/server/init', InitServerRequest.toJson(req)) - return InitServerResponse.fromJson((res.data as BaseResponse).body) -} \ No newline at end of file + const res = await http.post(API_PATH + '/server/init', InitServerRequest.toJson(req)) + return InitServerResponse.fromJson((res.data as BaseResponse).body) +} diff --git a/www/api/user.ts b/www/api/user.ts index c993e29..c1ff038 100644 --- a/www/api/user.ts +++ b/www/api/user.ts @@ -1,19 +1,21 @@ import http from '@/api/http' import { API_PATH } from '@/lib/consts' import { - GetUserInfoRequest, GetUserInfoResponse, - UpdateUserInfoRequest, UpdateUserInfoResponse + GetUserInfoRequest, + GetUserInfoResponse, + UpdateUserInfoRequest, + UpdateUserInfoResponse, } from '@/lib/pb/api_user' import { $userInfo } from '@/store/user' import { BaseResponse } from '@/types/api' export const getUserInfo = async (req: GetUserInfoRequest) => { - const res = await http.post(API_PATH + '/user/get', GetUserInfoRequest.toJson(req)) - $userInfo.set(GetUserInfoResponse.fromJson((res.data as BaseResponse).body).userInfo) - return GetUserInfoResponse.fromJson((res.data as BaseResponse).body) + const res = await http.post(API_PATH + '/user/get', GetUserInfoRequest.toJson(req)) + $userInfo.set(GetUserInfoResponse.fromJson((res.data as BaseResponse).body).userInfo) + return GetUserInfoResponse.fromJson((res.data as BaseResponse).body) } export const updateUserInfo = async (req: UpdateUserInfoRequest) => { - const res = await http.post(API_PATH + '/user/update', UpdateUserInfoRequest.toJson(req)) - return UpdateUserInfoResponse.fromJson((res.data as BaseResponse).body) -} \ No newline at end of file + const res = await http.post(API_PATH + '/user/update', UpdateUserInfoRequest.toJson(req)) + return UpdateUserInfoResponse.fromJson((res.data as BaseResponse).body) +} diff --git a/www/components.json b/www/components.json index e3c472d..ecfdab2 100644 --- a/www/components.json +++ b/www/components.json @@ -14,4 +14,4 @@ "components": "@/components", "utils": "@/lib/utils" } -} \ No newline at end of file +} diff --git a/www/components/apitest.tsx b/www/components/apitest.tsx index eaa8fd8..c21bcf2 100644 --- a/www/components/apitest.tsx +++ b/www/components/apitest.tsx @@ -1,124 +1,205 @@ -import { login, register } from "@/api/auth" -import { Button } from "./ui/button" -import { deleteClient, getClient, initClient, listClient } from "@/api/client" -import { deleteServer, getServer, initServer, listServer } from "@/api/server" -import { updateFRPC, updateFRPS } from "@/api/frp" -import { ClientConfig } from "@/types/client" -import { ServerConfig } from "@/types/server" -import { getUserInfo, updateUserInfo } from "@/api/user" -import { Separator } from "./ui/separator" -import { useState } from "react" -import { Input } from "./ui/input" -import { Label } from "@radix-ui/react-label" +import { login, register } from '@/api/auth' +import { Button } from './ui/button' +import { deleteClient, getClient, initClient, listClient } from '@/api/client' +import { deleteServer, getServer, initServer, listServer } from '@/api/server' +import { updateFRPC, updateFRPS } from '@/api/frp' +import { ClientConfig } from '@/types/client' +import { ServerConfig } from '@/types/server' +import { getUserInfo, updateUserInfo } from '@/api/user' +import { Separator } from './ui/separator' +import { useState } from 'react' +import { Input } from './ui/input' +import { Label } from '@radix-ui/react-label' export const APITest = () => { - const [serverID, setServerID] = useState("admin.server") - const [clientID, setClientID] = useState("admin.client") - const [username, setUsername] = useState("admin") - const [password, setPassword] = useState("admin") - const [email, setEmail] = useState("admin@localhost") + const [serverID, setServerID] = useState('admin.server') + const [clientID, setClientID] = useState('admin.client') + const [username, setUsername] = useState('admin') + const [password, setPassword] = useState('admin') + const [email, setEmail] = useState('admin@localhost') - return ( -
-
-
- - setUsername(e.target.value)} /> -
-
- - setPassword(e.target.value)} /> -
-
- - setEmail(e.target.value)} /> -
-
- - setClientID(e.target.value)} /> -
-
- - setServerID(e.target.value)} /> -
-
-
- - - - -
- -
- - - - -
- -
- - -
- -
- - - - -
- -
- - -
-
- ) -} \ No newline at end of file + return ( +
+
+
+ + setUsername(e.target.value)} /> +
+
+ + setPassword(e.target.value)} /> +
+
+ + setEmail(e.target.value)} /> +
+
+ + setClientID(e.target.value)} /> +
+
+ + setServerID(e.target.value)} /> +
+
+
+ + + + +
+ +
+ + + + +
+ +
+ + +
+ +
+ + + + +
+ +
+ + +
+
+ ) +} diff --git a/www/components/client_create_dialog.tsx b/www/components/client_create_dialog.tsx index 2d39a66..81de84a 100644 --- a/www/components/client_create_dialog.tsx +++ b/www/components/client_create_dialog.tsx @@ -1,66 +1,68 @@ -import { useState } from "react" -import { useMutation, useQuery } from "@tanstack/react-query" -import { initClient, listClient } from "@/api/client" -import { Label } from "./ui/label" -import { Input } from "./ui/input" -import { Button } from "./ui/button" -import { useToast } from "./ui/use-toast" -import { RespCode } from "@/lib/pb/common" +import { useState } from 'react' +import { useMutation, useQuery } from '@tanstack/react-query' +import { initClient, listClient } from '@/api/client' +import { Label } from './ui/label' +import { Input } from './ui/input' +import { Button } from './ui/button' +import { useToast } from './ui/use-toast' +import { RespCode } from '@/lib/pb/common' import { - Dialog, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@/components/ui/dialog" + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@/components/ui/dialog' export const CreateClientDialog = () => { - const [clientID, setClientID] = useState() - const newClient = useMutation({ - mutationFn: initClient, - }) - const dataQuery = useQuery({ - queryKey: ["listClient", { pageIndex: 0, pageSize: 10 }], - queryFn: async () => { - return await listClient({ page: 1, pageSize: 10 }) - } - }) - const { toast } = useToast() + const [clientID, setClientID] = useState() + const newClient = useMutation({ + mutationFn: initClient, + }) + const dataQuery = useQuery({ + queryKey: ['listClient', { pageIndex: 0, pageSize: 10 }], + queryFn: async () => { + return await listClient({ page: 1, pageSize: 10 }) + }, + }) + const { toast } = useToast() - const handleNewClient = async () => { - toast({ title: "已提交创建请求" }) - try { - let resp = await newClient.mutateAsync({ clientId: clientID }) - if (resp.status?.code !== RespCode.SUCCESS) { - toast({ title: "创建客户端失败" }) - return - } - toast({ title: "创建客户端成功" }) - dataQuery.refetch() - } catch (error) { - toast({ title: "创建客户端失败" }) - } - } + const handleNewClient = async () => { + toast({ title: '已提交创建请求' }) + try { + let resp = await newClient.mutateAsync({ clientId: clientID }) + if (resp.status?.code !== RespCode.SUCCESS) { + toast({ title: '创建客户端失败' }) + return + } + toast({ title: '创建客户端成功' }) + dataQuery.refetch() + } catch (error) { + toast({ title: '创建客户端失败' }) + } + } - return ( - - - - - - - 新建客户端 - 创建新的客户端用于连接,客户端ID必须唯一 - + return ( + + + + + + + 新建客户端 + 创建新的客户端用于连接,客户端ID必须唯一 + - - setClientID(e.target.value)} /> - - - - - - ) -} \ No newline at end of file + + setClientID(e.target.value)} /> + + + + + + ) +} diff --git a/www/components/client_item.tsx b/www/components/client_item.tsx index 4ff590e..2022276 100644 --- a/www/components/client_item.tsx +++ b/www/components/client_item.tsx @@ -1,252 +1,277 @@ -import { ColumnDef, Table } from "@tanstack/react-table" -import { MoreHorizontal } from "lucide-react" +import { ColumnDef, Table } from '@tanstack/react-table' +import { MoreHorizontal } from 'lucide-react' import { - Dialog, - DialogClose, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, - DialogTrigger, -} from "@/components/ui/dialog" + Dialog, + DialogClose, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from '@/components/ui/dialog' -import { Button } from "@/components/ui/button" +import { Button } from '@/components/ui/button' import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu" -import { useToast } from "./ui/use-toast" -import React, { useState } from "react" -import { ExecCommandStr, LinuxInstallCommand, WindowsInstallCommand } from "@/lib/consts" -import { useMutation, useQuery } from "@tanstack/react-query" -import { deleteClient, listClient } from "@/api/client" -import { useRouter } from "next/router" -import { useStore } from "@nanostores/react" -import { $platformInfo } from "@/store/user" -import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover" -import { getClientsStatus } from "@/api/platform" -import { ClientType } from "@/lib/pb/common" -import { ClientStatus, ClientStatus_Status } from "@/lib/pb/api_master" + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu' +import { useToast } from './ui/use-toast' +import React, { useState } from 'react' +import { ExecCommandStr, LinuxInstallCommand, WindowsInstallCommand } from '@/lib/consts' +import { useMutation, useQuery } from '@tanstack/react-query' +import { deleteClient, listClient } from '@/api/client' +import { useRouter } from 'next/router' +import { useStore } from '@nanostores/react' +import { $platformInfo } from '@/store/user' +import { Popover, PopoverContent, PopoverTrigger } from './ui/popover' +import { getClientsStatus } from '@/api/platform' +import { ClientType } from '@/lib/pb/common' +import { ClientStatus, ClientStatus_Status } from '@/lib/pb/api_master' export type ClientTableSchema = { - id: string, - status: "invalid" | "valid" - secret: string - info?: string - config?: string + id: string + status: 'invalid' | 'valid' + secret: string + info?: string + config?: string } export const columns: ColumnDef[] = [ - { - accessorKey: "id", - header: "ID", - cell: ({ row }) => { - return < ClientID client={row.original} /> - } + { + accessorKey: 'id', + header: 'ID', + cell: ({ row }) => { + return }, - { - accessorKey: "status", - header: "是否配置", - cell: ({ row }) => { - const client = row.original - return
{ - { - valid: "已配置", - invalid: "未配置", - }[client.status] - }
- } + }, + { + accessorKey: 'status', + header: '是否配置', + cell: ({ row }) => { + const client = row.original + return ( +
+ { + { + valid: '已配置', + invalid: '未配置', + }[client.status] + } +
+ ) }, - { - accessorKey: "info", - header: "运行信息", - cell: ({ row }) => { - const client = row.original - return - } + }, + { + accessorKey: 'info', + header: '运行信息', + cell: ({ row }) => { + const client = row.original + return }, - { - accessorKey: "secret", - header: "连接密钥", - cell: ({ row }) => { - const client = row.original - return - } + }, + { + accessorKey: 'secret', + header: '连接密钥', + cell: ({ row }) => { + const client = row.original + return }, - { - id: "action", - cell: ({ row, table }) => { - const client = row.original - return () - }, + }, + { + id: 'action', + cell: ({ row, table }) => { + const client = row.original + return }, + }, ] export const ClientID = ({ client }: { client: ClientTableSchema }) => { - const platformInfo = useStore($platformInfo) - return -
{client.id}
- -
Linux安装到systemd
-
- {platformInfo === undefined ? "获取平台信息失败" : LinuxInstallCommand("client", client, platformInfo)} -
- {/*
Windows
+ const platformInfo = useStore($platformInfo) + return ( + + +
{client.id}
+
+ +
Linux安装到systemd
+
+ {platformInfo === undefined ? '获取平台信息失败' : LinuxInstallCommand('client', client, platformInfo)} +
+ {/*
Windows
{platformInfo === undefined ? "获取平台信息失败" : WindowsInstallCommand("client", client, platformInfo)}
*/} -
+
+ ) } export const ClientInfo = ({ client }: { client: ClientTableSchema }) => { - const clientsInfo = useQuery({ - queryKey: ["getClientsStatus", [client.id]], - queryFn: async () => { - return await getClientsStatus({ - clientIds: [client.id], - clientType: ClientType.FRPC, - }) - } - }) + const clientsInfo = useQuery({ + queryKey: ['getClientsStatus', [client.id]], + queryFn: async () => { + return await getClientsStatus({ + clientIds: [client.id], + clientType: ClientType.FRPC, + }) + }, + }) - const trans = (info: ClientStatus | undefined) => { - let statusText: "在线" | "离线" | "错误" | "未知" = "未知"; - if (info === undefined) { - return statusText; - } - if (info.status === ClientStatus_Status.ONLINE) { - statusText = "在线"; - } else if (info.status === ClientStatus_Status.OFFLINE) { - statusText = "离线"; - } else if (info.status === ClientStatus_Status.ERROR) { - statusText = "错误"; - } return statusText; + const trans = (info: ClientStatus | undefined) => { + let statusText: '在线' | '离线' | '错误' | '未知' = '未知' + if (info === undefined) { + return statusText } + if (info.status === ClientStatus_Status.ONLINE) { + statusText = '在线' + } else if (info.status === ClientStatus_Status.OFFLINE) { + statusText = '离线' + } else if (info.status === ClientStatus_Status.ERROR) { + statusText = '错误' + } + return statusText + } - const infoColor = clientsInfo.data?.clients[client.id]?.status === ClientStatus_Status.ONLINE ? "text-green-500" : "text-red-500" + const infoColor = + clientsInfo.data?.clients[client.id]?.status === ClientStatus_Status.ONLINE ? 'text-green-500' : 'text-red-500' - return
- {`${clientsInfo.data?.clients[client.id].ping}ms, ${trans(clientsInfo.data?.clients[client.id])}`} + return ( +
+ {`${clientsInfo.data?.clients[client.id].ping}ms, ${trans(clientsInfo.data?.clients[client.id])}`}
+ ) } export const ClientSecret = ({ client }: { client: ClientTableSchema }) => { - const [showSecrect, setShowSecrect] = useState(false) - const fakeSecret = Array.from({ length: client.secret.length }).map(() => '*').join('') - const platformInfo = useStore($platformInfo) - const { toast } = useToast() - return - -
setShowSecrect(true)} - onMouseLeave={() => setShowSecrect(false)} - onClick={() => { - if (platformInfo) { - navigator.clipboard.writeText(ExecCommandStr("client", client, platformInfo)); - toast({ description: "复制成功", }); - } else { - toast({ description: "获取平台信息失败", }); - } - }} - className="font-medium hover:rounded hover:bg-slate-100 p-2 font-mono whitespace-nowrap">{ - showSecrect ? client.secret : fakeSecret - }
-
- -
- {platformInfo === undefined ? "获取平台信息失败" : ExecCommandStr("client", client, platformInfo)} -
-
+ const [showSecrect, setShowSecrect] = useState(false) + const fakeSecret = Array.from({ length: client.secret.length }) + .map(() => '*') + .join('') + const platformInfo = useStore($platformInfo) + const { toast } = useToast() + return ( + + +
setShowSecrect(true)} + onMouseLeave={() => setShowSecrect(false)} + onClick={() => { + if (platformInfo) { + navigator.clipboard.writeText(ExecCommandStr('client', client, platformInfo)) + toast({ description: '复制成功' }) + } else { + toast({ description: '获取平台信息失败' }) + } + }} + className="font-medium hover:rounded hover:bg-slate-100 p-2 font-mono whitespace-nowrap" + > + {showSecrect ? client.secret : fakeSecret} +
+
+ +
+ {platformInfo === undefined ? '获取平台信息失败' : ExecCommandStr('client', client, platformInfo)} +
+
+ ) } export interface ClientItemProps { - client: ClientTableSchema - table: Table + client: ClientTableSchema + table: Table } export const ClientActions: React.FC = ({ client, table }) => { - const { toast } = useToast() - const router = useRouter(); - const platformInfo = useStore($platformInfo) - const fetchDataOptions = { - pageIndex: table.getState().pagination.pageIndex, - pageSize: table.getState().pagination.pageSize, - } + const { toast } = useToast() + const router = useRouter() + const platformInfo = useStore($platformInfo) + const fetchDataOptions = { + pageIndex: table.getState().pagination.pageIndex, + pageSize: table.getState().pagination.pageSize, + } - const dataQuery = useQuery({ - queryKey: ["listClient", fetchDataOptions], - queryFn: async () => { - return await listClient({ - page: fetchDataOptions.pageIndex + 1, - pageSize: fetchDataOptions.pageSize - }) - } - }) + const dataQuery = useQuery({ + queryKey: ['listClient', fetchDataOptions], + queryFn: async () => { + return await listClient({ + page: fetchDataOptions.pageIndex + 1, + pageSize: fetchDataOptions.pageSize, + }) + }, + }) - const removeClient = useMutation({ - mutationFn: deleteClient, - onSuccess: () => { - toast({ description: "删除成功" }) - dataQuery.refetch() - }, - onError: () => { - toast({ description: "删除失败" }) - } - }) + const removeClient = useMutation({ + mutationFn: deleteClient, + onSuccess: () => { + toast({ description: '删除成功' }) + dataQuery.refetch() + }, + onError: () => { + toast({ description: '删除失败' }) + }, + }) - return - - - - - - 操作 - { - if (platformInfo) { - navigator.clipboard.writeText(ExecCommandStr("client", client, platformInfo)); - toast({ description: "复制成功,如果复制不成功,请点击ID字段手动复制", }); - } else { - toast({ description: "获取平台信息失败,如果复制不成功,请点击ID字段手动复制", }); - } - }} - > - 复制启动命令 - - - { - router.push({ pathname: "/clientedit", query: { clientID: client.id } }) - }}>修改 - - 删除 - - - - - - 确定删除该客户端? - -

- 此操作无法撤消。您确定要永久从我们的服务器中删除该客户端? -

-

删除后运行中的客户端将无法通过现有参数再次连接,如果您需要删除客户端对外的连接,可以选择清空配置

-
-
- - - - - -
+ return ( + + + + + + + 操作 + { + if (platformInfo) { + navigator.clipboard.writeText(ExecCommandStr('client', client, platformInfo)) + toast({ description: '复制成功,如果复制不成功,请点击ID字段手动复制' }) + } else { + toast({ description: '获取平台信息失败,如果复制不成功,请点击ID字段手动复制' }) + } + }} + > + 复制启动命令 + + + { + router.push({ pathname: '/clientedit', query: { clientID: client.id } }) + }} + > + 修改 + + + 删除 + + + + + + 确定删除该客户端? + +

此操作无法撤消。您确定要永久从我们的服务器中删除该客户端?

+

+ 删除后运行中的客户端将无法通过现有参数再次连接,如果您需要删除客户端对外的连接,可以选择清空配置 +

+
+
+ + + + + +
+ ) } diff --git a/www/components/client_list.tsx b/www/components/client_list.tsx index c068ca7..a6ce5ee 100644 --- a/www/components/client_list.tsx +++ b/www/components/client_list.tsx @@ -1,88 +1,90 @@ -import { Client } from "@/lib/pb/common"; -import { ClientTableSchema, columns as clientColumnsDef } from "./client_item"; -import { DataTable } from "./data_table"; +import { Client } from '@/lib/pb/common' +import { ClientTableSchema, columns as clientColumnsDef } from './client_item' +import { DataTable } from './data_table' import { - getSortedRowModel, - getCoreRowModel, - ColumnFiltersState, - useReactTable, - getFilteredRowModel, - getPaginationRowModel, - SortingState, - PaginationState, -} from "@tanstack/react-table" + getSortedRowModel, + getCoreRowModel, + ColumnFiltersState, + useReactTable, + getFilteredRowModel, + getPaginationRowModel, + SortingState, + PaginationState, +} from '@tanstack/react-table' -import React from "react" -import { useQuery } from "@tanstack/react-query"; -import { listClient } from "@/api/client"; +import React from 'react' +import { useQuery } from '@tanstack/react-query' +import { listClient } from '@/api/client' export interface ClientListProps { - Clients: Client[] + Clients: Client[] } export const ClientList: React.FC = ({ Clients }) => { - const [sorting, setSorting] = React.useState([]) - const [columnFilters, setColumnFilters] = React.useState( - [] - ) - const data = Clients.map((client) => - ({ - id: client.id == undefined ? "" : client.id, - status: client.config == undefined || client.config == "" ? "invalid" : "valid", - secret: client.secret == undefined ? "" : client.secret, - config: client.config - } as ClientTableSchema)) + const [sorting, setSorting] = React.useState([]) + const [columnFilters, setColumnFilters] = React.useState([]) + const data = Clients.map( + (client) => + ({ + id: client.id == undefined ? '' : client.id, + status: client.config == undefined || client.config == '' ? 'invalid' : 'valid', + secret: client.secret == undefined ? '' : client.secret, + config: client.config, + }) as ClientTableSchema, + ) - const [{ pageIndex, pageSize }, setPagination] = - React.useState({ - pageIndex: 0, - pageSize: 10, - }) + const [{ pageIndex, pageSize }, setPagination] = React.useState({ + pageIndex: 0, + pageSize: 10, + }) - const fetchDataOptions = { - pageIndex, - pageSize, - } - const pagination = React.useMemo( - () => ({ - pageIndex, - pageSize, - }), - [pageIndex, pageSize] - ) + const fetchDataOptions = { + pageIndex, + pageSize, + } + const pagination = React.useMemo( + () => ({ + pageIndex, + pageSize, + }), + [pageIndex, pageSize], + ) - const dataQuery = useQuery({ - queryKey: ["listClient", fetchDataOptions], - queryFn: async () => { - return await listClient({ page: fetchDataOptions.pageIndex + 1, pageSize: fetchDataOptions.pageSize }) - } - }) + const dataQuery = useQuery({ + queryKey: ['listClient', fetchDataOptions], + queryFn: async () => { + return await listClient({ page: fetchDataOptions.pageIndex + 1, pageSize: fetchDataOptions.pageSize }) + }, + }) - const table = useReactTable({ - data: dataQuery.data?.clients.map((client) => { - return { - id: client.id == undefined ? "" : client.id, - status: client.config == undefined || client.config == "" ? "invalid" : "valid", - secret: client.secret == undefined ? "" : client.secret, - config: client.config - } as ClientTableSchema - }) ?? data, - pageCount: Math.ceil((dataQuery.data?.total == undefined ? 0 : dataQuery.data?.total) / fetchDataOptions.pageSize ?? 0), - columns: clientColumnsDef, - getCoreRowModel: getCoreRowModel(), - getPaginationRowModel: getPaginationRowModel(), - onSortingChange: setSorting, - onPaginationChange: setPagination, - onColumnFiltersChange: setColumnFilters, - getFilteredRowModel: getFilteredRowModel(), - getSortedRowModel: getSortedRowModel(), - manualPagination: true, - state: { - sorting, - pagination, - columnFilters, - }, - }) - return -}; \ No newline at end of file + const table = useReactTable({ + data: + dataQuery.data?.clients.map((client) => { + return { + id: client.id == undefined ? '' : client.id, + status: client.config == undefined || client.config == '' ? 'invalid' : 'valid', + secret: client.secret == undefined ? '' : client.secret, + config: client.config, + } as ClientTableSchema + }) ?? data, + pageCount: Math.ceil( + (dataQuery.data?.total == undefined ? 0 : dataQuery.data?.total) / fetchDataOptions.pageSize ?? 0, + ), + columns: clientColumnsDef, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + onSortingChange: setSorting, + onPaginationChange: setPagination, + onColumnFiltersChange: setColumnFilters, + getFilteredRowModel: getFilteredRowModel(), + getSortedRowModel: getSortedRowModel(), + manualPagination: true, + state: { + sorting, + pagination, + columnFilters, + }, + }) + return +} diff --git a/www/components/column_header.tsx b/www/components/column_header.tsx index de4e6c0..3422de0 100644 --- a/www/components/column_header.tsx +++ b/www/components/column_header.tsx @@ -1,71 +1,61 @@ -import { - ArrowDownIcon, - ArrowUpIcon, - CaretSortIcon, - EyeNoneIcon, -} from "@radix-ui/react-icons" -import { Column } from "@tanstack/react-table" +import { ArrowDownIcon, ArrowUpIcon, CaretSortIcon, EyeNoneIcon } from '@radix-ui/react-icons' +import { Column } from '@tanstack/react-table' -import { cn } from "@/lib/utils" -import { Button } from "@/components/ui/button" +import { cn } from '@/lib/utils' +import { Button } from '@/components/ui/button' import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu" + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from '@/components/ui/dropdown-menu' -interface DataTableColumnHeaderProps - extends React.HTMLAttributes { - column: Column - title: string +interface DataTableColumnHeaderProps extends React.HTMLAttributes { + column: Column + title: string } export function DataTableColumnHeader({ - column, - title, - className, + column, + title, + className, }: DataTableColumnHeaderProps) { - if (!column.getCanSort()) { - return
{title}
- } + if (!column.getCanSort()) { + return
{title}
+ } - return ( -
- - - - - - column.toggleSorting(false)}> - - Asc - - column.toggleSorting(true)}> - - Desc - - - column.toggleVisibility(false)}> - - Hide - - - -
- ) + return ( +
+ + + + + + column.toggleSorting(false)}> + + Asc + + column.toggleSorting(true)}> + + Desc + + + column.toggleVisibility(false)}> + + Hide + + + +
+ ) } diff --git a/www/components/data_table.tsx b/www/components/data_table.tsx index ae9c0c5..38e803a 100644 --- a/www/components/data_table.tsx +++ b/www/components/data_table.tsx @@ -1,103 +1,81 @@ -"use client" +'use client' import { - ColumnDef, - flexRender, - getSortedRowModel, - getCoreRowModel, - ColumnFiltersState, - useReactTable, - getFilteredRowModel, - getPaginationRowModel, - SortingState, - Table as TableType, -} from "@tanstack/react-table" + ColumnDef, + flexRender, + getSortedRowModel, + getCoreRowModel, + ColumnFiltersState, + useReactTable, + getFilteredRowModel, + getPaginationRowModel, + SortingState, + Table as TableType, +} from '@tanstack/react-table' -import { - Table, - TableBody, - TableCell, - TableHead, - TableHeader, - TableRow, -} from "@/components/ui/table" +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' -import React from "react" -import { Input } from "@/components/ui/input" -import { DataTablePagination } from "./data_table_pagination" +import React from 'react' +import { Input } from '@/components/ui/input' +import { DataTablePagination } from './data_table_pagination' interface DataTableProps { - columns: ColumnDef[] - data?: TData[] - filterColumnName?: string - table: TableType + columns: ColumnDef[] + data?: TData[] + filterColumnName?: string + table: TableType } -export function DataTable({ - columns, - filterColumnName, - table, -}: DataTableProps) { - - return ( -
- {filterColumnName &&
- - table.getColumn(filterColumnName)?.setFilterValue(event.target.value) - } - className="max-w-sm" - /> -
} -
- - - {table.getHeaderGroups().map((headerGroup) => ( - - {headerGroup.headers.map((header) => { - return ( - - {header.isPlaceholder - ? null - : flexRender( - header.column.columnDef.header, - header.getContext() - )} - - ) - })} - - ))} - - - {table.getRowModel().rows?.length ? ( - table.getRowModel().rows.map((row) => ( - - {row.getVisibleCells().map((cell) => ( - - {flexRender(cell.column.columnDef.cell, cell.getContext())} - - ))} - - )) - ) : ( - - - 没有数据 - - - )} - -
-
-
- -
-
- ) +export function DataTable({ columns, filterColumnName, table }: DataTableProps) { + return ( +
+ {filterColumnName && ( +
+ table.getColumn(filterColumnName)?.setFilterValue(event.target.value)} + className="max-w-sm" + /> +
+ )} +
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())} + + ) + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + {flexRender(cell.column.columnDef.cell, cell.getContext())} + ))} + + )) + ) : ( + + + 没有数据 + + + )} + +
+
+
+ +
+
+ ) } diff --git a/www/components/data_table_pagination.tsx b/www/components/data_table_pagination.tsx index 39aae8b..b0adceb 100644 --- a/www/components/data_table_pagination.tsx +++ b/www/components/data_table_pagination.tsx @@ -1,97 +1,83 @@ -import { - ChevronLeftIcon, - ChevronRightIcon, - DoubleArrowLeftIcon, - DoubleArrowRightIcon, -} from "@radix-ui/react-icons" -import { Table } from "@tanstack/react-table" +import { ChevronLeftIcon, ChevronRightIcon, DoubleArrowLeftIcon, DoubleArrowRightIcon } from '@radix-ui/react-icons' +import { Table } from '@tanstack/react-table' -import { Button } from "@/components/ui/button" -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" +import { Button } from '@/components/ui/button' +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' interface DataTablePaginationProps { - table: Table + table: Table } -export function DataTablePagination({ - table, -}: DataTablePaginationProps) { - return ( -
- {/*
+export function DataTablePagination({ table }: DataTablePaginationProps) { + return ( +
+ {/*
{table.getFilteredSelectedRowModel().rows.length} of{" "} {table.getFilteredRowModel().rows.length} row(s) selected.
*/} -
-
- -

行 每页

-
-
- 第 {table.getState().pagination.pageIndex + 1} 页, 共{" "} - {table.getPageCount()}页 -
-
- - - - -
-
-
- ) +
+
+ +

行 每页

+
+
+ 第 {table.getState().pagination.pageIndex + 1} 页, 共 {table.getPageCount()}页 +
+
+ + + + +
+
+
+ ) } diff --git a/www/components/frpc_card.tsx b/www/components/frpc_card.tsx index 45a2b3e..95b98b4 100644 --- a/www/components/frpc_card.tsx +++ b/www/components/frpc_card.tsx @@ -1,138 +1,139 @@ -import React, { useEffect } from "react" -import { useState } from "react" -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" -import { Label } from "@radix-ui/react-label" +import React, { useEffect } from 'react' +import { useState } from 'react' +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select' +import { Label } from '@radix-ui/react-label' import { useQuery } from '@tanstack/react-query' -import { listServer } from "@/api/server" -import { getClient, listClient } from "@/api/client" -import { - Card, - CardContent, - CardDescription, - CardHeader, - CardTitle, -} from "@/components/ui/card" -import { Switch } from "./ui/switch" -import { FRPCEditor } from "./frpc_editor" -import { FRPCForm } from "./frpc_form" -import { useSearchParams } from "next/navigation" +import { listServer } from '@/api/server' +import { getClient, listClient } from '@/api/client' +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' +import { Switch } from './ui/switch' +import { FRPCEditor } from './frpc_editor' +import { FRPCForm } from './frpc_form' +import { useSearchParams } from 'next/navigation' export interface FRPCFormCardProps { - clientID?: string - serverID?: string + clientID?: string + serverID?: string } -export const FRPCFormCard: React.FC = ({ clientID: defaultClientID, serverID: defaultServerID }: FRPCFormCardProps) => { - const [advanceMode, setAdvanceMode] = useState(false) - const [clientID, setClientID] = useState() - const [serverID, setServerID] = useState() - const searchParams = useSearchParams() - const paramClientID = searchParams.get('clientID') - const handleServerChange = (value: string) => { - setServerID(value) +export const FRPCFormCard: React.FC = ({ + clientID: defaultClientID, + serverID: defaultServerID, +}: FRPCFormCardProps) => { + const [advanceMode, setAdvanceMode] = useState(false) + const [clientID, setClientID] = useState() + const [serverID, setServerID] = useState() + const searchParams = useSearchParams() + const paramClientID = searchParams.get('clientID') + const handleServerChange = (value: string) => { + setServerID(value) + } + + const handleClientChange = (value: string) => { + setClientID(value) + } + + useEffect(() => { + if (defaultClientID) { + setClientID(defaultClientID) } - - const handleClientChange = (value: string) => { - setClientID(value) + if (defaultServerID) { + setServerID(defaultServerID) } + }, [defaultClientID, defaultServerID]) - useEffect(() => { - if (defaultClientID) { - setClientID(defaultClientID) - } - if (defaultServerID) { - setServerID(defaultServerID) - } - }, [defaultClientID, defaultServerID]) + const { data: serverList, refetch: refetchServers } = useQuery({ + queryKey: ['listServer'], + queryFn: () => { + return listServer({ page: 1, pageSize: 500 }) + }, + }) - const { data: serverList, refetch: refetchServers } = useQuery({ - queryKey: ["listServer"], queryFn: () => { - return listServer({ page: 1, pageSize: 500 }) - } - }); + const { data: clientList, refetch: refetchClients } = useQuery({ + queryKey: ['listClient'], + queryFn: () => { + return listClient({ page: 1, pageSize: 500 }) + }, + }) - const { data: clientList, refetch: refetchClients } = useQuery({ - queryKey: ["listClient"], queryFn: () => { - return listClient({ page: 1, pageSize: 500 }) - } - }) + const { data: client, refetch: refetchClient } = useQuery({ + queryKey: ['getClient', clientID], + queryFn: () => { + return getClient({ clientId: clientID }) + }, + }) - const { data: client, refetch: refetchClient } = useQuery({ - queryKey: ["getClient", clientID], queryFn: () => { - return getClient({ clientId: clientID }) - } - }) + useEffect(() => { + if (paramClientID) { + setClientID(paramClientID) + setServerID(clientList?.clients?.find((client) => client.id == paramClientID)?.serverId) + } + }, [paramClientID, clientList]) - useEffect(() => { - if (paramClientID) { - setClientID(paramClientID) - setServerID(clientList?.clients?.find((client) => client.id == paramClientID)?.serverId) - } - }, [paramClientID, clientList]) - - return ( - - - 编辑隧道 - 选择客户端和服务端以编辑隧道 - - -
-
-

- 高级模式 -

-

- 编辑客户端原始配置文件 -

-
- -
-
- - - - - -
- {clientID && serverID && !advanceMode && } - {clientID && serverID && advanceMode && } -
-
- ) -} \ No newline at end of file + return ( + + + 编辑隧道 + 选择客户端和服务端以编辑隧道 + + +
+
+

高级模式

+

编辑客户端原始配置文件

+
+ +
+
+ + + + +
+ {clientID && serverID && !advanceMode && } + {clientID && serverID && advanceMode && } +
+
+ ) +} diff --git a/www/components/frpc_editor.tsx b/www/components/frpc_editor.tsx index c73df97..0e84714 100644 --- a/www/components/frpc_editor.tsx +++ b/www/components/frpc_editor.tsx @@ -1,70 +1,94 @@ -import { Label } from "@radix-ui/react-label" -import { Textarea } from "./ui/textarea" -import { FRPCFormProps } from "./frpc_form" -import { getClient } from "@/api/client"; -import { useMutation, useQuery } from "@tanstack/react-query"; -import { useEffect, useState } from "react"; -import { Button } from "./ui/button"; -import { updateFRPC } from "@/api/frp"; -import { useToast } from "./ui/use-toast"; -import { RespCode } from "@/lib/pb/common"; +import { Label } from '@radix-ui/react-label' +import { Textarea } from './ui/textarea' +import { FRPCFormProps } from './frpc_form' +import { getClient } from '@/api/client' +import { useMutation, useQuery } from '@tanstack/react-query' +import { useEffect, useState } from 'react' +import { Button } from './ui/button' +import { updateFRPC } from '@/api/frp' +import { useToast } from './ui/use-toast' +import { RespCode } from '@/lib/pb/common' export const FRPCEditor: React.FC = ({ clientID, serverID }) => { - const { toast } = useToast() - const { data: client, refetch: refetchClient } = useQuery({ - queryKey: ["getClient", clientID], queryFn: () => { - return getClient({ clientId: clientID }) - } - }); + const { toast } = useToast() + const { data: client, refetch: refetchClient } = useQuery({ + queryKey: ['getClient', clientID], + queryFn: () => { + return getClient({ clientId: clientID }) + }, + }) - const [configContent, setConfigContent] = useState("{}") - const updateFrpc = useMutation({ mutationFn: updateFRPC, }) - const [editorValue, setEditorValue] = useState("") + const [configContent, setConfigContent] = useState('{}') + const updateFrpc = useMutation({ mutationFn: updateFRPC }) + const [editorValue, setEditorValue] = useState('') - const handleSubmit = async () => { - try { - let res = await updateFrpc.mutateAsync({ - clientId: clientID, config: Buffer.from(editorValue), serverId: serverID - }) - if (res.status?.code !== RespCode.SUCCESS) { - toast({ title: "更新失败" }) - return - } - toast({ title: "更新成功" }) - } catch (error) { - toast({ title: "更新失败" }) - } - } + const handleSubmit = async () => { + try { + let res = await updateFrpc.mutateAsync({ + clientId: clientID, + config: Buffer.from(editorValue), + serverId: serverID, + }) + if (res.status?.code !== RespCode.SUCCESS) { + toast({ title: '更新失败' }) + return + } + toast({ title: '更新成功' }) + } catch (error) { + toast({ title: '更新失败' }) + } + } - useEffect(() => { - refetchClient() - try { - setConfigContent(JSON.stringify(JSON.parse(client?.client?.config == undefined ? "{}" || - client?.client?.config == "" : client?.client?.config), null, 2)) - setEditorValue(JSON.stringify(JSON.parse(client?.client?.config == undefined || - client?.client?.config == "" ? "{}" : client?.client?.config), null, 2)) - } catch (error) { - setConfigContent("{}") - setEditorValue("{}") - } - }, [client, refetchClient]) + useEffect(() => { + refetchClient() + try { + setConfigContent( + JSON.stringify( + JSON.parse( + client?.client?.config == undefined ? '{}' || client?.client?.config == '' : client?.client?.config, + ), + null, + 2, + ), + ) + setEditorValue( + JSON.stringify( + JSON.parse( + client?.client?.config == undefined || client?.client?.config == '' ? '{}' : client?.client?.config, + ), + null, + 2, + ), + ) + } catch (error) { + setConfigContent('{}') + setEditorValue('{}') + } + }, [client, refetchClient]) - return (
- -

- 只需要配置proxies和visitors字段,认证信息和服务器连接信息会由系统补全 -

-