From 923b0d71cc86d4b5b449615aa568ee73636a7868 Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Sun, 16 Mar 2025 23:20:14 +0100
Subject: [PATCH 01/14] FE-7 Initialize dashboard-settings component and add
 draft style

---
 .../dashboard-settings.component.html         | 42 +++++++++
 .../dashboard-settings.component.scss         | 86 +++++++++++++++++++
 .../dashboard-settings.component.spec.ts      | 23 +++++
 .../dashboard-settings.component.ts           | 23 +++++
 .../dashboard/dashboard.component.ts          | 21 ++++-
 5 files changed, 192 insertions(+), 3 deletions(-)
 create mode 100644 src/app/components/dashboard-settings/dashboard-settings.component.html
 create mode 100644 src/app/components/dashboard-settings/dashboard-settings.component.scss
 create mode 100644 src/app/components/dashboard-settings/dashboard-settings.component.spec.ts
 create mode 100644 src/app/components/dashboard-settings/dashboard-settings.component.ts

diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.html b/src/app/components/dashboard-settings/dashboard-settings.component.html
new file mode 100644
index 0000000..9ca3bc4
--- /dev/null
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.html
@@ -0,0 +1,42 @@
+<div class="dialog">
+  <h2 mat-dialog-title class="dialog__header">Settings</h2>
+  <mat-dialog-content class="dialog__content">
+    <div class="dialog__content__statistics__columns">
+      <div class="dialog__content__statistics__columns-title">
+        Statistics columns
+      </div>
+      <div class="dialog__content__statistics__columns-content">
+        <mat-slide-toggle [(ngModel)]="isChecked">Total packets</mat-slide-toggle>
+        <mat-slide-toggle [(ngModel)]="isChecked">Packets per seconds</mat-slide-toggle>
+        <mat-slide-toggle [(ngModel)]="isChecked">Total bytes</mat-slide-toggle>
+        <mat-slide-toggle [(ngModel)]="isChecked">Bytes per second</mat-slide-toggle>
+      </div>
+    </div>
+    <div class="dialog__content__statistics__rows">
+      <div class="dialog__content__statistics__rows-title">
+        Statistics rows & charts
+      </div>
+      <div class="dialog__content__statistics__rows-content">
+        <mat-slide-toggle [(ngModel)]="isChecked">ETH</mat-slide-toggle>
+        <mat-slide-toggle [(ngModel)]="isChecked">IPv4</mat-slide-toggle>
+        <mat-slide-toggle [(ngModel)]="isChecked">IPv6</mat-slide-toggle>
+        <mat-slide-toggle [(ngModel)]="isChecked">TCP</mat-slide-toggle>
+      </div>
+    </div>
+    <div class="dialog__content__statistics__ir">
+      <div class="dialog__content__statistics__ir-title">
+        Information Rate
+      </div>
+      <div class="dialog__content__statistics__ir-content">
+        <mat-slide-toggle [(ngModel)]="isChecked">Min value</mat-slide-toggle>
+        <mat-slide-toggle [(ngModel)]="isChecked">Max value</mat-slide-toggle>
+        <mat-slide-toggle [(ngModel)]="isChecked">Current value</mat-slide-toggle>
+
+      </div>
+    </div>
+  </mat-dialog-content>
+  <mat-dialog-actions class="dialog__actions">
+    <button mat-flat-button mat-dialog-close>Cancel</button>
+    <button mat-flat-button mat-dialog-close>Basic</button>
+  </mat-dialog-actions>
+</div>
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.scss b/src/app/components/dashboard-settings/dashboard-settings.component.scss
new file mode 100644
index 0000000..82aa7b9
--- /dev/null
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.scss
@@ -0,0 +1,86 @@
+@use '../../../vars';
+@use 'sass:map';
+
+
+.custom-dialog-container .mat-dialog-container  {
+
+
+
+}
+
+.dialog {
+  background-color: map.get(vars.$grey, 0);
+  &__header {
+    border-bottom: 1px solid map.get(vars.$grey, 30);
+    font-family: Monoton, cursive;
+
+    font-size: map.get(vars.$text, 'xxl');
+    padding: map.get(vars.$spacing, 'lg') map.get(vars.$spacing, 'none') map.get(vars.$spacing, 'lg') map.get(vars.$spacing, 'xl');
+  }
+
+  &__content {
+    font-weight: 500;
+    &__statistics {
+      &__columns {
+        &-title {
+          font-size: map.get(vars.$text, 'xl');
+          padding: map.get(vars.$spacing, 'xxl') map.get(vars.$spacing, 'none') map.get(vars.$spacing, 'sm') map.get(vars.$spacing, 'none');
+        }
+        &-content {
+          border-radius: map.get(vars.$radius, 'xs');
+          background-color: map.get(vars.$grey, 10);
+          padding: map.get(vars.$spacing, 'sm') map.get(vars.$spacing, 'lg');
+          mat-slide-toggle {
+            width: 25%;
+          }
+        }
+      }
+      &__rows {
+        &-title {
+          font-size: map.get(vars.$text, 'xl');
+          padding: map.get(vars.$spacing, 'xxl') map.get(vars.$spacing, 'none') map.get(vars.$spacing, 'sm') map.get(vars.$spacing, 'none');
+        }
+        &-content {
+          border-radius: map.get(vars.$radius, 'xs');
+          background-color: map.get(vars.$grey, 10);
+          padding: map.get(vars.$spacing, 'sm') map.get(vars.$spacing, 'lg');
+          mat-slide-toggle {
+            width: 25%;
+          }
+        }
+      }
+      &__ir {
+        &-title {
+          font-size: map.get(vars.$text, 'xl');
+          padding: map.get(vars.$spacing, 'xxl') map.get(vars.$spacing, 'none') map.get(vars.$spacing, 'sm') map.get(vars.$spacing, 'none');
+        }
+        &-content {
+          border-radius: map.get(vars.$radius, 'xs');
+          background-color: map.get(vars.$grey, 10);
+          padding: map.get(vars.$spacing, 'sm') map.get(vars.$spacing, 'lg');
+          mat-slide-toggle {
+            width: 25%;
+          }
+        }
+      }
+    }
+  }
+  &__actions {
+    margin-top: map.get(vars.$spacing, 'sm');
+    border-radius: map.get(vars.$radius, 'xs');
+    background-color: map.get(vars.$grey, 30);
+    //padding: map.get(vars.$spacing, 'none') map.get(vars.$spacing, 'none') map.get(vars.$spacing, 'xxxl') map.get(vars.$spacing, 'none');
+    button {
+      width: 33%;
+      border-radius: map.get(vars.$radius, 'sm');
+    }
+  }
+}
+
+
+
+
+::ng-deep .p-toggleswitch-input {
+  width:300px;
+  height:300px;
+}
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.spec.ts b/src/app/components/dashboard-settings/dashboard-settings.component.spec.ts
new file mode 100644
index 0000000..5a25de3
--- /dev/null
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.spec.ts
@@ -0,0 +1,23 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DashboardSettingsComponent } from './dashboard-settings.component';
+
+describe('DashboardSettingsComponent', () => {
+  let component: DashboardSettingsComponent;
+  let fixture: ComponentFixture<DashboardSettingsComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [DashboardSettingsComponent]
+    })
+    .compileComponents();
+
+    fixture = TestBed.createComponent(DashboardSettingsComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.ts b/src/app/components/dashboard-settings/dashboard-settings.component.ts
new file mode 100644
index 0000000..da7902c
--- /dev/null
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.ts
@@ -0,0 +1,23 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { MatDialogModule } from '@angular/material/dialog';
+import { ToggleSwitchModule } from 'primeng/toggleswitch';
+import { FormsModule } from '@angular/forms';
+import { MatSlideToggle } from '@angular/material/slide-toggle';
+import { MatButtonModule } from '@angular/material/button';
+
+@Component({
+  changeDetection: ChangeDetectionStrategy.OnPush,
+  imports: [
+    MatDialogModule,
+    ToggleSwitchModule,
+    FormsModule,
+    MatSlideToggle,
+    MatButtonModule,
+  ],
+  selector: 'app-dashboard-settings',
+  styleUrl: './dashboard-settings.component.scss',
+  templateUrl: './dashboard-settings.component.html',
+})
+export class DashboardSettingsComponent {
+  isChecked: Boolean = true;
+}
diff --git a/src/app/components/dashboard/dashboard.component.ts b/src/app/components/dashboard/dashboard.component.ts
index c9ea330..2638312 100644
--- a/src/app/components/dashboard/dashboard.component.ts
+++ b/src/app/components/dashboard/dashboard.component.ts
@@ -1,10 +1,18 @@
-import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
 import { PageWrapperComponent } from '../page-wrapper/page-wrapper.component';
 import { MatExpansionModule } from '@angular/material/expansion';
 import { MatIcon } from '@angular/material/icon';
-import { MatFabButton } from '@angular/material/button';
+import { MatButtonModule, MatFabButton } from '@angular/material/button';
 import { DashboardStatisticsComponent } from '../dashboard-statistics/dashboard-statistics.component';
 import { DashboardChartsComponent } from '../dashboard-charts/dashboard-charts.component';
+import {
+  MatDialog,
+  MatDialogActions,
+  MatDialogClose,
+  MatDialogContent,
+  MatDialogTitle,
+} from '@angular/material/dialog';
+import { DashboardSettingsComponent } from '../dashboard-settings/dashboard-settings.component';
 
 @Component({
   selector: 'app-dashboard',
@@ -21,5 +29,12 @@ import { DashboardChartsComponent } from '../dashboard-charts/dashboard-charts.c
   changeDetection: ChangeDetectionStrategy.OnPush,
 })
 export class DashboardComponent {
-  openSettings() {}
+  readonly dialog = inject(MatDialog);
+
+  openSettings() {
+    this.dialog.open(DashboardSettingsComponent, {
+      minWidth: '1100px',
+      minHeight: '550px',
+    });
+  }
 }
-- 
GitLab


From b232da0e952c3d5be0adb14438c996cf4383d139 Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Mon, 17 Mar 2025 13:14:24 +0100
Subject: [PATCH 02/14] FE-7 Change scss file in dashboard-settings and finish
 styling

---
 .../dashboard-settings.component.html         |  4 +-
 .../dashboard-settings.component.scss         | 66 ++++---------------
 2 files changed, 15 insertions(+), 55 deletions(-)

diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.html b/src/app/components/dashboard-settings/dashboard-settings.component.html
index 9ca3bc4..3f428bb 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.html
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.html
@@ -36,7 +36,7 @@
     </div>
   </mat-dialog-content>
   <mat-dialog-actions class="dialog__actions">
-    <button mat-flat-button mat-dialog-close>Cancel</button>
-    <button mat-flat-button mat-dialog-close>Basic</button>
+    <button mat-flat-button mat-dialog-close>CANCEL</button>
+    <button mat-flat-button mat-dialog-close>SAVE</button>
   </mat-dialog-actions>
 </div>
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.scss b/src/app/components/dashboard-settings/dashboard-settings.component.scss
index 82aa7b9..1b093d6 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.scss
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.scss
@@ -1,13 +1,6 @@
 @use '../../../vars';
 @use 'sass:map';
 
-
-.custom-dialog-container .mat-dialog-container  {
-
-
-
-}
-
 .dialog {
   background-color: map.get(vars.$grey, 0);
   &__header {
@@ -15,72 +8,39 @@
     font-family: Monoton, cursive;
 
     font-size: map.get(vars.$text, 'xxl');
-    padding: map.get(vars.$spacing, 'lg') map.get(vars.$spacing, 'none') map.get(vars.$spacing, 'lg') map.get(vars.$spacing, 'xl');
+    padding: map.get(vars.$spacing, 'lg') 0 map.get(vars.$spacing, 'lg') map.get(vars.$spacing, 'xl');
   }
 
   &__content {
     font-weight: 500;
+
     &__statistics {
-      &__columns {
-        &-title {
-          font-size: map.get(vars.$text, 'xl');
-          padding: map.get(vars.$spacing, 'xxl') map.get(vars.$spacing, 'none') map.get(vars.$spacing, 'sm') map.get(vars.$spacing, 'none');
-        }
-        &-content {
-          border-radius: map.get(vars.$radius, 'xs');
-          background-color: map.get(vars.$grey, 10);
-          padding: map.get(vars.$spacing, 'sm') map.get(vars.$spacing, 'lg');
-          mat-slide-toggle {
-            width: 25%;
-          }
-        }
-      }
-      &__rows {
-        &-title {
-          font-size: map.get(vars.$text, 'xl');
-          padding: map.get(vars.$spacing, 'xxl') map.get(vars.$spacing, 'none') map.get(vars.$spacing, 'sm') map.get(vars.$spacing, 'none');
-        }
-        &-content {
-          border-radius: map.get(vars.$radius, 'xs');
-          background-color: map.get(vars.$grey, 10);
-          padding: map.get(vars.$spacing, 'sm') map.get(vars.$spacing, 'lg');
-          mat-slide-toggle {
-            width: 25%;
-          }
-        }
-      }
+      &__columns,
+      &__rows,
       &__ir {
         &-title {
           font-size: map.get(vars.$text, 'xl');
-          padding: map.get(vars.$spacing, 'xxl') map.get(vars.$spacing, 'none') map.get(vars.$spacing, 'sm') map.get(vars.$spacing, 'none');
+          padding: map.get(vars.$spacing, 'xxl') 0 map.get(vars.$spacing, 'sm') 0;
         }
         &-content {
           border-radius: map.get(vars.$radius, 'xs');
           background-color: map.get(vars.$grey, 10);
-          padding: map.get(vars.$spacing, 'sm') map.get(vars.$spacing, 'lg');
-          mat-slide-toggle {
-            width: 25%;
-          }
+          padding: map.get(vars.$spacing, 'sm') 0 map.get(vars.$spacing, 'sm') map.get(vars.$spacing, 'xxl');
         }
       }
     }
+    mat-slide-toggle {
+      width: 25%;
+    }
   }
   &__actions {
-    margin-top: map.get(vars.$spacing, 'sm');
     border-radius: map.get(vars.$radius, 'xs');
-    background-color: map.get(vars.$grey, 30);
-    //padding: map.get(vars.$spacing, 'none') map.get(vars.$spacing, 'none') map.get(vars.$spacing, 'xxxl') map.get(vars.$spacing, 'none');
+    padding: map.get(vars.$spacing, 'xxl') 0 map.get(vars.$spacing, 'xl') 0;
     button {
-      width: 33%;
+      width: 40%;
       border-radius: map.get(vars.$radius, 'sm');
+      margin: map.get(vars.$spacing, 'xs') map.get(vars.$spacing, 'xxxl') 0 map.get(vars.$radius, 'xl');
+
     }
   }
 }
-
-
-
-
-::ng-deep .p-toggleswitch-input {
-  width:300px;
-  height:300px;
-}
-- 
GitLab


From 3f187e1d1f034a4f358a2d8f70486429fdeee628 Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Sat, 22 Mar 2025 22:11:32 +0100
Subject: [PATCH 03/14] feat: add slide-toggle component, fix color in
 dashboard-settings styles

---
 .../dashboard-settings.component.html         | 26 +++++++++----------
 .../dashboard-settings.component.scss         | 24 ++++++++++++-----
 .../dashboard-settings.component.ts           |  6 +++--
 .../slide-toggle/slide-toggle.component.html  |  4 +++
 .../slide-toggle/slide-toggle.component.scss  | 19 ++++++++++++++
 .../slide-toggle/slide-toggle.component.ts    | 10 +++++++
 6 files changed, 68 insertions(+), 21 deletions(-)
 create mode 100644 src/app/components/slide-toggle/slide-toggle.component.html
 create mode 100644 src/app/components/slide-toggle/slide-toggle.component.scss
 create mode 100644 src/app/components/slide-toggle/slide-toggle.component.ts

diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.html b/src/app/components/dashboard-settings/dashboard-settings.component.html
index 3f428bb..3f7c6f8 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.html
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.html
@@ -6,10 +6,10 @@
         Statistics columns
       </div>
       <div class="dialog__content__statistics__columns-content">
-        <mat-slide-toggle [(ngModel)]="isChecked">Total packets</mat-slide-toggle>
-        <mat-slide-toggle [(ngModel)]="isChecked">Packets per seconds</mat-slide-toggle>
-        <mat-slide-toggle [(ngModel)]="isChecked">Total bytes</mat-slide-toggle>
-        <mat-slide-toggle [(ngModel)]="isChecked">Bytes per second</mat-slide-toggle>
+        <app-slide-toggle>Total packets</app-slide-toggle>
+        <app-slide-toggle>Packets per seconds</app-slide-toggle>
+        <app-slide-toggle>Total bytes</app-slide-toggle>
+        <app-slide-toggle>Bytes per second</app-slide-toggle>
       </div>
     </div>
     <div class="dialog__content__statistics__rows">
@@ -17,10 +17,10 @@
         Statistics rows & charts
       </div>
       <div class="dialog__content__statistics__rows-content">
-        <mat-slide-toggle [(ngModel)]="isChecked">ETH</mat-slide-toggle>
-        <mat-slide-toggle [(ngModel)]="isChecked">IPv4</mat-slide-toggle>
-        <mat-slide-toggle [(ngModel)]="isChecked">IPv6</mat-slide-toggle>
-        <mat-slide-toggle [(ngModel)]="isChecked">TCP</mat-slide-toggle>
+        <app-slide-toggle>ETH</app-slide-toggle>
+        <app-slide-toggle>IPv4</app-slide-toggle>
+        <app-slide-toggle >IPv6</app-slide-toggle>
+        <app-slide-toggle >TCP</app-slide-toggle>
       </div>
     </div>
     <div class="dialog__content__statistics__ir">
@@ -28,15 +28,15 @@
         Information Rate
       </div>
       <div class="dialog__content__statistics__ir-content">
-        <mat-slide-toggle [(ngModel)]="isChecked">Min value</mat-slide-toggle>
-        <mat-slide-toggle [(ngModel)]="isChecked">Max value</mat-slide-toggle>
-        <mat-slide-toggle [(ngModel)]="isChecked">Current value</mat-slide-toggle>
+        <app-slide-toggle class="custom" >Min value</app-slide-toggle>
+        <app-slide-toggle >Max value</app-slide-toggle>
+        <app-slide-toggle >Current value</app-slide-toggle>
 
       </div>
     </div>
   </mat-dialog-content>
   <mat-dialog-actions class="dialog__actions">
-    <button mat-flat-button mat-dialog-close>CANCEL</button>
-    <button mat-flat-button mat-dialog-close>SAVE</button>
+    <app-button secondary class="cancel-button">CANCEL</app-button>
+    <app-button class="save-button">SAVE</app-button>
   </mat-dialog-actions>
 </div>
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.scss b/src/app/components/dashboard-settings/dashboard-settings.component.scss
index 1b093d6..ac32f2e 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.scss
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.scss
@@ -29,18 +29,30 @@
         }
       }
     }
-    mat-slide-toggle {
-      width: 25%;
+    ::ng-deep app-slide-toggle {
+      mat-slide-toggle {
+        width: 25% !important;
+      }
     }
   }
   &__actions {
     border-radius: map.get(vars.$radius, 'xs');
     padding: map.get(vars.$spacing, 'xxl') 0 map.get(vars.$spacing, 'xl') 0;
-    button {
-      width: 40%;
-      border-radius: map.get(vars.$radius, 'sm');
-      margin: map.get(vars.$spacing, 'xs') map.get(vars.$spacing, 'xxxl') 0 map.get(vars.$radius, 'xl');
+    display: flex;
+    justify-content: center;
+    gap: 150px;
+
+    ::ng-deep app-button {
+      button {
+        width: 450px;
+      }
+      margin: map.get(vars.$spacing, 'md') 0 0 0;
 
     }
   }
 }
+
+
+
+
+
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.ts b/src/app/components/dashboard-settings/dashboard-settings.component.ts
index da7902c..f3df6d3 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.ts
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.ts
@@ -2,8 +2,9 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
 import { MatDialogModule } from '@angular/material/dialog';
 import { ToggleSwitchModule } from 'primeng/toggleswitch';
 import { FormsModule } from '@angular/forms';
-import { MatSlideToggle } from '@angular/material/slide-toggle';
 import { MatButtonModule } from '@angular/material/button';
+import { ButtonComponent } from '../button/button.component';
+import { SlideToggleComponent } from '../slide-toggle/slide-toggle.component';
 
 @Component({
   changeDetection: ChangeDetectionStrategy.OnPush,
@@ -11,8 +12,9 @@ import { MatButtonModule } from '@angular/material/button';
     MatDialogModule,
     ToggleSwitchModule,
     FormsModule,
-    MatSlideToggle,
     MatButtonModule,
+    ButtonComponent,
+    SlideToggleComponent,
   ],
   selector: 'app-dashboard-settings',
   styleUrl: './dashboard-settings.component.scss',
diff --git a/src/app/components/slide-toggle/slide-toggle.component.html b/src/app/components/slide-toggle/slide-toggle.component.html
new file mode 100644
index 0000000..edb1a24
--- /dev/null
+++ b/src/app/components/slide-toggle/slide-toggle.component.html
@@ -0,0 +1,4 @@
+<mat-slide-toggle
+  [hideIcon]="true">
+  <ng-content />
+</mat-slide-toggle>
diff --git a/src/app/components/slide-toggle/slide-toggle.component.scss b/src/app/components/slide-toggle/slide-toggle.component.scss
new file mode 100644
index 0000000..88ed7b5
--- /dev/null
+++ b/src/app/components/slide-toggle/slide-toggle.component.scss
@@ -0,0 +1,19 @@
+@use '../../../vars';
+@use 'sass:map';
+
+::ng-deep .mat-mdc-slide-toggle.mat-mdc-slide-toggle-checked:not(.mat-disabled) .mdc-switch__shadow {
+  background-color: map.get(vars.$grey, 10);
+}
+
+::ng-deep .mat-mdc-slide-toggle.mat-mdc-slide-toggle-checked:not(.mat-disabled) .mdc-switch__track::after {
+  background-color: vars.$textPrimary !important;
+}
+
+::ng-deep .mdc-switch__track::before {
+  background-color: map.get(vars.$grey, 30) !important;
+}
+
+//.mat-slide-toggle.mat-checked:not(.mat-disabled) .mat-slide-toggle-thumb:before {
+//  content: "" !important;
+//  font: normal normal normal 14px/1 FontAwesome !important;
+//}
diff --git a/src/app/components/slide-toggle/slide-toggle.component.ts b/src/app/components/slide-toggle/slide-toggle.component.ts
new file mode 100644
index 0000000..05f96f8
--- /dev/null
+++ b/src/app/components/slide-toggle/slide-toggle.component.ts
@@ -0,0 +1,10 @@
+import { Component } from '@angular/core';
+import { MatSlideToggle } from '@angular/material/slide-toggle';
+
+@Component({
+  selector: 'app-slide-toggle',
+  imports: [MatSlideToggle],
+  templateUrl: './slide-toggle.component.html',
+  styleUrl: './slide-toggle.component.scss',
+})
+export class SlideToggleComponent {}
-- 
GitLab


From 9b042b355337db32e0f4ff5385ab78e327784ff9 Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Sun, 23 Mar 2025 21:55:04 +0100
Subject: [PATCH 04/14] feat: managing statistics from settings menu

---
 .../dashboard-settings.component.html         |  35 +++---
 .../dashboard-settings.component.scss         |  16 ++-
 .../dashboard-settings.component.spec.ts      |  23 ----
 .../dashboard-settings.component.ts           |  56 ++++++++-
 .../dashboard-statistics.component.html       | 119 ++++++++++++------
 .../dashboard-statistics.component.scss       |   1 +
 .../dashboard-statistics.component.ts         |  38 +++++-
 .../slide-toggle/slide-toggle.component.scss  |   4 -
 .../slide-toggle/slide-toggle.component.ts    |   2 +-
 src/app/models/settings.ts                    |  29 +++++
 src/app/service/settings.service.ts           |  39 ++++++
 11 files changed, 263 insertions(+), 99 deletions(-)
 delete mode 100644 src/app/components/dashboard-settings/dashboard-settings.component.spec.ts
 create mode 100644 src/app/models/settings.ts
 create mode 100644 src/app/service/settings.service.ts

diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.html b/src/app/components/dashboard-settings/dashboard-settings.component.html
index 3f7c6f8..bddf167 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.html
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.html
@@ -1,42 +1,41 @@
-<div class="dialog">
+<div class="dialog" [formGroup]="settingsForm">
   <h2 mat-dialog-title class="dialog__header">Settings</h2>
   <mat-dialog-content class="dialog__content">
-    <div class="dialog__content__statistics__columns">
+    <div formGroupName="statisticsColumns" class="dialog__content__statistics__columns">
       <div class="dialog__content__statistics__columns-title">
         Statistics columns
       </div>
       <div class="dialog__content__statistics__columns-content">
-        <app-slide-toggle>Total packets</app-slide-toggle>
-        <app-slide-toggle>Packets per seconds</app-slide-toggle>
-        <app-slide-toggle>Total bytes</app-slide-toggle>
-        <app-slide-toggle>Bytes per second</app-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" formControlName="showTotalPackets">Total packets</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" formControlName="showPacketsPerSec">Packets per seconds</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" formControlName="showTotalBytes">Total bytes</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" formControlName="showBytesPerSec">Bytes per second</mat-slide-toggle>
       </div>
     </div>
-    <div class="dialog__content__statistics__rows">
+    <div formGroupName="statisticsRowsAndCharts" class="dialog__content__statistics__rows">
       <div class="dialog__content__statistics__rows-title">
         Statistics rows & charts
       </div>
       <div class="dialog__content__statistics__rows-content">
-        <app-slide-toggle>ETH</app-slide-toggle>
-        <app-slide-toggle>IPv4</app-slide-toggle>
-        <app-slide-toggle >IPv6</app-slide-toggle>
-        <app-slide-toggle >TCP</app-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" formControlName="showETH">ETH</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" formControlName="showIPv4">IPv4</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" formControlName="showIPv6">IPv6</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" formControlName="showTCP">TCP</mat-slide-toggle>
       </div>
     </div>
-    <div class="dialog__content__statistics__ir">
+    <div formGroupName="statisticsIR" class="dialog__content__statistics__ir">
       <div class="dialog__content__statistics__ir-title">
         Information Rate
       </div>
       <div class="dialog__content__statistics__ir-content">
-        <app-slide-toggle class="custom" >Min value</app-slide-toggle>
-        <app-slide-toggle >Max value</app-slide-toggle>
-        <app-slide-toggle >Current value</app-slide-toggle>
-
+        <mat-slide-toggle [hideIcon]="true" formControlName="showMinValue">Min value</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" formControlName="showMaxValue">Max value</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" formControlName="showCurrentValue">Current value</mat-slide-toggle>
       </div>
     </div>
   </mat-dialog-content>
   <mat-dialog-actions class="dialog__actions">
-    <app-button secondary class="cancel-button">CANCEL</app-button>
-    <app-button class="save-button">SAVE</app-button>
+    <app-button secondary class="cancel-button" (click)="onCancel()">CANCEL</app-button>
+    <app-button class="save-button" (click)="onSubmit()">SAVE</app-button>
   </mat-dialog-actions>
 </div>
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.scss b/src/app/components/dashboard-settings/dashboard-settings.component.scss
index ac32f2e..712cfb4 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.scss
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.scss
@@ -29,10 +29,8 @@
         }
       }
     }
-    ::ng-deep app-slide-toggle {
-      mat-slide-toggle {
+    ::ng-deep mat-slide-toggle {
         width: 25% !important;
-      }
     }
   }
   &__actions {
@@ -47,12 +45,22 @@
         width: 450px;
       }
       margin: map.get(vars.$spacing, 'md') 0 0 0;
-
     }
   }
 }
 
 
+::ng-deep .mat-mdc-slide-toggle.mat-mdc-slide-toggle-checked:not(.mat-disabled) .mdc-switch__shadow {
+  background-color: map.get(vars.$grey, 10);
+}
+
+::ng-deep .mat-mdc-slide-toggle.mat-mdc-slide-toggle-checked:not(.mat-disabled) .mdc-switch__track::after {
+  background-color: vars.$textPrimary !important;
+}
+
+::ng-deep .mdc-switch__track::before {
+  background-color: map.get(vars.$grey, 30) !important;
+}
 
 
 
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.spec.ts b/src/app/components/dashboard-settings/dashboard-settings.component.spec.ts
deleted file mode 100644
index 5a25de3..0000000
--- a/src/app/components/dashboard-settings/dashboard-settings.component.spec.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { ComponentFixture, TestBed } from '@angular/core/testing';
-
-import { DashboardSettingsComponent } from './dashboard-settings.component';
-
-describe('DashboardSettingsComponent', () => {
-  let component: DashboardSettingsComponent;
-  let fixture: ComponentFixture<DashboardSettingsComponent>;
-
-  beforeEach(async () => {
-    await TestBed.configureTestingModule({
-      imports: [DashboardSettingsComponent]
-    })
-    .compileComponents();
-
-    fixture = TestBed.createComponent(DashboardSettingsComponent);
-    component = fixture.componentInstance;
-    fixture.detectChanges();
-  });
-
-  it('should create', () => {
-    expect(component).toBeTruthy();
-  });
-});
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.ts b/src/app/components/dashboard-settings/dashboard-settings.component.ts
index f3df6d3..dfff137 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.ts
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.ts
@@ -1,10 +1,17 @@
-import { ChangeDetectionStrategy, Component } from '@angular/core';
+import {
+  ChangeDetectionStrategy,
+  Component,
+  inject,
+  input,
+  OnInit,
+} from '@angular/core';
 import { MatDialogModule } from '@angular/material/dialog';
 import { ToggleSwitchModule } from 'primeng/toggleswitch';
-import { FormsModule } from '@angular/forms';
+import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { MatButtonModule } from '@angular/material/button';
 import { ButtonComponent } from '../button/button.component';
-import { SlideToggleComponent } from '../slide-toggle/slide-toggle.component';
+import { SettingsService } from '../../service/settings.service';
+import { MatSlideToggle } from '@angular/material/slide-toggle';
 
 @Component({
   changeDetection: ChangeDetectionStrategy.OnPush,
@@ -14,12 +21,49 @@ import { SlideToggleComponent } from '../slide-toggle/slide-toggle.component';
     FormsModule,
     MatButtonModule,
     ButtonComponent,
-    SlideToggleComponent,
+    ReactiveFormsModule,
+    MatSlideToggle,
   ],
   selector: 'app-dashboard-settings',
   styleUrl: './dashboard-settings.component.scss',
   templateUrl: './dashboard-settings.component.html',
 })
-export class DashboardSettingsComponent {
-  isChecked: Boolean = true;
+export class DashboardSettingsComponent implements OnInit {
+  private formBuilder = inject(FormBuilder);
+
+  settingsForm = this.formBuilder.group({
+    statisticsColumns: this.formBuilder.group({
+      showTotalPackets: [true],
+      showPacketsPerSec: [true],
+      showTotalBytes: [true],
+      showBytesPerSec: [true],
+    }),
+    statisticsRowsAndCharts: this.formBuilder.group({
+      showETH: [true],
+      showIPv4: [true],
+      showIPv6: [true],
+      showTCP: [true],
+    }),
+    statisticsIR: this.formBuilder.group({
+      showMinValue: [true],
+      showMaxValue: [true],
+      showCurrentValue: [true],
+    }),
+  });
+
+  private settingsService = inject(SettingsService);
+
+  ngOnInit() {
+    const currentSettings = this.settingsForm.value;
+    this.settingsForm.patchValue(currentSettings);
+  }
+
+  onSubmit() {
+    this.settingsService.updateSettings(this.settingsForm.value);
+  }
+
+  onCancel() {
+    const currentSettings = this.settingsService.getSettings();
+    this.settingsForm.patchValue(currentSettings);
+  }
 }
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.html b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
index bd5d0df..f40e325 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.html
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
@@ -6,70 +6,111 @@
         <ngx-skeleton-loader count="7" />
       }
     </div>
-  }
-  @else {
+  } @else {
     <div class="statistics__table">
       <div class="statistics__table__time">
         <p>Total time: {{ statistics.total_time | time }} </p>
       </div>
-      <table class="statistics__table__header">
-        <thead class="statistics__table__header-title">
+      @if (settings?.statisticsRowsAndCharts?.showETH) {
+        <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>
+            @if (settings?.statisticsColumns?.showTotalPackets) {
+              <th>Total packets</th>
+            }
+            @if (settings?.statisticsColumns?.showPacketsPerSec) {
+              <th>Packets per second</th>
+            }
+            @if (settings?.statisticsColumns?.showTotalBytes) {
+              <th>Total bytes</th>
+            }
+            @if (settings?.statisticsColumns?.showBytesPerSec) {
+              <th>Bytes per second</th>
+            }
           </tr>
-        </thead>
-        <tbody>
-          @let protocolEth = getETHStatistics(statistics.protocols);
+          </thead>
+          <tbody>
+            @let protocolEth = getETHStatistics(statistics.protocols);
           <tr class="statistics__table__header-eth">
             <td>{{ protocolEth.name }}</td>
-            <td>{{ protocolEth.total_packets | decimal }}</td>
-            <td>
-              {{ getPerSecond(protocolEth.total_packets, statistics.total_time) | decimal }}
-            </td>
-            <td>{{ protocolEth.total_bytes | decimal }}</td>
-            <td>
-              {{ getPerSecond(protocolEth.total_bytes, statistics.total_time) | decimal }}
-            </td>
-          </tr>
-        </tbody>
-      </table>
-      <table class="statistics__table__protocols">
-        <tbody>
-        @for (protocol of getProtocols(statistics.protocols); track protocol.name) {
-            <tr>
-              <td>{{ protocol.name }}</td>
-              <td>{{ protocol.total_packets | decimal }}</td>
+            @if (settings?.statisticsColumns?.showTotalPackets) {
+              <td>{{ protocolEth.total_packets | decimal }}</td>
+            }
+            @if (settings?.statisticsColumns?.showPacketsPerSec) {
               <td>
-                {{ getPerSecond(protocol.total_packets, statistics.total_time) | decimal }}
+                {{ getPerSecond(protocolEth.total_packets, statistics.total_time) | decimal }}
               </td>
-              <td>{{ protocol.total_bytes | decimal }}</td>
+            }
+            @if (settings?.statisticsColumns?.showTotalBytes) {
+              <td>{{ protocolEth.total_bytes | decimal }}</td>
+            }
+            @if (settings?.statisticsColumns?.showBytesPerSec) {
               <td>
-                {{ getPerSecond(protocol.total_bytes, statistics.total_time) | decimal }}
+                {{ getPerSecond(protocolEth.total_bytes, statistics.total_time) | decimal }}
               </td>
-            </tr>
-        }
+            }
+          </tr>
+          </tbody>
+        </table>
+      }
+      <table class="statistics__table__protocols">
+        <tbody>
+          @for (protocol of getProtocols(statistics.protocols); track protocol.name) {
+            @if (settings?.statisticsRowsAndCharts?.showIPv4 && protocol.name === 'IPv4' ||
+            settings?.statisticsRowsAndCharts?.showIPv6 && protocol.name === 'IPv6' ||
+            settings?.statisticsRowsAndCharts?.showTCP && protocol.name === 'TCP') {
+              <tr>
+                <td>{{ protocol.name }}</td>
+                @if (settings?.statisticsColumns?.showTotalPackets) {
+                  <td>{{ protocol.total_packets | decimal }}</td>
+                }
+                @if (settings?.statisticsColumns?.showPacketsPerSec) {
+                  <td>
+                    {{ getPerSecond(protocol.total_packets, statistics.total_time) | decimal }}
+                  </td>
+                }
+                @if (settings?.statisticsColumns?.showTotalBytes) {
+                  <td>{{ protocol.total_bytes | decimal }}</td>
+                }
+                @if (settings?.statisticsColumns?.showBytesPerSec) {
+                  <td>
+                    {{ getPerSecond(protocol.total_bytes, statistics.total_time) | decimal }}
+                  </td>
+                }
+              </tr>
+            }
+          }
         </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>
+          @if (settings?.statisticsIR?.showMinValue) {
+            <th>Min</th>
+          }
+          @if (settings?.statisticsIR?.showMaxValue) {
+            <th>Max</th>
+          }
+          @if (settings?.statisticsIR?.showCurrentValue) {
+            <th>Current</th>
+          }
         </tr>
         </thead>
         <tbody>
-          <tr class="statistics__table_ir-content">
-            <td>Information Rate</td>
+        <tr class="statistics__table_ir-content">
+          <td>Information Rate</td>
+          @if (settings?.statisticsIR?.showMinValue) {
             <td>{{ statistics.information_rate.min | decimal }}</td>
+          }
+          @if (settings?.statisticsIR?.showMaxValue) {
             <td>{{ statistics.information_rate.max | decimal }}</td>
+          }
+          @if (settings?.statisticsIR?.showCurrentValue) {
             <td>{{ statistics.information_rate.current | decimal }}</td>
-          </tr>
+          }
+        </tr>
         </tbody>
       </table>
     </div>
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.scss b/src/app/components/dashboard-statistics/dashboard-statistics.component.scss
index e11b5db..1814cde 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.scss
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.scss
@@ -74,6 +74,7 @@
         margin-top: map.get(vars.$spacing, 'lg');
         width: 100%;
 
+
         tbody td {
           border-top: 1px solid map.get(vars.$grey, 30);
         }
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
index 2b6f628..46f5e53 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
@@ -1,27 +1,57 @@
-import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
+import {
+  ChangeDetectionStrategy,
+  Component,
+  inject,
+  Input,
+  OnInit,
+} from '@angular/core';
 import { NgxSkeletonLoaderComponent } from 'ngx-skeleton-loader';
-import { AsyncPipe } from '@angular/common';
+import { AsyncPipe, NgIf } from '@angular/common';
 import { DashboardApi } from '../../api/dashboard.api';
+
 import { interval, shareReplay, switchMap } from 'rxjs';
 import { ProtocolStatistics } from '../../models/dashboard-statistics';
 import { TimePipe } from '../../pipes/time.pipe';
 import { DecimalPipe } from '../../pipes/decimal.pipe';
+import { FormGroup, ReactiveFormsModule } from '@angular/forms';
+import { SettingsService } from '../../service/settings.service';
 
 @Component({
   selector: 'app-dashboard-statistics',
-  imports: [NgxSkeletonLoaderComponent, AsyncPipe, TimePipe, DecimalPipe],
+  imports: [
+    NgxSkeletonLoaderComponent,
+    AsyncPipe,
+    TimePipe,
+    DecimalPipe,
+    ReactiveFormsModule,
+    NgIf,
+  ],
   templateUrl: './dashboard-statistics.component.html',
   styleUrl: './dashboard-statistics.component.scss',
   changeDetection: ChangeDetectionStrategy.OnPush,
 })
-export class DashboardStatisticsComponent {
+export class DashboardStatisticsComponent implements OnInit {
   dashboardApi = inject(DashboardApi);
+  settings: any;
+
+  private settingsService = inject(SettingsService);
+
+  ngOnInit() {
+    this.settingsService.settings$.subscribe(settings => {
+      this.settings = settings;
+      console.log('Settings received in Dashboard:', this.settings);
+    });
+  }
 
   dashboardStatistics = interval(1000).pipe(
     switchMap(() => this.dashboardApi.fetchStatistics()),
     shareReplay(1)
   );
 
+  get showETHSetting() {
+    return this.settings.value.statisticsRowsAndCharts.showETH;
+  }
+
   getPerSecond(value: number, time: Date): number {
     const totalSeconds = time.getTime() / 1000;
     return value / totalSeconds;
diff --git a/src/app/components/slide-toggle/slide-toggle.component.scss b/src/app/components/slide-toggle/slide-toggle.component.scss
index 88ed7b5..2ef9c9c 100644
--- a/src/app/components/slide-toggle/slide-toggle.component.scss
+++ b/src/app/components/slide-toggle/slide-toggle.component.scss
@@ -13,7 +13,3 @@
   background-color: map.get(vars.$grey, 30) !important;
 }
 
-//.mat-slide-toggle.mat-checked:not(.mat-disabled) .mat-slide-toggle-thumb:before {
-//  content: "" !important;
-//  font: normal normal normal 14px/1 FontAwesome !important;
-//}
diff --git a/src/app/components/slide-toggle/slide-toggle.component.ts b/src/app/components/slide-toggle/slide-toggle.component.ts
index 05f96f8..72ff668 100644
--- a/src/app/components/slide-toggle/slide-toggle.component.ts
+++ b/src/app/components/slide-toggle/slide-toggle.component.ts
@@ -7,4 +7,4 @@ import { MatSlideToggle } from '@angular/material/slide-toggle';
   templateUrl: './slide-toggle.component.html',
   styleUrl: './slide-toggle.component.scss',
 })
-export class SlideToggleComponent {}
+export class SlideToggleComponent extends MatSlideToggle {}
diff --git a/src/app/models/settings.ts b/src/app/models/settings.ts
new file mode 100644
index 0000000..94d2134
--- /dev/null
+++ b/src/app/models/settings.ts
@@ -0,0 +1,29 @@
+export type Settings = SettingsDto;
+
+export interface SettingsDto {
+  statisticsColumns: {
+    showTotalPackets: true;
+    showPacketsPerSec: true;
+    showTotalBytes: true;
+    showBytesPerSec: true;
+  };
+  statisticsRowsAndCharts: {
+    showETH: true;
+    showIPv4: true;
+    showIPv6: true;
+    showTCP: true;
+  };
+  statisticsIR: {
+    showMinValue: true;
+    showMaxValue: true;
+    showCurrentValue: true;
+  };
+}
+
+export function dtoToSettings(dto: SettingsDto): Settings {
+  return dto;
+}
+
+export function settingsToDto(settings: Settings): SettingsDto {
+  return settings;
+}
diff --git a/src/app/service/settings.service.ts b/src/app/service/settings.service.ts
new file mode 100644
index 0000000..fb59cb2
--- /dev/null
+++ b/src/app/service/settings.service.ts
@@ -0,0 +1,39 @@
+import { Injectable, OnInit } from '@angular/core';
+import { BehaviorSubject } from 'rxjs';
+import { Settings } from '../models/settings';
+
+@Injectable({
+  providedIn: 'root',
+})
+export class SettingsService implements OnInit {
+  private settingsSubject = new BehaviorSubject<any>({
+    statisticsColumns: {
+      showTotalPackets: true,
+      showPacketsPerSec: true,
+      showTotalBytes: true,
+      showBytesPerSec: true,
+    },
+    statisticsRowsAndCharts: {
+      showETH: true,
+      showIPv4: true,
+      showIPv6: true,
+      showTCP: true,
+    },
+    statisticsIR: {
+      showMinValue: true,
+      showMaxValue: true,
+      showCurrentValue: true,
+    },
+  });
+  settings$ = this.settingsSubject.asObservable();
+
+  ngOnInit() {}
+
+  updateSettings(settings: any) {
+    this.settingsSubject.next(settings);
+  }
+
+  getSettings() {
+    return this.settingsSubject.value;
+  }
+}
-- 
GitLab


From e74680e70e9a5ac5641049763da58eb9b306061e Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Sun, 23 Mar 2025 23:53:08 +0100
Subject: [PATCH 05/14] mod: minor modifications, remove app-slide-toggle
 component

---
 .../dashboard-charts.component.html           |  3 ++
 .../dashboard-charts.component.ts             | 19 +++++++-
 .../dashboard-settings.component.scss         | 29 ++++++------
 .../dashboard-settings.component.ts           | 42 +++++++++--------
 .../dashboard-statistics.component.ts         |  8 +---
 .../slide-toggle/slide-toggle.component.html  |  4 --
 .../slide-toggle/slide-toggle.component.scss  | 15 ------
 .../slide-toggle/slide-toggle.component.ts    | 10 ----
 src/app/models/settings.ts                    | 30 +++++-------
 src/app/service/settings.service.ts           | 46 +++++++++----------
 10 files changed, 93 insertions(+), 113 deletions(-)
 delete mode 100644 src/app/components/slide-toggle/slide-toggle.component.html
 delete mode 100644 src/app/components/slide-toggle/slide-toggle.component.scss
 delete mode 100644 src/app/components/slide-toggle/slide-toggle.component.ts

diff --git a/src/app/components/dashboard-charts/dashboard-charts.component.html b/src/app/components/dashboard-charts/dashboard-charts.component.html
index 9434f64..b47c127 100644
--- a/src/app/components/dashboard-charts/dashboard-charts.component.html
+++ b/src/app/components/dashboard-charts/dashboard-charts.component.html
@@ -1,11 +1,14 @@
 <mat-tab-group>
+  @if (settings?.statisticsRowsAndCharts?.showETH) {
   <mat-tab label="Frames">
     <app-dashboard-chart-frames />
   </mat-tab>
+  }
   <mat-tab label="Information Rate">
     <app-dashboard-chart-information-rate />
   </mat-tab>
   @for (protocol of protocols(); track $index) {
+
     <mat-tab [label]="protocol">
       <app-dashboard-chart-protocol [protocolName]="protocol" />
     </mat-tab>
diff --git a/src/app/components/dashboard-charts/dashboard-charts.component.ts b/src/app/components/dashboard-charts/dashboard-charts.component.ts
index f2da7bd..6ae5547 100644
--- a/src/app/components/dashboard-charts/dashboard-charts.component.ts
+++ b/src/app/components/dashboard-charts/dashboard-charts.component.ts
@@ -1,4 +1,9 @@
-import { ChangeDetectionStrategy, Component, input } from '@angular/core';
+import {
+  ChangeDetectionStrategy,
+  Component,
+  inject,
+  input,
+} from '@angular/core';
 import { MatTab, MatTabGroup } from '@angular/material/tabs';
 import { DashboardChartFramesComponent } from '../dashboard-chart-frames/dashboard-chart-frames.component';
 import { DashboardChartInformationRateComponent } from '../dashboard-chart-information-rate/dashboard-chart-information-rate.component';
@@ -6,6 +11,8 @@ import { DashboardChartProtocolComponent } from '../dashboard-chart-protocol/das
 import { SliderModule } from 'primeng/slider';
 import { FormsModule } from '@angular/forms';
 import { Skeleton } from 'primeng/skeleton';
+import { Settings } from '../../models/settings';
+import { SettingsService } from '../../service/settings.service';
 
 @Component({
   selector: 'app-dashboard-charts',
@@ -25,4 +32,14 @@ import { Skeleton } from 'primeng/skeleton';
 })
 export class DashboardChartsComponent {
   protocols = input.required<string[]>();
+  settings!: Settings;
+
+  private settingsService = inject(SettingsService);
+
+  constructor() {
+    this.settingsService.settings$.subscribe(settings => {
+      this.settings = settings;
+      console.log('Settings received in Dashboard:', this.settings);
+    });
+  }
 }
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.scss b/src/app/components/dashboard-settings/dashboard-settings.component.scss
index 712cfb4..b893759 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.scss
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.scss
@@ -29,9 +29,22 @@
         }
       }
     }
+
     ::ng-deep mat-slide-toggle {
         width: 25% !important;
     }
+    ::ng-deep .mat-mdc-slide-toggle.mat-mdc-slide-toggle-checked:not(.mat-disabled) .mdc-switch__shadow {
+      background-color: map.get(vars.$grey, 10);
+    }
+
+    ::ng-deep .mat-mdc-slide-toggle.mat-mdc-slide-toggle-checked:not(.mat-disabled) .mdc-switch__track::after {
+      background-color: vars.$textPrimary !important;
+    }
+
+    ::ng-deep .mdc-switch__track::before {
+      background-color: map.get(vars.$grey, 30) !important;
+    }
+
   }
   &__actions {
     border-radius: map.get(vars.$radius, 'xs');
@@ -48,19 +61,3 @@
     }
   }
 }
-
-
-::ng-deep .mat-mdc-slide-toggle.mat-mdc-slide-toggle-checked:not(.mat-disabled) .mdc-switch__shadow {
-  background-color: map.get(vars.$grey, 10);
-}
-
-::ng-deep .mat-mdc-slide-toggle.mat-mdc-slide-toggle-checked:not(.mat-disabled) .mdc-switch__track::after {
-  background-color: vars.$textPrimary !important;
-}
-
-::ng-deep .mdc-switch__track::before {
-  background-color: map.get(vars.$grey, 30) !important;
-}
-
-
-
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.ts b/src/app/components/dashboard-settings/dashboard-settings.component.ts
index dfff137..d264926 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.ts
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.ts
@@ -5,13 +5,14 @@ import {
   input,
   OnInit,
 } from '@angular/core';
-import { MatDialogModule } from '@angular/material/dialog';
+import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
 import { ToggleSwitchModule } from 'primeng/toggleswitch';
 import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { MatButtonModule } from '@angular/material/button';
 import { ButtonComponent } from '../button/button.component';
 import { SettingsService } from '../../service/settings.service';
 import { MatSlideToggle } from '@angular/material/slide-toggle';
+import { Settings, SettingsDto } from '../../models/settings';
 
 @Component({
   changeDetection: ChangeDetectionStrategy.OnPush,
@@ -29,41 +30,44 @@ import { MatSlideToggle } from '@angular/material/slide-toggle';
   templateUrl: './dashboard-settings.component.html',
 })
 export class DashboardSettingsComponent implements OnInit {
-  private formBuilder = inject(FormBuilder);
+  private formBuilder = inject(FormBuilder).nonNullable;
+
+  private dialogRef = inject(MatDialogRef<DashboardSettingsComponent>);
+
+  private settingsService = inject(SettingsService);
 
   settingsForm = this.formBuilder.group({
     statisticsColumns: this.formBuilder.group({
-      showTotalPackets: [true],
-      showPacketsPerSec: [true],
-      showTotalBytes: [true],
-      showBytesPerSec: [true],
+      showTotalPackets: [false],
+      showPacketsPerSec: [false],
+      showTotalBytes: [false],
+      showBytesPerSec: [false],
     }),
     statisticsRowsAndCharts: this.formBuilder.group({
-      showETH: [true],
-      showIPv4: [true],
-      showIPv6: [true],
-      showTCP: [true],
+      showETH: [false],
+      showIPv4: [false],
+      showIPv6: [false],
+      showTCP: [false],
     }),
     statisticsIR: this.formBuilder.group({
-      showMinValue: [true],
-      showMaxValue: [true],
-      showCurrentValue: [true],
+      showMinValue: [false],
+      showMaxValue: [false],
+      showCurrentValue: [false],
     }),
   });
 
-  private settingsService = inject(SettingsService);
-
   ngOnInit() {
-    const currentSettings = this.settingsForm.value;
+    const currentSettings = this.settingsService.getSettings();
     this.settingsForm.patchValue(currentSettings);
   }
 
   onSubmit() {
-    this.settingsService.updateSettings(this.settingsForm.value);
+    const settings: Settings = this.settingsForm.getRawValue();
+    this.settingsService.updateSettings(settings);
+    this.dialogRef.close();
   }
 
   onCancel() {
-    const currentSettings = this.settingsService.getSettings();
-    this.settingsForm.patchValue(currentSettings);
+    this.dialogRef.close();
   }
 }
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
index 46f5e53..29f8aa4 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
@@ -15,6 +15,7 @@ import { TimePipe } from '../../pipes/time.pipe';
 import { DecimalPipe } from '../../pipes/decimal.pipe';
 import { FormGroup, ReactiveFormsModule } from '@angular/forms';
 import { SettingsService } from '../../service/settings.service';
+import { Settings } from '../../models/settings';
 
 @Component({
   selector: 'app-dashboard-statistics',
@@ -24,7 +25,6 @@ import { SettingsService } from '../../service/settings.service';
     TimePipe,
     DecimalPipe,
     ReactiveFormsModule,
-    NgIf,
   ],
   templateUrl: './dashboard-statistics.component.html',
   styleUrl: './dashboard-statistics.component.scss',
@@ -32,7 +32,7 @@ import { SettingsService } from '../../service/settings.service';
 })
 export class DashboardStatisticsComponent implements OnInit {
   dashboardApi = inject(DashboardApi);
-  settings: any;
+  settings!: Settings;
 
   private settingsService = inject(SettingsService);
 
@@ -48,10 +48,6 @@ export class DashboardStatisticsComponent implements OnInit {
     shareReplay(1)
   );
 
-  get showETHSetting() {
-    return this.settings.value.statisticsRowsAndCharts.showETH;
-  }
-
   getPerSecond(value: number, time: Date): number {
     const totalSeconds = time.getTime() / 1000;
     return value / totalSeconds;
diff --git a/src/app/components/slide-toggle/slide-toggle.component.html b/src/app/components/slide-toggle/slide-toggle.component.html
deleted file mode 100644
index edb1a24..0000000
--- a/src/app/components/slide-toggle/slide-toggle.component.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<mat-slide-toggle
-  [hideIcon]="true">
-  <ng-content />
-</mat-slide-toggle>
diff --git a/src/app/components/slide-toggle/slide-toggle.component.scss b/src/app/components/slide-toggle/slide-toggle.component.scss
deleted file mode 100644
index 2ef9c9c..0000000
--- a/src/app/components/slide-toggle/slide-toggle.component.scss
+++ /dev/null
@@ -1,15 +0,0 @@
-@use '../../../vars';
-@use 'sass:map';
-
-::ng-deep .mat-mdc-slide-toggle.mat-mdc-slide-toggle-checked:not(.mat-disabled) .mdc-switch__shadow {
-  background-color: map.get(vars.$grey, 10);
-}
-
-::ng-deep .mat-mdc-slide-toggle.mat-mdc-slide-toggle-checked:not(.mat-disabled) .mdc-switch__track::after {
-  background-color: vars.$textPrimary !important;
-}
-
-::ng-deep .mdc-switch__track::before {
-  background-color: map.get(vars.$grey, 30) !important;
-}
-
diff --git a/src/app/components/slide-toggle/slide-toggle.component.ts b/src/app/components/slide-toggle/slide-toggle.component.ts
deleted file mode 100644
index 72ff668..0000000
--- a/src/app/components/slide-toggle/slide-toggle.component.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { Component } from '@angular/core';
-import { MatSlideToggle } from '@angular/material/slide-toggle';
-
-@Component({
-  selector: 'app-slide-toggle',
-  imports: [MatSlideToggle],
-  templateUrl: './slide-toggle.component.html',
-  styleUrl: './slide-toggle.component.scss',
-})
-export class SlideToggleComponent extends MatSlideToggle {}
diff --git a/src/app/models/settings.ts b/src/app/models/settings.ts
index 94d2134..cd24489 100644
--- a/src/app/models/settings.ts
+++ b/src/app/models/settings.ts
@@ -2,28 +2,20 @@ export type Settings = SettingsDto;
 
 export interface SettingsDto {
   statisticsColumns: {
-    showTotalPackets: true;
-    showPacketsPerSec: true;
-    showTotalBytes: true;
-    showBytesPerSec: true;
+    showTotalPackets: boolean;
+    showPacketsPerSec: boolean;
+    showTotalBytes: boolean;
+    showBytesPerSec: boolean;
   };
   statisticsRowsAndCharts: {
-    showETH: true;
-    showIPv4: true;
-    showIPv6: true;
-    showTCP: true;
+    showETH: boolean;
+    showIPv4: boolean;
+    showIPv6: boolean;
+    showTCP: boolean;
   };
   statisticsIR: {
-    showMinValue: true;
-    showMaxValue: true;
-    showCurrentValue: true;
+    showMinValue: boolean;
+    showMaxValue: boolean;
+    showCurrentValue: boolean;
   };
 }
-
-export function dtoToSettings(dto: SettingsDto): Settings {
-  return dto;
-}
-
-export function settingsToDto(settings: Settings): SettingsDto {
-  return settings;
-}
diff --git a/src/app/service/settings.service.ts b/src/app/service/settings.service.ts
index fb59cb2..4f7be8b 100644
--- a/src/app/service/settings.service.ts
+++ b/src/app/service/settings.service.ts
@@ -2,34 +2,34 @@ import { Injectable, OnInit } from '@angular/core';
 import { BehaviorSubject } from 'rxjs';
 import { Settings } from '../models/settings';
 
+const DEFAULT_SETTINGS: Settings = {
+  statisticsColumns: {
+    showTotalPackets: true,
+    showPacketsPerSec: true,
+    showTotalBytes: true,
+    showBytesPerSec: true,
+  },
+  statisticsRowsAndCharts: {
+    showETH: true,
+    showIPv4: true,
+    showIPv6: true,
+    showTCP: true,
+  },
+  statisticsIR: {
+    showMinValue: true,
+    showMaxValue: true,
+    showCurrentValue: true,
+  },
+};
+
 @Injectable({
   providedIn: 'root',
 })
-export class SettingsService implements OnInit {
-  private settingsSubject = new BehaviorSubject<any>({
-    statisticsColumns: {
-      showTotalPackets: true,
-      showPacketsPerSec: true,
-      showTotalBytes: true,
-      showBytesPerSec: true,
-    },
-    statisticsRowsAndCharts: {
-      showETH: true,
-      showIPv4: true,
-      showIPv6: true,
-      showTCP: true,
-    },
-    statisticsIR: {
-      showMinValue: true,
-      showMaxValue: true,
-      showCurrentValue: true,
-    },
-  });
+export class SettingsService {
+  private settingsSubject = new BehaviorSubject<Settings>(DEFAULT_SETTINGS);
   settings$ = this.settingsSubject.asObservable();
 
-  ngOnInit() {}
-
-  updateSettings(settings: any) {
+  updateSettings(settings: Settings) {
     this.settingsSubject.next(settings);
   }
 
-- 
GitLab


From d6d7a9abf950c1fe88ea2d69998f9d71e7d24d2f Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Mon, 24 Mar 2025 10:59:20 +0100
Subject: [PATCH 06/14] mod: hiding statistics is now working consistently

---
 .../dashboard-settings.component.ts           |   3 +-
 .../dashboard-statistics.component.html       | 101 +++++++++---------
 .../dashboard-statistics.component.ts         |  34 +++++-
 3 files changed, 84 insertions(+), 54 deletions(-)

diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.ts b/src/app/components/dashboard-settings/dashboard-settings.component.ts
index d264926..65a044a 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.ts
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.ts
@@ -2,7 +2,6 @@ import {
   ChangeDetectionStrategy,
   Component,
   inject,
-  input,
   OnInit,
 } from '@angular/core';
 import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
@@ -12,7 +11,7 @@ import { MatButtonModule } from '@angular/material/button';
 import { ButtonComponent } from '../button/button.component';
 import { SettingsService } from '../../service/settings.service';
 import { MatSlideToggle } from '@angular/material/slide-toggle';
-import { Settings, SettingsDto } from '../../models/settings';
+import { Settings } from '../../models/settings';
 
 @Component({
   changeDetection: ChangeDetectionStrategy.OnPush,
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.html b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
index f40e325..bf8dc88 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.html
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
@@ -11,7 +11,7 @@
       <div class="statistics__table__time">
         <p>Total time: {{ statistics.total_time | time }} </p>
       </div>
-      @if (settings?.statisticsRowsAndCharts?.showETH) {
+      @if (showAnyStatisticsColumn && showStatisticsRowsAndCharts) {
         <table class="statistics__table__header">
           <thead class="statistics__table__header-title">
           <tr>
@@ -30,59 +30,61 @@
             }
           </tr>
           </thead>
+          @if (settings?.statisticsRowsAndCharts?.showETH) {
+            <tbody>
+              @let protocolEth = getETHStatistics(statistics.protocols);
+            <tr class="statistics__table__header-eth">
+              <td>{{ protocolEth.name }}</td>
+              @if (settings?.statisticsColumns?.showTotalPackets) {
+                <td>{{ protocolEth.total_packets | decimal }}</td>
+              }
+              @if (settings?.statisticsColumns?.showPacketsPerSec) {
+                <td>
+                  {{ getPerSecond(protocolEth.total_packets, statistics.total_time) | decimal }}
+                </td>
+              }
+              @if (settings?.statisticsColumns?.showTotalBytes) {
+                <td>{{ protocolEth.total_bytes | decimal }}</td>
+              }
+              @if (settings?.statisticsColumns?.showBytesPerSec) {
+                <td>
+                  {{ getPerSecond(protocolEth.total_bytes, statistics.total_time) | decimal }}
+                </td>
+              }
+            </tr>
+            </tbody>
+          }
+        </table>
+
+        <table class="statistics__table__protocols">
           <tbody>
-            @let protocolEth = getETHStatistics(statistics.protocols);
-          <tr class="statistics__table__header-eth">
-            <td>{{ protocolEth.name }}</td>
-            @if (settings?.statisticsColumns?.showTotalPackets) {
-              <td>{{ protocolEth.total_packets | decimal }}</td>
-            }
-            @if (settings?.statisticsColumns?.showPacketsPerSec) {
-              <td>
-                {{ getPerSecond(protocolEth.total_packets, statistics.total_time) | decimal }}
-              </td>
-            }
-            @if (settings?.statisticsColumns?.showTotalBytes) {
-              <td>{{ protocolEth.total_bytes | decimal }}</td>
-            }
-            @if (settings?.statisticsColumns?.showBytesPerSec) {
-              <td>
-                {{ getPerSecond(protocolEth.total_bytes, statistics.total_time) | decimal }}
-              </td>
+            @for (protocol of getProtocols(statistics.protocols); track protocol.name) {
+              @if (showProtocolRow(protocol.name)) {
+                <tr>
+                  <td>{{ protocol.name }}</td>
+                  @if (settings?.statisticsColumns?.showTotalPackets) {
+                    <td>{{ protocol.total_packets | decimal }}</td>
+                  }
+                  @if (settings?.statisticsColumns?.showPacketsPerSec) {
+                    <td>
+                      {{ getPerSecond(protocol.total_packets, statistics.total_time) | decimal }}
+                    </td>
+                  }
+                  @if (settings?.statisticsColumns?.showTotalBytes) {
+                    <td>{{ protocol.total_bytes | decimal }}</td>
+                  }
+                  @if (settings?.statisticsColumns?.showBytesPerSec) {
+                    <td>
+                      {{ getPerSecond(protocol.total_bytes, statistics.total_time) | decimal }}
+                    </td>
+                  }
+                </tr>
+              }
             }
-          </tr>
           </tbody>
         </table>
       }
-      <table class="statistics__table__protocols">
-        <tbody>
-          @for (protocol of getProtocols(statistics.protocols); track protocol.name) {
-            @if (settings?.statisticsRowsAndCharts?.showIPv4 && protocol.name === 'IPv4' ||
-            settings?.statisticsRowsAndCharts?.showIPv6 && protocol.name === 'IPv6' ||
-            settings?.statisticsRowsAndCharts?.showTCP && protocol.name === 'TCP') {
-              <tr>
-                <td>{{ protocol.name }}</td>
-                @if (settings?.statisticsColumns?.showTotalPackets) {
-                  <td>{{ protocol.total_packets | decimal }}</td>
-                }
-                @if (settings?.statisticsColumns?.showPacketsPerSec) {
-                  <td>
-                    {{ getPerSecond(protocol.total_packets, statistics.total_time) | decimal }}
-                  </td>
-                }
-                @if (settings?.statisticsColumns?.showTotalBytes) {
-                  <td>{{ protocol.total_bytes | decimal }}</td>
-                }
-                @if (settings?.statisticsColumns?.showBytesPerSec) {
-                  <td>
-                    {{ getPerSecond(protocol.total_bytes, statistics.total_time) | decimal }}
-                  </td>
-                }
-              </tr>
-            }
-          }
-        </tbody>
-      </table>
+      @if (showInformationRate) {
       <table class="statistics__table__ir">
         <thead class="statistics__table__ir-header">
         <tr>
@@ -113,6 +115,7 @@
         </tr>
         </tbody>
       </table>
+      }
     </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 29f8aa4..7afcf20 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
@@ -2,18 +2,17 @@ import {
   ChangeDetectionStrategy,
   Component,
   inject,
-  Input,
   OnInit,
 } from '@angular/core';
 import { NgxSkeletonLoaderComponent } from 'ngx-skeleton-loader';
-import { AsyncPipe, NgIf } from '@angular/common';
+import { AsyncPipe } from '@angular/common';
 import { DashboardApi } from '../../api/dashboard.api';
 
 import { interval, shareReplay, switchMap } from 'rxjs';
 import { ProtocolStatistics } from '../../models/dashboard-statistics';
 import { TimePipe } from '../../pipes/time.pipe';
 import { DecimalPipe } from '../../pipes/decimal.pipe';
-import { FormGroup, ReactiveFormsModule } from '@angular/forms';
+import { ReactiveFormsModule } from '@angular/forms';
 import { SettingsService } from '../../service/settings.service';
 import { Settings } from '../../models/settings';
 
@@ -60,4 +59,33 @@ export class DashboardStatisticsComponent implements OnInit {
   getProtocols(protocols: ProtocolStatistics[]): ProtocolStatistics[] {
     return protocols.filter(protocol => protocol.name !== 'ETH');
   }
+
+  get showAnyStatisticsColumn(): boolean {
+    const cols = this.settings?.statisticsColumns;
+    return (
+      cols?.showBytesPerSec ||
+      cols?.showPacketsPerSec ||
+      cols?.showTotalBytes ||
+      cols?.showTotalPackets
+    );
+  }
+
+  get showStatisticsRowsAndCharts(): boolean {
+    const rows = this.settings?.statisticsRowsAndCharts;
+    return rows?.showETH || rows?.showIPv4 || rows?.showIPv6 || rows?.showTCP;
+  }
+
+  get showInformationRate(): boolean {
+    const ir = this.settings?.statisticsIR;
+    return ir?.showMinValue || ir?.showMaxValue || ir?.showCurrentValue;
+  }
+
+  showProtocolRow(protocolName: string): boolean {
+    const rows = this.settings?.statisticsRowsAndCharts;
+    return (
+      (rows?.showIPv4 && protocolName === 'IPv4') ||
+      (rows?.showIPv6 && protocolName === 'IPv6') ||
+      (rows?.showTCP && protocolName === 'TCP')
+    );
+  }
 }
-- 
GitLab


From 0547da48556ab3a2eee466dc78bfe1054494f8a9 Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Mon, 24 Mar 2025 17:54:21 +0100
Subject: [PATCH 07/14] feat: create dahsboard-settings form builder

---
 .../dashboard-charts.component.html           |  2 +-
 .../dashboard-charts.component.ts             |  4 +-
 .../dashboard-settings.builder.ts             | 67 +++++++++++++++++++
 .../dashboard-settings.component.html         | 30 ++++-----
 .../dashboard-settings.component.ts           | 48 ++++++-------
 .../dashboard-statistics.component.html       | 38 +++++------
 .../dashboard-statistics.component.ts         | 12 ++--
 src/app/models/settings.ts                    | 30 ++++-----
 src/app/service/settings.service.ts           | 32 ++++-----
 9 files changed, 159 insertions(+), 104 deletions(-)
 create mode 100644 src/app/components/dashboard-settings/dashboard-settings.builder.ts

diff --git a/src/app/components/dashboard-charts/dashboard-charts.component.html b/src/app/components/dashboard-charts/dashboard-charts.component.html
index b47c127..6e8dd56 100644
--- a/src/app/components/dashboard-charts/dashboard-charts.component.html
+++ b/src/app/components/dashboard-charts/dashboard-charts.component.html
@@ -1,5 +1,5 @@
 <mat-tab-group>
-  @if (settings?.statisticsRowsAndCharts?.showETH) {
+  @if (settings?.showETH) {
   <mat-tab label="Frames">
     <app-dashboard-chart-frames />
   </mat-tab>
diff --git a/src/app/components/dashboard-charts/dashboard-charts.component.ts b/src/app/components/dashboard-charts/dashboard-charts.component.ts
index 6ae5547..f2d0bbd 100644
--- a/src/app/components/dashboard-charts/dashboard-charts.component.ts
+++ b/src/app/components/dashboard-charts/dashboard-charts.component.ts
@@ -37,9 +37,9 @@ export class DashboardChartsComponent {
   private settingsService = inject(SettingsService);
 
   constructor() {
-    this.settingsService.settings$.subscribe(settings => {
+    this.settingsService.settingsObserver$.subscribe(settings => {
       this.settings = settings;
-      console.log('Settings received in Dashboard:', this.settings);
+      console.log('Settings received in charts:', this.settings);
     });
   }
 }
diff --git a/src/app/components/dashboard-settings/dashboard-settings.builder.ts b/src/app/components/dashboard-settings/dashboard-settings.builder.ts
new file mode 100644
index 0000000..cbb0caa
--- /dev/null
+++ b/src/app/components/dashboard-settings/dashboard-settings.builder.ts
@@ -0,0 +1,67 @@
+import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
+import { inject, Injectable } from '@angular/core';
+import { Settings } from '../../models/settings';
+
+export type SettingsForm = FormGroup<{
+  showTotalPackets: FormControl<boolean>;
+  showPacketsPerSec: FormControl<boolean>;
+  showTotalBytes: FormControl<boolean>;
+  showBytesPerSec: FormControl<boolean>;
+
+  showETH: FormControl<boolean>;
+  showIPv4: FormControl<boolean>;
+  showIPv6: FormControl<boolean>;
+  showTCP: FormControl<boolean>;
+
+  showMinValue: FormControl<boolean>;
+  showMaxValue: FormControl<boolean>;
+  showCurrentValue: FormControl<boolean>;
+}>;
+
+@Injectable({
+  providedIn: 'root',
+})
+export class SettingsFormBuilder {
+  formBuilder = inject(FormBuilder);
+
+  create(settings?: Settings): SettingsForm {
+    const fb = this.formBuilder.nonNullable;
+
+    return fb.group({
+      showTotalPackets: fb.control<boolean>(settings?.showTotalPackets || true),
+      showPacketsPerSec: fb.control<boolean>(
+        settings?.showPacketsPerSec || true
+      ),
+      showTotalBytes: fb.control<boolean>(settings?.showTotalBytes || true),
+      showBytesPerSec: fb.control<boolean>(settings?.showBytesPerSec || true),
+
+      showETH: fb.control<boolean>(settings?.showETH || true),
+      showIPv4: fb.control<boolean>(settings?.showIPv4 || true),
+      showIPv6: fb.control<boolean>(settings?.showIPv6 || true),
+      showTCP: fb.control<boolean>(settings?.showTCP || true),
+
+      showMinValue: fb.control<boolean>(settings?.showMinValue || true),
+      showMaxValue: fb.control<boolean>(settings?.showMaxValue || true),
+      showCurrentValue: fb.control<boolean>(settings?.showCurrentValue || true),
+    });
+  }
+
+  toValue(form: SettingsForm): Settings {
+    const data = form.value;
+    return <Settings>{
+      showTotalPackets: data.showTotalPackets ?? true,
+      showPacketsPerSec: data.showPacketsPerSec ?? true,
+      showTotalBytes: data.showTotalBytes ?? true,
+      showBytesPerSec: data.showBytesPerSec ?? true,
+
+      showETH: data.showETH ?? true,
+      showIPv4: data.showIPv4 ?? true,
+      showIPv6: data.showIPv6 ?? true,
+      showTCP: data.showTCP ?? true,
+
+      showMinValue: data.showMinValue ?? true,
+      showMaxValue: data.showMaxValue ?? true,
+      showCurrentValue: data.showCurrentValue ?? true,
+    };
+  }
+}
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.html b/src/app/components/dashboard-settings/dashboard-settings.component.html
index bddf167..3b5756c 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.html
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.html
@@ -1,36 +1,36 @@
-<div class="dialog" [formGroup]="settingsForm">
+<div class="dialog" [formGroup]="form">
   <h2 mat-dialog-title class="dialog__header">Settings</h2>
   <mat-dialog-content class="dialog__content">
-    <div formGroupName="statisticsColumns" class="dialog__content__statistics__columns">
+    <div class="dialog__content__statistics__columns">
       <div class="dialog__content__statistics__columns-title">
         Statistics columns
       </div>
       <div class="dialog__content__statistics__columns-content">
-        <mat-slide-toggle [hideIcon]="true" formControlName="showTotalPackets">Total packets</mat-slide-toggle>
-        <mat-slide-toggle [hideIcon]="true" formControlName="showPacketsPerSec">Packets per seconds</mat-slide-toggle>
-        <mat-slide-toggle [hideIcon]="true" formControlName="showTotalBytes">Total bytes</mat-slide-toggle>
-        <mat-slide-toggle [hideIcon]="true" formControlName="showBytesPerSec">Bytes per second</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" [formControl]="form.controls.showTotalPackets">Total packets</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" [formControl]="form.controls.showPacketsPerSec">Packets per seconds</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" [formControl]="form.controls.showTotalBytes">Total bytes</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" [formControl]="form.controls.showBytesPerSec">Bytes per second</mat-slide-toggle>
       </div>
     </div>
-    <div formGroupName="statisticsRowsAndCharts" class="dialog__content__statistics__rows">
+    <div class="dialog__content__statistics__rows">
       <div class="dialog__content__statistics__rows-title">
         Statistics rows & charts
       </div>
       <div class="dialog__content__statistics__rows-content">
-        <mat-slide-toggle [hideIcon]="true" formControlName="showETH">ETH</mat-slide-toggle>
-        <mat-slide-toggle [hideIcon]="true" formControlName="showIPv4">IPv4</mat-slide-toggle>
-        <mat-slide-toggle [hideIcon]="true" formControlName="showIPv6">IPv6</mat-slide-toggle>
-        <mat-slide-toggle [hideIcon]="true" formControlName="showTCP">TCP</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" [formControl]="form.controls.showETH">ETH</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" [formControl]="form.controls.showIPv4">IPv4</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" [formControl]="form.controls.showIPv6">IPv6</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" [formControl]="form.controls.showTCP">TCP</mat-slide-toggle>
       </div>
     </div>
-    <div formGroupName="statisticsIR" class="dialog__content__statistics__ir">
+    <div class="dialog__content__statistics__ir">
       <div class="dialog__content__statistics__ir-title">
         Information Rate
       </div>
       <div class="dialog__content__statistics__ir-content">
-        <mat-slide-toggle [hideIcon]="true" formControlName="showMinValue">Min value</mat-slide-toggle>
-        <mat-slide-toggle [hideIcon]="true" formControlName="showMaxValue">Max value</mat-slide-toggle>
-        <mat-slide-toggle [hideIcon]="true" formControlName="showCurrentValue">Current value</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" [formControl]="form.controls.showMinValue">Min value</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" [formControl]="form.controls.showMaxValue">Max value</mat-slide-toggle>
+        <mat-slide-toggle [hideIcon]="true" [formControl]="form.controls.showCurrentValue">Current value</mat-slide-toggle>
       </div>
     </div>
   </mat-dialog-content>
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.ts b/src/app/components/dashboard-settings/dashboard-settings.component.ts
index 65a044a..3acffaa 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.ts
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.ts
@@ -2,16 +2,21 @@ import {
   ChangeDetectionStrategy,
   Component,
   inject,
+  input,
   OnInit,
 } from '@angular/core';
 import { MatDialogModule, MatDialogRef } from '@angular/material/dialog';
 import { ToggleSwitchModule } from 'primeng/toggleswitch';
-import { FormBuilder, FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { MatButtonModule } from '@angular/material/button';
 import { ButtonComponent } from '../button/button.component';
 import { SettingsService } from '../../service/settings.service';
 import { MatSlideToggle } from '@angular/material/slide-toggle';
 import { Settings } from '../../models/settings';
+import {
+  SettingsForm,
+  SettingsFormBuilder,
+} from './dashboard-settings.builder';
 
 @Component({
   changeDetection: ChangeDetectionStrategy.OnPush,
@@ -29,39 +34,30 @@ import { Settings } from '../../models/settings';
   templateUrl: './dashboard-settings.component.html',
 })
 export class DashboardSettingsComponent implements OnInit {
-  private formBuilder = inject(FormBuilder).nonNullable;
-
-  private dialogRef = inject(MatDialogRef<DashboardSettingsComponent>);
+  settingsFormBuilder = inject(SettingsFormBuilder);
+  settings = input<Settings>();
+  form!: SettingsForm;
 
-  private settingsService = inject(SettingsService);
+  dialogRef = inject(MatDialogRef<DashboardSettingsComponent>);
 
-  settingsForm = this.formBuilder.group({
-    statisticsColumns: this.formBuilder.group({
-      showTotalPackets: [false],
-      showPacketsPerSec: [false],
-      showTotalBytes: [false],
-      showBytesPerSec: [false],
-    }),
-    statisticsRowsAndCharts: this.formBuilder.group({
-      showETH: [false],
-      showIPv4: [false],
-      showIPv6: [false],
-      showTCP: [false],
-    }),
-    statisticsIR: this.formBuilder.group({
-      showMinValue: [false],
-      showMaxValue: [false],
-      showCurrentValue: [false],
-    }),
-  });
+  settingsService = inject(SettingsService);
 
   ngOnInit() {
+    this.initializeForm();
+    this.loadSettings();
+  }
+
+  initializeForm() {
+    this.form = this.settingsFormBuilder.create(this.settings());
+  }
+
+  loadSettings() {
     const currentSettings = this.settingsService.getSettings();
-    this.settingsForm.patchValue(currentSettings);
+    this.form.patchValue(currentSettings);
   }
 
   onSubmit() {
-    const settings: Settings = this.settingsForm.getRawValue();
+    const settings: Settings = this.settingsFormBuilder.toValue(this.form);
     this.settingsService.updateSettings(settings);
     this.dialogRef.close();
   }
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.html b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
index bf8dc88..d7d6096 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.html
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
@@ -16,37 +16,37 @@
           <thead class="statistics__table__header-title">
           <tr>
             <th></th>
-            @if (settings?.statisticsColumns?.showTotalPackets) {
+            @if (settings?.showTotalPackets) {
               <th>Total packets</th>
             }
-            @if (settings?.statisticsColumns?.showPacketsPerSec) {
+            @if (settings?.showPacketsPerSec) {
               <th>Packets per second</th>
             }
-            @if (settings?.statisticsColumns?.showTotalBytes) {
+            @if (settings?.showTotalBytes) {
               <th>Total bytes</th>
             }
-            @if (settings?.statisticsColumns?.showBytesPerSec) {
+            @if (settings?.showBytesPerSec) {
               <th>Bytes per second</th>
             }
           </tr>
           </thead>
-          @if (settings?.statisticsRowsAndCharts?.showETH) {
+          @if (settings?.showETH) {
             <tbody>
               @let protocolEth = getETHStatistics(statistics.protocols);
             <tr class="statistics__table__header-eth">
               <td>{{ protocolEth.name }}</td>
-              @if (settings?.statisticsColumns?.showTotalPackets) {
+              @if (settings?.showTotalPackets) {
                 <td>{{ protocolEth.total_packets | decimal }}</td>
               }
-              @if (settings?.statisticsColumns?.showPacketsPerSec) {
+              @if (settings?.showPacketsPerSec) {
                 <td>
                   {{ getPerSecond(protocolEth.total_packets, statistics.total_time) | decimal }}
                 </td>
               }
-              @if (settings?.statisticsColumns?.showTotalBytes) {
+              @if (settings?.showTotalBytes) {
                 <td>{{ protocolEth.total_bytes | decimal }}</td>
               }
-              @if (settings?.statisticsColumns?.showBytesPerSec) {
+              @if (settings?.showBytesPerSec) {
                 <td>
                   {{ getPerSecond(protocolEth.total_bytes, statistics.total_time) | decimal }}
                 </td>
@@ -62,18 +62,18 @@
               @if (showProtocolRow(protocol.name)) {
                 <tr>
                   <td>{{ protocol.name }}</td>
-                  @if (settings?.statisticsColumns?.showTotalPackets) {
+                  @if (settings?.showTotalPackets) {
                     <td>{{ protocol.total_packets | decimal }}</td>
                   }
-                  @if (settings?.statisticsColumns?.showPacketsPerSec) {
+                  @if (settings?.showPacketsPerSec) {
                     <td>
                       {{ getPerSecond(protocol.total_packets, statistics.total_time) | decimal }}
                     </td>
                   }
-                  @if (settings?.statisticsColumns?.showTotalBytes) {
+                  @if (settings?.showTotalBytes) {
                     <td>{{ protocol.total_bytes | decimal }}</td>
                   }
-                  @if (settings?.statisticsColumns?.showBytesPerSec) {
+                  @if (settings?.showBytesPerSec) {
                     <td>
                       {{ getPerSecond(protocol.total_bytes, statistics.total_time) | decimal }}
                     </td>
@@ -89,13 +89,13 @@
         <thead class="statistics__table__ir-header">
         <tr>
           <th></th>
-          @if (settings?.statisticsIR?.showMinValue) {
+          @if (settings?.showMinValue) {
             <th>Min</th>
           }
-          @if (settings?.statisticsIR?.showMaxValue) {
+          @if (settings?.showMaxValue) {
             <th>Max</th>
           }
-          @if (settings?.statisticsIR?.showCurrentValue) {
+          @if (settings?.showCurrentValue) {
             <th>Current</th>
           }
         </tr>
@@ -103,13 +103,13 @@
         <tbody>
         <tr class="statistics__table_ir-content">
           <td>Information Rate</td>
-          @if (settings?.statisticsIR?.showMinValue) {
+          @if (settings?.showMinValue) {
             <td>{{ statistics.information_rate.min | decimal }}</td>
           }
-          @if (settings?.statisticsIR?.showMaxValue) {
+          @if (settings?.showMaxValue) {
             <td>{{ statistics.information_rate.max | decimal }}</td>
           }
-          @if (settings?.statisticsIR?.showCurrentValue) {
+          @if (settings?.showCurrentValue) {
             <td>{{ statistics.information_rate.current | decimal }}</td>
           }
         </tr>
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
index 7afcf20..ba39e03 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
@@ -33,10 +33,10 @@ export class DashboardStatisticsComponent implements OnInit {
   dashboardApi = inject(DashboardApi);
   settings!: Settings;
 
-  private settingsService = inject(SettingsService);
+  settingsService = inject(SettingsService);
 
   ngOnInit() {
-    this.settingsService.settings$.subscribe(settings => {
+    this.settingsService.settingsObserver$.subscribe(settings => {
       this.settings = settings;
       console.log('Settings received in Dashboard:', this.settings);
     });
@@ -61,7 +61,7 @@ export class DashboardStatisticsComponent implements OnInit {
   }
 
   get showAnyStatisticsColumn(): boolean {
-    const cols = this.settings?.statisticsColumns;
+    const cols = this.settings;
     return (
       cols?.showBytesPerSec ||
       cols?.showPacketsPerSec ||
@@ -71,17 +71,17 @@ export class DashboardStatisticsComponent implements OnInit {
   }
 
   get showStatisticsRowsAndCharts(): boolean {
-    const rows = this.settings?.statisticsRowsAndCharts;
+    const rows = this.settings;
     return rows?.showETH || rows?.showIPv4 || rows?.showIPv6 || rows?.showTCP;
   }
 
   get showInformationRate(): boolean {
-    const ir = this.settings?.statisticsIR;
+    const ir = this.settings;
     return ir?.showMinValue || ir?.showMaxValue || ir?.showCurrentValue;
   }
 
   showProtocolRow(protocolName: string): boolean {
-    const rows = this.settings?.statisticsRowsAndCharts;
+    const rows = this.settings;
     return (
       (rows?.showIPv4 && protocolName === 'IPv4') ||
       (rows?.showIPv6 && protocolName === 'IPv6') ||
diff --git a/src/app/models/settings.ts b/src/app/models/settings.ts
index cd24489..09e4e13 100644
--- a/src/app/models/settings.ts
+++ b/src/app/models/settings.ts
@@ -1,21 +1,17 @@
 export type Settings = SettingsDto;
 
 export interface SettingsDto {
-  statisticsColumns: {
-    showTotalPackets: boolean;
-    showPacketsPerSec: boolean;
-    showTotalBytes: boolean;
-    showBytesPerSec: boolean;
-  };
-  statisticsRowsAndCharts: {
-    showETH: boolean;
-    showIPv4: boolean;
-    showIPv6: boolean;
-    showTCP: boolean;
-  };
-  statisticsIR: {
-    showMinValue: boolean;
-    showMaxValue: boolean;
-    showCurrentValue: boolean;
-  };
+  showTotalPackets: boolean;
+  showPacketsPerSec: boolean;
+  showTotalBytes: boolean;
+  showBytesPerSec: boolean;
+
+  showETH: boolean;
+  showIPv4: boolean;
+  showIPv6: boolean;
+  showTCP: boolean;
+
+  showMinValue: boolean;
+  showMaxValue: boolean;
+  showCurrentValue: boolean;
 }
diff --git a/src/app/service/settings.service.ts b/src/app/service/settings.service.ts
index 4f7be8b..8c8d3e1 100644
--- a/src/app/service/settings.service.ts
+++ b/src/app/service/settings.service.ts
@@ -3,23 +3,19 @@ import { BehaviorSubject } from 'rxjs';
 import { Settings } from '../models/settings';
 
 const DEFAULT_SETTINGS: Settings = {
-  statisticsColumns: {
-    showTotalPackets: true,
-    showPacketsPerSec: true,
-    showTotalBytes: true,
-    showBytesPerSec: true,
-  },
-  statisticsRowsAndCharts: {
-    showETH: true,
-    showIPv4: true,
-    showIPv6: true,
-    showTCP: true,
-  },
-  statisticsIR: {
-    showMinValue: true,
-    showMaxValue: true,
-    showCurrentValue: true,
-  },
+  showTotalPackets: true,
+  showPacketsPerSec: true,
+  showTotalBytes: true,
+  showBytesPerSec: true,
+
+  showETH: true,
+  showIPv4: true,
+  showIPv6: true,
+  showTCP: true,
+
+  showMinValue: true,
+  showMaxValue: true,
+  showCurrentValue: true,
 };
 
 @Injectable({
@@ -27,7 +23,7 @@ const DEFAULT_SETTINGS: Settings = {
 })
 export class SettingsService {
   private settingsSubject = new BehaviorSubject<Settings>(DEFAULT_SETTINGS);
-  settings$ = this.settingsSubject.asObservable();
+  settingsObserver$ = this.settingsSubject.asObservable();
 
   updateSettings(settings: Settings) {
     this.settingsSubject.next(settings);
-- 
GitLab


From 6952e22d5cd8d747b258d5046007ebd4368a058d Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Mon, 24 Mar 2025 18:05:26 +0100
Subject: [PATCH 08/14] feat: make the charts responsive to the settings

---
 .../dashboard-charts.component.html           | 23 +++++++++++--------
 .../dashboard-charts.component.ts             |  9 ++++++++
 2 files changed, 22 insertions(+), 10 deletions(-)

diff --git a/src/app/components/dashboard-charts/dashboard-charts.component.html b/src/app/components/dashboard-charts/dashboard-charts.component.html
index 6e8dd56..8360ae8 100644
--- a/src/app/components/dashboard-charts/dashboard-charts.component.html
+++ b/src/app/components/dashboard-charts/dashboard-charts.component.html
@@ -1,18 +1,21 @@
 <mat-tab-group>
   @if (settings?.showETH) {
-  <mat-tab label="Frames">
-    <app-dashboard-chart-frames />
-  </mat-tab>
+    <mat-tab label="Frames">
+      <app-dashboard-chart-frames />
+    </mat-tab>
   }
-  <mat-tab label="Information Rate">
-    <app-dashboard-chart-information-rate />
-  </mat-tab>
-  @for (protocol of protocols(); track $index) {
-
-    <mat-tab [label]="protocol">
-      <app-dashboard-chart-protocol [protocolName]="protocol" />
+  @if (settings?.showCurrentValue || settings?.showMaxValue || settings?.showMinValue) {
+    <mat-tab label="Information Rate">
+      <app-dashboard-chart-information-rate />
     </mat-tab>
   }
+  @for (protocol of protocols(); track $index) {
+    @if (showProtocolChart(protocol)) {
+      <mat-tab [label]="protocol">
+        <app-dashboard-chart-protocol [protocolName]="protocol" />
+      </mat-tab>
+    }
+  }
 </mat-tab-group>
 
 <!--@todo: find other way to fix scrolling to the top of the page-->
diff --git a/src/app/components/dashboard-charts/dashboard-charts.component.ts b/src/app/components/dashboard-charts/dashboard-charts.component.ts
index f2d0bbd..a332749 100644
--- a/src/app/components/dashboard-charts/dashboard-charts.component.ts
+++ b/src/app/components/dashboard-charts/dashboard-charts.component.ts
@@ -42,4 +42,13 @@ export class DashboardChartsComponent {
       console.log('Settings received in charts:', this.settings);
     });
   }
+
+  showProtocolChart(protocolName: string): boolean {
+    const rows = this.settings;
+    return (
+      (rows?.showIPv4 && protocolName === 'ipv4') ||
+      (rows?.showIPv6 && protocolName === 'ipv6') ||
+      (rows?.showTCP && protocolName === 'tcp')
+    );
+  }
 }
-- 
GitLab


From 4987385629b6ba666ebf4af0c76d066a727d1822 Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Mon, 24 Mar 2025 18:11:32 +0100
Subject: [PATCH 09/14] mod: remove debugging console log messages

---
 .../components/dashboard-charts/dashboard-charts.component.ts   | 1 -
 .../dashboard-statistics/dashboard-statistics.component.scss    | 1 +
 .../dashboard-statistics/dashboard-statistics.component.ts      | 1 -
 src/app/service/settings.service.ts                             | 2 +-
 4 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/app/components/dashboard-charts/dashboard-charts.component.ts b/src/app/components/dashboard-charts/dashboard-charts.component.ts
index a332749..91d3680 100644
--- a/src/app/components/dashboard-charts/dashboard-charts.component.ts
+++ b/src/app/components/dashboard-charts/dashboard-charts.component.ts
@@ -39,7 +39,6 @@ export class DashboardChartsComponent {
   constructor() {
     this.settingsService.settingsObserver$.subscribe(settings => {
       this.settings = settings;
-      console.log('Settings received in charts:', this.settings);
     });
   }
 
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.scss b/src/app/components/dashboard-statistics/dashboard-statistics.component.scss
index 1814cde..6c25990 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.scss
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.scss
@@ -6,6 +6,7 @@
     display: flex;
     flex-direction: row;
     gap: map.get(vars.$spacing, 'md');
+
     ::ng-deep * {
       height: 50px;
     }
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
index ba39e03..df46c05 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
@@ -38,7 +38,6 @@ export class DashboardStatisticsComponent implements OnInit {
   ngOnInit() {
     this.settingsService.settingsObserver$.subscribe(settings => {
       this.settings = settings;
-      console.log('Settings received in Dashboard:', this.settings);
     });
   }
 
diff --git a/src/app/service/settings.service.ts b/src/app/service/settings.service.ts
index 8c8d3e1..77ad00c 100644
--- a/src/app/service/settings.service.ts
+++ b/src/app/service/settings.service.ts
@@ -1,4 +1,4 @@
-import { Injectable, OnInit } from '@angular/core';
+import { Injectable } from '@angular/core';
 import { BehaviorSubject } from 'rxjs';
 import { Settings } from '../models/settings';
 
-- 
GitLab


From 0907b37a042644361eb2844aa9adb9443db7d1a2 Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Thu, 27 Mar 2025 12:10:36 +0100
Subject: [PATCH 10/14] mod: review changes

---
 src/app/api/configuration.api.ts              | 31 ++++++++-
 .../dashboard-charts.component.html           | 21 ++++---
 .../dashboard-charts.component.ts             | 28 ++++-----
 .../dashboard-settings.builder.ts             | 63 +++++++++----------
 .../dashboard-settings.component.html         |  8 ++-
 .../dashboard-settings.component.scss         |  6 +-
 .../dashboard-settings.component.ts           | 17 ++---
 .../dashboard-statistics.component.html       | 49 ++++++++-------
 .../dashboard-statistics.component.ts         | 46 +++++---------
 .../dashboard/dashboard.component.ts          | 45 ++++++++-----
 .../interceptor/mocks/configuration-1.json    |  4 +-
 .../interceptor/mocks/configuration-2.json    |  2 +-
 src/app/interceptor/mocks/configurations.json |  6 +-
 .../mocks/dashboard-statistics-2.json         |  2 +-
 .../mocks/dashboard-statistics.json           |  2 +-
 src/app/models/settings.ts                    |  8 +--
 src/app/service/settings.service.ts           | 53 +++++++++-------
 17 files changed, 216 insertions(+), 175 deletions(-)

diff --git a/src/app/api/configuration.api.ts b/src/app/api/configuration.api.ts
index fd761e3..2d778cd 100644
--- a/src/app/api/configuration.api.ts
+++ b/src/app/api/configuration.api.ts
@@ -1,6 +1,6 @@
 import { inject, Injectable } from '@angular/core';
 import { HttpClient } from '@angular/common/http';
-import { map, Observable, tap } from 'rxjs';
+import { map, mergeMap, Observable, tap } from 'rxjs';
 import {
   Configuration,
   ConfigurationDto,
@@ -9,7 +9,7 @@ import {
 } from '../models/configuration';
 import { ApiResponse } from '../models/api-response';
 
-export const CONFIGURATION_API_URL = '/api/configurations';
+export const CONFIGURATION_API_URL = '/api/configuration';
 
 @Injectable({
   providedIn: 'root',
@@ -23,6 +23,33 @@ export class ConfigurationApi {
       .pipe(map(dto => dto.data.map(dtoToConfiguration)));
   }
 
+  fetchAppliedConfiguration(): Observable<Configuration> {
+    return this.httpClient
+      .get<ApiResponse<ConfigurationDto[]>>(CONFIGURATION_API_URL)
+      .pipe(
+        map(dto => dto.data),
+
+        map(configurations => {
+          const appliedConfiguration = configurations.find(
+            dto => dto.is_applied
+          );
+
+          if (!appliedConfiguration) {
+            throw new Error('No applied configuration found');
+          }
+          return appliedConfiguration.id;
+        }),
+
+        mergeMap(appliedConfigId => {
+          return this.httpClient
+            .get<
+              ApiResponse<ConfigurationDto>
+            >(`${CONFIGURATION_API_URL}/${appliedConfigId}`)
+            .pipe(map(dto => dtoToConfiguration(dto.data)));
+        })
+      );
+  }
+
   find(configName: string): Observable<Configuration> {
     return this.httpClient
       .get<
diff --git a/src/app/components/dashboard-charts/dashboard-charts.component.html b/src/app/components/dashboard-charts/dashboard-charts.component.html
index 8360ae8..ea0113f 100644
--- a/src/app/components/dashboard-charts/dashboard-charts.component.html
+++ b/src/app/components/dashboard-charts/dashboard-charts.component.html
@@ -1,22 +1,27 @@
+@let settings = settings$ | async;
+
+@if (settings) {
 <mat-tab-group>
-  @if (settings?.showETH) {
+  @if (settings.showETH) {
     <mat-tab label="Frames">
       <app-dashboard-chart-frames />
     </mat-tab>
   }
-  @if (settings?.showCurrentValue || settings?.showMaxValue || settings?.showMinValue) {
+  @if (settings.showCurrentValue) {
     <mat-tab label="Information Rate">
       <app-dashboard-chart-information-rate />
     </mat-tab>
   }
-  @for (protocol of protocols(); track $index) {
-    @if (showProtocolChart(protocol)) {
-      <mat-tab [label]="protocol">
-        <app-dashboard-chart-protocol [protocolName]="protocol" />
-      </mat-tab>
+  @if (settings.protocols) {
+    @for (protocol of protocols(); track $index) {
+      @if ((protocols$ | async)?.includes(protocol)) {
+        <mat-tab [label]="protocol">
+          <app-dashboard-chart-protocol [protocolName]="protocol" />
+        </mat-tab>
+     }
     }
   }
 </mat-tab-group>
-
+}
 <!--@todo: find other way to fix scrolling to the top of the page-->
 <p-skeleton height="300px" />
diff --git a/src/app/components/dashboard-charts/dashboard-charts.component.ts b/src/app/components/dashboard-charts/dashboard-charts.component.ts
index 91d3680..059f6c8 100644
--- a/src/app/components/dashboard-charts/dashboard-charts.component.ts
+++ b/src/app/components/dashboard-charts/dashboard-charts.component.ts
@@ -13,6 +13,9 @@ import { FormsModule } from '@angular/forms';
 import { Skeleton } from 'primeng/skeleton';
 import { Settings } from '../../models/settings';
 import { SettingsService } from '../../service/settings.service';
+import { map, Observable } from 'rxjs';
+import { AsyncPipe } from '@angular/common';
+import { ProtocolStatistics } from '../../models/dashboard-statistics';
 
 @Component({
   selector: 'app-dashboard-charts',
@@ -25,6 +28,7 @@ import { SettingsService } from '../../service/settings.service';
     SliderModule,
     FormsModule,
     Skeleton,
+    AsyncPipe,
   ],
   templateUrl: './dashboard-charts.component.html',
   styleUrl: './dashboard-charts.component.scss',
@@ -32,22 +36,14 @@ import { SettingsService } from '../../service/settings.service';
 })
 export class DashboardChartsComponent {
   protocols = input.required<string[]>();
-  settings!: Settings;
-
   private settingsService = inject(SettingsService);
+  settings$: Observable<Settings> = this.settingsService.settings$;
 
-  constructor() {
-    this.settingsService.settingsObserver$.subscribe(settings => {
-      this.settings = settings;
-    });
-  }
-
-  showProtocolChart(protocolName: string): boolean {
-    const rows = this.settings;
-    return (
-      (rows?.showIPv4 && protocolName === 'ipv4') ||
-      (rows?.showIPv6 && protocolName === 'ipv6') ||
-      (rows?.showTCP && protocolName === 'tcp')
-    );
-  }
+  protocols$: Observable<string[]> = this.settingsService.settings$.pipe(
+    map(settings =>
+      Object.keys(settings.protocols || {})
+        .filter(key => settings.protocols[key])
+        .map(key => key.toLowerCase())
+    )
+  );
 }
diff --git a/src/app/components/dashboard-settings/dashboard-settings.builder.ts b/src/app/components/dashboard-settings/dashboard-settings.builder.ts
index cbb0caa..048c153 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.builder.ts
+++ b/src/app/components/dashboard-settings/dashboard-settings.builder.ts
@@ -1,6 +1,8 @@
 import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
 import { inject, Injectable } from '@angular/core';
 import { Settings } from '../../models/settings';
+import { interval, shareReplay, switchMap } from 'rxjs';
+import { DashboardApi } from '../../api/dashboard.api';
 
 export type SettingsForm = FormGroup<{
   showTotalPackets: FormControl<boolean>;
@@ -9,9 +11,7 @@ export type SettingsForm = FormGroup<{
   showBytesPerSec: FormControl<boolean>;
 
   showETH: FormControl<boolean>;
-  showIPv4: FormControl<boolean>;
-  showIPv6: FormControl<boolean>;
-  showTCP: FormControl<boolean>;
+  protocols: FormGroup<{ [key: string]: FormControl<boolean> }>;
 
   showMinValue: FormControl<boolean>;
   showMaxValue: FormControl<boolean>;
@@ -24,44 +24,39 @@ export type SettingsForm = FormGroup<{
 export class SettingsFormBuilder {
   formBuilder = inject(FormBuilder);
 
-  create(settings?: Settings): SettingsForm {
+  createDefaultForm(protocols: string[]): SettingsForm {
     const fb = this.formBuilder.nonNullable;
 
-    return fb.group({
-      showTotalPackets: fb.control<boolean>(settings?.showTotalPackets || true),
-      showPacketsPerSec: fb.control<boolean>(
-        settings?.showPacketsPerSec || true
+    const protocolControls = protocols.reduce(
+      (acc, protocolName) => {
+        acc[protocolName] = new FormControl<boolean>(true, {
+          nonNullable: true,
+        });
+        return acc;
+      },
+      {} as { [key: string]: FormControl<boolean> }
+    );
+
+    const form = fb.group({
+      showTotalPackets: fb.control<boolean>(true),
+      showPacketsPerSec: fb.control<boolean>(true),
+      showTotalBytes: fb.control<boolean>(true),
+      showBytesPerSec: fb.control<boolean>(true),
+
+      showETH: fb.control<boolean>(true),
+      protocols: fb.group<{ [key: string]: FormControl<boolean> }>(
+        protocolControls
       ),
-      showTotalBytes: fb.control<boolean>(settings?.showTotalBytes || true),
-      showBytesPerSec: fb.control<boolean>(settings?.showBytesPerSec || true),
 
-      showETH: fb.control<boolean>(settings?.showETH || true),
-      showIPv4: fb.control<boolean>(settings?.showIPv4 || true),
-      showIPv6: fb.control<boolean>(settings?.showIPv6 || true),
-      showTCP: fb.control<boolean>(settings?.showTCP || true),
-
-      showMinValue: fb.control<boolean>(settings?.showMinValue || true),
-      showMaxValue: fb.control<boolean>(settings?.showMaxValue || true),
-      showCurrentValue: fb.control<boolean>(settings?.showCurrentValue || true),
+      showMinValue: fb.control<boolean>(true),
+      showMaxValue: fb.control<boolean>(true),
+      showCurrentValue: fb.control<boolean>(true),
     });
+
+    return form;
   }
 
   toValue(form: SettingsForm): Settings {
-    const data = form.value;
-    return <Settings>{
-      showTotalPackets: data.showTotalPackets ?? true,
-      showPacketsPerSec: data.showPacketsPerSec ?? true,
-      showTotalBytes: data.showTotalBytes ?? true,
-      showBytesPerSec: data.showBytesPerSec ?? true,
-
-      showETH: data.showETH ?? true,
-      showIPv4: data.showIPv4 ?? true,
-      showIPv6: data.showIPv6 ?? true,
-      showTCP: data.showTCP ?? true,
-
-      showMinValue: data.showMinValue ?? true,
-      showMaxValue: data.showMaxValue ?? true,
-      showCurrentValue: data.showCurrentValue ?? true,
-    };
+    return form.getRawValue();
   }
 }
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.html b/src/app/components/dashboard-settings/dashboard-settings.component.html
index 3b5756c..6ea1fa3 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.html
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.html
@@ -18,9 +18,11 @@
       </div>
       <div class="dialog__content__statistics__rows-content">
         <mat-slide-toggle [hideIcon]="true" [formControl]="form.controls.showETH">ETH</mat-slide-toggle>
-        <mat-slide-toggle [hideIcon]="true" [formControl]="form.controls.showIPv4">IPv4</mat-slide-toggle>
-        <mat-slide-toggle [hideIcon]="true" [formControl]="form.controls.showIPv6">IPv6</mat-slide-toggle>
-        <mat-slide-toggle [hideIcon]="true" [formControl]="form.controls.showTCP">TCP</mat-slide-toggle>
+          @for (entry of Object.entries(form.controls.protocols.controls); track $index) {
+            <mat-slide-toggle [hideIcon]="true" [formControl]="entry[1]">{{
+                entry[0]
+              }}</mat-slide-toggle>
+          }
       </div>
     </div>
     <div class="dialog__content__statistics__ir">
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.scss b/src/app/components/dashboard-settings/dashboard-settings.component.scss
index b893759..04e2056 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.scss
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.scss
@@ -48,10 +48,9 @@
   }
   &__actions {
     border-radius: map.get(vars.$radius, 'xs');
-    padding: map.get(vars.$spacing, 'xxl') 0 map.get(vars.$spacing, 'xl') 0;
+    padding: map.get(vars.$spacing, 'xxl') map.get(vars.$spacing, 'xl') map.get(vars.$spacing, 'xl') map.get(vars.$spacing, 'xl');
     display: flex;
-    justify-content: center;
-    gap: 150px;
+    justify-content: space-between;
 
     ::ng-deep app-button {
       button {
@@ -61,3 +60,4 @@
     }
   }
 }
+
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.ts b/src/app/components/dashboard-settings/dashboard-settings.component.ts
index 3acffaa..c34a6d9 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.ts
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.ts
@@ -35,23 +35,22 @@ import {
 })
 export class DashboardSettingsComponent implements OnInit {
   settingsFormBuilder = inject(SettingsFormBuilder);
-  settings = input<Settings>();
-  form!: SettingsForm;
 
   dialogRef = inject(MatDialogRef<DashboardSettingsComponent>);
 
   settingsService = inject(SettingsService);
+  form!: SettingsForm;
 
   ngOnInit() {
-    this.initializeForm();
-    this.loadSettings();
-  }
+    this.settingsService.settings$.subscribe(settings => {
+      const protocols = Object.keys(settings.protocols);
+      this.form = this.settingsFormBuilder.createDefaultForm(protocols);
 
-  initializeForm() {
-    this.form = this.settingsFormBuilder.create(this.settings());
+      this.initializeForm();
+    });
   }
 
-  loadSettings() {
+  initializeForm() {
     const currentSettings = this.settingsService.getSettings();
     this.form.patchValue(currentSettings);
   }
@@ -65,4 +64,6 @@ export class DashboardSettingsComponent implements OnInit {
   onCancel() {
     this.dialogRef.close();
   }
+
+  protected readonly Object = Object;
 }
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.html b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
index d7d6096..f508b0e 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.html
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
@@ -7,46 +7,48 @@
       }
     </div>
   } @else {
+    @let settings = settings$ | async;
+    @if (settings) {
     <div class="statistics__table">
       <div class="statistics__table__time">
         <p>Total time: {{ statistics.total_time | time }} </p>
       </div>
-      @if (showAnyStatisticsColumn && showStatisticsRowsAndCharts) {
+      @if (showAnyStatisticsColumn(settings) && showStatisticsRowsAndCharts(settings)) {
         <table class="statistics__table__header">
           <thead class="statistics__table__header-title">
           <tr>
             <th></th>
-            @if (settings?.showTotalPackets) {
+            @if (settings.showTotalPackets) {
               <th>Total packets</th>
             }
-            @if (settings?.showPacketsPerSec) {
+            @if (settings.showPacketsPerSec) {
               <th>Packets per second</th>
             }
-            @if (settings?.showTotalBytes) {
+            @if (settings.showTotalBytes) {
               <th>Total bytes</th>
             }
-            @if (settings?.showBytesPerSec) {
+            @if (settings.showBytesPerSec) {
               <th>Bytes per second</th>
             }
           </tr>
           </thead>
-          @if (settings?.showETH) {
+          @if (settings.showETH) {
             <tbody>
               @let protocolEth = getETHStatistics(statistics.protocols);
             <tr class="statistics__table__header-eth">
               <td>{{ protocolEth.name }}</td>
-              @if (settings?.showTotalPackets) {
+              @if (settings.showTotalPackets) {
                 <td>{{ protocolEth.total_packets | decimal }}</td>
               }
-              @if (settings?.showPacketsPerSec) {
+              @if (settings.showPacketsPerSec) {
                 <td>
                   {{ getPerSecond(protocolEth.total_packets, statistics.total_time) | decimal }}
                 </td>
               }
-              @if (settings?.showTotalBytes) {
+              @if (settings.showTotalBytes) {
                 <td>{{ protocolEth.total_bytes | decimal }}</td>
               }
-              @if (settings?.showBytesPerSec) {
+              @if (settings.showBytesPerSec) {
                 <td>
                   {{ getPerSecond(protocolEth.total_bytes, statistics.total_time) | decimal }}
                 </td>
@@ -59,43 +61,43 @@
         <table class="statistics__table__protocols">
           <tbody>
             @for (protocol of getProtocols(statistics.protocols); track protocol.name) {
-              @if (showProtocolRow(protocol.name)) {
+                @if(settings.protocols[protocol.name]) {
                 <tr>
                   <td>{{ protocol.name }}</td>
-                  @if (settings?.showTotalPackets) {
+                  @if (settings.showTotalPackets) {
                     <td>{{ protocol.total_packets | decimal }}</td>
                   }
-                  @if (settings?.showPacketsPerSec) {
+                  @if (settings.showPacketsPerSec) {
                     <td>
                       {{ getPerSecond(protocol.total_packets, statistics.total_time) | decimal }}
                     </td>
                   }
-                  @if (settings?.showTotalBytes) {
+                  @if (settings.showTotalBytes) {
                     <td>{{ protocol.total_bytes | decimal }}</td>
                   }
-                  @if (settings?.showBytesPerSec) {
+                  @if (settings.showBytesPerSec) {
                     <td>
                       {{ getPerSecond(protocol.total_bytes, statistics.total_time) | decimal }}
                     </td>
                   }
                 </tr>
-              }
+                }
             }
           </tbody>
         </table>
       }
-      @if (showInformationRate) {
+      @if (showInformationRate(settings!)) {
       <table class="statistics__table__ir">
         <thead class="statistics__table__ir-header">
         <tr>
           <th></th>
-          @if (settings?.showMinValue) {
+          @if (settings.showMinValue) {
             <th>Min</th>
           }
-          @if (settings?.showMaxValue) {
+          @if (settings.showMaxValue) {
             <th>Max</th>
           }
-          @if (settings?.showCurrentValue) {
+          @if (settings.showCurrentValue) {
             <th>Current</th>
           }
         </tr>
@@ -103,13 +105,13 @@
         <tbody>
         <tr class="statistics__table_ir-content">
           <td>Information Rate</td>
-          @if (settings?.showMinValue) {
+          @if (settings.showMinValue) {
             <td>{{ statistics.information_rate.min | decimal }}</td>
           }
-          @if (settings?.showMaxValue) {
+          @if (settings.showMaxValue) {
             <td>{{ statistics.information_rate.max | decimal }}</td>
           }
-          @if (settings?.showCurrentValue) {
+          @if (settings.showCurrentValue) {
             <td>{{ statistics.information_rate.current | decimal }}</td>
           }
         </tr>
@@ -117,5 +119,6 @@
       </table>
       }
     </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 df46c05..13fe0cb 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
@@ -8,7 +8,7 @@ import { NgxSkeletonLoaderComponent } from 'ngx-skeleton-loader';
 import { AsyncPipe } from '@angular/common';
 import { DashboardApi } from '../../api/dashboard.api';
 
-import { interval, shareReplay, switchMap } from 'rxjs';
+import { interval, Observable, shareReplay, switchMap } from 'rxjs';
 import { ProtocolStatistics } from '../../models/dashboard-statistics';
 import { TimePipe } from '../../pipes/time.pipe';
 import { DecimalPipe } from '../../pipes/decimal.pipe';
@@ -29,17 +29,10 @@ import { Settings } from '../../models/settings';
   styleUrl: './dashboard-statistics.component.scss',
   changeDetection: ChangeDetectionStrategy.OnPush,
 })
-export class DashboardStatisticsComponent implements OnInit {
+export class DashboardStatisticsComponent {
   dashboardApi = inject(DashboardApi);
-  settings!: Settings;
-
   settingsService = inject(SettingsService);
-
-  ngOnInit() {
-    this.settingsService.settingsObserver$.subscribe(settings => {
-      this.settings = settings;
-    });
-  }
+  settings$: Observable<Settings> = this.settingsService.settings$;
 
   dashboardStatistics = interval(1000).pipe(
     switchMap(() => this.dashboardApi.fetchStatistics()),
@@ -59,32 +52,27 @@ export class DashboardStatisticsComponent implements OnInit {
     return protocols.filter(protocol => protocol.name !== 'ETH');
   }
 
-  get showAnyStatisticsColumn(): boolean {
-    const cols = this.settings;
+  showAnyStatisticsColumn(settings: Settings): boolean {
     return (
-      cols?.showBytesPerSec ||
-      cols?.showPacketsPerSec ||
-      cols?.showTotalBytes ||
-      cols?.showTotalPackets
+      settings.showBytesPerSec ||
+      settings.showPacketsPerSec ||
+      settings.showTotalBytes ||
+      settings.showTotalPackets
     );
   }
 
-  get showStatisticsRowsAndCharts(): boolean {
-    const rows = this.settings;
-    return rows?.showETH || rows?.showIPv4 || rows?.showIPv6 || rows?.showTCP;
-  }
-
-  get showInformationRate(): boolean {
-    const ir = this.settings;
-    return ir?.showMinValue || ir?.showMaxValue || ir?.showCurrentValue;
+  showStatisticsRowsAndCharts(settings: Settings): boolean {
+    return (
+      settings.showETH ||
+      Object.values(settings.protocols).some(v => v === true)
+    );
   }
 
-  showProtocolRow(protocolName: string): boolean {
-    const rows = this.settings;
+  showInformationRate(settings: Settings): boolean {
     return (
-      (rows?.showIPv4 && protocolName === 'IPv4') ||
-      (rows?.showIPv6 && protocolName === 'IPv6') ||
-      (rows?.showTCP && protocolName === 'TCP')
+      settings.showMinValue ||
+      settings.showMaxValue ||
+      settings.showCurrentValue
     );
   }
 }
diff --git a/src/app/components/dashboard/dashboard.component.ts b/src/app/components/dashboard/dashboard.component.ts
index 2638312..de8f32d 100644
--- a/src/app/components/dashboard/dashboard.component.ts
+++ b/src/app/components/dashboard/dashboard.component.ts
@@ -1,18 +1,20 @@
-import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
+import {
+  ChangeDetectionStrategy,
+  Component,
+  inject,
+  OnInit,
+} from '@angular/core';
 import { PageWrapperComponent } from '../page-wrapper/page-wrapper.component';
 import { MatExpansionModule } from '@angular/material/expansion';
 import { MatIcon } from '@angular/material/icon';
-import { MatButtonModule, MatFabButton } from '@angular/material/button';
+import { MatFabButton } from '@angular/material/button';
 import { DashboardStatisticsComponent } from '../dashboard-statistics/dashboard-statistics.component';
 import { DashboardChartsComponent } from '../dashboard-charts/dashboard-charts.component';
-import {
-  MatDialog,
-  MatDialogActions,
-  MatDialogClose,
-  MatDialogContent,
-  MatDialogTitle,
-} from '@angular/material/dialog';
+import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
 import { DashboardSettingsComponent } from '../dashboard-settings/dashboard-settings.component';
+import { ConfigurationApi } from '../../api/configuration.api';
+import { SettingsService } from '../../service/settings.service';
+import { map, Observable } from 'rxjs';
 
 @Component({
   selector: 'app-dashboard',
@@ -28,13 +30,28 @@ import { DashboardSettingsComponent } from '../dashboard-settings/dashboard-sett
   styleUrl: './dashboard.component.scss',
   changeDetection: ChangeDetectionStrategy.OnPush,
 })
-export class DashboardComponent {
+export class DashboardComponent implements OnInit {
   readonly dialog = inject(MatDialog);
 
-  openSettings() {
-    this.dialog.open(DashboardSettingsComponent, {
-      minWidth: '1100px',
-      minHeight: '550px',
+  configurationApi = inject(ConfigurationApi);
+  settingsService = inject(SettingsService);
+
+  ngOnInit() {
+    this.configurationApi.fetchAppliedConfiguration().subscribe(config => {
+      if (config) {
+        this.settingsService.initSettings(config.protocols);
+      } else {
+        console.error('Failed to fetch configuration');
+      }
     });
   }
+
+  openSettings() {
+    const config = new MatDialogConfig();
+
+    config.minWidth = '1100px';
+    config.minHeight = '550px';
+
+    this.dialog.open(DashboardSettingsComponent, config);
+  }
 }
diff --git a/src/app/interceptor/mocks/configuration-1.json b/src/app/interceptor/mocks/configuration-1.json
index 6e97131..93c1d9b 100644
--- a/src/app/interceptor/mocks/configuration-1.json
+++ b/src/app/interceptor/mocks/configuration-1.json
@@ -2,7 +2,7 @@
   "data": {
     "id": "1abc",
     "name": "Custom",
-    "is_applied": false,
+    "is_applied": true,
     "mac_source": [
       "01:23:45:67:89:00",
       "01:23:45:67:89:11",
@@ -19,6 +19,6 @@
       [128, 255],
       [1024, 1518]
     ],
-    "protocols": ["IPv4", "IP6", "UDP"]
+    "protocols": ["IPv4", "IPv6", "UDP"]
   }
 }
diff --git a/src/app/interceptor/mocks/configuration-2.json b/src/app/interceptor/mocks/configuration-2.json
index d18ca94..f047b8b 100644
--- a/src/app/interceptor/mocks/configuration-2.json
+++ b/src/app/interceptor/mocks/configuration-2.json
@@ -2,7 +2,7 @@
   "data": {
     "id": "2def",
     "name": "Everything",
-    "is_applied": true,
+    "is_applied": false,
     "mac_source": [],
     "mac_destination": [],
     "frame_ranges": [],
diff --git a/src/app/interceptor/mocks/configurations.json b/src/app/interceptor/mocks/configurations.json
index b1ed282..e7de125 100644
--- a/src/app/interceptor/mocks/configurations.json
+++ b/src/app/interceptor/mocks/configurations.json
@@ -3,7 +3,7 @@
     {
       "id": "1abc",
       "name": "Custom",
-      "is_applied": false,
+      "is_applied": true,
       "mac_source": [
         "01:23:45:67:89:00",
         "01:23:45:67:89:11",
@@ -20,12 +20,12 @@
         [128, 255],
         [1024, 1518]
       ],
-      "protocols": ["IPv4", "IP6", "UDP"]
+      "protocols": ["IPv4", "IPv6", "UDP"]
     },
     {
       "id": "2def",
       "name": "Everything",
-      "is_applied": true,
+      "is_applied": false,
       "mac_source": [],
       "mac_destination": [],
       "frame_ranges": [],
diff --git a/src/app/interceptor/mocks/dashboard-statistics-2.json b/src/app/interceptor/mocks/dashboard-statistics-2.json
index 9d58d0f..08e38b5 100644
--- a/src/app/interceptor/mocks/dashboard-statistics-2.json
+++ b/src/app/interceptor/mocks/dashboard-statistics-2.json
@@ -9,7 +9,7 @@
         "total-bytes": 123678901
       },
       {
-        "name": "TCP",
+        "name": "UDP",
         "total-packets": 323344,
         "total-bytes": 32112345
       },
diff --git a/src/app/interceptor/mocks/dashboard-statistics.json b/src/app/interceptor/mocks/dashboard-statistics.json
index b05d511..d9b9013 100644
--- a/src/app/interceptor/mocks/dashboard-statistics.json
+++ b/src/app/interceptor/mocks/dashboard-statistics.json
@@ -9,7 +9,7 @@
           "total-bytes": 123456789
         },
         {
-          "name": "TCP",
+          "name": "UDP",
           "total-packets": 321312,
           "total-bytes": 32143245
         },
diff --git a/src/app/models/settings.ts b/src/app/models/settings.ts
index 09e4e13..79a2ce6 100644
--- a/src/app/models/settings.ts
+++ b/src/app/models/settings.ts
@@ -1,15 +1,11 @@
-export type Settings = SettingsDto;
-
-export interface SettingsDto {
+export interface Settings {
   showTotalPackets: boolean;
   showPacketsPerSec: boolean;
   showTotalBytes: boolean;
   showBytesPerSec: boolean;
 
   showETH: boolean;
-  showIPv4: boolean;
-  showIPv6: boolean;
-  showTCP: boolean;
+  protocols: { [key: string]: boolean };
 
   showMinValue: boolean;
   showMaxValue: boolean;
diff --git a/src/app/service/settings.service.ts b/src/app/service/settings.service.ts
index 77ad00c..46b34db 100644
--- a/src/app/service/settings.service.ts
+++ b/src/app/service/settings.service.ts
@@ -1,35 +1,46 @@
-import { Injectable } from '@angular/core';
-import { BehaviorSubject } from 'rxjs';
+import { inject, Injectable } from '@angular/core';
+import {
+  BehaviorSubject,
+  interval,
+  shareReplay,
+  Subject,
+  switchMap,
+} from 'rxjs';
 import { Settings } from '../models/settings';
-
-const DEFAULT_SETTINGS: Settings = {
-  showTotalPackets: true,
-  showPacketsPerSec: true,
-  showTotalBytes: true,
-  showBytesPerSec: true,
-
-  showETH: true,
-  showIPv4: true,
-  showIPv6: true,
-  showTCP: true,
-
-  showMinValue: true,
-  showMaxValue: true,
-  showCurrentValue: true,
-};
+import { SettingsFormBuilder } from '../components/dashboard-settings/dashboard-settings.builder';
 
 @Injectable({
   providedIn: 'root',
 })
 export class SettingsService {
-  private settingsSubject = new BehaviorSubject<Settings>(DEFAULT_SETTINGS);
-  settingsObserver$ = this.settingsSubject.asObservable();
+  settingsFormBuilder = inject(SettingsFormBuilder);
+
+  private settingsSubject = new BehaviorSubject<Settings>({
+    showBytesPerSec: true,
+    showPacketsPerSec: true,
+    showTotalBytes: true,
+    showTotalPackets: true,
+    showETH: true,
+    protocols: {},
+    showMinValue: true,
+    showMaxValue: true,
+    showCurrentValue: true,
+  });
+
+  settings$ = this.settingsSubject.asObservable();
+
+  initSettings(protocols: string[]) {
+    const defaultSettings = this.settingsFormBuilder.toValue(
+      this.settingsFormBuilder.createDefaultForm(protocols)
+    );
+    this.settingsSubject.next(defaultSettings);
+  }
 
   updateSettings(settings: Settings) {
     this.settingsSubject.next(settings);
   }
 
-  getSettings() {
+  getSettings(): Settings {
     return this.settingsSubject.value;
   }
 }
-- 
GitLab


From cb9cc9737f3662c279a00203189a585a97d956ff Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Thu, 27 Mar 2025 12:15:18 +0100
Subject: [PATCH 11/14] mod: change dashboard-statistics styling

---
 .../dashboard-settings/dashboard-settings.component.scss   | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.scss b/src/app/components/dashboard-settings/dashboard-settings.component.scss
index 04e2056..b3de426 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.scss
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.scss
@@ -18,11 +18,15 @@
       &__columns,
       &__rows,
       &__ir {
+
         &-title {
           font-size: map.get(vars.$text, 'xl');
           padding: map.get(vars.$spacing, 'xxl') 0 map.get(vars.$spacing, 'sm') 0;
         }
         &-content {
+          display: grid;
+          grid-template-columns: repeat(4, 1fr);
+
           border-radius: map.get(vars.$radius, 'xs');
           background-color: map.get(vars.$grey, 10);
           padding: map.get(vars.$spacing, 'sm') 0 map.get(vars.$spacing, 'sm') map.get(vars.$spacing, 'xxl');
@@ -30,9 +34,6 @@
       }
     }
 
-    ::ng-deep mat-slide-toggle {
-        width: 25% !important;
-    }
     ::ng-deep .mat-mdc-slide-toggle.mat-mdc-slide-toggle-checked:not(.mat-disabled) .mdc-switch__shadow {
       background-color: map.get(vars.$grey, 10);
     }
-- 
GitLab


From 5dfc7e39c8e2ab93b6d53de3cdd8815bb8f69fdf Mon Sep 17 00:00:00 2001
From: Ruslan Rabadanov <ruslanrabadanov2101@gmail.com>
Date: Thu, 27 Mar 2025 20:10:03 +0100
Subject: [PATCH 12/14] Fix: http returns unpredicted objects for current
 protocol record; Refactor: replace observables with signals

---
 src/app/api/dashboard.api.ts                  |   7 +-
 .../dashboard-chart-protocol.component.ts     |  10 +-
 .../dashboard-charts.component.html           |  22 +-
 .../dashboard-charts.component.ts             |  22 +-
 .../dashboard-statistics.component.html       | 229 ++++++++++--------
 .../dashboard-statistics.component.ts         |  13 +-
 .../dashboard/dashboard.component.html        |  15 +-
 .../dashboard/dashboard.component.ts          |   6 +-
 src/app/interceptor/interceptor.ts            |   4 +-
 src/app/interceptor/mock-interceptor.ts       |   2 +-
 10 files changed, 174 insertions(+), 156 deletions(-)

diff --git a/src/app/api/dashboard.api.ts b/src/app/api/dashboard.api.ts
index 3168c8b..3573fa3 100644
--- a/src/app/api/dashboard.api.ts
+++ b/src/app/api/dashboard.api.ts
@@ -1,6 +1,6 @@
 import { ApiResponse } from '../models/api-response';
 import { ChartFrames } from '../models/chart-frames';
-import { map, Observable, tap } from 'rxjs';
+import { filter, map, Observable } from 'rxjs';
 import { ChartInformationRate } from '../models/chart-information-rate';
 import { ChartProtocol } from '../models/chart-protocol';
 import { inject, Injectable } from '@angular/core';
@@ -88,6 +88,9 @@ export class DashboardApi {
       .get<
         ApiResponse<ChartProtocol>
       >(`${DASHBOARD_API_URL}/${protocolName}/current`)
-      .pipe(map(response => response.data));
+      .pipe(
+        map((response): ChartProtocol => response.data),
+        filter(d => d.packets !== undefined && d.bytes !== undefined) // for some reason, the HTTP client returns object of type Settings instead of ChartProtocol
+      );
   }
 }
diff --git a/src/app/components/dashboard-chart-protocol/dashboard-chart-protocol.component.ts b/src/app/components/dashboard-chart-protocol/dashboard-chart-protocol.component.ts
index aae9f5d..5a6edf2 100644
--- a/src/app/components/dashboard-chart-protocol/dashboard-chart-protocol.component.ts
+++ b/src/app/components/dashboard-chart-protocol/dashboard-chart-protocol.component.ts
@@ -42,7 +42,9 @@ export class DashboardChartProtocolComponent {
   protocolHistory = signal<ChartProtocol[]>([]);
   data = computed(() => {
     const protocols = this.protocolHistory();
-    if (!protocols) return;
+
+    if (!protocols.length) return;
+
     return this.#chartService.getProtocolChartDataConfig(
       protocols,
       this.recordsInterval()
@@ -69,11 +71,11 @@ export class DashboardChartProtocolComponent {
           ),
           shareReplay(1)
         )
-        .subscribe(ir => {
+        .subscribe(cp => {
           this.protocolHistory.update(protocols => {
             if (protocols.length < this.recordsLimit())
-              return [...protocols, ir];
-            return [...protocols.splice(1), ir];
+              return [...protocols, cp];
+            return [...protocols.splice(1), cp];
           });
         });
     });
diff --git a/src/app/components/dashboard-charts/dashboard-charts.component.html b/src/app/components/dashboard-charts/dashboard-charts.component.html
index ea0113f..26951b6 100644
--- a/src/app/components/dashboard-charts/dashboard-charts.component.html
+++ b/src/app/components/dashboard-charts/dashboard-charts.component.html
@@ -1,27 +1,17 @@
-@let settings = settings$ | async;
-
-@if (settings) {
 <mat-tab-group>
-  @if (settings.showETH) {
+  @if (settings().showETH) {
     <mat-tab label="Frames">
       <app-dashboard-chart-frames />
     </mat-tab>
   }
-  @if (settings.showCurrentValue) {
+  @if (settings().showCurrentValue) {
     <mat-tab label="Information Rate">
       <app-dashboard-chart-information-rate />
     </mat-tab>
   }
-  @if (settings.protocols) {
-    @for (protocol of protocols(); track $index) {
-      @if ((protocols$ | async)?.includes(protocol)) {
-        <mat-tab [label]="protocol">
-          <app-dashboard-chart-protocol [protocolName]="protocol" />
-        </mat-tab>
-     }
-    }
+  @for (protocol of protocols(); track $index) {
+    <mat-tab [label]="protocol">
+      <app-dashboard-chart-protocol [protocolName]="protocol" />
+    </mat-tab>
   }
 </mat-tab-group>
-}
-<!--@todo: find other way to fix scrolling to the top of the page-->
-<p-skeleton height="300px" />
diff --git a/src/app/components/dashboard-charts/dashboard-charts.component.ts b/src/app/components/dashboard-charts/dashboard-charts.component.ts
index 059f6c8..c8f4455 100644
--- a/src/app/components/dashboard-charts/dashboard-charts.component.ts
+++ b/src/app/components/dashboard-charts/dashboard-charts.component.ts
@@ -1,7 +1,7 @@
 import {
   ChangeDetectionStrategy,
   Component,
-  inject,
+  computed,
   input,
 } from '@angular/core';
 import { MatTab, MatTabGroup } from '@angular/material/tabs';
@@ -10,12 +10,7 @@ import { DashboardChartInformationRateComponent } from '../dashboard-chart-infor
 import { DashboardChartProtocolComponent } from '../dashboard-chart-protocol/dashboard-chart-protocol.component';
 import { SliderModule } from 'primeng/slider';
 import { FormsModule } from '@angular/forms';
-import { Skeleton } from 'primeng/skeleton';
 import { Settings } from '../../models/settings';
-import { SettingsService } from '../../service/settings.service';
-import { map, Observable } from 'rxjs';
-import { AsyncPipe } from '@angular/common';
-import { ProtocolStatistics } from '../../models/dashboard-statistics';
 
 @Component({
   selector: 'app-dashboard-charts',
@@ -27,23 +22,16 @@ import { ProtocolStatistics } from '../../models/dashboard-statistics';
     DashboardChartProtocolComponent,
     SliderModule,
     FormsModule,
-    Skeleton,
-    AsyncPipe,
   ],
   templateUrl: './dashboard-charts.component.html',
   styleUrl: './dashboard-charts.component.scss',
   changeDetection: ChangeDetectionStrategy.OnPush,
 })
 export class DashboardChartsComponent {
-  protocols = input.required<string[]>();
-  private settingsService = inject(SettingsService);
-  settings$: Observable<Settings> = this.settingsService.settings$;
-
-  protocols$: Observable<string[]> = this.settingsService.settings$.pipe(
-    map(settings =>
-      Object.keys(settings.protocols || {})
-        .filter(key => settings.protocols[key])
-        .map(key => key.toLowerCase())
+  settings = input.required<Settings>();
+  protocols = computed(() =>
+    Object.keys(this.settings().protocols).filter(
+      key => this.settings().protocols[key]
     )
   );
 }
diff --git a/src/app/components/dashboard-statistics/dashboard-statistics.component.html b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
index f508b0e..d00a3ab 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.html
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.html
@@ -7,118 +7,143 @@
       }
     </div>
   } @else {
-    @let settings = settings$ | async;
-    @if (settings) {
-    <div class="statistics__table">
-      <div class="statistics__table__time">
-        <p>Total time: {{ statistics.total_time | time }} </p>
-      </div>
-      @if (showAnyStatisticsColumn(settings) && showStatisticsRowsAndCharts(settings)) {
-        <table class="statistics__table__header">
-          <thead class="statistics__table__header-title">
-          <tr>
-            <th></th>
-            @if (settings.showTotalPackets) {
-              <th>Total packets</th>
-            }
-            @if (settings.showPacketsPerSec) {
-              <th>Packets per second</th>
-            }
-            @if (settings.showTotalBytes) {
-              <th>Total bytes</th>
-            }
-            @if (settings.showBytesPerSec) {
-              <th>Bytes per second</th>
-            }
-          </tr>
-          </thead>
-          @if (settings.showETH) {
-            <tbody>
-              @let protocolEth = getETHStatistics(statistics.protocols);
-            <tr class="statistics__table__header-eth">
-              <td>{{ protocolEth.name }}</td>
-              @if (settings.showTotalPackets) {
-                <td>{{ protocolEth.total_packets | decimal }}</td>
-              }
-              @if (settings.showPacketsPerSec) {
-                <td>
-                  {{ getPerSecond(protocolEth.total_packets, statistics.total_time) | decimal }}
-                </td>
-              }
-              @if (settings.showTotalBytes) {
-                <td>{{ protocolEth.total_bytes | decimal }}</td>
-              }
-              @if (settings.showBytesPerSec) {
-                <td>
-                  {{ getPerSecond(protocolEth.total_bytes, statistics.total_time) | decimal }}
-                </td>
-              }
-            </tr>
-            </tbody>
-          }
-        </table>
-
-        <table class="statistics__table__protocols">
-          <tbody>
-            @for (protocol of getProtocols(statistics.protocols); track protocol.name) {
-                @if(settings.protocols[protocol.name]) {
-                <tr>
-                  <td>{{ protocol.name }}</td>
-                  @if (settings.showTotalPackets) {
-                    <td>{{ protocol.total_packets | decimal }}</td>
+    @if (settings()) {
+      <div class="statistics__table">
+        <div class="statistics__table__time">
+          <p>Total time: {{ statistics.total_time | time }}</p>
+        </div>
+        @if (
+          showAnyStatisticsColumn(settings()) &&
+          showStatisticsRowsAndCharts(settings())
+        ) {
+          <table class="statistics__table__header">
+            <thead class="statistics__table__header-title">
+              <tr>
+                <th></th>
+                @if (settings().showTotalPackets) {
+                  <th>Total packets</th>
+                }
+                @if (settings().showPacketsPerSec) {
+                  <th>Packets per second</th>
+                }
+                @if (settings().showTotalBytes) {
+                  <th>Total bytes</th>
+                }
+                @if (settings().showBytesPerSec) {
+                  <th>Bytes per second</th>
+                }
+              </tr>
+            </thead>
+            @if (settings().showETH) {
+              <tbody>
+                @let protocolEth = getETHStatistics(statistics.protocols);
+                <tr class="statistics__table__header-eth">
+                  <td>{{ protocolEth.name }}</td>
+                  @if (settings().showTotalPackets) {
+                    <td>{{ protocolEth.total_packets | decimal }}</td>
                   }
-                  @if (settings.showPacketsPerSec) {
+                  @if (settings().showPacketsPerSec) {
                     <td>
-                      {{ getPerSecond(protocol.total_packets, statistics.total_time) | decimal }}
+                      {{
+                        getPerSecond(
+                          protocolEth.total_packets,
+                          statistics.total_time
+                        ) | decimal
+                      }}
                     </td>
                   }
-                  @if (settings.showTotalBytes) {
-                    <td>{{ protocol.total_bytes | decimal }}</td>
+                  @if (settings().showTotalBytes) {
+                    <td>{{ protocolEth.total_bytes | decimal }}</td>
                   }
-                  @if (settings.showBytesPerSec) {
+                  @if (settings().showBytesPerSec) {
                     <td>
-                      {{ getPerSecond(protocol.total_bytes, statistics.total_time) | decimal }}
+                      {{
+                        getPerSecond(
+                          protocolEth.total_bytes,
+                          statistics.total_time
+                        ) | decimal
+                      }}
                     </td>
                   }
                 </tr>
-                }
+              </tbody>
             }
-          </tbody>
-        </table>
-      }
-      @if (showInformationRate(settings!)) {
-      <table class="statistics__table__ir">
-        <thead class="statistics__table__ir-header">
-        <tr>
-          <th></th>
-          @if (settings.showMinValue) {
-            <th>Min</th>
-          }
-          @if (settings.showMaxValue) {
-            <th>Max</th>
-          }
-          @if (settings.showCurrentValue) {
-            <th>Current</th>
-          }
-        </tr>
-        </thead>
-        <tbody>
-        <tr class="statistics__table_ir-content">
-          <td>Information Rate</td>
-          @if (settings.showMinValue) {
-            <td>{{ statistics.information_rate.min | decimal }}</td>
-          }
-          @if (settings.showMaxValue) {
-            <td>{{ statistics.information_rate.max | decimal }}</td>
-          }
-          @if (settings.showCurrentValue) {
-            <td>{{ statistics.information_rate.current | decimal }}</td>
-          }
-        </tr>
-        </tbody>
-      </table>
-      }
-    </div>
+          </table>
+
+          <table class="statistics__table__protocols">
+            <tbody>
+              @for (
+                protocol of getProtocols(statistics.protocols);
+                track protocol.name
+              ) {
+                @if (settings().protocols[protocol.name]) {
+                  <tr>
+                    <td>{{ protocol.name }}</td>
+                    @if (settings().showTotalPackets) {
+                      <td>{{ protocol.total_packets | decimal }}</td>
+                    }
+                    @if (settings().showPacketsPerSec) {
+                      <td>
+                        {{
+                          getPerSecond(
+                            protocol.total_packets,
+                            statistics.total_time
+                          ) | decimal
+                        }}
+                      </td>
+                    }
+                    @if (settings().showTotalBytes) {
+                      <td>{{ protocol.total_bytes | decimal }}</td>
+                    }
+                    @if (settings().showBytesPerSec) {
+                      <td>
+                        {{
+                          getPerSecond(
+                            protocol.total_bytes,
+                            statistics.total_time
+                          ) | decimal
+                        }}
+                      </td>
+                    }
+                  </tr>
+                }
+              }
+            </tbody>
+          </table>
+        }
+        @if (showInformationRate(settings()!)) {
+          <table class="statistics__table__ir">
+            <thead class="statistics__table__ir-header">
+              <tr>
+                <th></th>
+                @if (settings().showMinValue) {
+                  <th>Min</th>
+                }
+                @if (settings().showMaxValue) {
+                  <th>Max</th>
+                }
+                @if (settings().showCurrentValue) {
+                  <th>Current</th>
+                }
+              </tr>
+            </thead>
+            <tbody>
+              <tr class="statistics__table_ir-content">
+                <td>Information Rate</td>
+                @if (settings().showMinValue) {
+                  <td>{{ statistics.information_rate.min | decimal }}</td>
+                }
+                @if (settings().showMaxValue) {
+                  <td>{{ statistics.information_rate.max | decimal }}</td>
+                }
+                @if (settings().showCurrentValue) {
+                  <td>{{ statistics.information_rate.current | decimal }}</td>
+                }
+              </tr>
+            </tbody>
+          </table>
+        }
+      </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 13fe0cb..1e41d25 100644
--- a/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
+++ b/src/app/components/dashboard-statistics/dashboard-statistics.component.ts
@@ -2,18 +2,17 @@ import {
   ChangeDetectionStrategy,
   Component,
   inject,
-  OnInit,
+  input,
 } from '@angular/core';
 import { NgxSkeletonLoaderComponent } from 'ngx-skeleton-loader';
 import { AsyncPipe } from '@angular/common';
 import { DashboardApi } from '../../api/dashboard.api';
 
-import { interval, Observable, shareReplay, switchMap } from 'rxjs';
+import { interval, shareReplay, switchMap } from 'rxjs';
 import { ProtocolStatistics } from '../../models/dashboard-statistics';
 import { TimePipe } from '../../pipes/time.pipe';
 import { DecimalPipe } from '../../pipes/decimal.pipe';
 import { ReactiveFormsModule } from '@angular/forms';
-import { SettingsService } from '../../service/settings.service';
 import { Settings } from '../../models/settings';
 
 @Component({
@@ -31,8 +30,7 @@ import { Settings } from '../../models/settings';
 })
 export class DashboardStatisticsComponent {
   dashboardApi = inject(DashboardApi);
-  settingsService = inject(SettingsService);
-  settings$: Observable<Settings> = this.settingsService.settings$;
+  settings = input.required<Settings>();
 
   dashboardStatistics = interval(1000).pipe(
     switchMap(() => this.dashboardApi.fetchStatistics()),
@@ -62,10 +60,7 @@ export class DashboardStatisticsComponent {
   }
 
   showStatisticsRowsAndCharts(settings: Settings): boolean {
-    return (
-      settings.showETH ||
-      Object.values(settings.protocols).some(v => v === true)
-    );
+    return settings.showETH || Object.values(settings.protocols).some(v => v);
   }
 
   showInformationRate(settings: Settings): boolean {
diff --git a/src/app/components/dashboard/dashboard.component.html b/src/app/components/dashboard/dashboard.component.html
index c86a0de..ee374a8 100644
--- a/src/app/components/dashboard/dashboard.component.html
+++ b/src/app/components/dashboard/dashboard.component.html
@@ -1,3 +1,4 @@
+@let settings = settings$ | async;
 <app-page-wrapper>
   <div title>Monitoring and Analysis</div>
 
@@ -14,15 +15,25 @@
           Statistics
         </mat-panel-title>
       </mat-expansion-panel-header>
-      <app-dashboard-statistics />
+
+      @if (settings) {
+        <app-dashboard-statistics [settings]="settings" />
+      }
     </mat-expansion-panel>
+
     <mat-expansion-panel class="accordion__panel">
       <mat-expansion-panel-header class="accordion__panel-header">
         <mat-panel-title class="accordion__panel-title">
           Charts
         </mat-panel-title>
       </mat-expansion-panel-header>
-      <app-dashboard-charts [protocols]="['ipv4']" />
+
+      @if (settings) {
+        <app-dashboard-charts [settings]="settings" />
+      }
     </mat-expansion-panel>
   </mat-accordion>
+
+  <!--@todo: find other way to fix scrolling to the top of the page-->
+  <p-skeleton height="300px" />
 </app-page-wrapper>
diff --git a/src/app/components/dashboard/dashboard.component.ts b/src/app/components/dashboard/dashboard.component.ts
index de8f32d..ebec538 100644
--- a/src/app/components/dashboard/dashboard.component.ts
+++ b/src/app/components/dashboard/dashboard.component.ts
@@ -14,7 +14,8 @@ import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
 import { DashboardSettingsComponent } from '../dashboard-settings/dashboard-settings.component';
 import { ConfigurationApi } from '../../api/configuration.api';
 import { SettingsService } from '../../service/settings.service';
-import { map, Observable } from 'rxjs';
+import { AsyncPipe } from '@angular/common';
+import { Skeleton } from 'primeng/skeleton';
 
 @Component({
   selector: 'app-dashboard',
@@ -25,6 +26,8 @@ import { map, Observable } from 'rxjs';
     MatFabButton,
     DashboardStatisticsComponent,
     DashboardChartsComponent,
+    AsyncPipe,
+    Skeleton,
   ],
   templateUrl: './dashboard.component.html',
   styleUrl: './dashboard.component.scss',
@@ -35,6 +38,7 @@ export class DashboardComponent implements OnInit {
 
   configurationApi = inject(ConfigurationApi);
   settingsService = inject(SettingsService);
+  settings$ = this.settingsService.settings$;
 
   ngOnInit() {
     this.configurationApi.fetchAppliedConfiguration().subscribe(config => {
diff --git a/src/app/interceptor/interceptor.ts b/src/app/interceptor/interceptor.ts
index 93d051b..6cab5d5 100644
--- a/src/app/interceptor/interceptor.ts
+++ b/src/app/interceptor/interceptor.ts
@@ -40,11 +40,11 @@ export const urls = [
     json: () => irHistorical,
   },
   {
-    url: '/api/statistics/ipv4/current',
+    url: '/api/statistics/IPv4/current',
     json: () => ipv4Current,
   },
   {
-    url: '/api/statistics/ipv4/historical',
+    url: '/api/statistics/IPv4/historical',
     json: () => ipv4Historical,
   },
   {
diff --git a/src/app/interceptor/mock-interceptor.ts b/src/app/interceptor/mock-interceptor.ts
index 0ce7c4c..0c336b6 100644
--- a/src/app/interceptor/mock-interceptor.ts
+++ b/src/app/interceptor/mock-interceptor.ts
@@ -16,7 +16,7 @@ export const MockInterceptor: HttpInterceptorFn = (req, next) => {
       body = getRandomFrameRecord();
     } else if (url === DASHBOARD_API_URL + '/information-rate/current') {
       body = getRandomInformationRateRecord();
-    } else if (url === DASHBOARD_API_URL + '/ipv4/current') {
+    } else if (url === DASHBOARD_API_URL + '/IPv4/current') {
       body = getRandomProtocolRecord();
     }
 
-- 
GitLab


From 4a77ff7c4aaf3bc21f39f9c71b18ec22551fdce1 Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Thu, 27 Mar 2025 21:16:24 +0100
Subject: [PATCH 13/14] mod: review changes

---
 src/app/api/configuration.api.ts               |  5 +----
 .../dashboard-settings.component.html          |  2 ++
 .../dashboard-settings.component.ts            | 18 ++++++++++++------
 .../dashboard/dashboard.component.ts           |  2 --
 4 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/src/app/api/configuration.api.ts b/src/app/api/configuration.api.ts
index 2d778cd..45e9943 100644
--- a/src/app/api/configuration.api.ts
+++ b/src/app/api/configuration.api.ts
@@ -34,10 +34,7 @@ export class ConfigurationApi {
             dto => dto.is_applied
           );
 
-          if (!appliedConfiguration) {
-            throw new Error('No applied configuration found');
-          }
-          return appliedConfiguration.id;
+          return appliedConfiguration!.id;
         }),
 
         mergeMap(appliedConfigId => {
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.html b/src/app/components/dashboard-settings/dashboard-settings.component.html
index 6ea1fa3..5c590d2 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.html
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.html
@@ -1,3 +1,4 @@
+@if(form) {
 <div class="dialog" [formGroup]="form">
   <h2 mat-dialog-title class="dialog__header">Settings</h2>
   <mat-dialog-content class="dialog__content">
@@ -41,3 +42,4 @@
     <app-button class="save-button" (click)="onSubmit()">SAVE</app-button>
   </mat-dialog-actions>
 </div>
+}
diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.ts b/src/app/components/dashboard-settings/dashboard-settings.component.ts
index c34a6d9..130f008 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.ts
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.ts
@@ -39,26 +39,32 @@ export class DashboardSettingsComponent implements OnInit {
   dialogRef = inject(MatDialogRef<DashboardSettingsComponent>);
 
   settingsService = inject(SettingsService);
-  form!: SettingsForm;
+  form: SettingsForm | null = null;
 
   ngOnInit() {
     this.settingsService.settings$.subscribe(settings => {
       const protocols = Object.keys(settings.protocols);
       this.form = this.settingsFormBuilder.createDefaultForm(protocols);
 
-      this.initializeForm();
+      if (this.form) {
+        this.initializeForm();
+      }
     });
   }
 
   initializeForm() {
     const currentSettings = this.settingsService.getSettings();
-    this.form.patchValue(currentSettings);
+    if (this.form) {
+      this.form.patchValue(currentSettings);
+    }
   }
 
   onSubmit() {
-    const settings: Settings = this.settingsFormBuilder.toValue(this.form);
-    this.settingsService.updateSettings(settings);
-    this.dialogRef.close();
+    if (this.form) {
+      const settings: Settings = this.settingsFormBuilder.toValue(this.form);
+      this.settingsService.updateSettings(settings);
+      this.dialogRef.close();
+    }
   }
 
   onCancel() {
diff --git a/src/app/components/dashboard/dashboard.component.ts b/src/app/components/dashboard/dashboard.component.ts
index ebec538..170da9b 100644
--- a/src/app/components/dashboard/dashboard.component.ts
+++ b/src/app/components/dashboard/dashboard.component.ts
@@ -44,8 +44,6 @@ export class DashboardComponent implements OnInit {
     this.configurationApi.fetchAppliedConfiguration().subscribe(config => {
       if (config) {
         this.settingsService.initSettings(config.protocols);
-      } else {
-        console.error('Failed to fetch configuration');
       }
     });
   }
-- 
GitLab


From 079a3894749789e1a3d2f75c2ade10c551ad6a1f Mon Sep 17 00:00:00 2001
From: Artem Dychenko <s192441@student.pg.edu.pl>
Date: Thu, 27 Mar 2025 21:45:46 +0100
Subject: [PATCH 14/14] mod: change form initialization

---
 .../dashboard-settings.component.ts             | 17 ++++++-----------
 .../components/dashboard/dashboard.component.ts |  4 +---
 src/app/service/settings.service.ts             |  4 ----
 3 files changed, 7 insertions(+), 18 deletions(-)

diff --git a/src/app/components/dashboard-settings/dashboard-settings.component.ts b/src/app/components/dashboard-settings/dashboard-settings.component.ts
index 130f008..768be1a 100644
--- a/src/app/components/dashboard-settings/dashboard-settings.component.ts
+++ b/src/app/components/dashboard-settings/dashboard-settings.component.ts
@@ -43,20 +43,15 @@ export class DashboardSettingsComponent implements OnInit {
 
   ngOnInit() {
     this.settingsService.settings$.subscribe(settings => {
-      const protocols = Object.keys(settings.protocols);
-      this.form = this.settingsFormBuilder.createDefaultForm(protocols);
-
-      if (this.form) {
-        this.initializeForm();
-      }
+      this.initializeForm(settings);
     });
   }
 
-  initializeForm() {
-    const currentSettings = this.settingsService.getSettings();
-    if (this.form) {
-      this.form.patchValue(currentSettings);
-    }
+  initializeForm(settings: Settings) {
+    const protocols = Object.keys(settings.protocols);
+
+    this.form = this.settingsFormBuilder.createDefaultForm(protocols);
+    this.form.patchValue(settings);
   }
 
   onSubmit() {
diff --git a/src/app/components/dashboard/dashboard.component.ts b/src/app/components/dashboard/dashboard.component.ts
index 170da9b..9d0e380 100644
--- a/src/app/components/dashboard/dashboard.component.ts
+++ b/src/app/components/dashboard/dashboard.component.ts
@@ -42,9 +42,7 @@ export class DashboardComponent implements OnInit {
 
   ngOnInit() {
     this.configurationApi.fetchAppliedConfiguration().subscribe(config => {
-      if (config) {
-        this.settingsService.initSettings(config.protocols);
-      }
+      this.settingsService.initSettings(config.protocols);
     });
   }
 
diff --git a/src/app/service/settings.service.ts b/src/app/service/settings.service.ts
index 46b34db..8e9ee7e 100644
--- a/src/app/service/settings.service.ts
+++ b/src/app/service/settings.service.ts
@@ -39,8 +39,4 @@ export class SettingsService {
   updateSettings(settings: Settings) {
     this.settingsSubject.next(settings);
   }
-
-  getSettings(): Settings {
-    return this.settingsSubject.value;
-  }
 }
-- 
GitLab