From a4b0e1cc4582d0710e237198d74511d9716ef0d7 Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Fri, 28 Feb 2025 20:11:19 +0100
Subject: [PATCH 1/7] feat: add statistisc mock

---
 .../dashboard-statistics.component.html       |  4 +++
 src/app/interceptor/interceptor.ts            |  5 +++
 .../mocks/dashboard-statistics.json           | 33 +++++++++++++++++++
 3 files changed, 42 insertions(+)
 create mode 100644 src/app/interceptor/mocks/dashboard-statistics.json

diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.html b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
index 12e92e1..2eaf5d2 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.html
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
@@ -1 +1,5 @@
+
+
+
+
 <ngx-skeleton-loader count="10" />
diff --git a/src/app/interceptor/interceptor.ts b/src/app/interceptor/interceptor.ts
index 2dfdedf..1b55567 100644
--- a/src/app/interceptor/interceptor.ts
+++ b/src/app/interceptor/interceptor.ts
@@ -1,6 +1,7 @@
 import * as configurationList from './mocks/configurations.json';
 import * as configuration1 from './mocks/configuration-1.json';
 import * as configuration2 from './mocks/configuration-2.json';
+import * as dashboardStats from './mocks/dashboard-statistics.json';
 
 export const urls = [
   {
@@ -15,4 +16,8 @@ export const urls = [
     url: '/api/v1/configuration',
     json: configurationList,
   },
+  {
+    url: '/api/v1/dashboard/statistics',
+    json: dashboardStats,
+  },
 ];
diff --git a/src/app/interceptor/mocks/dashboard-statistics.json b/src/app/interceptor/mocks/dashboard-statistics.json
new file mode 100644
index 0000000..073d63b
--- /dev/null
+++ b/src/app/interceptor/mocks/dashboard-statistics.json
@@ -0,0 +1,33 @@
+{
+  "data": {
+    "id": "statistics",
+    "total_time": "01:05:30",
+    "protocols": [
+        {
+          "name": "ETH",
+          "total-packets": 1234567,
+          "total-bytes": 123456789
+        },
+        {
+          "name": "TCP",
+          "total-packets": 321312,
+          "total-bytes": 32143245
+        },
+        {
+          "name": "IPv4",
+          "total-packets": 3333,
+          "total-bytes": 777
+        },
+        {
+          "name": "IPv6",
+          "total-packets": 0,
+          "total-bytes": 0
+        }
+      ],
+    "information-rate": {
+        "min": 1.23,
+        "max": 123456,
+        "current": 123.45
+      }
+  }
+}
-- 
GitLab


From ca05fa446a966c8b02a0929e37620cbf0b8bca7c Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Sat, 1 Mar 2025 18:00:53 +0100
Subject: [PATCH 2/7] Implement dashboard statistics API part, add d.
 statistics model and make initial html

---
 src/app/api/dashboard.api.ts                  | 23 ++++++--
 .../dashboard-statistics.component.html       | 47 ++++++++++++++--
 .../dashboard-statistics.component.ts         | 47 ++++++++++++++--
 .../mocks/dashboard-statistics.json           |  2 +-
 src/app/models/dashboard-statistics.ts        | 53 +++++++++++++++++++
 5 files changed, 160 insertions(+), 12 deletions(-)
 create mode 100644 src/app/models/dashboard-statistics.ts

diff --git a/src/app/api/dashboard.api.ts b/src/app/api/dashboard.api.ts
index 3f08285..498536d 100644
--- a/src/app/api/dashboard.api.ts
+++ b/src/app/api/dashboard.api.ts
@@ -1,8 +1,25 @@
-import { Injectable } from '@angular/core';
+import { inject, Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { map, Observable, tap } from 'rxjs';
+import {
+  DashboardStatistics,
+  DashboardStatisticsDto,
+  dashboardStatisticsToDto,
+  dtoToDashboardStatistics,
+} from '../models/dashboard-statistics';
+import { ApiResponse } from '../models/api-response';
 
-export const DASHBOARD_API_URL = '/api/v1/dashboard';
+export const DASHBOARD_API_URL = '/api/v1/dashboard/statistics';
 
 @Injectable({
   providedIn: 'root',
 })
-export class DashboardApi {}
+export class DashboardApi {
+  private readonly httpClient = inject(HttpClient);
+
+  fetch(): 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 2eaf5d2..7da5152 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.html
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
@@ -1,5 +1,42 @@
-
-
-
-
-<ngx-skeleton-loader count="10" />
+<div class="statistics">
+  @if (isLoading()) {
+    <div class="statistics__loader">
+      <div eth class="statistics__eth">
+        <div class="statistics__eth-content">
+          <ngx-skeleton-loader count="7" />
+        </div>
+      </div>
+      <div protocols class="statistics__prot">
+        <div class="statistics__prot-content">
+          <ngx-skeleton-loader count="7" />
+        </div>
+      </div>
+      <div ir>
+        <ngx-skeleton-loader count="10" />
+      </div>
+    </div>
+  }
+  @else {
+    <div class="statistics__content">
+      <p>Total time {{ dashboardStatistic()?.total_time }} </p>
+<!--      @for (mac of configuration()?.mac_source; track $index) {-->
+<!--        <app-pill>{{ mac }}</app-pill>-->
+<!--      } @empty {-->
+<!--        <app-pill>All addresses</app-pill>-->
+<!--      }-->
+      <div eth class="statistics__eth">
+        <div class="statistics__eth-content">
+<!--          <p>ETH Price: {{ statistics.ethPrice }} USD</p>-->
+        </div>
+      </div>
+      <div protocols class="statistics__prot">
+        <div class="statistics__prot-content">
+<!--          <p>Number of active protocols: {{ statistics.protocols }}</p>-->
+        </div>
+      </div>
+      <div ir>
+<!--        <p>Other data: {{ statistics.otherData }}</p>-->
+      </div>
+    </div>
+  }
+</div>
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
index 4f88f14..56a83da 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
@@ -1,10 +1,51 @@
-import { Component } from '@angular/core';
+import {
+  afterNextRender,
+  Component,
+  effect,
+  inject,
+  signal,
+} from '@angular/core';
 import { NgxSkeletonLoaderComponent } from 'ngx-skeleton-loader';
+import { NgTemplateOutlet } from '@angular/common';
+import { DashboardApi } from '../../api/dashboard.api';
+import { map, Observable, tap } from 'rxjs';
+import { DashboardStatistics } from '../../models/dashboard-statistics';
+import { PillComponent } from '../pill/pill.component';
 
 @Component({
   selector: 'app-dashboard-statistics',
-  imports: [NgxSkeletonLoaderComponent],
+  imports: [NgxSkeletonLoaderComponent, NgTemplateOutlet, PillComponent],
   templateUrl: './dashboard-statistics.component.html',
   styleUrl: './dashboard-statistics.component.scss',
 })
-export class DashboardStatisticsComponent {}
+export class DashboardStatisticsComponent {
+  dashboardApi = inject(DashboardApi);
+
+  isLoading = signal<boolean>(false);
+  dashboardStatistic = signal<DashboardStatistics | undefined>(undefined);
+
+  constructor() {
+    effect(() => {
+      this.isLoading.set(true);
+
+      this.dashboardApi.fetch().subscribe(data => {
+        this.isLoading.set(false);
+        this.dashboardStatistic.set(data);
+      });
+    });
+  }
+
+  private fetchConfigurationOptions(): Observable<DashboardStatistics> {
+    this.isLoading.set(true);
+    return this.dashboardApi.fetch().pipe(
+      map(dashboardStatistics => {
+        return {
+          total_time: dashboardStatistics.total_time,
+          protocols: dashboardStatistics.protocols,
+          information_rate: dashboardStatistics.information_rate,
+        };
+      }),
+      tap(() => this.isLoading.set(false))
+    );
+  }
+}
diff --git a/src/app/interceptor/mocks/dashboard-statistics.json b/src/app/interceptor/mocks/dashboard-statistics.json
index 073d63b..65334a5 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": "01:05:30",
+    "total-time": "1740770761000",
     "protocols": [
         {
           "name": "ETH",
diff --git a/src/app/models/dashboard-statistics.ts b/src/app/models/dashboard-statistics.ts
new file mode 100644
index 0000000..8d07d36
--- /dev/null
+++ b/src/app/models/dashboard-statistics.ts
@@ -0,0 +1,53 @@
+export type DashboardStatistics = DashboardStatisticsDto;
+
+export interface ProtocolStatistics {
+  name: string;
+  total_packets: number;
+  total_bytes: number;
+}
+
+export interface InformationRate {
+  min: number;
+  max: number;
+  current: number;
+}
+
+export interface DashboardStatisticsDto {
+  total_time: string;
+  protocols: ProtocolStatistics[];
+  information_rate: InformationRate;
+}
+
+export function dtoToDashboardStatistics(dto: any): DashboardStatistics {
+  return {
+    total_time: dto['total-time'],
+    protocols: dto.protocols.map((protocol: any) => ({
+      name: protocol.name,
+      total_packets: protocol['total-packets'],
+      total_bytes: protocol['total-bytes'],
+    })),
+    information_rate: {
+      min: dto['information-rate'].min,
+      max: dto['information-rate'].max,
+      current: dto['information-rate'].current,
+    },
+  };
+}
+
+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,
+    },
+  };
+}
-- 
GitLab


From 490122ecc212a7c19220821b54fff1316f395092 Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Sat, 1 Mar 2025 18:08:06 +0100
Subject: [PATCH 3/7] mod: change dashboard statistics html

---
 .../dashboard-statistics.component.html       | 22 +++++++++++--------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.html b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
index 7da5152..c34d1b5 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.html
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
@@ -1,6 +1,9 @@
 <div class="statistics">
   @if (isLoading()) {
     <div class="statistics__loader">
+      <div time class="statistics__total-time">
+          <ngx-skeleton-loader count="7" />
+      </div>
       <div eth class="statistics__eth">
         <div class="statistics__eth-content">
           <ngx-skeleton-loader count="7" />
@@ -11,19 +14,18 @@
           <ngx-skeleton-loader count="7" />
         </div>
       </div>
-      <div ir>
-        <ngx-skeleton-loader count="10" />
+      <div ir class="statistics__ir">
+        <div class="statistics__ir-content">
+          <ngx-skeleton-loader count="7" />
+        </div>
       </div>
     </div>
   }
   @else {
     <div class="statistics__content">
-      <p>Total time {{ dashboardStatistic()?.total_time }} </p>
-<!--      @for (mac of configuration()?.mac_source; track $index) {-->
-<!--        <app-pill>{{ mac }}</app-pill>-->
-<!--      } @empty {-->
-<!--        <app-pill>All addresses</app-pill>-->
-<!--      }-->
+      <div time class="statistics__total-time">
+        <p>Total time {{ dashboardStatistic()?.total_time }} </p>
+      </div>
       <div eth class="statistics__eth">
         <div class="statistics__eth-content">
 <!--          <p>ETH Price: {{ statistics.ethPrice }} USD</p>-->
@@ -34,8 +36,10 @@
 <!--          <p>Number of active protocols: {{ statistics.protocols }}</p>-->
         </div>
       </div>
-      <div ir>
+      <div ir class="statistics__ir">
+        <div class="statistics__ir-content">
 <!--        <p>Other data: {{ statistics.otherData }}</p>-->
+        </div>
       </div>
     </div>
   }
-- 
GitLab


From 7aeaf5510333f3b6640ef0e9b09324209e29dfc3 Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Mon, 3 Mar 2025 22:50:15 +0100
Subject: [PATCH 4/7] feat: add all API info on html, add time pipe, fix
 total_time type in mock

---
 src/app/api/dashboard.api.ts                  |  2 +-
 .../dashboard-statistics.component.html       | 37 +++++++-
 .../dashboard-statistics.component.scss       | 34 +++++++
 .../dashboard-statistics.component.ts         | 93 +++++++++++++++----
 .../mocks/dashboard-statistics.json           |  2 +-
 src/app/models/dashboard-statistics.ts        |  2 +-
 src/app/pipes/time.pipe.ts                    | 15 +++
 7 files changed, 161 insertions(+), 24 deletions(-)
 create mode 100644 src/app/pipes/time.pipe.ts

diff --git a/src/app/api/dashboard.api.ts b/src/app/api/dashboard.api.ts
index 498536d..c0378e5 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 c34d1b5..5a6fc81 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 e69de29..a52ca0a 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 56a83da..34ccbc3 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 65334a5..f12cab4 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 8d07d36..2214b87 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 0000000..3213400
--- /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')}`;
+  }
+}
-- 
GitLab


From 2879ee49a27378c263c426fceb51b5dde719aaa2 Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Tue, 4 Mar 2025 14:37:57 +0100
Subject: [PATCH 5/7] finish emplement html and add styling

---
 .../dashboard-statistics.component.html       | 124 ++++++++++--------
 .../dashboard-statistics.component.scss       |  96 +++++++++++---
 .../dashboard-statistics.component.ts         |   8 ++
 .../mocks/dashboard-statistics.json           |   6 +-
 4 files changed, 157 insertions(+), 77 deletions(-)

diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.html b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
index 5a6fc81..75ab2a0 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.html
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
@@ -2,72 +2,84 @@
   @let statistics = dashboardStatistics | async;
   @if (!statistics) {
     <div class="statistics__loader">
-      <div time class="statistics__total-time">
-          <ngx-skeleton-loader count="7" />
+      <div class="statistics__loader-time">
+        <ngx-skeleton-loader count="7" />
       </div>
-      <div eth class="statistics__eth">
-        <div class="statistics__eth-content">
-          <ngx-skeleton-loader count="7" />
-        </div>
+      <div class="statistics__loader-eth">
+        <ngx-skeleton-loader count="7" />
       </div>
-      <div protocols class="statistics__prot">
-        <div class="statistics__prot-content">
-          <ngx-skeleton-loader count="7" />
-        </div>
+      <div class="statistics__loader-protocol">
+        <ngx-skeleton-loader count="7" />
       </div>
-      <div ir class="statistics__ir">
-        <div class="statistics__ir-content">
-          <ngx-skeleton-loader count="7" />
-        </div>
+      <div class="statistics__loader-ir">
+        <ngx-skeleton-loader count="7" />
       </div>
     </div>
   }
   @else {
-    <div class="statistics__content">
-      <div time class="statistics__total-time">
+    <div class="statistics__table">
+      <div class="statistics__table__time">
         <p>Total time: {{ statistics.total_time | time }} </p>
       </div>
-      <div eth class="statistics__eth">
-        <div class="statistics__eth-content">
-          <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>
+      <table class="statistics__table__header">
+        <thead class="statistics__table__header-title">
+          <tr>
+            <th></th>
+            <th>Total packets</th>
+            <th>Packets per second</th>
+            <th>Total bytes</th>
+            <th>Bytes per second</th>
+          </tr>
+        </thead>
+        <tbody>
+          <tr *ngIf="getProtocolETH() | async as protocol" class="statistics__table__header-eth">
+            <td>{{ protocol.name }}</td>
+            <td>{{ protocol.total_packets }}</td>
+            <td>
+              {{ (getPacketsPerSecond(protocol.name) | async) === 0 ? 0 : (getPacketsPerSecond(protocol.name) | async) }}
+            </td>
+            <td>{{ protocol.total_bytes }}</td>
+            <td>
+              {{ (getBytesPerSecond(protocol.name) | async) === 0 ? 0 : (getBytesPerSecond(protocol.name) | async) }}
+            </td>
+          </tr>
+        </tbody>
+      </table>
+      <table class="statistics__table__protocols">
+        <tbody>
+          <ng-container *ngFor="let protocol of getProtocolOthers() | async">
+            <tr>
+              <td>{{ protocol.name }}</td>
+              <td>{{ protocol.total_packets }}</td>
+              <td>
+                {{ (getPacketsPerSecond(protocol.name) | async) === 0 ? 0 : (getPacketsPerSecond(protocol.name) | async) }}
+              </td>
+              <td>{{ protocol.total_bytes }}</td>
+              <td>
+                {{ (getBytesPerSecond(protocol.name) | async) === 0 ? 0 : (getBytesPerSecond(protocol.name) | async) }}
+              </td>
+            </tr>
           </ng-container>
-        </div>
-      </div>
-      <div protocols class="statistics__prot">
-        <div class="statistics__prot-content">
-          <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">
-          <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>
+        </tbody>
+      </table>
+      <table class="statistics__table__ir">
+        <thead class="statistics__table__ir-header">
+        <tr>
+          <th></th>
+          <th>Min</th>
+          <th>Max</th>
+          <th>Current</th>
+        </tr>
+        </thead>
+        <tbody>
+          <tr *ngIf="getIR() | async as information_rate" class="statistics__table_ir-content">
+            <td>Information Rate</td>
+            <td>{{ information_rate.min }}</td>
+            <td>{{ information_rate.max }}</td>
+            <td>{{ information_rate.current }}</td>
+          </tr>
+        </tbody>
+      </table>
     </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 a52ca0a..b4f8a6c 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.scss
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.scss
@@ -5,30 +5,90 @@
   height: 100%;
   width: 100%;
 
-  .statistics {
-      &content {
-        display: flex;
-        gap: map.get(vars.$spacing, 'xs');
+  ngx-skeleton-loader {
+    display: flex;
+    flex-direction: row;
+    gap: map.get(vars.$spacing, 'md');
+
+    ::ng-deep * {
+      height: 50px;
     }
+  }
 
-    &__eth {
-      display: flex;
-      justify-content: space-between;
 
-      &-title {
-        color: map.get(vars.$grey, 100);
-        font-size: map.get(vars.$text, 'lg');
+  .statistics {
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    font-weight: bold;
+
+    &__table {
+      &__time {
+        font-size: map.get(vars.$text, 'md');
       }
 
-      &-content {
-        width: calc(100% - 200px);
+      &__header {
+        width: 100%;
+        border-radius: map.get(vars.$radius, 'xs');
+        background-color: map.get(vars.$grey, 0);
+        padding: map.get(vars.$spacing, 'none') map.get(vars.$spacing, 'xl');
+
+        &-title {
+          border-radius: map.get(vars.$radius, 'xs');
+          background-color: map.get(vars.$grey, 0);
+          padding: map.get(vars.$spacing, 'none') map.get(vars.$spacing, 'xl');
+        }
+
+        &-eth td {
+          border-top: 1px solid map.get(vars.$grey, 30);
+        }
+
+        th, td {
+          width: 20%;
+          padding: map.get(vars.$spacing, 'sm');
+          text-align: left;
+        }
+
       }
-    }
-  }
 
-  // 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');
+      &__protocols {
+        border-radius: map.get(vars.$radius, 'xs');
+        background-color: map.get(vars.$grey, 0);
+        padding: map.get(vars.$spacing, 'none') map.get(vars.$spacing, 'xl');
+
+        margin-top: map.get(vars.$text, 'lg');
+        width: 100%;
+
+
+        th, td {
+          width: 20%;
+          padding: map.get(vars.$spacing, 'sm');
+          text-align: left;
+        }
+
+        tr:not(:last-child) td {
+          border-bottom: 1px solid map.get(vars.$grey, 30);
+        }
+      }
+
+      &__ir {
+        border-radius: map.get(vars.$radius, 'xs');
+        background-color: map.get(vars.$grey, 0);
+        padding: map.get(vars.$spacing, 'none') map.get(vars.$spacing, 'xl');
+
+        margin-top: map.get(vars.$spacing, 'lg');
+        width: 100%;
+
+        tbody td {
+          border-top: 1px solid map.get(vars.$grey, 30);
+        }
+
+        th, td {
+          width: 25%;
+          padding: map.get(vars.$spacing, 'sm');
+          text-align: left;
+        }
+      }
+    }
   }
 }
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
index 34ccbc3..99bf83c 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
@@ -57,6 +57,10 @@ export class DashboardStatisticsComponent {
           return 0;
         }
 
+        if (protocol.total_packets == 0) {
+          return 0;
+        }
+
         const totalPackets = protocol.total_packets;
         const totalSeconds = dashboardStatistics.total_time.getTime() / 1000;
         return totalPackets / totalSeconds;
@@ -75,6 +79,10 @@ export class DashboardStatisticsComponent {
           return 0;
         }
 
+        if (protocol.total_bytes == 0) {
+          return 0;
+        }
+
         const totalBytes = protocol.total_bytes;
         const totalSeconds = dashboardStatistics.total_time.getTime() / 1000;
         return totalBytes / totalSeconds;
diff --git a/src/app/interceptor/mocks/dashboard-statistics.json b/src/app/interceptor/mocks/dashboard-statistics.json
index f12cab4..b05d511 100644
--- a/src/app/interceptor/mocks/dashboard-statistics.json
+++ b/src/app/interceptor/mocks/dashboard-statistics.json
@@ -25,9 +25,9 @@
         }
       ],
     "information-rate": {
-        "min": 1.23,
-        "max": 123456,
-        "current": 123.45
+        "min": 0,
+        "max": 0,
+        "current": 0
       }
   }
 }
-- 
GitLab


From 2255bb8944e3882f81a94dd50039b15517299042 Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Tue, 4 Mar 2025 14:41:16 +0100
Subject: [PATCH 6/7] make some minor changes

---
 src/app/api/dashboard.api.ts                                    | 1 -
 .../dashboard-statistics/dashboard-statistics.component.scss    | 2 --
 2 files changed, 3 deletions(-)

diff --git a/src/app/api/dashboard.api.ts b/src/app/api/dashboard.api.ts
index c0378e5..435ea30 100644
--- a/src/app/api/dashboard.api.ts
+++ b/src/app/api/dashboard.api.ts
@@ -4,7 +4,6 @@ import { map, Observable, tap } from 'rxjs';
 import {
   DashboardStatistics,
   DashboardStatisticsDto,
-  dashboardStatisticsToDto,
   dtoToDashboardStatistics,
 } from '../models/dashboard-statistics';
 import { ApiResponse } from '../models/api-response';
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.scss b/src/app/components/dashboard-statistics/dashboard-statistics.component.scss
index b4f8a6c..d47873a 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.scss
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.scss
@@ -15,7 +15,6 @@
     }
   }
 
-
   .statistics {
     display: flex;
     flex-direction: column;
@@ -59,7 +58,6 @@
         margin-top: map.get(vars.$text, 'lg');
         width: 100%;
 
-
         th, td {
           width: 20%;
           padding: map.get(vars.$spacing, 'sm');
-- 
GitLab


From 515e18653f5b6e9a54a5167403ed926e32dc6bdf Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Thu, 6 Mar 2025 20:42:51 +0100
Subject: [PATCH 7/7] add review changes and add decimal pipe

---
 src/app/api/dashboard.api.ts                  |   2 +-
 .../dashboard-statistics.component.html       |  46 ++++----
 .../dashboard-statistics.component.scss       |   7 +-
 .../dashboard-statistics.component.ts         | 102 +++---------------
 .../dashboard/dashboard.component.scss        |   4 +
 src/app/interceptor/interceptor.ts            |   2 +-
 src/app/models/dashboard-statistics.ts        |  42 ++++----
 src/app/pipes/decimal.pipe.ts                 |  16 +++
 8 files changed, 75 insertions(+), 146 deletions(-)
 create mode 100644 src/app/pipes/decimal.pipe.ts

diff --git a/src/app/api/dashboard.api.ts b/src/app/api/dashboard.api.ts
index 435ea30..e81df04 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 75ab2a0..bd5d0df 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 d47873a..e11b5db 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 99bf83c..d9040ee 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 1938814..d11c2b9 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 1b55567..8e088ac 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 2214b87..3a8befc 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 0000000..1d9a6e1
--- /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, ' ');
+  }
+}
-- 
GitLab