feat(admin-remnawave): enrich panel stats UI and fix nodes-online display

- Show nodes as "online / total" (fixes "56 online" when only 5 nodes exist)
- Add recap, devices (+top users by device count), top-consumers, panel
  health and subscription-request widgets, with profile-specific Phosphor
  metric icons (CPU/RAM/uptime/devices/event-loop)
- Add the matching adminRemnawave API types and methods
This commit is contained in:
c0mrade
2026-05-31 18:51:12 +03:00
parent d0e0b6b7e3
commit b8be98939a
2 changed files with 368 additions and 45 deletions

View File

@@ -21,12 +21,57 @@ export interface SystemSummary {
total_users: number;
active_connections: number;
nodes_online: number;
total_nodes: number;
users_last_day: number;
users_last_week: number;
users_never_online: number;
total_user_traffic: number;
}
// Panel recap / devices / top consumers
export interface RecapResponse {
version: string | null;
init_date: string | null;
total: {
users: number;
nodes: number;
traffic_bytes: number;
nodes_ram_bytes: number;
nodes_cpu_cores: number;
distinct_countries: number;
};
this_month: { users: number; traffic_bytes: number };
}
export interface DevicesStatsResponse {
by_platform: { platform: string; count: number }[];
by_app: { app: string; count: number }[];
top_users: { username: string; devices_count: number }[];
total_unique_devices: number;
total_hwid_devices: number;
average_devices_per_user: number;
}
export interface TopConsumersResponse {
period_days: number;
users: { username: string; total_bytes: number }[];
}
export interface HealthResponse {
instances: number;
rss_bytes: number;
heap_used_bytes: number;
heap_total_bytes: number;
event_loop_delay_ms: number;
event_loop_p99_ms: number;
uptime_seconds: number;
instance_id: string | null;
}
export interface SubscriptionRequestStatsResponse {
by_app: { app: string; count: number }[];
}
export interface ServerInfo {
cpu_cores: number;
memory_total: number;
@@ -292,6 +337,34 @@ export const adminRemnawaveApi = {
return response.data;
},
// Panel recap / devices / top consumers
getRecap: async (): Promise<RecapResponse> => {
const response = await apiClient.get('/cabinet/admin/remnawave/recap');
return response.data;
},
getDevicesStats: async (): Promise<DevicesStatsResponse> => {
const response = await apiClient.get('/cabinet/admin/remnawave/devices-stats');
return response.data;
},
getTopConsumers: async (days = 7, limit = 10): Promise<TopConsumersResponse> => {
const response = await apiClient.get('/cabinet/admin/remnawave/top-consumers', {
params: { days, limit },
});
return response.data;
},
getHealth: async (): Promise<HealthResponse> => {
const response = await apiClient.get('/cabinet/admin/remnawave/health');
return response.data;
},
getSubscriptionRequests: async (): Promise<SubscriptionRequestStatsResponse> => {
const response = await apiClient.get('/cabinet/admin/remnawave/subscription-requests');
return response.data;
},
// Nodes
getNodes: async (): Promise<NodesListResponse> => {
const response = await apiClient.get('/cabinet/admin/remnawave/nodes');