import React, { useMemo, useRef, useState } from 'react'; import { Badge, Button, Divider, Empty, Form, Input, Modal, Popconfirm, Steps, Switch, Table, Tabs, Tooltip, Typography, } from 'antd'; import { ColumnsType } from 'antd/es/table'; import { PlusOutlined } from '@ant-design/icons'; import { ServerStatusInfo } from '../../types'; import { useSocketSubscribe } from '../api/socketio'; import { filesize } from 'filesize'; import prettyMilliseconds from 'pretty-ms'; import { UpDownCounter } from '../components/UpDownCounter'; import { max } from 'lodash-es'; import dayjs from 'dayjs'; import { useCurrentWorkspaceId } from '../store/user'; import { useWatch } from '../hooks/useWatch'; import { Loading } from '../components/Loading'; import { without } from 'lodash-es'; import { useIntervalUpdate } from '../hooks/useIntervalUpdate'; import clsx from 'clsx'; import { isServerOnline } from '../../shared'; import { defaultErrorHandler, trpc } from '../api/trpc'; import { useEvent } from '../hooks/useEvent'; import { useRequest } from '../hooks/useRequest'; export const Servers: React.FC = React.memo(() => { const [isModalOpen, setIsModalOpen] = useState(false); const [hideOfflineServer, setHideOfflineServer] = useState(false); const workspaceId = useCurrentWorkspaceId(); const handleOk = () => { setIsModalOpen(false); }; const clearOfflineNodeMutation = trpc.serverStatus.clearOfflineServerStatus.useMutation({ onError: defaultErrorHandler, }); const [{ loading }, handleClearOfflineNode] = useRequest(async (e) => { await clearOfflineNodeMutation.mutateAsync({ workspaceId, }); }); return (
Servers
Hide Offline
setIsModalOpen(false)} >
, }, { key: 'manual', label: 'Manual', children: , }, ]} />
); }); Servers.displayName = 'Servers'; function useServerMap(): Record { const serverMap = useSocketSubscribe>( 'onServerStatusUpdate', {} ); return serverMap; } export const ServerList: React.FC<{ hideOfflineServer: boolean; }> = React.memo((props) => { const serverMap = useServerMap(); const inc = useIntervalUpdate(2 * 1000); const { hideOfflineServer } = props; const dataSource = useMemo( () => Object.values(serverMap) .sort((info) => (isServerOnline(info) ? -1 : 1)) .filter((info) => { if (hideOfflineServer) { return isServerOnline(info); } return true; }), // make online server is up and offline is down [serverMap, inc, hideOfflineServer] ); const lastUpdatedAt = max(dataSource.map((d) => d.updatedAt)); const columns = useMemo((): ColumnsType => { return [ { key: 'status', title: 'Status', render: (val, record) => { return isServerOnline(record) ? ( ) : ( ); }, }, { dataIndex: 'name', title: 'Node Name', }, { dataIndex: 'hostname', title: 'Host Name', }, // { // dataIndex: ['payload', 'system'], // title: 'System', // }, { dataIndex: ['payload', 'uptime'], title: 'Uptime', render: (val) => prettyMilliseconds(Number(val) * 1000), }, { dataIndex: ['payload', 'load'], title: 'Load', }, { key: 'nework', title: 'Network', render: (_, record) => { return ( ); }, }, { key: 'traffic', title: 'Traffic', render: (_, record) => { return ( ); }, }, { dataIndex: ['payload', 'cpu'], title: 'cpu', render: (val) => `${val}%`, }, { key: 'ram', title: 'ram', render: (_, record) => { return `${filesize(record.payload.memory_used * 1000)} / ${filesize( record.payload.memory_total * 1000 )}`; }, }, { key: 'hdd', title: 'hdd', render: (_, record) => { return `${filesize( record.payload.hdd_used * 1000 * 1000 )} / ${filesize(record.payload.hdd_total * 1000 * 1000)}`; }, }, ]; }, []); return (
Last updated at: {dayjs(lastUpdatedAt).format('YYYY-MM-DD HH:mm:ss')}
}} rowClassName={(record) => clsx(!isServerOnline(record) && 'opacity-60')} /> ); }); ServerList.displayName = 'ServerList'; export const InstallScript: React.FC = React.memo(() => { const workspaceId = useCurrentWorkspaceId(); const command = `curl -o- ${window.location.origin}/serverStatus/${workspaceId}/install.sh | bash`; return (
Run this command in your linux machine
{command}
); }); export const AddServerStep: React.FC = React.memo(() => { const workspaceId = useCurrentWorkspaceId(); const [current, setCurrent] = useState(0); const serverMap = useServerMap(); const [checking, setChecking] = useState(false); const oldServerMapNames = useRef([]); const [diffServerNames, setDiffServerNames] = useState([]); const allServerNames = useMemo(() => Object.keys(serverMap), [serverMap]); useWatch([checking], () => { if (checking === true) { oldServerMapNames.current = [...allServerNames]; } }); useWatch([allServerNames], () => { if (checking === true) { setDiffServerNames(without(allServerNames, ...oldServerMapNames.current)); } }); const command = `./tianji-reporter --url ${window.location.origin} --workspace ${workspaceId}`; return ( Download reporter from{' '} { if (current === 0) { setCurrent(1); setChecking(true); } }} > Releases Page ), }, { title: 'Run', description: (
run reporter with:{' '} {command}
), }, { title: 'Waiting for receive UDP pack', description: (
{diffServerNames.length === 0 || checking === false ? ( ) : (
Is this your servers? {diffServerNames.map((n) => (
- {n}
))}
)}
), }, ]} /> ); }); AddServerStep.displayName = 'AddServerStep';