diff --git a/app/db/crud.py b/app/db/crud.py index c35acf2..ce2876b 100644 --- a/app/db/crud.py +++ b/app/db/crud.py @@ -314,7 +314,7 @@ def get_users( def get_total_usages( db: Session, admin: Admin, start: datetime, end: datetime -): +) -> TrafficUsageSeries: usages = defaultdict(int) query = ( @@ -338,20 +338,20 @@ def get_total_usages( .join(User, NodeUserUsage.user_id == User.id) .join(Admin, User.admin_id == Admin.id) ) + for created_at, used_traffic in query.all(): - usages[created_at.replace(tzinfo=timezone.utc).timestamp()] += int( - used_traffic - ) + timestamp = created_at.replace(tzinfo=timezone.utc).timestamp() + usages[timestamp] += int(used_traffic) - result = TrafficUsageSeries(usages=[]) + result = TrafficUsageSeries(usages=[], total=0) current = start.astimezone(timezone.utc).replace( minute=0, second=0, microsecond=0 ) while current <= end.replace(tzinfo=timezone.utc): - result.usages.append( - (int(current.timestamp()), usages.get(current.timestamp()) or 0) - ) + usage = usages.get(current.timestamp()) or 0 + result.usages.append((int(current.timestamp()), usage)) + result.total += usage current += timedelta(hours=1) return result @@ -363,24 +363,27 @@ def get_user_usages( start: datetime, end: datetime, ) -> UserUsageSeriesResponse: + + usages = defaultdict(dict) + cond = and_( NodeUserUsage.user_id == db_user.id, NodeUserUsage.created_at >= start, NodeUserUsage.created_at <= end, ) - usages = defaultdict(dict) - for v in db.query(NodeUserUsage).filter(cond): - usages[v.node_id][ - v.created_at.replace(tzinfo=timezone.utc).timestamp() - ] = v.used_traffic + timestamp = v.created_at.replace(tzinfo=timezone.utc).timestamp() + usages[v.node_id][timestamp] = v.used_traffic node_ids = list(usages.keys()) nodes = db.query(Node).where(Node.id.in_(node_ids)) node_id_names = {node.id: node.name for node in nodes} - result = UserUsageSeriesResponse(username=db_user.username, node_usages=[]) + result = UserUsageSeriesResponse( + username=db_user.username, node_usages=[], total=0 + ) + for node_id, rows in usages.items(): node_usages = UserNodeUsageSeries( node_id=node_id, node_name=node_id_names[node_id], usages=[] @@ -390,11 +393,12 @@ def get_user_usages( ) while current <= end: - node_usages.usages.append( - (int(current.timestamp()), rows.get(current.timestamp()) or 0) - ) + usage = rows.get(current.timestamp()) or 0 + node_usages.usages.append((int(current.timestamp()), usage)) current += timedelta(hours=1) + result.total += usage result.node_usages.append(node_usages) + return result diff --git a/app/models/system.py b/app/models/system.py index e137bc1..be885cf 100644 --- a/app/models/system.py +++ b/app/models/system.py @@ -41,3 +41,4 @@ class NodesStats(BaseModel): class TrafficUsageSeries(BaseModel): usages: list[tuple[int, int]] + total: int diff --git a/app/models/user.py b/app/models/user.py index 7f48f2c..88c4397 100644 --- a/app/models/user.py +++ b/app/models/user.py @@ -155,3 +155,4 @@ class UserNodeUsageSeries(BaseModel): class UserUsageSeriesResponse(BaseModel): username: str node_usages: list[UserNodeUsageSeries] + total: int diff --git a/dashboard/src/common/stats-charts/components/select-date-view.tsx b/dashboard/src/common/stats-charts/components/select-date-view.tsx index 84407a5..6339283 100644 --- a/dashboard/src/common/stats-charts/components/select-date-view.tsx +++ b/dashboard/src/common/stats-charts/components/select-date-view.tsx @@ -1,40 +1,39 @@ +import type { FC, PropsWithChildren } from 'react'; import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, + RadioGroup, + RadioGroupItem, + Label } from "@marzneshin/components"; -import { useTranslation } from 'react-i18next'; + +const SelectDateViewItem: FC = ({ interval, children }) => ( +
+ + +
+) export const SelectDateView = ( { timeRange, setTimeRange }: { timeRange: string, setTimeRange: (s: string) => void } ) => { - const { t } = useTranslation(); - return ( - + + 24H + 7D + 30D + 3M + ) }; - diff --git a/dashboard/src/components/widgets/section-widget/index.tsx b/dashboard/src/components/widgets/section-widget/index.tsx index 6fd8092..a11cdf8 100644 --- a/dashboard/src/components/widgets/section-widget/index.tsx +++ b/dashboard/src/components/widgets/section-widget/index.tsx @@ -39,10 +39,10 @@ export const SectionWidget: FC = ({ } - + {content || children} - {footer && {footer} } + {footer && {footer} } ) } diff --git a/dashboard/src/features/total-traffic-widget/api/total-traffic.query.ts b/dashboard/src/features/total-traffic-widget/api/total-traffic.query.ts index f8fd0bd..0bb722d 100644 --- a/dashboard/src/features/total-traffic-widget/api/total-traffic.query.ts +++ b/dashboard/src/features/total-traffic-widget/api/total-traffic.query.ts @@ -5,6 +5,7 @@ export type UsageMetric = number[]; export interface TotalTrafficsResponse { usages: Array; + total: number; } export interface TotalTrafficsQueryOptions { @@ -15,6 +16,7 @@ export interface TotalTrafficsQueryOptions { export type TotalTrafficsQueryKey = [string, string, string, { start?: string, end?: string }] export const TotalTrafficsDefault = { + total: 0, usages: [] } diff --git a/dashboard/src/features/total-traffic-widget/index.tsx b/dashboard/src/features/total-traffic-widget/index.tsx index c9ed7d1..df4e297 100644 --- a/dashboard/src/features/total-traffic-widget/index.tsx +++ b/dashboard/src/features/total-traffic-widget/index.tsx @@ -33,6 +33,7 @@ export const TotalTrafficsWidget: FC = () => { const { start, end } = useFromNowInterval(timeRange as ChartDateInterval); const { data, isPending } = useTotalTrafficQuery({ start, end }) const chartData = useTransformData(data.usages); + const [totalAmount, totalMetric] = formatByte(data.total); return ( { title={
{t("page.home.total-traffics.title")} -
} description={t("page.home.total-traffics.desc")} + options={ +
+ + {totalAmount} {totalMetric} + + + Total + +
+ } + footer={ + + } > { diff --git a/dashboard/src/modules/users/components/widgets/user-nodes-usage-widget/index.tsx b/dashboard/src/modules/users/components/widgets/user-nodes-usage-widget/index.tsx index a6be3a4..71d3f7c 100644 --- a/dashboard/src/modules/users/components/widgets/user-nodes-usage-widget/index.tsx +++ b/dashboard/src/modules/users/components/widgets/user-nodes-usage-widget/index.tsx @@ -27,13 +27,27 @@ export const UserNodesUsageWidget: FC = ({ const { data, isPending } = useUserNodeUsagesQuery({ username: user.username, start, end }) const chartData = useTransformData(data); const config = useChartConfig(data); + const [totalAmount, totalMetric] = formatByte(data.total); return ( {t("page.users.settings.nodes-usage.title")} } + title={
{t("page.users.settings.nodes-usage.title")}
} description={t("page.users.settings.nodes-usage.desc")} + options={ +
+ + {totalAmount} {totalMetric} + + + Total + +
+ } + footer={ + + } >