From 11514175e6ad7eeac2c7d6f5952d9b8f533eb270 Mon Sep 17 00:00:00 2001 From: moonrailgun Date: Sat, 14 Jan 2023 01:26:37 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0tailchat=20=E7=BD=91?= =?UTF-8?q?=E7=BB=9C=E8=8F=9C=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pnpm-lock.yaml | 15 ++- server/admin/app/ra/App.tsx | 11 ++- server/admin/app/ra/components/ChipItems.tsx | 17 ++++ server/admin/app/ra/layout/Menu.tsx | 29 ++++++ server/admin/app/ra/layout/index.tsx | 8 ++ server/admin/app/ra/network/index.tsx | 96 ++++++++++++++++++++ server/admin/app/ra/request.ts | 29 ++++++ server/admin/app/ra/resources/user.tsx | 1 - server/admin/package.json | 2 + 9 files changed, 204 insertions(+), 4 deletions(-) create mode 100644 server/admin/app/ra/components/ChipItems.tsx create mode 100644 server/admin/app/ra/layout/Menu.tsx create mode 100644 server/admin/app/ra/layout/index.tsx create mode 100644 server/admin/app/ra/network/index.tsx create mode 100644 server/admin/app/ra/request.ts diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cc715bfb..46605b4d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -907,6 +907,8 @@ importers: '@types/morgan': ^1.9.4 '@types/react': ^18.0.25 '@types/react-dom': ^18.0.8 + ahooks: ^3.7.4 + axios: ^1.2.2 body-parser: ^1.20.1 compression: ^1.7.4 cross-env: ^7.0.3 @@ -937,6 +939,8 @@ importers: '@remix-run/react': 1.9.0_biqbaboplfbrettd7655fr4n2y '@typegoose/typegoose': 9.3.1 '@types/md5': 2.3.2 + ahooks: 3.7.4_react@18.2.0 + axios: 1.2.2 body-parser: 1.20.1 compression: 1.7.4 express: 4.18.2 @@ -15384,6 +15388,16 @@ packages: - debug dev: false + /axios/1.2.2: + resolution: {integrity: sha512-bz/J4gS2S3I7mpN/YZfGFTqhXTYzRho8Ay38w2otuuDR322KzFIWm/4W2K6gIwvWaws5n+mnb7D1lN9uD+QH6Q==} + dependencies: + follow-redirects: 1.15.2 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: false + /b-tween/0.3.3: resolution: {integrity: sha512-oEHegcRpA7fAuc9KC4nktucuZn2aS8htymCPcP3qkEGPqiBH+GfqtqoG2l7LxHngg6O0HFM7hOeOYExl1Oz4ZA==} dev: false @@ -30899,7 +30913,6 @@ packages: /proxy-from-env/1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - dev: true /prr/1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} diff --git a/server/admin/app/ra/App.tsx b/server/admin/app/ra/App.tsx index 24192c66..835095a5 100644 --- a/server/admin/app/ra/App.tsx +++ b/server/admin/app/ra/App.tsx @@ -1,10 +1,9 @@ import { Admin, Resource, - ListGuesser, fetchUtils, - EditGuesser, ShowGuesser, + CustomRoutes, } from 'react-admin'; import jsonServerProvider from 'ra-data-json-server'; import { authProvider, authStorageKey } from './authProvider'; @@ -19,6 +18,9 @@ import GroupIcon from '@mui/icons-material/Group'; import AttachFileIcon from '@mui/icons-material/AttachFile'; import { theme } from './theme'; import { Dashboard } from './dashboard'; +import { Route } from 'react-router-dom'; +import { TailchatNetwork } from './network'; +import { TailchatLayout } from './layout'; const httpClient: typeof fetchUtils.fetchJson = (url, options = {}) => { try { @@ -47,6 +49,7 @@ export const App = () => ( basename="/admin" theme={theme} dashboard={Dashboard} + layout={TailchatLayout} disableTelemetry={true} authProvider={authProvider} dataProvider={dataProvider} @@ -80,5 +83,9 @@ export const App = () => ( list={FileList} show={ShowGuesser} /> + + + } /> + ); diff --git a/server/admin/app/ra/components/ChipItems.tsx b/server/admin/app/ra/components/ChipItems.tsx new file mode 100644 index 00000000..47076979 --- /dev/null +++ b/server/admin/app/ra/components/ChipItems.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { Chip, Grid } from '@mui/material'; + +export const ChipItems: React.FC<{ + items: string[]; +}> = React.memo((props) => { + return ( + + {props.items.map((item) => ( + + + + ))} + + ); +}); +ChipItems.displayName = 'ChipItems'; diff --git a/server/admin/app/ra/layout/Menu.tsx b/server/admin/app/ra/layout/Menu.tsx new file mode 100644 index 00000000..c7a7b8f1 --- /dev/null +++ b/server/admin/app/ra/layout/Menu.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { + Menu, + MenuProps, + ResourceMenuItem, + useResourceDefinitions, +} from 'react-admin'; +import FilterDramaIcon from '@mui/icons-material/FilterDrama'; + +export const TailchatMenu: React.FC = React.memo((props) => { + const resources = useResourceDefinitions(); + + return ( + + + + {...Object.keys(resources) + .filter((name) => resources[name].hasList) + .map((name) => )} + + } + /> + + ); +}); +TailchatMenu.displayName = 'TailchatMenu'; diff --git a/server/admin/app/ra/layout/index.tsx b/server/admin/app/ra/layout/index.tsx new file mode 100644 index 00000000..90a72584 --- /dev/null +++ b/server/admin/app/ra/layout/index.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import { LayoutComponent } from 'react-admin'; +import { Layout } from 'react-admin'; +import { TailchatMenu } from './Menu'; + +export const TailchatLayout: LayoutComponent = (props) => ( + +); diff --git a/server/admin/app/ra/network/index.tsx b/server/admin/app/ra/network/index.tsx new file mode 100644 index 00000000..6461fc20 --- /dev/null +++ b/server/admin/app/ra/network/index.tsx @@ -0,0 +1,96 @@ +import React from 'react'; +import { request } from '../request'; +import { useRequest } from 'ahooks'; +import { + CircularProgress, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + Typography, + Box, +} from '@mui/material'; +import _uniq from 'lodash/uniq'; +import { ChipItems } from '../components/ChipItems'; + +/** + * Tailchat 网络状态 + */ +export const TailchatNetwork: React.FC = React.memo(() => { + const { data, loading } = useRequest(async () => { + const { data } = await request('/network/all'); + + return data; + }); + + if (loading) { + return ; + } + + return ( + + + 节点列表 + + + + + ID + 主机名 + CPU占用 + IP地址列表 + SDK版本 + + + + {(data.nodes ?? []).map((row) => ( + + + {row.id} + {row.local && (*)} + + {row.hostname} + {row.cpu}% + + + + {row.client.version} + + ))} + +
+ + + 服务列表 + + + (data.services ?? [])} /> + + + + 操作列表 + + + (data.actions ?? [])} /> + + + + 事件列表 + + + (data.events ?? [])} /> + +
+ ); +}); +TailchatNetwork.displayName = 'TailchatNetwork'; diff --git a/server/admin/app/ra/request.ts b/server/admin/app/ra/request.ts new file mode 100644 index 00000000..74e1104e --- /dev/null +++ b/server/admin/app/ra/request.ts @@ -0,0 +1,29 @@ +import axios from 'axios'; +import { authStorageKey } from './authProvider'; +import _set from 'lodash/set'; + +/** + * 创建请求实例 + */ +function createRequest() { + const ins = axios.create({ + baseURL: '/admin/api', + }); + + ins.interceptors.request.use(async (val) => { + try { + const { token } = JSON.parse( + window.localStorage.getItem(authStorageKey) ?? '{}' + ); + _set(val, ['headers', 'Authorization'], `Bearer ${token}`); + + return val; + } catch (err) { + throw err; + } + }); + + return ins; +} + +export const request = createRequest(); diff --git a/server/admin/app/ra/resources/user.tsx b/server/admin/app/ra/resources/user.tsx index 951ea8b1..edec9f3b 100644 --- a/server/admin/app/ra/resources/user.tsx +++ b/server/admin/app/ra/resources/user.tsx @@ -39,7 +39,6 @@ export const UserList: React.FC = () => ( - diff --git a/server/admin/package.json b/server/admin/package.json index 35750546..7369dfb0 100644 --- a/server/admin/package.json +++ b/server/admin/package.json @@ -18,6 +18,8 @@ "@remix-run/react": "^1.9.0", "@typegoose/typegoose": "9.3.1", "@types/md5": "^2.3.2", + "ahooks": "^3.7.4", + "axios": "^1.2.2", "body-parser": "^1.20.1", "compression": "^1.7.4", "express": "^4.18.2",