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