Docker images / prepare-release (push) Successful in 10s
Docker images / backend-test (push) Successful in 2m23s
Docker images / frontend-image (push) Successful in 3m30s
Docker images / updater-image (push) Successful in 52s
Docker images / backend-image (push) Successful in 3m8s
Docker images / notify-webhook (push) Skipped
Docker images / publish-release (push) Successful in 14s
Сопоставить клиентов с ifIndex как на карте трафика, чтобы KPI пользователей не обнулялся. На экране — разрез остальных измерений и сводная матрица. Co-authored-by: Cursor <[email protected]>
100 lines
3.1 KiB
TypeScript
100 lines
3.1 KiB
TypeScript
import { z } from "zod"
|
|
|
|
export const STATISTICS_UNBOUND_USER_ID = "__unbound__"
|
|
|
|
export const statisticsPivotDimSchema = z.enum([
|
|
"country",
|
|
"service",
|
|
"asn",
|
|
"server",
|
|
"user",
|
|
"iface",
|
|
])
|
|
|
|
export const statisticsBreakdownRowSchema = z.object({
|
|
id: z.string(),
|
|
label: z.string(),
|
|
bytes: z.number().nonnegative(),
|
|
packets: z.number().nonnegative(),
|
|
bps: z.number().nonnegative(),
|
|
percent: z.number().nonnegative(),
|
|
})
|
|
|
|
export const statisticsSeriesPointSchema = z.object({
|
|
t: z.string(),
|
|
bytes: z.number().nonnegative(),
|
|
})
|
|
|
|
export const statisticsKpisSchema = z.object({
|
|
bytes: z.number().nonnegative(),
|
|
packets: z.number().nonnegative(),
|
|
avgBps: z.number().nonnegative(),
|
|
users: z.number().int().nonnegative(),
|
|
servers: z.number().int().nonnegative(),
|
|
ifaces: z.number().int().nonnegative(),
|
|
topCountry: z.string(),
|
|
topService: z.string(),
|
|
})
|
|
|
|
export const statisticsQuerySchema = z.object({
|
|
from: z.string().min(1),
|
|
to: z.string().min(1),
|
|
serverId: z.coerce.number().int().positive().optional(),
|
|
userId: z.string().min(1).optional(),
|
|
iface: z.string().min(1).optional(),
|
|
country: z.string().min(2).max(2).optional(),
|
|
service: z.string().min(1).optional(),
|
|
asn: z.coerce.number().int().optional(),
|
|
})
|
|
|
|
export const statisticsDtoSchema = z.object({
|
|
from: z.string(),
|
|
to: z.string(),
|
|
grain: z.enum(["hour", "day"]),
|
|
kpis: statisticsKpisSchema,
|
|
series: z.array(statisticsSeriesPointSchema),
|
|
users: z.array(statisticsBreakdownRowSchema),
|
|
servers: z.array(statisticsBreakdownRowSchema),
|
|
interfaces: z.array(statisticsBreakdownRowSchema),
|
|
countries: z.array(statisticsBreakdownRowSchema),
|
|
services: z.array(statisticsBreakdownRowSchema),
|
|
asns: z.array(statisticsBreakdownRowSchema),
|
|
})
|
|
|
|
export const statisticsPivotQuerySchema = statisticsQuerySchema.extend({
|
|
row: statisticsPivotDimSchema,
|
|
col: statisticsPivotDimSchema,
|
|
metric: z.enum(["bytes", "packets"]).default("bytes"),
|
|
})
|
|
|
|
export const statisticsPivotColumnSchema = z.object({
|
|
id: z.string(),
|
|
label: z.string(),
|
|
total: z.number().nonnegative(),
|
|
})
|
|
|
|
export const statisticsPivotRowSchema = z.object({
|
|
id: z.string(),
|
|
label: z.string(),
|
|
total: z.number().nonnegative(),
|
|
cells: z.record(z.string(), z.number().nonnegative()),
|
|
})
|
|
|
|
export const statisticsPivotDtoSchema = z.object({
|
|
rowDim: statisticsPivotDimSchema,
|
|
colDim: statisticsPivotDimSchema,
|
|
metric: z.enum(["bytes", "packets"]),
|
|
columns: z.array(statisticsPivotColumnSchema),
|
|
rows: z.array(statisticsPivotRowSchema),
|
|
otherBytes: z.number().nonnegative(),
|
|
})
|
|
|
|
export type StatisticsBreakdownRow = z.infer<typeof statisticsBreakdownRowSchema>
|
|
export type StatisticsSeriesPoint = z.infer<typeof statisticsSeriesPointSchema>
|
|
export type StatisticsKpis = z.infer<typeof statisticsKpisSchema>
|
|
export type StatisticsQuery = z.infer<typeof statisticsQuerySchema>
|
|
export type StatisticsDto = z.infer<typeof statisticsDtoSchema>
|
|
export type StatisticsPivotDim = z.infer<typeof statisticsPivotDimSchema>
|
|
export type StatisticsPivotQuery = z.infer<typeof statisticsPivotQuerySchema>
|
|
export type StatisticsPivotDto = z.infer<typeof statisticsPivotDtoSchema>
|