-
This commit is contained in:
228
kms-frontend/src/components/Dashboard.tsx
Normal file
228
kms-frontend/src/components/Dashboard.tsx
Normal file
@ -0,0 +1,228 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Card, Row, Col, Statistic, Typography, Space, Alert, Spin } from 'antd';
|
||||
import {
|
||||
AppstoreOutlined,
|
||||
KeyOutlined,
|
||||
UserOutlined,
|
||||
CheckCircleOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { apiService } from '../services/apiService';
|
||||
|
||||
const { Title } = Typography;
|
||||
|
||||
interface DashboardStats {
|
||||
totalApplications: number;
|
||||
totalTokens: number;
|
||||
healthStatus: 'healthy' | 'unhealthy';
|
||||
readinessStatus: 'ready' | 'not-ready';
|
||||
}
|
||||
|
||||
const Dashboard: React.FC = () => {
|
||||
const [stats, setStats] = useState<DashboardStats>({
|
||||
totalApplications: 0,
|
||||
totalTokens: 0,
|
||||
healthStatus: 'unhealthy',
|
||||
readinessStatus: 'not-ready',
|
||||
});
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string>('');
|
||||
|
||||
useEffect(() => {
|
||||
loadDashboardData();
|
||||
}, []);
|
||||
|
||||
const loadDashboardData = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
setError('');
|
||||
|
||||
// Load health status
|
||||
const [healthResponse, readinessResponse] = await Promise.allSettled([
|
||||
apiService.healthCheck(),
|
||||
apiService.readinessCheck(),
|
||||
]);
|
||||
|
||||
const healthStatus = healthResponse.status === 'fulfilled' ? 'healthy' : 'unhealthy';
|
||||
const readinessStatus = readinessResponse.status === 'fulfilled' ? 'ready' : 'not-ready';
|
||||
|
||||
// Load applications count
|
||||
let totalApplications = 0;
|
||||
let totalTokens = 0;
|
||||
|
||||
try {
|
||||
const appsResponse = await apiService.getApplications(100, 0);
|
||||
totalApplications = appsResponse.count;
|
||||
|
||||
// Count tokens across all applications
|
||||
for (const app of appsResponse.data) {
|
||||
try {
|
||||
const tokensResponse = await apiService.getTokensForApplication(app.app_id, 100, 0);
|
||||
totalTokens += tokensResponse.count;
|
||||
} catch (tokenError) {
|
||||
console.warn(`Failed to load tokens for app ${app.app_id}:`, tokenError);
|
||||
}
|
||||
}
|
||||
} catch (appsError) {
|
||||
console.warn('Failed to load applications:', appsError);
|
||||
}
|
||||
|
||||
setStats({
|
||||
totalApplications,
|
||||
totalTokens,
|
||||
healthStatus,
|
||||
readinessStatus,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Dashboard error:', err);
|
||||
setError('Failed to load dashboard data. Please check your connection.');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div style={{ textAlign: 'center', padding: '50px' }}>
|
||||
<Spin size="large" />
|
||||
<div style={{ marginTop: '16px' }}>Loading dashboard...</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Space direction="vertical" size="large" style={{ width: '100%' }}>
|
||||
<div>
|
||||
<Title level={2}>Dashboard</Title>
|
||||
<p>Welcome to the Key Management System dashboard. Monitor your applications, tokens, and system health.</p>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<Alert
|
||||
message="Error"
|
||||
description={error}
|
||||
type="error"
|
||||
showIcon
|
||||
closable
|
||||
onClose={() => setError('')}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* System Status */}
|
||||
<Card title="System Status" style={{ marginBottom: '24px' }}>
|
||||
<Row gutter={16}>
|
||||
<Col span={12}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title="Health Status"
|
||||
value={stats.healthStatus === 'healthy' ? 'Healthy' : 'Unhealthy'}
|
||||
prefix={
|
||||
stats.healthStatus === 'healthy' ? (
|
||||
<CheckCircleOutlined style={{ color: '#52c41a' }} />
|
||||
) : (
|
||||
<ExclamationCircleOutlined style={{ color: '#ff4d4f' }} />
|
||||
)
|
||||
}
|
||||
valueStyle={{
|
||||
color: stats.healthStatus === 'healthy' ? '#52c41a' : '#ff4d4f',
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title="Readiness Status"
|
||||
value={stats.readinessStatus === 'ready' ? 'Ready' : 'Not Ready'}
|
||||
prefix={
|
||||
stats.readinessStatus === 'ready' ? (
|
||||
<CheckCircleOutlined style={{ color: '#52c41a' }} />
|
||||
) : (
|
||||
<ExclamationCircleOutlined style={{ color: '#ff4d4f' }} />
|
||||
)
|
||||
}
|
||||
valueStyle={{
|
||||
color: stats.readinessStatus === 'ready' ? '#52c41a' : '#ff4d4f',
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
{/* Statistics */}
|
||||
<Row gutter={16}>
|
||||
<Col xs={24} sm={12} lg={8}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title="Total Applications"
|
||||
value={stats.totalApplications}
|
||||
prefix={<AppstoreOutlined />}
|
||||
valueStyle={{ color: '#1890ff' }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} lg={8}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title="Total Tokens"
|
||||
value={stats.totalTokens}
|
||||
prefix={<KeyOutlined />}
|
||||
valueStyle={{ color: '#52c41a' }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={12} lg={8}>
|
||||
<Card>
|
||||
<Statistic
|
||||
title="Active Users"
|
||||
value={1}
|
||||
prefix={<UserOutlined />}
|
||||
valueStyle={{ color: '#722ed1' }}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{/* Quick Actions */}
|
||||
<Card title="Quick Actions">
|
||||
<Row gutter={16}>
|
||||
<Col xs={24} sm={8}>
|
||||
<Card
|
||||
hoverable
|
||||
onClick={() => window.location.pathname = '/applications'}
|
||||
style={{ textAlign: 'center', cursor: 'pointer' }}
|
||||
>
|
||||
<AppstoreOutlined style={{ fontSize: '32px', color: '#1890ff', marginBottom: '8px' }} />
|
||||
<div>Manage Applications</div>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={8}>
|
||||
<Card
|
||||
hoverable
|
||||
onClick={() => window.location.pathname = '/tokens'}
|
||||
style={{ textAlign: 'center', cursor: 'pointer' }}
|
||||
>
|
||||
<KeyOutlined style={{ fontSize: '32px', color: '#52c41a', marginBottom: '8px' }} />
|
||||
<div>Manage Tokens</div>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col xs={24} sm={8}>
|
||||
<Card
|
||||
hoverable
|
||||
onClick={() => window.location.pathname = '/audit'}
|
||||
style={{ textAlign: 'center', cursor: 'pointer' }}
|
||||
>
|
||||
<ExclamationCircleOutlined style={{ fontSize: '32px', color: '#fa8c16', marginBottom: '8px' }} />
|
||||
<div>View Audit Log</div>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Dashboard;
|
||||
Reference in New Issue
Block a user