diff --git a/src/app/api/dashboard.api.ts b/src/app/api/dashboard.api.ts index 435ea300e31ff2c68245248832340890c853f602..e81df041320410aa5f893f6c1f7044fbc3286c44 100644 --- a/src/app/api/dashboard.api.ts +++ b/src/app/api/dashboard.api.ts @@ -8,7 +8,7 @@ import { } from '../models/dashboard-statistics'; import { ApiResponse } from '../models/api-response'; -export const DASHBOARD_API_URL = '/api/v1/dashboard/statistics'; +export const DASHBOARD_API_URL = '/api/statistics'; @Injectable({ providedIn: 'root', diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.html b/src/app/components/dashboard-statistics/dashboard-statistics.component.html index 75ab2a07cf45d59e24cb8b83550f166072c41c1f..bd5d0df4699d5f06ed48f2a9e093d3c5bfcfa6ae 100644 --- a/src/app/components/dashboard-statistics/dashboard-statistics.component.html +++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.html @@ -2,18 +2,9 @@ @let statistics = dashboardStatistics | async; @if (!statistics) { <div class="statistics__loader"> - <div class="statistics__loader-time"> + @for (_ of [].constructor(4); track $index) { <ngx-skeleton-loader count="7" /> - </div> - <div class="statistics__loader-eth"> - <ngx-skeleton-loader count="7" /> - </div> - <div class="statistics__loader-protocol"> - <ngx-skeleton-loader count="7" /> - </div> - <div class="statistics__loader-ir"> - <ngx-skeleton-loader count="7" /> - </div> + } </div> } @else { @@ -32,34 +23,35 @@ </tr> </thead> <tbody> - <tr *ngIf="getProtocolETH() | async as protocol" class="statistics__table__header-eth"> - <td>{{ protocol.name }}</td> - <td>{{ protocol.total_packets }}</td> + @let protocolEth = getETHStatistics(statistics.protocols); + <tr class="statistics__table__header-eth"> + <td>{{ protocolEth.name }}</td> + <td>{{ protocolEth.total_packets | decimal }}</td> <td> - {{ (getPacketsPerSecond(protocol.name) | async) === 0 ? 0 : (getPacketsPerSecond(protocol.name) | async) }} + {{ getPerSecond(protocolEth.total_packets, statistics.total_time) | decimal }} </td> - <td>{{ protocol.total_bytes }}</td> + <td>{{ protocolEth.total_bytes | decimal }}</td> <td> - {{ (getBytesPerSecond(protocol.name) | async) === 0 ? 0 : (getBytesPerSecond(protocol.name) | async) }} + {{ getPerSecond(protocolEth.total_bytes, statistics.total_time) | decimal }} </td> </tr> </tbody> </table> <table class="statistics__table__protocols"> <tbody> - <ng-container *ngFor="let protocol of getProtocolOthers() | async"> + @for (protocol of getProtocols(statistics.protocols); track protocol.name) { <tr> <td>{{ protocol.name }}</td> - <td>{{ protocol.total_packets }}</td> + <td>{{ protocol.total_packets | decimal }}</td> <td> - {{ (getPacketsPerSecond(protocol.name) | async) === 0 ? 0 : (getPacketsPerSecond(protocol.name) | async) }} + {{ getPerSecond(protocol.total_packets, statistics.total_time) | decimal }} </td> - <td>{{ protocol.total_bytes }}</td> + <td>{{ protocol.total_bytes | decimal }}</td> <td> - {{ (getBytesPerSecond(protocol.name) | async) === 0 ? 0 : (getBytesPerSecond(protocol.name) | async) }} + {{ getPerSecond(protocol.total_bytes, statistics.total_time) | decimal }} </td> </tr> - </ng-container> + } </tbody> </table> <table class="statistics__table__ir"> @@ -72,11 +64,11 @@ </tr> </thead> <tbody> - <tr *ngIf="getIR() | async as information_rate" class="statistics__table_ir-content"> + <tr class="statistics__table_ir-content"> <td>Information Rate</td> - <td>{{ information_rate.min }}</td> - <td>{{ information_rate.max }}</td> - <td>{{ information_rate.current }}</td> + <td>{{ statistics.information_rate.min | decimal }}</td> + <td>{{ statistics.information_rate.max | decimal }}</td> + <td>{{ statistics.information_rate.current | decimal }}</td> </tr> </tbody> </table> diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.scss b/src/app/components/dashboard-statistics/dashboard-statistics.component.scss index d47873acccb583766cc8f47ff775c1de8229f330..e11b5db12cf23fcea68df59b4eba90d9989305d9 100644 --- a/src/app/components/dashboard-statistics/dashboard-statistics.component.scss +++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.scss @@ -2,14 +2,10 @@ @use 'sass:map'; :host { - height: 100%; - width: 100%; - ngx-skeleton-loader { display: flex; flex-direction: row; gap: map.get(vars.$spacing, 'md'); - ::ng-deep * { height: 50px; } @@ -19,7 +15,8 @@ display: flex; flex-direction: column; justify-content: space-between; - font-weight: bold; + font-weight: 500; + font-size: map.get(vars.$text, 'lg'); &__table { &__time { diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts index 99bf83c6ccbe4227c89ab1b3fc1cff5c4c575904..d9040eefc2f0c494965136360d354b45bc934222 100644 --- a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts +++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts @@ -6,115 +6,41 @@ import { signal, } from '@angular/core'; import { NgxSkeletonLoaderComponent } from 'ngx-skeleton-loader'; -import { AsyncPipe, NgForOf, NgIf, NgTemplateOutlet } from '@angular/common'; +import { AsyncPipe, NgTemplateOutlet } from '@angular/common'; import { DashboardApi } from '../../api/dashboard.api'; import { interval, map, Observable, shareReplay, switchMap, tap } from 'rxjs'; -import { DashboardStatistics } from '../../models/dashboard-statistics'; +import { + DashboardStatistics, + ProtocolStatistics, +} from '../../models/dashboard-statistics'; import { PillComponent } from '../pill/pill.component'; import { TimePipe } from '../../pipes/time.pipe'; +import { DecimalPipe } from '../../pipes/decimal.pipe'; @Component({ selector: 'app-dashboard-statistics', - imports: [NgxSkeletonLoaderComponent, AsyncPipe, TimePipe, NgIf, NgForOf], + imports: [NgxSkeletonLoaderComponent, AsyncPipe, TimePipe, DecimalPipe], templateUrl: './dashboard-statistics.component.html', styleUrl: './dashboard-statistics.component.scss', }) export class DashboardStatisticsComponent { dashboardApi = inject(DashboardApi); - isLoading = signal<boolean>(false); - dashboardStatistics = interval(1000).pipe( switchMap(() => this.dashboardApi.fetchStatistics()), - map(dashboardStatistics => ({ - ...dashboardStatistics, - total_time: new Date(dashboardStatistics.total_time * 1000), - })), shareReplay(1) ); - constructor() { - effect(() => { - this.isLoading.set(true); - - this.dashboardApi.fetchStatistics().subscribe(data => { - this.isLoading.set(false); - this.dashboardApi.fetchStatistics().subscribe(() => { - this.isLoading.set(false); - }); - }); - }); - } - - getPacketsPerSecond(protocolName: string): Observable<number> { - return this.dashboardStatistics.pipe( - map(dashboardStatistics => { - const protocol = dashboardStatistics.protocols.find( - protocol => protocol.name === protocolName - ); - - if (!protocol) { - return 0; - } - - if (protocol.total_packets == 0) { - return 0; - } - - const totalPackets = protocol.total_packets; - const totalSeconds = dashboardStatistics.total_time.getTime() / 1000; - return totalPackets / totalSeconds; - }) - ); - } - - getBytesPerSecond(protocolName: string): Observable<number> { - return this.dashboardStatistics.pipe( - map(dashboardStatistics => { - const protocol = dashboardStatistics.protocols.find( - protocol => protocol.name === protocolName - ); - - if (!protocol) { - return 0; - } - - if (protocol.total_bytes == 0) { - return 0; - } - - const totalBytes = protocol.total_bytes; - const totalSeconds = dashboardStatistics.total_time.getTime() / 1000; - return totalBytes / totalSeconds; - }) - ); - } - - getProtocolETH() { - return this.dashboardStatistics.pipe( - map(dashboardStatistics => { - return dashboardStatistics.protocols.find( - protocol => protocol.name === 'ETH' - ); - }) - ); + getPerSecond(value: number, time: Date): number { + const totalSeconds = time.getTime() / 1000; + return value / totalSeconds; } - getProtocolOthers() { - return this.dashboardStatistics.pipe( - map(dashboardStatistics => { - return dashboardStatistics.protocols.filter( - protocol => protocol.name !== 'ETH' - ); - }) - ); + getETHStatistics(protocols: ProtocolStatistics[]): ProtocolStatistics { + return protocols.find(protocol => protocol.name === 'ETH')!; } - getIR() { - return this.dashboardStatistics.pipe( - map(dashboardStatistics => { - return dashboardStatistics.information_rate; - }) - ); + getProtocols(protocols: ProtocolStatistics[]): ProtocolStatistics[] { + return protocols.filter(protocol => protocol.name !== 'ETH'); } } diff --git a/src/app/components/dashboard/dashboard.component.scss b/src/app/components/dashboard/dashboard.component.scss index 1938814a9ffa012336e43c56745f11cf1ea4b54c..d11c2b9c25b202716ae17166d1acf99a1ccdeb1e 100644 --- a/src/app/components/dashboard/dashboard.component.scss +++ b/src/app/components/dashboard/dashboard.component.scss @@ -29,6 +29,10 @@ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); border-bottom: 1px solid map.get(vars.$grey, 30); + &-title { + font-size: map.get(vars.$text, 'lg'); + } + &:last-child { border-bottom: none; } diff --git a/src/app/interceptor/interceptor.ts b/src/app/interceptor/interceptor.ts index 1b55567610df484894bfb9a4cf91c7c5208f700b..8e088acb883c638b72a88c594d0f501efd77132d 100644 --- a/src/app/interceptor/interceptor.ts +++ b/src/app/interceptor/interceptor.ts @@ -17,7 +17,7 @@ export const urls = [ json: configurationList, }, { - url: '/api/v1/dashboard/statistics', + url: '/api/statistics', json: dashboardStats, }, ]; diff --git a/src/app/models/dashboard-statistics.ts b/src/app/models/dashboard-statistics.ts index 2214b870259ea6266559824a37fc0d71d4ace82b..3a8befc246d094db7c2a652aa599b2a4e49273cd 100644 --- a/src/app/models/dashboard-statistics.ts +++ b/src/app/models/dashboard-statistics.ts @@ -1,11 +1,15 @@ -export type DashboardStatistics = DashboardStatisticsDto; - export interface ProtocolStatistics { name: string; total_packets: number; total_bytes: number; } +export interface ProtocolStatisticsDto { + name: string; + 'total-packets': number; + 'total-bytes': number; +} + export interface InformationRate { min: number; max: number; @@ -13,15 +17,23 @@ export interface InformationRate { } export interface DashboardStatisticsDto { - total_time: number; + 'total-time': number; + protocols: ProtocolStatisticsDto[]; + 'information-rate': InformationRate; +} + +export interface DashboardStatistics { + total_time: Date; protocols: ProtocolStatistics[]; information_rate: InformationRate; } -export function dtoToDashboardStatistics(dto: any): DashboardStatistics { +export function dtoToDashboardStatistics( + dto: DashboardStatisticsDto +): DashboardStatistics { return { - total_time: dto['total-time'], - protocols: dto.protocols.map((protocol: any) => ({ + total_time: new Date(dto['total-time'] * 1000), + protocols: dto.protocols.map((protocol: ProtocolStatisticsDto) => ({ name: protocol.name, total_packets: protocol['total-packets'], total_bytes: protocol['total-bytes'], @@ -33,21 +45,3 @@ export function dtoToDashboardStatistics(dto: any): DashboardStatistics { }, }; } - -export function dashboardStatisticsToDto( - dashboardStatistics: DashboardStatistics -): any { - return { - 'total-time': dashboardStatistics.total_time, - protocols: dashboardStatistics.protocols.map(protocol => ({ - name: protocol.name, - 'total-packets': protocol.total_packets, - 'total-bytes': protocol.total_bytes, - })), - 'information-rate': { - min: dashboardStatistics.information_rate.min, - max: dashboardStatistics.information_rate.max, - current: dashboardStatistics.information_rate.current, - }, - }; -} diff --git a/src/app/pipes/decimal.pipe.ts b/src/app/pipes/decimal.pipe.ts new file mode 100644 index 0000000000000000000000000000000000000000..1d9a6e1a701c08b48bb6e60c15e014a713d7c9cd --- /dev/null +++ b/src/app/pipes/decimal.pipe.ts @@ -0,0 +1,16 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'decimal', +}) +export class DecimalPipe implements PipeTransform { + transform(value: number | string, decimalPlaces: number = 2): string { + if (value == null || isNaN(Number(value))) { + return ''; + } + + let num = Number(value).toFixed(decimalPlaces); + + return num.replace(/\B(?=(\d{3})+(?!\d))/g, ' '); + } +}