mirror of
https://github.com/lordmathis/lemma.git
synced 2025-11-05 23:44:22 +00:00
Update admin stats
This commit is contained in:
@@ -1,17 +1,18 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import { Table, Text, Box, LoadingOverlay, Alert } from '@mantine/core';
|
||||||
Grid,
|
import { IconAlertCircle } from '@tabler/icons-react';
|
||||||
Card,
|
|
||||||
Stack,
|
|
||||||
Text,
|
|
||||||
Title,
|
|
||||||
LoadingOverlay,
|
|
||||||
Alert,
|
|
||||||
RingProgress,
|
|
||||||
} from '@mantine/core';
|
|
||||||
import { IconUsers, IconFolders, IconAlertCircle } from '@tabler/icons-react';
|
|
||||||
import { useAdmin } from '../../../hooks/useAdmin';
|
import { useAdmin } from '../../../hooks/useAdmin';
|
||||||
import StatCard from './StatCard';
|
|
||||||
|
const formatBytes = (bytes) => {
|
||||||
|
const units = ['B', 'KB', 'MB', 'GB'];
|
||||||
|
let size = bytes;
|
||||||
|
let unitIndex = 0;
|
||||||
|
while (size >= 1024 && unitIndex < units.length - 1) {
|
||||||
|
size /= 1024;
|
||||||
|
unitIndex++;
|
||||||
|
}
|
||||||
|
return `${size.toFixed(1)} ${units[unitIndex]}`;
|
||||||
|
};
|
||||||
|
|
||||||
const AdminStatsTab = () => {
|
const AdminStatsTab = () => {
|
||||||
const { data: stats, loading, error } = useAdmin('stats');
|
const { data: stats, loading, error } = useAdmin('stats');
|
||||||
@@ -28,61 +29,37 @@ const AdminStatsTab = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const statsRows = [
|
||||||
|
{ label: 'Total Users', value: stats.totalUsers },
|
||||||
|
{ label: 'Active Users', value: stats.activeUsers },
|
||||||
|
{ label: 'Total Workspaces', value: stats.totalWorkspaces },
|
||||||
|
{ label: 'Total Files', value: stats.totalFiles },
|
||||||
|
{ label: 'Total Storage Size', value: formatBytes(stats.totalSize) },
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Box pos="relative">
|
||||||
<Text size="xl" fw={700}>
|
<Text size="xl" fw={700} mb="md">
|
||||||
System Statistics
|
System Statistics
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<Grid>
|
<Table striped highlightOnHover withBorder>
|
||||||
<Grid.Col span={{ base: 12, md: 6, lg: 3 }}>
|
<Table.Thead>
|
||||||
<StatCard
|
<Table.Tr>
|
||||||
title="Total Users"
|
<Table.Th>Metric</Table.Th>
|
||||||
value={stats.totalUsers}
|
<Table.Th>Value</Table.Th>
|
||||||
icon={IconUsers}
|
</Table.Tr>
|
||||||
color="blue"
|
</Table.Thead>
|
||||||
/>
|
<Table.Tbody>
|
||||||
</Grid.Col>
|
{statsRows.map((row) => (
|
||||||
<Grid.Col span={{ base: 12, md: 6, lg: 3 }}>
|
<Table.Tr key={row.label}>
|
||||||
<StatCard
|
<Table.Td>{row.label}</Table.Td>
|
||||||
title="Total Workspaces"
|
<Table.Td>{row.value}</Table.Td>
|
||||||
value={stats.totalWorkspaces}
|
</Table.Tr>
|
||||||
icon={IconFolders}
|
))}
|
||||||
color="grape"
|
</Table.Tbody>
|
||||||
/>
|
</Table>
|
||||||
</Grid.Col>
|
</Box>
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<Grid mt="md">
|
|
||||||
<Grid.Col span={{ base: 12, md: 6 }}>
|
|
||||||
<Card withBorder>
|
|
||||||
<Stack align="center">
|
|
||||||
<Title order={3}>Active Users</Title>
|
|
||||||
<RingProgress
|
|
||||||
size={200}
|
|
||||||
thickness={16}
|
|
||||||
roundCaps
|
|
||||||
sections={[
|
|
||||||
{
|
|
||||||
value: (stats.activeUsers / stats.totalUsers) * 100,
|
|
||||||
color: 'blue',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
label={
|
|
||||||
<Text ta="center" fw={700} size="xl">
|
|
||||||
{((stats.activeUsers / stats.totalUsers) * 100).toFixed(1)}%
|
|
||||||
</Text>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<Text c="dimmed" size="sm">
|
|
||||||
{stats.activeUsers} out of {stats.totalUsers} users active in
|
|
||||||
last 30 days
|
|
||||||
</Text>
|
|
||||||
</Stack>
|
|
||||||
</Card>
|
|
||||||
</Grid.Col>
|
|
||||||
</Grid>
|
|
||||||
</Stack>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { Card, Group, Box, Text } from '@mantine/core';
|
|
||||||
|
|
||||||
const StatCard = ({ title, value, icon: Icon, color = 'blue' }) => (
|
|
||||||
<Card withBorder p="md">
|
|
||||||
<Group>
|
|
||||||
<Box style={{ flex: 1 }}>
|
|
||||||
<Text size="xs" tt="uppercase" fw={700} c="dimmed">
|
|
||||||
{title}
|
|
||||||
</Text>
|
|
||||||
<Text fw={700} size="xl">
|
|
||||||
{value}
|
|
||||||
</Text>
|
|
||||||
</Box>
|
|
||||||
<Icon size={32} color={`var(--mantine-color-${color}-filled)`} />
|
|
||||||
</Group>
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default StatCard;
|
|
||||||
Reference in New Issue
Block a user