mirror of https://github.com/msgbyte/tailchat
feat: 增加tailchat 网络菜单
parent
7cdb5220c5
commit
11514175e6
@ -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 (
|
||||
<Grid container spacing={1}>
|
||||
{props.items.map((item) => (
|
||||
<Grid key={item} item>
|
||||
<Chip label={item} />
|
||||
</Grid>
|
||||
))}
|
||||
</Grid>
|
||||
);
|
||||
});
|
||||
ChipItems.displayName = 'ChipItems';
|
@ -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<MenuProps> = React.memo((props) => {
|
||||
const resources = useResourceDefinitions();
|
||||
|
||||
return (
|
||||
<Menu {...props}>
|
||||
<Menu.DashboardItem />
|
||||
|
||||
{...Object.keys(resources)
|
||||
.filter((name) => resources[name].hasList)
|
||||
.map((name) => <ResourceMenuItem key={name} name={name} />)}
|
||||
|
||||
<Menu.Item
|
||||
to="/admin/network"
|
||||
primaryText="Tailchat 网络"
|
||||
leftIcon={<FilterDramaIcon />}
|
||||
/>
|
||||
</Menu>
|
||||
);
|
||||
});
|
||||
TailchatMenu.displayName = 'TailchatMenu';
|
@ -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) => (
|
||||
<Layout {...props} menu={TailchatMenu} />
|
||||
);
|
@ -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 <CircularProgress />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
paddingTop: 2,
|
||||
paddingBottom: 2,
|
||||
maxWidth: '100vw',
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
节点列表
|
||||
</Typography>
|
||||
<Table sx={{ minWidth: 650 }} aria-label="simple table">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>ID</TableCell>
|
||||
<TableCell>主机名</TableCell>
|
||||
<TableCell>CPU占用</TableCell>
|
||||
<TableCell>IP地址列表</TableCell>
|
||||
<TableCell>SDK版本</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{(data.nodes ?? []).map((row) => (
|
||||
<TableRow
|
||||
key={row.name}
|
||||
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
|
||||
>
|
||||
<TableCell component="th" scope="row">
|
||||
{row.id}
|
||||
{row.local && <span> (*)</span>}
|
||||
</TableCell>
|
||||
<TableCell>{row.hostname}</TableCell>
|
||||
<TableCell>{row.cpu}%</TableCell>
|
||||
<TableCell>
|
||||
<ChipItems items={row.ipList ?? []} />
|
||||
</TableCell>
|
||||
<TableCell>{row.client.version}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
|
||||
<Typography variant="h6" gutterBottom>
|
||||
服务列表
|
||||
</Typography>
|
||||
<Box flexWrap="wrap" overflow="hidden">
|
||||
<ChipItems items={_uniq<string>(data.services ?? [])} />
|
||||
</Box>
|
||||
|
||||
<Typography variant="h6" gutterBottom>
|
||||
操作列表
|
||||
</Typography>
|
||||
<Box flexWrap="wrap" overflow="hidden">
|
||||
<ChipItems items={_uniq<string>(data.actions ?? [])} />
|
||||
</Box>
|
||||
|
||||
<Typography variant="h6" gutterBottom>
|
||||
事件列表
|
||||
</Typography>
|
||||
<Box flexWrap="wrap" overflow="hidden">
|
||||
<ChipItems items={_uniq<string>(data.events ?? [])} />
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
TailchatNetwork.displayName = 'TailchatNetwork';
|
@ -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();
|
Loading…
Reference in New Issue