import React, { useState, useMemo } from 'react'; import { Table, Button, Space, message, Layout, Typography, Card, Tooltip, Badge, Row, Col, Statistic, Dropdown, Avatar } from 'antd'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { PlayCircleFilled, PauseCircleFilled, ReloadOutlined, SettingOutlined, CloudUploadOutlined, FileTextOutlined, PlusOutlined, MoreOutlined, GlobalOutlined, UserOutlined, AppstoreOutlined, ThunderboltFilled } from '@ant-design/icons'; // API & Components import { getStatus, startGroup, stopGroup, restartGroup } from '../api'; import ConfigModal from '../components/ConfigModal'; import UpgradeModal from '../components/UpgradeModal'; import LogViewer from '../components/LogViewer'; import CreateGroupModal from '../components/CreateGroupModal'; const { Header, Content } = Layout; const { Title, Text } = Typography; const Dashboard = () => { const queryClient = useQueryClient(); // State const [configGroupId, setConfigGroupId] = useState(null); const [logGroupId, setLogGroupId] = useState(null); const [isUpgradeOpen, setIsUpgradeOpen] = useState(false); const [isCreateOpen, setIsCreateOpen] = useState(false); // 1. Data Fetching const { data: statusResp, isLoading } = useQuery({ queryKey: ['status'], queryFn: getStatus, refetchInterval: 3000, refetchOnWindowFocus: true, }); const dataSource = statusResp?.data || []; // 2. Statistics Calculation const stats = useMemo(() => { const total = dataSource.length; const running = dataSource.filter(d => d.running).length; const stopped = total - running; const totalInstances = dataSource.reduce((acc, curr) => acc + (curr.instances || 0), 0); return { total, running, stopped, totalInstances }; }, [dataSource]); // 3. Actions const actionMutation = useMutation({ mutationFn: ({ fn, id }) => fn(id), onSuccess: () => { message.success('Command sent successfully'); queryClient.invalidateQueries(['status']); }, onError: (err) => message.error('Operation failed: ' + err.message), }); const handleAction = (fn, id) => actionMutation.mutate({ fn, id }); // 4. Columns Definition const columns = [ { title: 'Identity', key: 'identity', width: 220, render: (_, record) => ( } style={{ backgroundColor: record.running ? '#e6f7ff' : '#f5f5f5', color: record.running ? '#1890ff' : '#ccc' }} />
{record.id} {record.plugin}
) }, { title: 'Status', key: 'status', width: 120, render: (_, record) => ( {record.running ? 'Running' : 'Stopped'} } /> ), }, { title: 'Target', dataIndex: 'instances', key: 'instances', width: 100, align: 'center', render: (val) => }, { title: 'Resources', key: 'pools', render: (_, record) => ( {record.local_account_pool || 'N/A'} {record.proxies_pool || 'N/A'} ) }, { title: 'Actions', key: 'action', width: 200, align: 'right', render: (_, record) => { // Dropdown Menu for secondary actions const menuItems = [ { key: 'logs', label: 'View Logs', icon: , onClick: () => setLogGroupId(record.id) }, { key: 'config', label: 'Configuration', icon: , onClick: () => setConfigGroupId(record.id) }, ]; return ( {record.running ? ( {/* 2. Stats Overview Cards */} } color="#1890ff" /> } color="#52c41a" /> } color="#ff4d4f" /> } color="#faad14" /> {/* 3. Main Data Table */} {/* Modals */} {configGroupId && setConfigGroupId(null)} />} {logGroupId && setLogGroupId(null)} />} setIsUpgradeOpen(false)} /> setIsCreateOpen(false)} /> ); }; // --- Helper Components --- const StatCard = ({ title, value, icon, color }) => ( {title}} value={value} valueStyle={{ fontWeight: 'bold', fontSize: '24px', color: '#262626' }} prefix={{icon}} /> ); const TagPill = ({ value, label }) => (
{value} {label}
); export default Dashboard;