mirror of
https://github.com/rustmailer/bichon.git
synced 2026-08-03 07:48:34 +02:00
Update index.tsx
This commit is contained in:
@@ -106,16 +106,20 @@ export default function MailArchiveDashboard() {
|
|||||||
queryKey: ['dashboard-stats'],
|
queryKey: ['dashboard-stats'],
|
||||||
enabled: !!token,
|
enabled: !!token,
|
||||||
queryFn: get_dashboard_stats,
|
queryFn: get_dashboard_stats,
|
||||||
initialData: INITIAL_DASHBOARD_STATS,
|
placeholderData: INITIAL_DASHBOARD_STATS,
|
||||||
});
|
});
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const currentLocale = i18n.resolvedLanguage || i18n.language || navigator.language;
|
const currentLocale = i18n.resolvedLanguage || i18n.language || navigator.language;
|
||||||
|
|
||||||
const logicalSize = stats?.total_size_bytes ?? 0;
|
|
||||||
const blobSize = stats?.storage_usage_bytes ?? 0;
|
const stats1 = stats ?? INITIAL_DASHBOARD_STATS;
|
||||||
const indexSize = stats?.index_usage_bytes ?? 0;
|
|
||||||
|
|
||||||
|
const logicalSize = stats1.total_size_bytes ?? 0;
|
||||||
|
const blobSize = stats1.storage_usage_bytes ?? 0;
|
||||||
|
const indexSize = stats1.index_usage_bytes ?? 0;
|
||||||
const physicalTotal = blobSize + indexSize;
|
const physicalTotal = blobSize + indexSize;
|
||||||
|
|
||||||
const savingsPercent = logicalSize > 0
|
const savingsPercent = logicalSize > 0
|
||||||
@@ -125,13 +129,13 @@ export default function MailArchiveDashboard() {
|
|||||||
const blobWidth = logicalSize > 0 ? (blobSize / logicalSize) * 100 : 0;
|
const blobWidth = logicalSize > 0 ? (blobSize / logicalSize) * 100 : 0;
|
||||||
const indexWidth = logicalSize > 0 ? (indexSize / logicalSize) * 100 : 0;
|
const indexWidth = logicalSize > 0 ? (indexSize / logicalSize) * 100 : 0;
|
||||||
|
|
||||||
const totalAttachments = (stats?.with_attachment_count ?? 0) + (stats?.without_attachment_count ?? 0);
|
const totalAttachments = (stats1.with_attachment_count ?? 0) + (stats1.without_attachment_count ?? 0);
|
||||||
const attachmentRatio = totalAttachments > 0 ? (stats?.with_attachment_count ?? 0) / totalAttachments : 0;
|
const attachmentRatio = totalAttachments > 0 ? (stats1.with_attachment_count ?? 0) / totalAttachments : 0;
|
||||||
|
|
||||||
const hasRecentActivity = stats?.recent_activity && stats.recent_activity.length > 0;
|
const hasRecentActivity = stats1.recent_activity && stats1.recent_activity.length > 0;
|
||||||
const hasTopSenders = stats?.top_senders && stats.top_senders.length > 0;
|
const hasTopSenders = stats1.top_senders && stats1.top_senders.length > 0;
|
||||||
const hasTopEmails = stats?.top_largest_emails && stats.top_largest_emails.length > 0;
|
const hasTopEmails = stats1.top_largest_emails && stats1.top_largest_emails.length > 0;
|
||||||
const hasTopAccounts = stats?.top_accounts && stats.top_accounts.length > 0;
|
const hasTopAccounts = stats1.top_accounts && stats1.top_accounts.length > 0;
|
||||||
|
|
||||||
const { minimalList } = useMinimalAccountList();
|
const { minimalList } = useMinimalAccountList();
|
||||||
const getAccountIdByEmail = (email: string): number | null => {
|
const getAccountIdByEmail = (email: string): number | null => {
|
||||||
@@ -200,7 +204,7 @@ export default function MailArchiveDashboard() {
|
|||||||
<Users className="h-4 w-4 text-muted-foreground" />
|
<Users className="h-4 w-4 text-muted-foreground" />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="text-xl font-bold">{formatNumber(stats!.account_count)}</div>
|
<div className="text-xl font-bold">{formatNumber(stats1.account_count)}</div>
|
||||||
<p className="text-xs text-muted-foreground">{t('dashboard.connected')}</p>
|
<p className="text-xs text-muted-foreground">{t('dashboard.connected')}</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -211,7 +215,7 @@ export default function MailArchiveDashboard() {
|
|||||||
<Mail className="h-4 w-4 text-muted-foreground" />
|
<Mail className="h-4 w-4 text-muted-foreground" />
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className="text-xl font-bold">{formatNumber(stats!.email_count)}</div>
|
<div className="text-xl font-bold">{formatNumber(stats1.email_count)}</div>
|
||||||
<p className="text-xs text-muted-foreground">{t('dashboard.syncedLocally')}</p>
|
<p className="text-xs text-muted-foreground">{t('dashboard.syncedLocally')}</p>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -221,15 +225,15 @@ export default function MailArchiveDashboard() {
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent>
|
<CardContent>
|
||||||
<div className='text-xl font-bold truncate text-primary tracking-tighter'>
|
<div className='text-xl font-bold truncate text-primary tracking-tighter'>
|
||||||
{stats!.system_version ? (
|
{stats1.system_version ? (
|
||||||
<a href={`https://github.com/rustmailer/bichon/releases/tag/${stats!.system_version}`} target="_blank" rel="noopener noreferrer" className="hover:underline">
|
<a href={`https://github.com/rustmailer/bichon/releases/tag/${stats1.system_version}`} target="_blank" rel="noopener noreferrer" className="hover:underline">
|
||||||
{stats!.system_version}
|
{stats1.system_version}
|
||||||
</a>
|
</a>
|
||||||
) : 'N/A'}
|
) : 'N/A'}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-1.5 mt-1">
|
<div className="flex items-center gap-1.5 mt-1">
|
||||||
<GithubIcon className="h-5 w-5 text-muted-foreground" />
|
<GithubIcon className="h-5 w-5 text-muted-foreground" />
|
||||||
<p className="text-xs text-muted-foreground font-mono truncate">{stats!.commit_hash?.substring(0, 7) ?? 'N/A'}</p>
|
<p className="text-xs text-muted-foreground font-mono truncate">{stats1.commit_hash?.substring(0, 7) ?? 'N/A'}</p>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
@@ -288,7 +292,7 @@ export default function MailArchiveDashboard() {
|
|||||||
<CardContent className="h-36">
|
<CardContent className="h-36">
|
||||||
{hasRecentActivity ? (
|
{hasRecentActivity ? (
|
||||||
<ResponsiveContainer width="100%" height="100%">
|
<ResponsiveContainer width="100%" height="100%">
|
||||||
<BarChart data={convertRecentActivity(stats!.recent_activity, currentLocale)} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}>
|
<BarChart data={convertRecentActivity(stats1.recent_activity, currentLocale)} margin={{ top: 20, right: 30, left: 20, bottom: 5 }}>
|
||||||
<CartesianGrid strokeDasharray="3 3" vertical={false} opacity={0.3} />
|
<CartesianGrid strokeDasharray="3 3" vertical={false} opacity={0.3} />
|
||||||
<XAxis dataKey="date" tick={{ fontSize: 12 }} interval="preserveStart" tickCount={10} />
|
<XAxis dataKey="date" tick={{ fontSize: 12 }} interval="preserveStart" tickCount={10} />
|
||||||
<YAxis tick={{ fontSize: 12 }} />
|
<YAxis tick={{ fontSize: 12 }} />
|
||||||
@@ -377,7 +381,7 @@ export default function MailArchiveDashboard() {
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{stats!.top_senders.map((s) => (
|
{stats1.top_senders.map((s) => (
|
||||||
<TableRow key={s.key}>
|
<TableRow key={s.key}>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<div className="group relative flex items-center w-full min-w-0 h-full px-2 overflow-hidden">
|
<div className="group relative flex items-center w-full min-w-0 h-full px-2 overflow-hidden">
|
||||||
@@ -422,7 +426,7 @@ export default function MailArchiveDashboard() {
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{stats!.top_largest_emails.map((m, i) => (
|
{stats1.top_largest_emails.map((m, i) => (
|
||||||
<TableRow key={i}>
|
<TableRow key={i}>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<div className="group relative flex items-center w-full min-w-0 h-full px-2 overflow-hidden">
|
<div className="group relative flex items-center w-full min-w-0 h-full px-2 overflow-hidden">
|
||||||
@@ -453,51 +457,6 @@ export default function MailArchiveDashboard() {
|
|||||||
)}
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
<Card>
|
|
||||||
<CardHeader className="!px-4 !pt-4 !pb-1">
|
|
||||||
<CardTitle className="text-xs font-bold uppercase tracking-wider">{t('dashboard.top10Accounts')}</CardTitle>
|
|
||||||
</CardHeader>
|
|
||||||
<CardContent className="p-0">
|
|
||||||
{hasTopAccounts ? (
|
|
||||||
<Table>
|
|
||||||
<TableHeader>
|
|
||||||
<TableRow>
|
|
||||||
<TableHead className="text-xs">{t('dashboard.account')}</TableHead>
|
|
||||||
<TableHead className="text-right text-xs">{t('dashboard.emails')}</TableHead>
|
|
||||||
</TableRow>
|
|
||||||
</TableHeader>
|
|
||||||
<TableBody>
|
|
||||||
{stats!.top_accounts.map((acc) => (
|
|
||||||
<TableRow key={acc.key}>
|
|
||||||
<TableCell>
|
|
||||||
<div className="group relative flex items-center w-full min-w-0 h-full px-2 overflow-hidden">
|
|
||||||
<div className="absolute left-0 top-0 bottom-0 w-[2px] bg-primary opacity-0 group-hover:opacity-100 transition-opacity" />
|
|
||||||
<div className="text-xs flex flex-wrap gap-x-1 min-w-0 flex-1">
|
|
||||||
<span className="flex items-center">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
handleQuickSearch({ account_ids: [getAccountIdByEmail(acc.key) || 0] })
|
|
||||||
}}
|
|
||||||
className="hover:text-primary hover:underline transition-colors truncate max-w-[258px]"
|
|
||||||
>
|
|
||||||
{acc.key}
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</TableCell>
|
|
||||||
<TableCell className="text-right font-mono text-xs">{formatNumber(acc.count)}</TableCell>
|
|
||||||
</TableRow>
|
|
||||||
))}
|
|
||||||
</TableBody>
|
|
||||||
</Table>
|
|
||||||
) : (
|
|
||||||
<EmptyTable title={t('dashboard.noAccountData')} />
|
|
||||||
)}
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader className="!px-4 !pt-4 !pb-1">
|
<CardHeader className="!px-4 !pt-4 !pb-1">
|
||||||
<CardTitle className="text-xs font-bold uppercase tracking-wider">
|
<CardTitle className="text-xs font-bold uppercase tracking-wider">
|
||||||
@@ -550,6 +509,51 @@ export default function MailArchiveDashboard() {
|
|||||||
)}
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
<Card>
|
||||||
|
<CardHeader className="!px-4 !pt-4 !pb-1">
|
||||||
|
<CardTitle className="text-xs font-bold uppercase tracking-wider">{t('dashboard.top10Accounts')}</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="p-0">
|
||||||
|
{hasTopAccounts ? (
|
||||||
|
<Table>
|
||||||
|
<TableHeader>
|
||||||
|
<TableRow>
|
||||||
|
<TableHead className="text-xs">{t('dashboard.account')}</TableHead>
|
||||||
|
<TableHead className="text-right text-xs">{t('dashboard.emails')}</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{stats1.top_accounts.map((acc) => (
|
||||||
|
<TableRow key={acc.key}>
|
||||||
|
<TableCell>
|
||||||
|
<div className="group relative flex items-center w-full min-w-0 h-full px-2 overflow-hidden">
|
||||||
|
<div className="absolute left-0 top-0 bottom-0 w-[2px] bg-primary opacity-0 group-hover:opacity-100 transition-opacity" />
|
||||||
|
<div className="text-xs flex flex-wrap gap-x-1 min-w-0 flex-1">
|
||||||
|
<span className="flex items-center">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
handleQuickSearch({ account_ids: [getAccountIdByEmail(acc.key) || 0] })
|
||||||
|
}}
|
||||||
|
className="hover:text-primary hover:underline transition-colors truncate max-w-[258px]"
|
||||||
|
>
|
||||||
|
{acc.key}
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-right font-mono text-xs">{formatNumber(acc.count)}</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
) : (
|
||||||
|
<EmptyTable title={t('dashboard.noAccountData')} />
|
||||||
|
)}
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Main>
|
</Main>
|
||||||
|
|||||||
Reference in New Issue
Block a user