diff --git a/src/app/api/dashboard.api.ts b/src/app/api/dashboard.api.ts index 498536d9e33cd842d3aad26ef7219866c49f8727..c0378e578080391477224b2e328834d66ac890ee 100644 --- a/src/app/api/dashboard.api.ts +++ b/src/app/api/dashboard.api.ts @@ -17,7 +17,7 @@ export const DASHBOARD_API_URL = '/api/v1/dashboard/statistics'; export class DashboardApi { private readonly httpClient = inject(HttpClient); - fetch(): Observable<DashboardStatistics> { + fetchStatistics(): Observable<DashboardStatistics> { return this.httpClient .get<ApiResponse<DashboardStatisticsDto>>(DASHBOARD_API_URL) .pipe(map(dto => dtoToDashboardStatistics(dto.data))); diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.html b/src/app/components/dashboard-statistics/dashboard-statistics.component.html index c34d1b589061b0ba3f9a3b9b4a2577dddae117d4..5a6fc81b322e306b35bee3c59ff07e3431cf1bdb 100644 --- a/src/app/components/dashboard-statistics/dashboard-statistics.component.html +++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.html @@ -1,5 +1,6 @@ <div class="statistics"> - @if (isLoading()) { + @let statistics = dashboardStatistics | async; + @if (!statistics) { <div class="statistics__loader"> <div time class="statistics__total-time"> <ngx-skeleton-loader count="7" /> @@ -24,21 +25,47 @@ @else { <div class="statistics__content"> <div time class="statistics__total-time"> - <p>Total time {{ dashboardStatistic()?.total_time }} </p> + <p>Total time: {{ statistics.total_time | time }} </p> </div> <div eth class="statistics__eth"> <div class="statistics__eth-content"> -<!-- <p>ETH Price: {{ statistics.ethPrice }} USD</p>--> + <ng-container *ngIf="getProtocolETH() | async as protocol"> + {{ protocol.name }} + {{ protocol.total_packets }} + <ng-container *ngIf="getPacketsPerSecond(protocol.name) | async as packetsPerSecond"> + {{ packetsPerSecond }} + </ng-container> + {{protocol.total_bytes}} + <ng-container *ngIf="getBytesPerSecond(protocol.name) | async as bytesPerSecond"> + {{ bytesPerSecond }} + </ng-container> + </ng-container> </div> </div> <div protocols class="statistics__prot"> <div class="statistics__prot-content"> -<!-- <p>Number of active protocols: {{ statistics.protocols }}</p>--> + <div *ngFor="let protocol of getProtocolOthers() | async"> + {{ protocol.name }} + {{ protocol.total_packets }} + <ng-container *ngIf="getPacketsPerSecond(protocol.name) | async as packetsPerSecond"> + {{ packetsPerSecond }} + </ng-container> + {{protocol.total_bytes}} + <ng-container *ngIf="getBytesPerSecond(protocol.name) | async as bytesPerSecond"> + {{ bytesPerSecond }} + </ng-container> + </div> </div> </div> <div ir class="statistics__ir"> <div class="statistics__ir-content"> -<!-- <p>Other data: {{ statistics.otherData }}</p>--> + <ng-container *ngIf="getIR() | async as information_rate"> + Information Rate + {{information_rate.min}} + {{information_rate.max}} + {{information_rate.current}} + MB/s + </ng-container> </div> </div> </div> diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.scss b/src/app/components/dashboard-statistics/dashboard-statistics.component.scss index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..a52ca0a3e8a6e244e44aefba58e5eaad8a816f82 100644 --- a/src/app/components/dashboard-statistics/dashboard-statistics.component.scss +++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.scss @@ -0,0 +1,34 @@ +@use '../../../vars'; +@use 'sass:map'; + +:host { + height: 100%; + width: 100%; + + .statistics { + &content { + display: flex; + gap: map.get(vars.$spacing, 'xs'); + } + + &__eth { + display: flex; + justify-content: space-between; + + &-title { + color: map.get(vars.$grey, 100); + font-size: map.get(vars.$text, 'lg'); + } + + &-content { + width: calc(100% - 200px); + } + } + } + + // Configuration select + ::ng-deep .mdc-text-field--filled:not(.mdc-text-field--disabled) { + background-color: map.get(vars.$grey, 10); + border-radius: map.get(vars.$radius, 'xs'); + } +} diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts index 56a83da82ecc15ff75a340fb8d1d88e6ef272312..34ccbc3d3d961728293dbcd3109655247474193b 100644 --- a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts +++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts @@ -6,15 +6,16 @@ import { signal, } from '@angular/core'; import { NgxSkeletonLoaderComponent } from 'ngx-skeleton-loader'; -import { NgTemplateOutlet } from '@angular/common'; +import { AsyncPipe, NgForOf, NgIf, NgTemplateOutlet } from '@angular/common'; import { DashboardApi } from '../../api/dashboard.api'; -import { map, Observable, tap } from 'rxjs'; +import { interval, map, Observable, shareReplay, switchMap, tap } from 'rxjs'; import { DashboardStatistics } from '../../models/dashboard-statistics'; import { PillComponent } from '../pill/pill.component'; +import { TimePipe } from '../../pipes/time.pipe'; @Component({ selector: 'app-dashboard-statistics', - imports: [NgxSkeletonLoaderComponent, NgTemplateOutlet, PillComponent], + imports: [NgxSkeletonLoaderComponent, AsyncPipe, TimePipe, NgIf, NgForOf], templateUrl: './dashboard-statistics.component.html', styleUrl: './dashboard-statistics.component.scss', }) @@ -22,30 +23,90 @@ export class DashboardStatisticsComponent { dashboardApi = inject(DashboardApi); isLoading = signal<boolean>(false); - dashboardStatistic = signal<DashboardStatistics | undefined>(undefined); + + 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.fetch().subscribe(data => { + this.dashboardApi.fetchStatistics().subscribe(data => { this.isLoading.set(false); - this.dashboardStatistic.set(data); + this.dashboardApi.fetchStatistics().subscribe(() => { + this.isLoading.set(false); + }); }); }); } - private fetchConfigurationOptions(): Observable<DashboardStatistics> { - this.isLoading.set(true); - return this.dashboardApi.fetch().pipe( + getPacketsPerSecond(protocolName: string): Observable<number> { + return this.dashboardStatistics.pipe( + map(dashboardStatistics => { + const protocol = dashboardStatistics.protocols.find( + protocol => protocol.name === protocolName + ); + + if (!protocol) { + 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; + } + + 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' + ); + }) + ); + } + + getProtocolOthers() { + return this.dashboardStatistics.pipe( + map(dashboardStatistics => { + return dashboardStatistics.protocols.filter( + protocol => protocol.name !== 'ETH' + ); + }) + ); + } + + getIR() { + return this.dashboardStatistics.pipe( map(dashboardStatistics => { - return { - total_time: dashboardStatistics.total_time, - protocols: dashboardStatistics.protocols, - information_rate: dashboardStatistics.information_rate, - }; - }), - tap(() => this.isLoading.set(false)) + return dashboardStatistics.information_rate; + }) ); } } diff --git a/src/app/interceptor/mocks/dashboard-statistics.json b/src/app/interceptor/mocks/dashboard-statistics.json index 65334a5ce19190e5dba7438db760a338983c3cfa..f12cab4318e12b34f0f34613b8016c4530f41854 100644 --- a/src/app/interceptor/mocks/dashboard-statistics.json +++ b/src/app/interceptor/mocks/dashboard-statistics.json @@ -1,7 +1,7 @@ { "data": { "id": "statistics", - "total-time": "1740770761000", + "total-time": 160401, "protocols": [ { "name": "ETH", diff --git a/src/app/models/dashboard-statistics.ts b/src/app/models/dashboard-statistics.ts index 8d07d365cf01e7fab4f978caef9544b1a2385e69..2214b870259ea6266559824a37fc0d71d4ace82b 100644 --- a/src/app/models/dashboard-statistics.ts +++ b/src/app/models/dashboard-statistics.ts @@ -13,7 +13,7 @@ export interface InformationRate { } export interface DashboardStatisticsDto { - total_time: string; + total_time: number; protocols: ProtocolStatistics[]; information_rate: InformationRate; } diff --git a/src/app/pipes/time.pipe.ts b/src/app/pipes/time.pipe.ts new file mode 100644 index 0000000000000000000000000000000000000000..3213400b643d473c4d78b29282cb866ca4ffd76a --- /dev/null +++ b/src/app/pipes/time.pipe.ts @@ -0,0 +1,15 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'time', +}) +export class TimePipe implements PipeTransform { + transform(date: Date): string { + let totalSeconds = Math.floor(date.getTime() / 1000); + const hours = Math.floor(totalSeconds / 3600); + totalSeconds %= 3600; + const minutes = Math.floor(totalSeconds / 60); + const seconds = totalSeconds % 60; + return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; + } +}