mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-05 12:44:22 +00:00
fix(inbounds): correct per-inbound client counts and align stat colors
The client column under-counted clients attached to an inbound whose shared client_traffics row is keyed to a different inbound: rollupClients filtered settings.clients down to emails that had a stat row on that inbound. Count from settings.clients membership instead. Also surface all/active/disable/depleted/online with the Clients-page color scheme and widen the column.
This commit is contained in:
parent
44a8c94108
commit
d2058f07dd
2 changed files with 17 additions and 23 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
import { useMemo, type ReactElement } from 'react';
|
import { useMemo, type ReactElement } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Popover, Switch, Tag, type TableColumnType } from 'antd';
|
import { Popover, Switch, Tag, type TableColumnType } from 'antd';
|
||||||
|
import { TeamOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
import { SizeFormatter, IntlUtil, ColorUtils } from '@/utils';
|
import { SizeFormatter, IntlUtil, ColorUtils } from '@/utils';
|
||||||
import { InfinityIcon } from '@/components/ui';
|
import { InfinityIcon } from '@/components/ui';
|
||||||
|
|
@ -152,15 +153,27 @@ export function useInboundColumns({
|
||||||
title: t('clients'),
|
title: t('clients'),
|
||||||
key: 'clients',
|
key: 'clients',
|
||||||
align: 'left',
|
align: 'left',
|
||||||
width: 50,
|
width: 80,
|
||||||
render: (_, record) => {
|
render: (_, record) => {
|
||||||
const cc = clientCount[record.id];
|
const cc = clientCount[record.id];
|
||||||
if (!cc) return null;
|
if (!cc) return null;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tag color="green" className="client-count-tag" style={{ margin: 0, padding: '0 2px' }}>
|
<Tag className="client-count-tag" style={{ margin: 0, padding: '0 2px' }}>
|
||||||
{cc.clients}
|
<TeamOutlined /> {cc.clients}
|
||||||
</Tag>
|
</Tag>
|
||||||
|
{cc.active.length > 0 && (
|
||||||
|
<Popover
|
||||||
|
title={t('subscription.active')}
|
||||||
|
content={(
|
||||||
|
<div className="client-email-list">
|
||||||
|
{cc.active.map((e) => <div key={e}>{e}</div>)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Tag color="green" className="client-count-tag" style={{ margin: 0, padding: '0 2px' }}>{cc.active.length}</Tag>
|
||||||
|
</Popover>
|
||||||
|
)}
|
||||||
{cc.deactive.length > 0 && (
|
{cc.deactive.length > 0 && (
|
||||||
<Popover
|
<Popover
|
||||||
title={t('disabled')}
|
title={t('disabled')}
|
||||||
|
|
@ -185,18 +198,6 @@ export function useInboundColumns({
|
||||||
<Tag color="red" className="client-count-tag" style={{ margin: 0, padding: '0 2px' }}>{cc.depleted.length}</Tag>
|
<Tag color="red" className="client-count-tag" style={{ margin: 0, padding: '0 2px' }}>{cc.depleted.length}</Tag>
|
||||||
</Popover>
|
</Popover>
|
||||||
)}
|
)}
|
||||||
{cc.expiring.length > 0 && (
|
|
||||||
<Popover
|
|
||||||
title={t('depletingSoon')}
|
|
||||||
content={(
|
|
||||||
<div className="client-email-list">
|
|
||||||
{cc.expiring.map((e) => <div key={e}>{e}</div>)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<Tag color="orange" className="client-count-tag" style={{ margin: 0, padding: '0 2px' }}>{cc.expiring.length}</Tag>
|
|
||||||
</Popover>
|
|
||||||
)}
|
|
||||||
{cc.online.length > 0 && (
|
{cc.online.length > 0 && (
|
||||||
<Popover
|
<Popover
|
||||||
title={t('online')}
|
title={t('online')}
|
||||||
|
|
|
||||||
|
|
@ -142,14 +142,7 @@ export function useInbounds() {
|
||||||
const clientStats = Array.isArray((dbInbound as { clientStats?: unknown }).clientStats)
|
const clientStats = Array.isArray((dbInbound as { clientStats?: unknown }).clientStats)
|
||||||
? (dbInbound as unknown as { clientStats: { email: string; total: number; up: number; down: number; expiryTime: number }[] }).clientStats
|
? (dbInbound as unknown as { clientStats: { email: string; total: number; up: number; down: number; expiryTime: number }[] }).clientStats
|
||||||
: [];
|
: [];
|
||||||
const allClients = inbound?.clients || [];
|
const clients = inbound?.clients || [];
|
||||||
const statsEmails = new Set<string>();
|
|
||||||
for (const s of clientStats) {
|
|
||||||
if (s && s.email) statsEmails.add(s.email);
|
|
||||||
}
|
|
||||||
const clients = clientStats.length > 0
|
|
||||||
? allClients.filter((c) => c && c.email && statsEmails.has(c.email))
|
|
||||||
: allClients;
|
|
||||||
const active: string[] = [];
|
const active: string[] = [];
|
||||||
const deactive: string[] = [];
|
const deactive: string[] = [];
|
||||||
const depleted: string[] = [];
|
const depleted: string[] = [];
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue