From 456672f7b4565177a8ebda74339581a86a0408b7 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Tue, 16 Nov 2021 14:16:43 +0100 Subject: [PATCH 01/18] Made the first additions to multicast in frontend. Will try to connect to backend next. --- .../application-detail.component.html | 1 + .../applications-routing.module.ts | 14 +- src/app/applications/applications.module.ts | 57 ++++---- .../datatarget-edit.component.ts | 6 +- .../datatarget-table.component.html | 2 +- .../multicast-detail.component.html | 24 ++++ .../multicast-detail.component.scss | 0 .../multicast-detail.component.spec.ts | 25 ++++ .../multicast-detail.component.ts | 98 +++++++++++++ .../multicast-edit.component.html | 97 +++++++++++++ .../multicast-edit.component.scss | 0 .../multicast-edit.component.spec.ts | 25 ++++ .../multicast-edit.component.ts | 134 ++++++++++++++++++ .../multicast-list.component.html | 13 ++ .../multicast-list.component.scss | 0 .../multicast-list.component.spec.ts | 25 ++++ .../multicast-list.component.ts | 47 ++++++ .../multicast-table.component.html | 53 +++++++ .../multicast-table.component.scss | 0 .../multicast-table.component.spec.ts | 25 ++++ .../multicast-table.component.ts | 120 ++++++++++++++++ .../applications/multicast/multicast.model.ts | 20 +++ .../multicast/multicast.module.ts | 43 ++++++ .../multicast/multicast.service.spec.ts | 16 +++ .../multicast/multicast.service.ts | 49 +++++++ src/app/shared/enums/multicast-type.ts | 4 + src/assets/i18n/da.json | 49 ++++++- 27 files changed, 912 insertions(+), 35 deletions(-) create mode 100644 src/app/applications/multicast/multicast-detail/multicast-detail.component.html create mode 100644 src/app/applications/multicast/multicast-detail/multicast-detail.component.scss create mode 100644 src/app/applications/multicast/multicast-detail/multicast-detail.component.spec.ts create mode 100644 src/app/applications/multicast/multicast-detail/multicast-detail.component.ts create mode 100644 src/app/applications/multicast/multicast-edit/multicast-edit.component.html create mode 100644 src/app/applications/multicast/multicast-edit/multicast-edit.component.scss create mode 100644 src/app/applications/multicast/multicast-edit/multicast-edit.component.spec.ts create mode 100644 src/app/applications/multicast/multicast-edit/multicast-edit.component.ts create mode 100644 src/app/applications/multicast/multicast-list/multicast-list.component.html create mode 100644 src/app/applications/multicast/multicast-list/multicast-list.component.scss create mode 100644 src/app/applications/multicast/multicast-list/multicast-list.component.spec.ts create mode 100644 src/app/applications/multicast/multicast-list/multicast-list.component.ts create mode 100644 src/app/applications/multicast/multicast-table/multicast-table.component.html create mode 100644 src/app/applications/multicast/multicast-table/multicast-table.component.scss create mode 100644 src/app/applications/multicast/multicast-table/multicast-table.component.spec.ts create mode 100644 src/app/applications/multicast/multicast-table/multicast-table.component.ts create mode 100644 src/app/applications/multicast/multicast.model.ts create mode 100644 src/app/applications/multicast/multicast.module.ts create mode 100644 src/app/applications/multicast/multicast.service.spec.ts create mode 100644 src/app/applications/multicast/multicast.service.ts create mode 100644 src/app/shared/enums/multicast-type.ts diff --git a/src/app/applications/application-detail/application-detail.component.html b/src/app/applications/application-detail/application-detail.component.html index 1eac588d..647d2c1c 100644 --- a/src/app/applications/application-detail/application-detail.component.html +++ b/src/app/applications/application-detail/application-detail.component.html @@ -1,5 +1,6 @@
diff --git a/src/app/applications/applications-routing.module.ts b/src/app/applications/applications-routing.module.ts index f563dfab..d48876b1 100644 --- a/src/app/applications/applications-routing.module.ts +++ b/src/app/applications/applications-routing.module.ts @@ -10,6 +10,9 @@ import { DatatargetEditComponent } from './datatarget/datatarget-edit/datatarget import { DatatargetListComponent } from './datatarget/datatarget-list/datatarget-list.component'; import { DatatargetDetailComponent } from './datatarget/datatarget-detail/datatarget-detail.component'; import { BulkImportComponent } from './bulk-import/bulk-import.component'; +import { MulticastListComponent } from './multicast/multicast-list/multicast-list.component'; +import { MulticastEditComponent } from './multicast/multicast-edit/multicast-edit.component'; +import { MulticastDetailComponent } from './multicast/multicast-detail/multicast-detail.component'; const applicationRoutes: Routes = [ @@ -37,7 +40,16 @@ const applicationRoutes: Routes = [ ] }, - { path: 'bulk-import', component: BulkImportComponent } + { + path: 'multicast-list/:name', + children: [ + { path: '', component: MulticastListComponent }, + { path: 'multicast-edit', component: MulticastEditComponent}, + { path: 'multicast-edit/:multicastId', component: MulticastEditComponent }, + { path: 'multicast/:multicastId', component: MulticastDetailComponent } + ] + }, + { path: 'bulk-import', component: BulkImportComponent }, ], }, diff --git a/src/app/applications/applications.module.ts b/src/app/applications/applications.module.ts index 69f3114c..acc30053 100644 --- a/src/app/applications/applications.module.ts +++ b/src/app/applications/applications.module.ts @@ -17,34 +17,35 @@ import { NGMaterialModule } from '@shared/Modules/materiale.module'; import { BulkImportComponent } from './bulk-import/bulk-import.component'; import { PipesModule } from '@shared/pipes/pipes.module'; import { ApplicationsTableComponent } from './applications-list/applications-table/applications-table.component'; - +import { MulticastModule } from './multicast/multicast.module'; @NgModule({ - declarations: [ - ApplicationsComponent, - ApplicationDetailComponent, - ApplicationEditComponent, - ApplicationsListComponent, - ApplicationsTableComponent, - BulkImportComponent, - ], - exports: [ - ApplicaitonsRoutingModule, - ApplicationsComponent, - ApplicationsTableComponent, - ], - imports: [ - CommonModule, - RouterModule, - TranslateModule, - IotDevicesModule, - DatatargetModule, - DirectivesModule, - FormModule, - SharedModule, - FontAwesomeModule, - NGMaterialModule, - PipesModule, - ], + declarations: [ + ApplicationsComponent, + ApplicationDetailComponent, + ApplicationEditComponent, + ApplicationsListComponent, + ApplicationsTableComponent, + BulkImportComponent, + ], + exports: [ + ApplicaitonsRoutingModule, + ApplicationsComponent, + ApplicationsTableComponent, + ], + imports: [ + CommonModule, + RouterModule, + TranslateModule, + IotDevicesModule, + DatatargetModule, + DirectivesModule, + FormModule, + SharedModule, + FontAwesomeModule, + NGMaterialModule, + PipesModule, + MulticastModule, + ], }) -export class ApplicationsModule { } +export class ApplicationsModule {} diff --git a/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.ts b/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.ts index 968df9e2..568dfb77 100644 --- a/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.ts +++ b/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.ts @@ -44,7 +44,7 @@ export class DatatargetEditComponent implements OnInit, OnDestroy { public formFailedSubmit = false; public datatargetid: number; private applicationId: number; - private applicationNane: string; + private applicationName: string; public application: Application; public devices: IotDevice[]; public payloadDecoders = []; @@ -94,7 +94,7 @@ export class DatatargetEditComponent implements OnInit, OnDestroy { this.datatargetid = +this.route.snapshot.paramMap.get('datatargetId'); this.applicationId = +this.route.snapshot.paramMap.get('id'); - this.applicationNane = this.route.snapshot.paramMap.get('name'); + this.applicationName = this.route.snapshot.paramMap.get('name'); if (this.datatargetid !== 0) { this.getDatatarget(this.datatargetid); this.getPayloadDeviceDatatarget(this.datatargetid); @@ -288,7 +288,7 @@ export class DatatargetEditComponent implements OnInit, OnDestroy { } routeToDatatargets(): void { - this.router.navigate(['applications',this.applicationId.toString(),'datatarget-list', this.applicationNane]) + this.router.navigate(['applications',this.applicationId.toString(),'datatarget-list', this.applicationName]) } onCoordinateKey(event: any) { diff --git a/src/app/applications/datatarget/datatarget-table/datatarget-table.component.html b/src/app/applications/datatarget/datatarget-table/datatarget-table.component.html index 43de08b9..c839d784 100644 --- a/src/app/applications/datatarget/datatarget-table/datatarget-table.component.html +++ b/src/app/applications/datatarget/datatarget-table/datatarget-table.component.html @@ -15,7 +15,7 @@ - + {{ 'DATATARGET-TABLE.TYPE' | translate }} diff --git a/src/app/applications/multicast/multicast-detail/multicast-detail.component.html b/src/app/applications/multicast/multicast-detail/multicast-detail.component.html new file mode 100644 index 00000000..a8aede80 --- /dev/null +++ b/src/app/applications/multicast/multicast-detail/multicast-detail.component.html @@ -0,0 +1,24 @@ +
+ +
+
+
+
+

{{ 'MULTICAST.DETAILS' | translate }}

+ + +

{{ 'MULTICAST.GROUPNAME' | translate }}{{multicast.groupName | translate }}

+

{{ 'MULTICAST.ADDRESS' | translate }}{{multicast.address | translate}}

+

{{ 'MULTICAST.NETWORK-KEY' | translate }}{{multicast.networkSessionKey | translate}}

+

{{ 'MULTICAST.APPLICATION-KEY' | translate }}{{multicast.applicationSessionKey | translate}}

+

{{ 'MULTICAST.FRAMECOUNTER' | translate }}{{multicast.frameCounter}}

+

{{ 'MULTICAST.DATARATE' | translate }}{{multicast.dataRate}}

+

{{ 'MULTICAST.FREQUENCY' | translate }}{{multicast.frequency}}

+

{{ 'MULTICAST.GROUPTYPE' | translate }}{{multicast.groupType}}

+ +
+
+
+
+
\ No newline at end of file diff --git a/src/app/applications/multicast/multicast-detail/multicast-detail.component.scss b/src/app/applications/multicast/multicast-detail/multicast-detail.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/applications/multicast/multicast-detail/multicast-detail.component.spec.ts b/src/app/applications/multicast/multicast-detail/multicast-detail.component.spec.ts new file mode 100644 index 00000000..20b2cf8e --- /dev/null +++ b/src/app/applications/multicast/multicast-detail/multicast-detail.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MulticastDetailComponent } from './multicast-detail.component'; + +describe('MulticastDetailComponent', () => { + let component: MulticastDetailComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ MulticastDetailComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MulticastDetailComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts b/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts new file mode 100644 index 00000000..9e480e8d --- /dev/null +++ b/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts @@ -0,0 +1,98 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service'; +import { BackButton } from '@shared/models/back-button.model'; +import { DropdownButton } from '@shared/models/dropdown-button.model'; +import { Subscription } from 'rxjs'; +import { Multicast } from '../multicast.model'; +import { Location } from '@angular/common'; +import { MulticastService } from '../multicast.service'; + +@Component({ + selector: 'app-multicast-detail', + templateUrl: './multicast-detail.component.html', + styleUrls: ['./multicast-detail.component.scss'], +}) +export class MulticastDetailComponent implements OnInit { + public multicastSubscription: Subscription; + public multicast: Multicast; + public backButton: BackButton = { label: '', routerLink: '/multicast-list' }; + private deleteDialogSubscription: Subscription; + public dropdownButton: DropdownButton; + private applicationName: string; + private applicationId: number; + + constructor( + private route: ActivatedRoute, + private deleteDialogService: DeleteDialogService, + private location: Location, + private multicastService: MulticastService, + public translate: TranslateService + ) {} + + ngOnInit(): void { + const id: number = +this.route.snapshot.paramMap.get('multicastId'); + this.applicationName = this.route.snapshot.paramMap.get('name'); + if (id) { + this.getMulticast(id); + this.dropdownButton = { + label: '', + editRouterLink: '../../multicast-edit/' + id, + isErasable: true, + }; + this.applicationId = +this.route.snapshot.paramMap.get('id'); + } + this.translate + .get(['GEN.BACK', 'MULTICAST-TABLE-ROW.SHOW-OPTIONS']) + .subscribe((translations) => { + this.backButton.label = translations['GEN.BACK']; + this.dropdownButton.label = + translations['MULTICAST-TABLE-ROW.SHOW-OPTIONS']; + }); + } + + getMulticast(id: number) { + this.multicastService.get(id).subscribe((multicast: Multicast) => { + this.multicast = multicast; + this.setBackButton(this.applicationId); + }); + } + + private setBackButton(applicationId: number) { + this.backButton.routerLink = [ + 'applications', + applicationId.toString(), + 'multicast-list', + this.applicationName, + ]; + } + + //only if classB can be used + // canShowPeriodicity(): boolean { + // if (this.multicast.groupType === MulticastType.ClassB) { + // return true; + // } else return false; + // } + + onDeleteDatatarget() { + this.deleteDialogSubscription = this.deleteDialogService + .showSimpleDialog() + .subscribe((response) => { + if (response) { + this.multicastService + .delete(this.multicast.id) + .subscribe((response) => {}); + this.location.back(); + } else { + console.log(response); + } + }); + } + + ngOnDestroy(): void { + if (this.deleteDialogSubscription) { + this.deleteDialogSubscription.unsubscribe(); + } + } +} diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.html b/src/app/applications/multicast/multicast-edit/multicast-edit.component.html new file mode 100644 index 00000000..10554638 --- /dev/null +++ b/src/app/applications/multicast/multicast-edit/multicast-edit.component.html @@ -0,0 +1,97 @@ + + +
+
+
    +
  • + {{error | translate}} +
  • +
+
+ + +
+
+ * + +
+ +
+ * + +
+ +
+ * + +
+ +
+ * + +
+ +
+ * + +
+ +
+ * + +
+ +
+ * + +
+ +
+ + + + {{multicastType}} + + +
+ + + +
+ + +
+ + +
+
\ No newline at end of file diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.scss b/src/app/applications/multicast/multicast-edit/multicast-edit.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.spec.ts b/src/app/applications/multicast/multicast-edit/multicast-edit.component.spec.ts new file mode 100644 index 00000000..84638528 --- /dev/null +++ b/src/app/applications/multicast/multicast-edit/multicast-edit.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MulticastEditComponent } from './multicast-edit.component'; + +describe('MulticastEditComponent', () => { + let component: MulticastEditComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ MulticastEditComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MulticastEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts b/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts new file mode 100644 index 00000000..7bf3b22a --- /dev/null +++ b/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts @@ -0,0 +1,134 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { Component, Input, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { MulticastType } from '@shared/enums/multicast-type'; +import { ErrorMessageService } from '@shared/error-message.service'; +import { ScrollToTopService } from '@shared/services/scroll-to-top.service'; +import { Subscription } from 'rxjs'; +import { Multicast } from '../multicast.model'; +import { MulticastService } from '../multicast.service'; + +@Component({ + selector: 'app-multicast-edit', + templateUrl: './multicast-edit.component.html', + styleUrls: ['./multicast-edit.component.scss'], +}) +export class MulticastEditComponent implements OnInit { + public title: string; + public multicastId: number; + public errorMessages: any; + private multicastSubscription: Subscription; + public errorFields: string[]; + @Input() submitButton: string; + public backButtonTitle: string; + public multicast: Multicast = new Multicast(); + private counter: number; + private applicationId: number; + private applicationName: string; + public formFailedSubmit: boolean = false; + public multicastTypes: string[] = Object.values(MulticastType); + public periodicities: number[] = [2, 4, 8, 16, 32, 64, 128]; + + constructor( + public translate: TranslateService, + private route: ActivatedRoute, + private router: Router, + public multicastService: MulticastService, + public errorMessageService: ErrorMessageService, + public scrollToTopService: ScrollToTopService + ) {} + + ngOnInit(): void { + this.translate + .get([ + 'FORM.CREATE-NEW-MULTICAST', + 'FORM.EDIT-MULTICAST', + 'MULTICAST.SAVE', + 'NAV.MULTICAST', + ]) + .subscribe((translations) => { + const multicastId = +this.route.snapshot.paramMap.get('multicastId'); + if (multicastId !== 0) { + this.title = translations['FORM.EDIT-MULTICAST']; + } else { + this.title = translations['FORM.CREATE-NEW-MULTICAST']; + } + this.submitButton = translations['MULTICAST.SAVE']; + this.backButtonTitle = translations['NAV.MULTICAST']; + }); + + this.multicastId = +this.route.snapshot.paramMap.get('multicastId'); + this.applicationId = +this.route.snapshot.paramMap.get('id'); + this.applicationName = this.route.snapshot.paramMap.get('name'); + + if (this.multicastId !== 0) { + this.getMulticast(this.multicastId); + } + } + onSubmit(): void { + this.counter = 0; + if (this.multicastId) { + this.updateMulticast(); + } else { + this.createMulticast(); + } + } + + getMulticast(id: number) { + this.multicastSubscription = this.multicastService + .get(id) + .subscribe((response: Multicast) => { + this.multicast = response; + }); + } + + //only if classB can be used + // showPeriodicity(): boolean { + // if (this.multicast.groupType === MulticastType.ClassB) { + // return true; + // } else return false; + // } + + updateMulticast(): void { + this.multicastService.update(this.multicast).subscribe( + (response) => { + console.log(response); + this.router.navigateByUrl('/applications'); + }, + (error: HttpErrorResponse) => { + this.handleError(error); + } + ); + } + createMulticast(): void { + this.multicastService.create(this.multicast).subscribe( + (response) => { + console.log(response); + this.router.navigateByUrl('/multicast-list'); + }, + (error: HttpErrorResponse) => { + this.handleError(error); + } + ); + } + routeBack(): void { + this.router.navigate([ + 'applications', + this.applicationId.toString(), + 'multicast-list', + this.applicationName, + ]); + } + handleError(error: HttpErrorResponse) { + const errors = this.errorMessageService.handleErrorMessageWithFields(error); + this.errorFields = errors.errorFields; + this.errorMessages = errors.errorMessages; + this.scrollToTopService.scrollToTop(); + } + ngOnDestroy(): void { + if (this.multicastSubscription) { + this.multicastSubscription.unsubscribe(); + } + } +} diff --git a/src/app/applications/multicast/multicast-list/multicast-list.component.html b/src/app/applications/multicast/multicast-list/multicast-list.component.html new file mode 100644 index 00000000..6ff143d4 --- /dev/null +++ b/src/app/applications/multicast/multicast-list/multicast-list.component.html @@ -0,0 +1,13 @@ + + +
+
+
+
+ +
+
+
+
\ No newline at end of file diff --git a/src/app/applications/multicast/multicast-list/multicast-list.component.scss b/src/app/applications/multicast/multicast-list/multicast-list.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/applications/multicast/multicast-list/multicast-list.component.spec.ts b/src/app/applications/multicast/multicast-list/multicast-list.component.spec.ts new file mode 100644 index 00000000..353f2cb9 --- /dev/null +++ b/src/app/applications/multicast/multicast-list/multicast-list.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MulticastListComponent } from './multicast-list.component'; + +describe('MulticastListComponent', () => { + let component: MulticastListComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ MulticastListComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MulticastListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/applications/multicast/multicast-list/multicast-list.component.ts b/src/app/applications/multicast/multicast-list/multicast-list.component.ts new file mode 100644 index 00000000..a4ad955c --- /dev/null +++ b/src/app/applications/multicast/multicast-list/multicast-list.component.ts @@ -0,0 +1,47 @@ +import { Component, OnInit } from '@angular/core'; +import { Title } from '@angular/platform-browser'; +import { ActivatedRoute } from '@angular/router'; +import { environment } from '@environments/environment'; +import { TranslateService } from '@ngx-translate/core'; +import { BackButton } from '@shared/models/back-button.model'; + +@Component({ + selector: 'app-multicast-list', + templateUrl: './multicast-list.component.html', + styleUrls: ['./multicast-list.component.scss'], +}) +export class MulticastListComponent implements OnInit { + public pageLimit = environment.tablePageSize; + public title: string; + public backButton: BackButton = { label: '', routerLink: '' }; + private applicationId: string; + + constructor( + public translate: TranslateService, + private titleService: Title, + private route: ActivatedRoute + ) { + translate.use('da'); + } + + ngOnInit(): void { + const applicationName: string = this.route.snapshot.paramMap.get('name'); + this.applicationId = this.route.snapshot.paramMap.get('id'); + this.translate + .get(['NAV.MULTICAST', 'NAV.APPLICATIONS', 'TITLE.MULTICAST']) + .subscribe((translate) => { + this.title = translate['NAV.MULTICAST'] + ' - ' + applicationName; + this.backButton.label = translate['NAV.APPLICATIONS']; + this.titleService.setTitle(translate['TITLE.MULTICAST']); + }); + this.setBackButton(); + } + + setBackButton() { + this.backButton.routerLink = ['applications', this.applicationId]; + } + + updatePageLimit(limit: any) { + console.log(limit); + } +} diff --git a/src/app/applications/multicast/multicast-table/multicast-table.component.html b/src/app/applications/multicast/multicast-table/multicast-table.component.html new file mode 100644 index 00000000..adfb5208 --- /dev/null +++ b/src/app/applications/multicast/multicast-table/multicast-table.component.html @@ -0,0 +1,53 @@ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+ {{ 'MULTICAST-TABLE.NAME' | translate }} + + {{element.groupName}} + + {{ 'MULTICAST-TABLE.TYPE' | translate }} + + {{element.groupType | translate}} + +
+ + +
\ No newline at end of file diff --git a/src/app/applications/multicast/multicast-table/multicast-table.component.scss b/src/app/applications/multicast/multicast-table/multicast-table.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/applications/multicast/multicast-table/multicast-table.component.spec.ts b/src/app/applications/multicast/multicast-table/multicast-table.component.spec.ts new file mode 100644 index 00000000..4a46e62b --- /dev/null +++ b/src/app/applications/multicast/multicast-table/multicast-table.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { MulticastTableComponent } from './multicast-table.component'; + +describe('MulticastTableComponent', () => { + let component: MulticastTableComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ MulticastTableComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(MulticastTableComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/applications/multicast/multicast-table/multicast-table.component.ts b/src/app/applications/multicast/multicast-table/multicast-table.component.ts new file mode 100644 index 00000000..ff0786ce --- /dev/null +++ b/src/app/applications/multicast/multicast-table/multicast-table.component.ts @@ -0,0 +1,120 @@ +import { + AfterViewInit, + Component, + Input, + OnDestroy, + OnInit, + ViewChild, +} from '@angular/core'; +import { MatPaginator } from '@angular/material/paginator'; +import { MatSort } from '@angular/material/sort'; +import { MatTableDataSource } from '@angular/material/table'; +import { ActivatedRoute } from '@angular/router'; +import { environment } from '@environments/environment'; +import { TranslateService } from '@ngx-translate/core'; +import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service'; +import { MulticastType } from '@shared/enums/multicast-type'; +import { tableSorter } from '@shared/helpers/table-sorting.helper'; +import { MeService } from '@shared/services/me.service'; +import { Subscription } from 'rxjs'; +import { Multicast, MulticastData } from '../multicast.model'; +import { MulticastService } from '../multicast.service'; + +@Component({ + selector: 'app-multicast-table', + templateUrl: './multicast-table.component.html', + styleUrls: ['./multicast-table.component.scss'], +}) +export class MulticastTableComponent + implements OnInit, AfterViewInit, OnDestroy { + @ViewChild(MatPaginator) paginator: MatPaginator; + @ViewChild(MatSort) sort: MatSort; + displayedColumns: string[] = ['groupName', 'groupType', 'menu']; + dataSource = new MatTableDataSource(); + multicasts: Multicast[]; + resultsLength = 0; + public canEdit = false; + @Input() isLoadingResults: boolean = true; + public pageSize = environment.tablePageSize; + + @Input() pageLimit: number; + public pageOffset = 0; + public pageTotal: number; + public applicationId: number; + + private multicastSubscription: Subscription; + private deleteDialogSubscription: Subscription; + + constructor( + private route: ActivatedRoute, + private deleteDialogService: DeleteDialogService, + private multicastService: MulticastService, + private meService: MeService, + public translate: TranslateService + ) { + translate.use('da'); + } + + ngOnInit(): void { + this.applicationId = +Number( + this.route.parent.parent.snapshot.paramMap.get('id') + ); + console.log(this.applicationId); + this.getMulticast(); + this.canEdit = this.meService.canWriteInTargetOrganization(); + } + + ngAfterViewInit() { + this.dataSource.paginator = this.paginator; + this.dataSource.sort = this.sort; + } + + getMulticast(): void { + const appId: number = this.applicationId; + if (appId) { + this.multicastSubscription = this.multicastService + .getByApplicationId( + this.pageLimit, + this.pageOffset * this.pageLimit, + appId + ) + .subscribe((multicasts: MulticastData) => { + this.multicasts = multicasts.data; + this.dataSource = new MatTableDataSource(this.multicasts); + this.dataSource.paginator = this.paginator; + this.dataSource.sort = this.sort; + this.dataSource.sortingDataAccessor = tableSorter; + this.isLoadingResults = false; + if (this.pageLimit) { + this.pageTotal = Math.ceil(multicasts.count / this.pageLimit); + } + }); + } + } + + deleteMulticast(element: any) { + this.deleteDialogSubscription = this.deleteDialogService + .showSimpleDialog() + .subscribe((response) => { + if (response) { + this.multicastService.delete(element.id).subscribe((response) => { + if (response.ok && response.body.affected > 0) { + this.getMulticast(); + } + }); + } else { + console.log(response); + } + }); + } + + ngOnDestroy() { + // prevent memory leak by unsubscribing + if (this.multicastSubscription) { + this.multicastSubscription.unsubscribe(); + } + if (this.deleteDialogSubscription) { + this.deleteDialogSubscription.unsubscribe(); + } + } +} diff --git a/src/app/applications/multicast/multicast.model.ts b/src/app/applications/multicast/multicast.model.ts new file mode 100644 index 00000000..0f374bcf --- /dev/null +++ b/src/app/applications/multicast/multicast.model.ts @@ -0,0 +1,20 @@ +import { MulticastType } from '@shared/enums/multicast-type'; + +export class Multicast { + id: number; + groupName: string; + address: string; + networkSessionKey: string; + applicationSessionKey: string; + frameCounter: number = 0; + dataRate: number = 0; + frequency: number = 0; + groupType: MulticastType; + // periodicity: number; -> only if classB is gonna be used +} + +export class MulticastData { + data: Multicast[]; + ok?: boolean; + count?: number; +} \ No newline at end of file diff --git a/src/app/applications/multicast/multicast.module.ts b/src/app/applications/multicast/multicast.module.ts new file mode 100644 index 00000000..7f38d76b --- /dev/null +++ b/src/app/applications/multicast/multicast.module.ts @@ -0,0 +1,43 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { SharedModule } from '@shared/shared.module'; +import { MulticastListComponent } from './multicast-list/multicast-list.component'; +import { MulticastDetailComponent } from './multicast-detail/multicast-detail.component'; +import { MulticastEditComponent } from './multicast-edit/multicast-edit.component'; +import { MulticastTableComponent } from './multicast-table/multicast-table.component'; +import { DatatargetModule } from '@applications/datatarget/datatarget.module'; +import { RouterModule } from '@angular/router'; +import { TranslateModule } from '@ngx-translate/core'; +import { NGMaterialModule } from '@shared/Modules/materiale.module'; +import { FormModule } from '@shared/components/forms/form.module'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; +import { PipesModule } from '@shared/pipes/pipes.module'; + +@NgModule({ + declarations: [ + MulticastListComponent, + MulticastDetailComponent, + MulticastEditComponent, + MulticastTableComponent, + ], + imports: [ + CommonModule, + RouterModule, + TranslateModule, + FormModule, + NGMaterialModule, + FontAwesomeModule, + ReactiveFormsModule, + FormsModule, + SharedModule, + PipesModule, + ], + exports: [ + MulticastListComponent, + MulticastDetailComponent, + MulticastEditComponent, + MulticastTableComponent, + ], +}) +export class MulticastModule {} diff --git a/src/app/applications/multicast/multicast.service.spec.ts b/src/app/applications/multicast/multicast.service.spec.ts new file mode 100644 index 00000000..c86a61c3 --- /dev/null +++ b/src/app/applications/multicast/multicast.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { MulticastService } from './multicast.service'; + +describe('MulticastService', () => { + let service: MulticastService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(MulticastService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/applications/multicast/multicast.service.ts b/src/app/applications/multicast/multicast.service.ts new file mode 100644 index 00000000..4b083571 --- /dev/null +++ b/src/app/applications/multicast/multicast.service.ts @@ -0,0 +1,49 @@ +import { Injectable } from '@angular/core'; +import { RestService } from '@shared/services/rest.service'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { Multicast, MulticastData } from './multicast.model'; + +@Injectable({ + providedIn: 'root', +}) +export class MulticastService { + constructor(private restService: RestService) {} + + private multicastURL = 'multicast'; + getByApplicationId( + limit: number, + offset: number, + applicationId: number + ): Observable { + const body = { + limit, + offset, + applicationId, + // sort: sort, + // orderOn: orderOn, + // todo tilføj når iot-314 er tilføjet + }; + return this.restService.get(this.multicastURL, body); + } + get(id: number): Observable { + return this.restService.get(this.multicastURL, {}, id).pipe( + map((response: Multicast) => { + return response; + }) + ); + } + delete(id: number) { + return this.restService.delete(this.multicastURL, id); + } + update(multicast: Multicast): Observable { + return this.restService.put(this.multicastURL, multicast, multicast.id, { + observe: 'response', + }); + } + create(multicast: Multicast): Observable { + return this.restService.post(this.multicastURL, multicast, { + observe: 'response', + }); + } +} diff --git a/src/app/shared/enums/multicast-type.ts b/src/app/shared/enums/multicast-type.ts new file mode 100644 index 00000000..c4d895cf --- /dev/null +++ b/src/app/shared/enums/multicast-type.ts @@ -0,0 +1,4 @@ +export enum MulticastType { + // ClassB = 'Class-B', + ClassC = 'Class-C' +} diff --git a/src/assets/i18n/da.json b/src/assets/i18n/da.json index 96c8b754..1bc2965d 100644 --- a/src/assets/i18n/da.json +++ b/src/assets/i18n/da.json @@ -17,6 +17,7 @@ "ALL-IOT-DEVICES": "Alle IoT enheder", "LORA-GATEWAYS": "LoRaWAN gateways", "DATATARGET": "Datatarget", + "MULTICAST": "Multicast", "MY-DATATARGET": "Tilbage", "DATATARGET-APPLIKATION": "for applikation:", "PROFILES": "LoRaWAN profiler", @@ -81,10 +82,12 @@ "SAVE": "Gem applikation", "DELETE": "Slet applikation", "DELETE-HAS-DEVICES-PROMPT": "Der er knyttet IoT-enheder til denne applikation. Disse vil også blive slettet. Slet alligevel?", + "DELETE-HAS-SIGFOX-DEVICES-PROMPT": "Applikationen kan ikke slettes, da der er knyttet Sigfox enheder til den", "NAME": "Applikationens navn", "DESCRIPTION": "Applikationens beskrivelse", "ATTACHED-IOT": "Tilknyttede IoT enheder", "DATATARGET-SHOW": "Tilknyttede data targets", + "MULTICAST-SHOW": "Tilknyttede multicast grupper", "IMPORT-CSV": "Bulk import af IoT enheder", "BULK": { "TEMPLATE": { @@ -153,6 +156,19 @@ "OPENDATA-DK": "OpenDataDK", "NO-OPENDATA-DK": "Der er ikke oprettet nogen datadeling med Open Data DK endnu" }, + "MULTICAST": { + "SAVE": "Gem multicast", + "DETAILS": "Detaljer", + "GROUPNAME": "Gruppe navn", + "ADDRESS": "Adresse", + "NETWORK-KEY": "Network session key", + "APPLICATION-KEY": "Network application key", + "FRAMECOUNTER": "Frame counter", + "DATARATE": "Data rate", + "FREQUENCY": "Frekvens (Hz)", + "GROUPTYPE": "Gruppe type", + "PERIODICITY": "Periodicitet" + }, "OPENDATADK": { "QUESTION": { "GIVE-OPENDATADK-NAME": "Datasæt titel", @@ -240,6 +256,10 @@ "NAME": "Navn", "TYPE": "Type" }, + "MULTICAST-TABLE":{ + "NAME": "Gruppenavn", + "TYPE": "Gruppetype" + }, "IOT-DEVICE-TYPES": { "GENERIC_HTTP": "Generisk HTTP", "LORAWAN": "LoRaWAN", @@ -264,7 +284,13 @@ }, "DATATARGET-TABLE-ROW": { "DELETE": "Slet datatarget", - "EDIT": "Redigér" + "EDIT": "Redigér", + "SHOW-OPTIONS": "Håndter datatarget" + }, + "MULTICAST-TABLE-ROW": { + "DELETE": "Slet multicast", + "EDIT": "Redigér", + "SHOW-OPTIONS": "Håndter multicast" }, "PAYLOAD-DECODER": { "DELETE-FAILED": "Slet fejlede", @@ -364,7 +390,9 @@ "CREATE-NEW-LORA-GATEWAY": "Opret ny LoRaWAN gateway", "CREATE-NEW-DEVICE-MODEL": "Opret ny device model", "CREATE-NEW-DATATARGET": "Opret nyt datatarget", + "CREATE-NEW-MULTICAST": "Opret nyt multicast", "EDIT-DATATARGET": "Redigér datatarget", + "EDIT-MULTICAST": "Redigér multicast", "CREATE-NEW-IOT-DEVICE": "Tilføj en IoT enhed", "EDIT-NEW-GATEWAY": "Redigér LoRaWAN gateway", "EDIT-NEW-APPLICATION": "Redigér applikation", @@ -426,6 +454,22 @@ "GIVE-PAYLOADDECODER-PAYLOAD-INVALID-JSON": "Det angivne JSON var ikke gyldigt i feltet payload", "GIVE-ORGANISATION-NAME": "Navngiv organisation", "GIVE-ORGANISATION-NAME-PLACEHOLDER": "F.eks. 'Aarhus Kommune'", + "GIVE-MULTICAST-NAME":"Navngiv multicast", + "GIVE-MULTICAST-ADDRESS": "Angiv multicast adressen", + "GIVE-MULTICAST-NETWORK-KEY": "Angiv multicast network session key", + "GIVE-MULTICAST-APPLICATION-KEY": "Angiv multicast application session key", + "GIVE-MULTICAST-FRAMECOUNTER": "Angiv frame counter", + "GIVE-MULTICAST-DATARATE": "Angiv data rate", + "GIVE-MULTICAST-FREQUENCY": "Angiv frekvens (Hz)", + "GIVE-MULTICAST-GROUP-TYPE": "Angiv multicast gruppe type", + "GIVE-MULTICAST-PERIODICITY": "Angiv multicast ping-slot periodicitet", + "GIVE-MULTICAST-GROUPTYPE": "Angiv multicast gruppe typen", + "MULTICAST-NAME-PLACEHOLDER": "Multicastens navn", + "MULTICAST-ADDRESS-PLACEHOLDER": "Multicast adressen", + "MULTICAST-NETWORK-KEY-PLACEHOLDER": "Multicastens network session key", + "MULTICAST-APPLICATION-KEY-PLACEHOLDER": "Multicastens application session key", + "MULTICAST-GROUPTYPE-PLACEHOLDER": "Vælg multicast gruppe typen", + "MULTICAST-PERIODICITY-PLACEHOLDER": "Vælg Class-B ping periodiciteten", "OTAAAPPLICATIONKEY": "OTAA application key (AppKey)", "OTAAAPPLICATIONKEY-PLACEHOLDER": "Indtast OTAA application key", "DEVADDR": "Device adress", @@ -697,7 +741,7 @@ "PINGSLOTFREQ": "Class-B ping-slot frequency", "SUPPORTSCLASSC_ACTIVATE": "Device supports Class-C", "CLASSCTIMEOUT": "Class C confirmed downlink timeout", - "CANCEL": "Anuller", + "CANCEL": "Annuller", "SAVE": "Gem", "OTAA-ABP": "Join (OTAA / ABP)", "MACVERSION_PLACEHOLDER": "1.0.0", @@ -821,6 +865,7 @@ "PERMISSION": "OS2IoT - Brugergrupper", "ORGANIZATION": "OS2IoT - Organisationer", "DATATARGET": "OS2IoT - Datatarget", + "MULTICAST": "OS2IoT - Multicast", "BULKIMPORT": "OS2IoT - Bulk import", "IOTDEVICE": "OS2IoT - IoT enhed", "FRONTPAGE": "OS2IoT - Forside" From f73d376deaa9729b1b4cc9540b371b141c5d8ecd Mon Sep 17 00:00:00 2001 From: August Andersen Date: Wed, 17 Nov 2021 16:22:05 +0100 Subject: [PATCH 02/18] Minor changes to make it work with backend. --- .../multicast-edit.component.html | 14 +++++------ .../multicast-edit.component.ts | 25 +++++++++++++++++-- .../applications/multicast/multicast.model.ts | 1 + 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.html b/src/app/applications/multicast/multicast-edit/multicast-edit.component.html index 10554638..62f53aea 100644 --- a/src/app/applications/multicast/multicast-edit/multicast-edit.component.html +++ b/src/app/applications/multicast/multicast-edit/multicast-edit.component.html @@ -28,19 +28,19 @@
- * + * + class="form-control" id="networkSessionKey" name="networkSessionKey" [(ngModel)]="multicast.networkSessionKey" + [ngClass]="{'is-invalid' : formFailedSubmit && errorFields.includes('networkSessionKey'), 'is-valid' : formFailedSubmit && !errorFields.includes('networkSessionKey')}">
- * + * + class="form-control" id="appliciationSessionKey" name="applicationSessionKey" [(ngModel)]="multicast.applicationSessionKey" + [ngClass]="{'is-invalid' : formFailedSubmit && errorFields.includes('applicationSessionKey'), 'is-valid' : formFailedSubmit && !errorFields.includes('applicationSessionKey')}">
@@ -68,7 +68,7 @@
- + * diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts b/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts index 7bf3b22a..ba0740c8 100644 --- a/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts +++ b/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts @@ -91,24 +91,40 @@ export class MulticastEditComponent implements OnInit { // } updateMulticast(): void { + this.resetErrors(); + this.multicast.applicationId = this.applicationId; this.multicastService.update(this.multicast).subscribe( (response) => { console.log(response); - this.router.navigateByUrl('/applications'); + this.router.navigate([ + 'applications', + this.applicationId.toString(), + 'multicast-list', + this.applicationName, + ]); }, (error: HttpErrorResponse) => { this.handleError(error); + this.formFailedSubmit = true; } ); } createMulticast(): void { + this.resetErrors(); + this.multicast.applicationId = this.applicationId; this.multicastService.create(this.multicast).subscribe( (response) => { console.log(response); - this.router.navigateByUrl('/multicast-list'); + this.router.navigate([ + 'applications', + this.applicationId.toString(), + 'multicast-list', + this.applicationName, + ]); }, (error: HttpErrorResponse) => { this.handleError(error); + this.formFailedSubmit = true; } ); } @@ -120,6 +136,11 @@ export class MulticastEditComponent implements OnInit { this.applicationName, ]); } + private resetErrors() { + this.errorFields = []; + this.errorMessages = undefined; + this.formFailedSubmit = false; + } handleError(error: HttpErrorResponse) { const errors = this.errorMessageService.handleErrorMessageWithFields(error); this.errorFields = errors.errorFields; diff --git a/src/app/applications/multicast/multicast.model.ts b/src/app/applications/multicast/multicast.model.ts index 0f374bcf..69976706 100644 --- a/src/app/applications/multicast/multicast.model.ts +++ b/src/app/applications/multicast/multicast.model.ts @@ -2,6 +2,7 @@ import { MulticastType } from '@shared/enums/multicast-type'; export class Multicast { id: number; + applicationId: number; groupName: string; address: string; networkSessionKey: string; From 6d8c9896b02222604d2d2a9f6174fb57cc147161 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Fri, 19 Nov 2021 12:53:38 +0100 Subject: [PATCH 03/18] Minor changes so detail page will show how updated/created the multicast --- .../datatarget/datatarget.service.ts | 2 +- .../multicast/multicast-response.model.ts | 22 +++++++ .../applications/multicast/multicast.model.ts | 14 ++-- .../multicast/multicast.service.ts | 64 ++++++++++++++++--- 4 files changed, 87 insertions(+), 15 deletions(-) create mode 100644 src/app/applications/multicast/multicast-response.model.ts diff --git a/src/app/applications/datatarget/datatarget.service.ts b/src/app/applications/datatarget/datatarget.service.ts index 72abdb98..74e3688c 100644 --- a/src/app/applications/datatarget/datatarget.service.ts +++ b/src/app/applications/datatarget/datatarget.service.ts @@ -66,7 +66,7 @@ export class DatatargetService { return datatarget; } ) - );; + ); } delete(id: number) { diff --git a/src/app/applications/multicast/multicast-response.model.ts b/src/app/applications/multicast/multicast-response.model.ts new file mode 100644 index 00000000..1b80fbd8 --- /dev/null +++ b/src/app/applications/multicast/multicast-response.model.ts @@ -0,0 +1,22 @@ +import { Application } from '@applications/application.model'; +import { MulticastType } from '@shared/enums/multicast-type'; + +export class MulticastResponse { + id: number; + application: Application; + groupName: string; + address: string; + networkSessionKey: string; + applicationSessionKey: string; + frameCounter: number = 0; + dataRate: number = 0; + frequency: number = 0; + groupType: MulticastType; + // periodicity: number; -> only if classB is gonna be used + createdAt: string; + updatedAt: string; + createdBy: number; + updatedBy: number; + createdByName: string; + updatedByName: string; +} \ No newline at end of file diff --git a/src/app/applications/multicast/multicast.model.ts b/src/app/applications/multicast/multicast.model.ts index 69976706..ec5566e4 100644 --- a/src/app/applications/multicast/multicast.model.ts +++ b/src/app/applications/multicast/multicast.model.ts @@ -12,10 +12,16 @@ export class Multicast { frequency: number = 0; groupType: MulticastType; // periodicity: number; -> only if classB is gonna be used + createdAt: string; + updatedAt: string; + createdBy: number; + updatedBy: number; + createdByName: string; + updatedByName: string; } export class MulticastData { - data: Multicast[]; - ok?: boolean; - count?: number; -} \ No newline at end of file + data: Multicast[]; + ok?: boolean; + count?: number; +} diff --git a/src/app/applications/multicast/multicast.service.ts b/src/app/applications/multicast/multicast.service.ts index 4b083571..44ec3ebb 100644 --- a/src/app/applications/multicast/multicast.service.ts +++ b/src/app/applications/multicast/multicast.service.ts @@ -1,14 +1,19 @@ import { Injectable } from '@angular/core'; +import { UserMinimalService } from '@app/admin/users/user-minimal.service'; import { RestService } from '@shared/services/rest.service'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; +import { MulticastResponse } from './multicast-response.model'; import { Multicast, MulticastData } from './multicast.model'; @Injectable({ providedIn: 'root', }) export class MulticastService { - constructor(private restService: RestService) {} + constructor( + private restService: RestService, + private userMinimalService: UserMinimalService + ) {} private multicastURL = 'multicast'; getByApplicationId( @@ -28,22 +33,61 @@ export class MulticastService { } get(id: number): Observable { return this.restService.get(this.multicastURL, {}, id).pipe( - map((response: Multicast) => { - return response; - }) + map( + (response: MulticastResponse) => { + const datatarget = this.mapToMulticast(response); + return datatarget; + } + ) ); } delete(id: number) { return this.restService.delete(this.multicastURL, id); } update(multicast: Multicast): Observable { - return this.restService.put(this.multicastURL, multicast, multicast.id, { - observe: 'response', - }); + return this.restService.put(this.multicastURL, multicast, multicast.id, { observe: 'response' }).pipe( + map( + (response: MulticastResponse) => { + const datatarget = this.mapToMulticast(response); + return datatarget; + } + ) + ); } create(multicast: Multicast): Observable { - return this.restService.post(this.multicastURL, multicast, { - observe: 'response', - }); + return this.restService.post(this.multicastURL, multicast).pipe( + map( + (response: MulticastResponse) => { + const datatarget = this.mapToMulticast(response); + return datatarget; + } + ) + ); + } + + private mapToMulticast(multicastResponse: MulticastResponse): Multicast { + const model: Multicast = { + id: multicastResponse.id, + groupName: multicastResponse.groupName, + groupType: multicastResponse.groupType, + address: multicastResponse.address, + applicationSessionKey: multicastResponse.applicationSessionKey, + dataRate: multicastResponse.dataRate, + frameCounter: multicastResponse.frameCounter, + frequency: multicastResponse.frequency, + networkSessionKey: multicastResponse.networkSessionKey, + applicationId: multicastResponse.application.id, + createdAt: multicastResponse.createdAt, + updatedAt: multicastResponse.updatedAt, + createdBy: multicastResponse.createdBy, + updatedBy: multicastResponse.updatedBy, + createdByName: this.userMinimalService.getUserNameFrom( + multicastResponse.createdBy + ), + updatedByName: this.userMinimalService.getUserNameFrom( + multicastResponse.updatedBy + ), + }; + return model; } } From 16038ff6c64b8857a368d492685f8106a559298a Mon Sep 17 00:00:00 2001 From: August Andersen Date: Tue, 23 Nov 2021 14:16:00 +0100 Subject: [PATCH 04/18] Moved two buttons, multicast and datatargets, to a tab bar in application details. --- .../application-detail.component.html | 81 ++++-- .../application-detail.component.ts | 6 + .../applications-routing.module.ts | 30 +- .../datatarget-detail.component.ts | 2 +- .../datatarget-edit.component.ts | 7 +- .../datatarget-list.component.spec.ts | 40 +-- .../datatarget-list.component.ts | 84 +++--- .../datatarget-table.component.ts | 2 +- .../datatarget/datatarget.module.ts | 3 - .../multicast-detail.component.ts | 27 +- .../multicast-edit.component.html | 267 +++++++++++++----- .../multicast-edit.component.ts | 46 +-- .../multicast-list.component.html | 24 +- .../multicast-list.component.spec.ts | 40 +-- .../multicast-list.component.ts | 84 +++--- .../multicast-table.component.ts | 26 +- .../multicast/multicast.module.ts | 4 - .../payload-decoder-edit.component.ts | 4 +- src/app/shared/services/save-snack.service.ts | 17 -- src/app/shared/services/snack.service.ts | 39 +++ src/assets/i18n/da.json | 11 +- 21 files changed, 532 insertions(+), 312 deletions(-) delete mode 100644 src/app/shared/services/save-snack.service.ts create mode 100644 src/app/shared/services/snack.service.ts diff --git a/src/app/applications/application-detail/application-detail.component.html b/src/app/applications/application-detail/application-detail.component.html index 647d2c1c..d044ddea 100644 --- a/src/app/applications/application-detail/application-detail.component.html +++ b/src/app/applications/application-detail/application-detail.component.html @@ -1,8 +1,7 @@
+ [addDetailDowndown]="true" [dropDownButton]="dropdownButton" (deleteSelectedInDropdown)="onDeleteApplication()" + [pageLimit]="pageLimit" (updatePageLimit)="updatePageLimit($event)">
@@ -19,22 +18,68 @@

Detaljer

-
-
-
-
- - + + +
+
+
+
+
+ + +
+ + + + + +
+
- - - - -
-
-
+ + +
+
+
+
+
+ + +
+ + + + + +
+
+
+
+
+ +
+
+
+
+
+ + +
+ + + + + +
+
+
+
+
+
\ No newline at end of file diff --git a/src/app/applications/application-detail/application-detail.component.ts b/src/app/applications/application-detail/application-detail.component.ts index 009f3a63..168f6ac8 100644 --- a/src/app/applications/application-detail/application-detail.component.ts +++ b/src/app/applications/application-detail/application-detail.component.ts @@ -3,6 +3,7 @@ import { Title } from '@angular/platform-browser'; import { ActivatedRoute, Router } from '@angular/router'; import { Application } from '@applications/application.model'; import { ApplicationService } from '@applications/application.service'; +import { environment } from '@environments/environment'; import { TranslateService } from '@ngx-translate/core'; import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service'; import { BackButton } from '@shared/models/back-button.model'; @@ -22,6 +23,7 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy { public application: Application; public backButton: BackButton = { label: '', routerLink: '/applications' }; public id: number; + public pageLimit = environment.tablePageSize; public dropdownButton: DropdownButton; public errorMessage: string; public canEdit = false; @@ -86,6 +88,7 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy { return this.application.iotDevices?.length > 0; } + bindApplication(id: number): void { this.applicationsSubscription = this.applicationService.getApplication(id).subscribe((application) => { this.application = application; @@ -100,4 +103,7 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy { this.deleteDialogSubscription.unsubscribe(); } } + updatePageLimit(limit: any) { + console.log(limit); + } } diff --git a/src/app/applications/applications-routing.module.ts b/src/app/applications/applications-routing.module.ts index d48876b1..d5dcd3eb 100644 --- a/src/app/applications/applications-routing.module.ts +++ b/src/app/applications/applications-routing.module.ts @@ -7,10 +7,8 @@ import { ApplicationsComponent } from './applications.component'; import { IoTDeviceDetailComponent } from './iot-devices/iot-device-detail/iot-device-detail.component'; import { IotDeviceEditComponent } from './iot-devices/iot-device-edit/iot-device-edit.component'; import { DatatargetEditComponent } from './datatarget/datatarget-edit/datatarget-edit.component'; -import { DatatargetListComponent } from './datatarget/datatarget-list/datatarget-list.component'; import { DatatargetDetailComponent } from './datatarget/datatarget-detail/datatarget-detail.component'; import { BulkImportComponent } from './bulk-import/bulk-import.component'; -import { MulticastListComponent } from './multicast/multicast-list/multicast-list.component'; import { MulticastEditComponent } from './multicast/multicast-edit/multicast-edit.component'; import { MulticastDetailComponent } from './multicast/multicast-detail/multicast-detail.component'; @@ -29,26 +27,16 @@ const applicationRoutes: Routes = [ { path: '', component: ApplicationDetailComponent }, { path: 'new-iot-device', component: IotDeviceEditComponent, }, { path: 'iot-device-edit/:deviceId', component: IotDeviceEditComponent, }, - { path: 'iot-device/:deviceId', component: IoTDeviceDetailComponent, }, - { - path: 'datatarget-list/:name', - children: [ - { path: '', component: DatatargetListComponent }, - { path: 'datatarget-edit', component: DatatargetEditComponent }, - { path: 'datatarget-edit/:datatargetId', component: DatatargetEditComponent }, - { path: 'datatarget/:datatargetId', component: DatatargetDetailComponent } - ] + { path: 'iot-device/:deviceId', component: IoTDeviceDetailComponent, }, - }, - { - path: 'multicast-list/:name', - children: [ - { path: '', component: MulticastListComponent }, - { path: 'multicast-edit', component: MulticastEditComponent}, - { path: 'multicast-edit/:multicastId', component: MulticastEditComponent }, - { path: 'multicast/:multicastId', component: MulticastDetailComponent } - ] - }, + { path: 'datatarget-edit', component: DatatargetEditComponent }, + { path: 'datatarget-edit/:datatargetId', component: DatatargetEditComponent }, + { path: 'datatarget/:datatargetId', component: DatatargetDetailComponent }, + + { path: 'multicast-edit', component: MulticastEditComponent}, + { path: 'multicast-edit/:multicastId', component: MulticastEditComponent }, + { path: 'multicast/:multicastId', component: MulticastDetailComponent }, + { path: 'bulk-import', component: BulkImportComponent }, ], }, diff --git a/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.ts b/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.ts index 7af25889..34aa9507 100644 --- a/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.ts +++ b/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.ts @@ -65,7 +65,7 @@ export class DatatargetDetailComponent implements OnInit, OnDestroy { } private setBackButton(applicationId: number) { - this.backButton.routerLink = ['applications', applicationId.toString(), 'datatarget-list', this.applicationName ] + this.backButton.routerLink = ['applications', applicationId.toString()] } onDeleteDatatarget() { diff --git a/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.ts b/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.ts index 568dfb77..fa1f81f9 100644 --- a/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.ts +++ b/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.ts @@ -11,7 +11,7 @@ import { DatatargetService } from '../datatarget.service'; import { ApplicationService } from '@applications/application.service'; import { PayloadDecoderService } from '@payload-decoder/payload-decoder.service'; import { PayloadDeviceDatatargetService } from '@payload-decoder/payload-device-datatarget.service'; -import { SaveSnackService } from '@shared/services/save-snack.service'; +import { SnackService } from '@shared/services/snack.service'; import { MatDialog } from '@angular/material/dialog'; import { HttpErrorResponse } from '@angular/common/http'; import { PayloadDecoderMappedResponse } from '@payload-decoder/payload-decoder.model'; @@ -63,7 +63,7 @@ export class DatatargetEditComponent implements OnInit, OnDestroy { private applicationService: ApplicationService, private payloadDecoderService: PayloadDecoderService, private payloadDeviceDataTargetService: PayloadDeviceDatatargetService, - private saveSnackService: SaveSnackService, + private saveSnackService: SnackService, private dialog: MatDialog, private errorMessageService: ErrorMessageService, private opendatadkService: OpendatadkService, @@ -237,6 +237,7 @@ export class DatatargetEditComponent implements OnInit, OnDestroy { this.datatarget.openDataDkDataset.acceptTerms = true; } this.showSavedSnack(); + this.routeToDatatargets(); }, (error: HttpErrorResponse) => { this.checkDataTargetModelOpendatadkdatasaet(); @@ -288,7 +289,7 @@ export class DatatargetEditComponent implements OnInit, OnDestroy { } routeToDatatargets(): void { - this.router.navigate(['applications',this.applicationId.toString(),'datatarget-list', this.applicationName]) + this.router.navigate(['applications',this.applicationId.toString()]) } onCoordinateKey(event: any) { diff --git a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.spec.ts b/src/app/applications/datatarget/datatarget-list/datatarget-list.component.spec.ts index 7b515efa..a3455dce 100644 --- a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.spec.ts +++ b/src/app/applications/datatarget/datatarget-list/datatarget-list.component.spec.ts @@ -1,25 +1,25 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +// import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { DatatargetListComponent } from './datatarget-list.component'; +// import { DatatargetListComponent } from './datatarget-list.component'; -describe('DatatargetListComponent', () => { - let component: DatatargetListComponent; - let fixture: ComponentFixture; +// describe('DatatargetListComponent', () => { +// let component: DatatargetListComponent; +// let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ DatatargetListComponent ] - }) - .compileComponents(); - })); +// beforeEach(async(() => { +// TestBed.configureTestingModule({ +// declarations: [ DatatargetListComponent ] +// }) +// .compileComponents(); +// })); - beforeEach(() => { - fixture = TestBed.createComponent(DatatargetListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); +// beforeEach(() => { +// fixture = TestBed.createComponent(DatatargetListComponent); +// component = fixture.componentInstance; +// fixture.detectChanges(); +// }); - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); +// it('should create', () => { +// expect(component).toBeTruthy(); +// }); +// }); diff --git a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.ts b/src/app/applications/datatarget/datatarget-list/datatarget-list.component.ts index 2f5236cd..cf6ce46d 100644 --- a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.ts +++ b/src/app/applications/datatarget/datatarget-list/datatarget-list.component.ts @@ -1,49 +1,49 @@ -import { Component, OnInit, Input } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { ActivatedRoute } from '@angular/router'; -import { Datatarget } from '../datatarget.model'; -import { BackButton } from '@shared/models/back-button.model'; -import { environment } from '@environments/environment'; -import { Title } from '@angular/platform-browser'; +// import { Component, OnInit, Input } from '@angular/core'; +// import { TranslateService } from '@ngx-translate/core'; +// import { ActivatedRoute } from '@angular/router'; +// import { Datatarget } from '../datatarget.model'; +// import { BackButton } from '@shared/models/back-button.model'; +// import { environment } from '@environments/environment'; +// import { Title } from '@angular/platform-browser'; -@Component({ - selector: 'a[app-datatarget-list]', - templateUrl: './datatarget-list.component.html', - styleUrls: ['./datatarget-list.component.scss'] -}) -export class DatatargetListComponent implements OnInit { +// @Component({ +// selector: 'a[app-datatarget-list]', +// templateUrl: './datatarget-list.component.html', +// styleUrls: ['./datatarget-list.component.scss'] +// }) +// export class DatatargetListComponent implements OnInit { - public pageLimit = environment.tablePageSize; - public title: string; - public backButton: BackButton = { label: '', routerLink: ''}; - public datatarget: Datatarget; - private applikationId: string; +// public pageLimit = environment.tablePageSize; +// public title: string; +// public backButton: BackButton = { label: '', routerLink: ''}; +// public datatarget: Datatarget; +// private applikationId: string; - constructor( - public translate: TranslateService, - private titleService: Title, - private route: ActivatedRoute) { - translate.use('da'); - } +// constructor( +// public translate: TranslateService, +// private titleService: Title, +// private route: ActivatedRoute) { +// translate.use('da'); +// } - ngOnInit(): void { - const applikationName: string = this.route.snapshot.paramMap.get('name'); - this.applikationId = this.route.snapshot.paramMap.get('id'); - this.translate.get(["NAV.DATATARGET", "NAV.APPLICATIONS", "TITLE.DATATARGET"]) - .subscribe((translate) => { - this.title = translate['NAV.DATATARGET'] + ' - ' + applikationName; - this.backButton.label = translate['NAV.APPLICATIONS']; - this.titleService.setTitle(translate['TITLE.DATATARGET']); - }); - this.setBackButton() - } +// ngOnInit(): void { +// const applikationName: string = this.route.snapshot.paramMap.get('name'); +// this.applikationId = this.route.snapshot.paramMap.get('id'); +// this.translate.get(["NAV.DATATARGET", "NAV.APPLICATIONS", "TITLE.DATATARGET"]) +// .subscribe((translate) => { +// this.title = translate['NAV.DATATARGET'] + ' - ' + applikationName; +// this.backButton.label = translate['NAV.APPLICATIONS']; +// this.titleService.setTitle(translate['TITLE.DATATARGET']); +// }); +// this.setBackButton() +// } - setBackButton() { - this.backButton.routerLink = ['applications', this.applikationId]; - } +// setBackButton() { +// this.backButton.routerLink = ['applications', this.applikationId]; +// } - updatePageLimit(limit: any) { - console.log(limit); - } -} +// updatePageLimit(limit: any) { +// console.log(limit); +// } +// } diff --git a/src/app/applications/datatarget/datatarget-table/datatarget-table.component.ts b/src/app/applications/datatarget/datatarget-table/datatarget-table.component.ts index c3bbc0df..fa4eb35d 100644 --- a/src/app/applications/datatarget/datatarget-table/datatarget-table.component.ts +++ b/src/app/applications/datatarget/datatarget-table/datatarget-table.component.ts @@ -46,7 +46,7 @@ export class DatatargetTableComponent implements OnInit, AfterViewInit, OnDestro } ngOnInit(): void { - this.applicationId = +Number(this.route.parent.parent.snapshot.paramMap.get('id')); + this.applicationId = +Number(this.route.parent.snapshot.paramMap.get('id')); console.log(this.applicationId); this.getDatatarget(); this.canEdit = this.meService.canWriteInTargetOrganization() diff --git a/src/app/applications/datatarget/datatarget.module.ts b/src/app/applications/datatarget/datatarget.module.ts index 58bd4078..46be0a33 100644 --- a/src/app/applications/datatarget/datatarget.module.ts +++ b/src/app/applications/datatarget/datatarget.module.ts @@ -1,7 +1,6 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { DatatargetTableComponent } from './datatarget-table/datatarget-table.component'; -import { DatatargetListComponent } from './datatarget-list/datatarget-list.component'; import { DatatargetEditComponent } from './datatarget-edit/datatarget-edit.component'; import { DatatargetDetailComponent } from './datatarget-detail/datatarget-detail.component'; import { TranslateModule } from '@ngx-translate/core'; @@ -19,7 +18,6 @@ import { PipesModule } from '@shared/pipes/pipes.module'; @NgModule({ declarations: [ DatatargetTableComponent, - DatatargetListComponent, DatatargetEditComponent, DatatargetDetailComponent, OpendatadkComponent, @@ -39,7 +37,6 @@ import { PipesModule } from '@shared/pipes/pipes.module'; ], exports: [ DatatargetTableComponent, - DatatargetListComponent, DatatargetEditComponent, DatatargetDetailComponent, NGMaterialModule diff --git a/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts b/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts index 9e480e8d..3676f02f 100644 --- a/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts +++ b/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts @@ -8,6 +8,7 @@ import { Subscription } from 'rxjs'; import { Multicast } from '../multicast.model'; import { Location } from '@angular/common'; import { MulticastService } from '../multicast.service'; +import { SnackService } from '@shared/services/snack.service'; @Component({ selector: 'app-multicast-detail', @@ -28,7 +29,8 @@ export class MulticastDetailComponent implements OnInit { private deleteDialogService: DeleteDialogService, private location: Location, private multicastService: MulticastService, - public translate: TranslateService + public translate: TranslateService, + public snackService: SnackService ) {} ngOnInit(): void { @@ -62,9 +64,7 @@ export class MulticastDetailComponent implements OnInit { private setBackButton(applicationId: number) { this.backButton.routerLink = [ 'applications', - applicationId.toString(), - 'multicast-list', - this.applicationName, + applicationId.toString() ]; } @@ -82,14 +82,29 @@ export class MulticastDetailComponent implements OnInit { if (response) { this.multicastService .delete(this.multicast.id) - .subscribe((response) => {}); - this.location.back(); + .subscribe((response) => { + if (response.status !== 0) { + this.showDeletedSnack(); + this.location.back(); + } + else{ + this.showFailSnack(); + } + }); } else { console.log(response); } }); } + showDeletedSnack(): void { + this.snackService.showDeletedSnack(); + } + + showFailSnack(): void{ + this.snackService.showFailSnack(); + } + ngOnDestroy(): void { if (this.deleteDialogSubscription) { this.deleteDialogSubscription.unsubscribe(); diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.html b/src/app/applications/multicast/multicast-edit/multicast-edit.component.html index 62f53aea..95dca867 100644 --- a/src/app/applications/multicast/multicast-edit/multicast-edit.component.html +++ b/src/app/applications/multicast/multicast-edit/multicast-edit.component.html @@ -1,84 +1,196 @@
-
-
    -
  • - {{error | translate}} -
  • -
-
+
+
    +
  • + {{ error | translate }} +
  • +
+
+
+
+ * + +
-
-
- * - -
- -
- * - -
+
+ * + +
-
- * - -
+
+ * + +
-
- * - -
+
+ * + +
-
- * - -
+
+ * + +
-
- * - -
+
+ * + +
-
- * - -
+
+ * + +
-
- * - - - {{multicastType}} - - -
+
+ * + + + {{ multicastType }} + + +
- - + -
- +
-
- - -
-
\ No newline at end of file +
+ + +
+ diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts b/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts index ba0740c8..435f3e7a 100644 --- a/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts +++ b/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts @@ -4,10 +4,12 @@ import { ActivatedRoute, Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { MulticastType } from '@shared/enums/multicast-type'; import { ErrorMessageService } from '@shared/error-message.service'; +import { SnackService } from '@shared/services/snack.service'; import { ScrollToTopService } from '@shared/services/scroll-to-top.service'; import { Subscription } from 'rxjs'; import { Multicast } from '../multicast.model'; import { MulticastService } from '../multicast.service'; +import { THIS_EXPR } from '@angular/compiler/src/output/output_ast'; @Component({ selector: 'app-multicast-edit', @@ -36,7 +38,8 @@ export class MulticastEditComponent implements OnInit { private router: Router, public multicastService: MulticastService, public errorMessageService: ErrorMessageService, - public scrollToTopService: ScrollToTopService + public scrollToTopService: ScrollToTopService, + public snackService: SnackService ) {} ngOnInit(): void { @@ -95,13 +98,8 @@ export class MulticastEditComponent implements OnInit { this.multicast.applicationId = this.applicationId; this.multicastService.update(this.multicast).subscribe( (response) => { - console.log(response); - this.router.navigate([ - 'applications', - this.applicationId.toString(), - 'multicast-list', - this.applicationName, - ]); + this.showUpdatedSnack(); + this.routeBack(); }, (error: HttpErrorResponse) => { this.handleError(error); @@ -114,13 +112,8 @@ export class MulticastEditComponent implements OnInit { this.multicast.applicationId = this.applicationId; this.multicastService.create(this.multicast).subscribe( (response) => { - console.log(response); - this.router.navigate([ - 'applications', - this.applicationId.toString(), - 'multicast-list', - this.applicationName, - ]); + this.showSavedSnack(); + this.routeBack(); }, (error: HttpErrorResponse) => { this.handleError(error); @@ -129,12 +122,23 @@ export class MulticastEditComponent implements OnInit { ); } routeBack(): void { - this.router.navigate([ - 'applications', - this.applicationId.toString(), - 'multicast-list', - this.applicationName, - ]); + this.router.navigate(['applications', this.applicationId.toString()]); + } + showSavedSnack() { + this.snackService.showSavedSnack(); + } + showUpdatedSnack() { + this.snackService.showUpdatedSnack(); + } + keyPressAlphaNumeric(event) { + var inp = String.fromCharCode(event.keyCode); + + if (/[a-zA-Z0-9]/.test(inp)) { + return true; + } else { + event.preventDefault(); + return false; + } } private resetErrors() { this.errorFields = []; diff --git a/src/app/applications/multicast/multicast-list/multicast-list.component.html b/src/app/applications/multicast/multicast-list/multicast-list.component.html index 6ff143d4..52e442c4 100644 --- a/src/app/applications/multicast/multicast-list/multicast-list.component.html +++ b/src/app/applications/multicast/multicast-list/multicast-list.component.html @@ -1,13 +1,19 @@ - +
-
-
-
- -
+
+
+
+
-
\ No newline at end of file +
+
diff --git a/src/app/applications/multicast/multicast-list/multicast-list.component.spec.ts b/src/app/applications/multicast/multicast-list/multicast-list.component.spec.ts index 353f2cb9..ab2d625e 100644 --- a/src/app/applications/multicast/multicast-list/multicast-list.component.spec.ts +++ b/src/app/applications/multicast/multicast-list/multicast-list.component.spec.ts @@ -1,25 +1,25 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +// import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { MulticastListComponent } from './multicast-list.component'; +// import { MulticastListComponent } from './multicast-list.component'; -describe('MulticastListComponent', () => { - let component: MulticastListComponent; - let fixture: ComponentFixture; +// describe('MulticastListComponent', () => { +// let component: MulticastListComponent; +// let fixture: ComponentFixture; - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ MulticastListComponent ] - }) - .compileComponents(); - })); +// beforeEach(async(() => { +// TestBed.configureTestingModule({ +// declarations: [ MulticastListComponent ] +// }) +// .compileComponents(); +// })); - beforeEach(() => { - fixture = TestBed.createComponent(MulticastListComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); +// beforeEach(() => { +// fixture = TestBed.createComponent(MulticastListComponent); +// component = fixture.componentInstance; +// fixture.detectChanges(); +// }); - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); +// it('should create', () => { +// expect(component).toBeTruthy(); +// }); +// }); diff --git a/src/app/applications/multicast/multicast-list/multicast-list.component.ts b/src/app/applications/multicast/multicast-list/multicast-list.component.ts index a4ad955c..b0b338b5 100644 --- a/src/app/applications/multicast/multicast-list/multicast-list.component.ts +++ b/src/app/applications/multicast/multicast-list/multicast-list.component.ts @@ -1,47 +1,47 @@ -import { Component, OnInit } from '@angular/core'; -import { Title } from '@angular/platform-browser'; -import { ActivatedRoute } from '@angular/router'; -import { environment } from '@environments/environment'; -import { TranslateService } from '@ngx-translate/core'; -import { BackButton } from '@shared/models/back-button.model'; +// import { Component, OnInit } from '@angular/core'; +// import { Title } from '@angular/platform-browser'; +// import { ActivatedRoute } from '@angular/router'; +// import { environment } from '@environments/environment'; +// import { TranslateService } from '@ngx-translate/core'; +// import { BackButton } from '@shared/models/back-button.model'; -@Component({ - selector: 'app-multicast-list', - templateUrl: './multicast-list.component.html', - styleUrls: ['./multicast-list.component.scss'], -}) -export class MulticastListComponent implements OnInit { - public pageLimit = environment.tablePageSize; - public title: string; - public backButton: BackButton = { label: '', routerLink: '' }; - private applicationId: string; +// @Component({ +// selector: 'app-multicast-list', +// templateUrl: './multicast-list.component.html', +// styleUrls: ['./multicast-list.component.scss'], +// }) +// export class MulticastListComponent implements OnInit { +// public pageLimit = environment.tablePageSize; +// public title: string; +// public backButton: BackButton = { label: '', routerLink: '' }; +// private applicationId: string; - constructor( - public translate: TranslateService, - private titleService: Title, - private route: ActivatedRoute - ) { - translate.use('da'); - } +// constructor( +// public translate: TranslateService, +// private titleService: Title, +// private route: ActivatedRoute +// ) { +// translate.use('da'); +// } - ngOnInit(): void { - const applicationName: string = this.route.snapshot.paramMap.get('name'); - this.applicationId = this.route.snapshot.paramMap.get('id'); - this.translate - .get(['NAV.MULTICAST', 'NAV.APPLICATIONS', 'TITLE.MULTICAST']) - .subscribe((translate) => { - this.title = translate['NAV.MULTICAST'] + ' - ' + applicationName; - this.backButton.label = translate['NAV.APPLICATIONS']; - this.titleService.setTitle(translate['TITLE.MULTICAST']); - }); - this.setBackButton(); - } +// ngOnInit(): void { +// const applicationName: string = this.route.snapshot.paramMap.get('name'); +// this.applicationId = this.route.snapshot.paramMap.get('id'); +// this.translate +// .get(['NAV.MULTICAST', 'NAV.APPLICATIONS', 'TITLE.MULTICAST']) +// .subscribe((translate) => { +// this.title = translate['NAV.MULTICAST'] + ' - ' + applicationName; +// this.backButton.label = translate['NAV.APPLICATIONS']; +// this.titleService.setTitle(translate['TITLE.MULTICAST']); +// }); +// this.setBackButton(); +// } - setBackButton() { - this.backButton.routerLink = ['applications', this.applicationId]; - } +// setBackButton() { +// this.backButton.routerLink = ['applications', this.applicationId]; +// } - updatePageLimit(limit: any) { - console.log(limit); - } -} +// updatePageLimit(limit: any) { +// console.log(limit); +// } +// } diff --git a/src/app/applications/multicast/multicast-table/multicast-table.component.ts b/src/app/applications/multicast/multicast-table/multicast-table.component.ts index ff0786ce..8e557d0d 100644 --- a/src/app/applications/multicast/multicast-table/multicast-table.component.ts +++ b/src/app/applications/multicast/multicast-table/multicast-table.component.ts @@ -16,7 +16,9 @@ import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dia import { MulticastType } from '@shared/enums/multicast-type'; import { tableSorter } from '@shared/helpers/table-sorting.helper'; import { MeService } from '@shared/services/me.service'; +import { SnackService } from '@shared/services/snack.service'; import { Subscription } from 'rxjs'; +import { multicast } from 'rxjs/operators'; import { Multicast, MulticastData } from '../multicast.model'; import { MulticastService } from '../multicast.service'; @@ -50,16 +52,14 @@ export class MulticastTableComponent private deleteDialogService: DeleteDialogService, private multicastService: MulticastService, private meService: MeService, - public translate: TranslateService + public translate: TranslateService, + public snackService: SnackService ) { translate.use('da'); } ngOnInit(): void { - this.applicationId = +Number( - this.route.parent.parent.snapshot.paramMap.get('id') - ); - console.log(this.applicationId); + this.applicationId = +Number(this.route.parent.snapshot.paramMap.get('id')); this.getMulticast(); this.canEdit = this.meService.canWriteInTargetOrganization(); } @@ -79,6 +79,7 @@ export class MulticastTableComponent appId ) .subscribe((multicasts: MulticastData) => { + console.log(multicasts); this.multicasts = multicasts.data; this.dataSource = new MatTableDataSource(this.multicasts); this.dataSource.paginator = this.paginator; @@ -88,6 +89,9 @@ export class MulticastTableComponent if (this.pageLimit) { this.pageTotal = Math.ceil(multicasts.count / this.pageLimit); } + if (multicasts.ok === false) { + this.showLoadFailSnack(); + } }); } } @@ -100,6 +104,9 @@ export class MulticastTableComponent this.multicastService.delete(element.id).subscribe((response) => { if (response.ok && response.body.affected > 0) { this.getMulticast(); + this.showDeletedSnack(); + } else { + this.showFailSnack(); } }); } else { @@ -108,6 +115,15 @@ export class MulticastTableComponent }); } + showLoadFailSnack() { + this.snackService.showLoadFailSnack(); + } + showFailSnack() { + this.snackService.showFailSnack(); + } + showDeletedSnack() { + this.snackService.showDeletedSnack(); + } ngOnDestroy() { // prevent memory leak by unsubscribing if (this.multicastSubscription) { diff --git a/src/app/applications/multicast/multicast.module.ts b/src/app/applications/multicast/multicast.module.ts index 7f38d76b..690e3daa 100644 --- a/src/app/applications/multicast/multicast.module.ts +++ b/src/app/applications/multicast/multicast.module.ts @@ -1,11 +1,9 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SharedModule } from '@shared/shared.module'; -import { MulticastListComponent } from './multicast-list/multicast-list.component'; import { MulticastDetailComponent } from './multicast-detail/multicast-detail.component'; import { MulticastEditComponent } from './multicast-edit/multicast-edit.component'; import { MulticastTableComponent } from './multicast-table/multicast-table.component'; -import { DatatargetModule } from '@applications/datatarget/datatarget.module'; import { RouterModule } from '@angular/router'; import { TranslateModule } from '@ngx-translate/core'; import { NGMaterialModule } from '@shared/Modules/materiale.module'; @@ -16,7 +14,6 @@ import { PipesModule } from '@shared/pipes/pipes.module'; @NgModule({ declarations: [ - MulticastListComponent, MulticastDetailComponent, MulticastEditComponent, MulticastTableComponent, @@ -34,7 +31,6 @@ import { PipesModule } from '@shared/pipes/pipes.module'; PipesModule, ], exports: [ - MulticastListComponent, MulticastDetailComponent, MulticastEditComponent, MulticastTableComponent, diff --git a/src/app/payload-decoder/payload-decoder-edit/payload-decoder-edit.component.ts b/src/app/payload-decoder/payload-decoder-edit/payload-decoder-edit.component.ts index cf7462e0..e4bb105b 100644 --- a/src/app/payload-decoder/payload-decoder-edit/payload-decoder-edit.component.ts +++ b/src/app/payload-decoder/payload-decoder-edit/payload-decoder-edit.component.ts @@ -18,7 +18,7 @@ import { DeviceModelService } from '@app/device-model/device-model.service'; import { faExchangeAlt } from '@fortawesome/free-solid-svg-icons'; import { TestPayloadDecoder } from '@payload-decoder/test-payload-decoder.model'; import { TestPayloadDecoderService } from '@payload-decoder/test-payload-decoder.service'; -import { SaveSnackService } from '@shared/services/save-snack.service'; +import { SnackService } from '@shared/services/snack.service'; import { ErrorMessageService } from '@shared/error-message.service'; import { ScrollToTopService } from '@shared/services/scroll-to-top.service'; import { environment } from '@environments/environment'; @@ -75,7 +75,7 @@ export class PayloadDecoderEditComponent implements OnInit { private sharedVariableService: SharedVariableService, private iotDeviceService: IoTDeviceService, private deviceModelService: DeviceModelService, - private saveSnackService: SaveSnackService, + private saveSnackService: SnackService, private errorMessageService: ErrorMessageService, private scrollToTopService: ScrollToTopService, ) { } diff --git a/src/app/shared/services/save-snack.service.ts b/src/app/shared/services/save-snack.service.ts deleted file mode 100644 index fcee59d7..00000000 --- a/src/app/shared/services/save-snack.service.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Injectable } from '@angular/core'; -import { MatSnackBar } from '@angular/material/snack-bar'; - - -@Injectable({ - providedIn: 'root', -}) -export class SaveSnackService { - constructor( - private snackBar: MatSnackBar) { } - - public showSavedSnack() { - this.snackBar.open('Gemt Succesfuldt', 'Luk', { - duration: 10000, - }); - } -} diff --git a/src/app/shared/services/snack.service.ts b/src/app/shared/services/snack.service.ts new file mode 100644 index 00000000..6eb98829 --- /dev/null +++ b/src/app/shared/services/snack.service.ts @@ -0,0 +1,39 @@ +import { Injectable } from '@angular/core'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { TranslateService } from '@ngx-translate/core'; + +@Injectable({ + providedIn: 'root', +}) +export class SnackService { + constructor( + private snackBar: MatSnackBar, + public translate: TranslateService + ) {} + + public showSavedSnack() { + this.snackBar.open(this.translate.instant('SNACK.SAVE'), 'Luk', { + duration: 10000, + }); + } + public showDeletedSnack() { + this.snackBar.open(this.translate.instant('SNACK.DELETE'), 'Luk', { + duration: 10000, + }); + } + public showUpdatedSnack() { + this.snackBar.open(this.translate.instant('SNACK.UPDATE'), 'Luk', { + duration: 10000, + }); + } + public showFailSnack() { + this.snackBar.open(this.translate.instant('SNACK.FAIL'), 'Luk', { + duration: 10000, + }); + } + public showLoadFailSnack() { + this.snackBar.open(this.translate.instant('SNACK.LOADFAIL'), 'Luk', { + duration: 10000, + }); + } +} diff --git a/src/assets/i18n/da.json b/src/assets/i18n/da.json index 1bc2965d..9dcdb9f6 100644 --- a/src/assets/i18n/da.json +++ b/src/assets/i18n/da.json @@ -46,6 +46,13 @@ "DELETE": "Slet" } }, + "SNACK": { + "SAVE": "Gemt succesfuldt", + "DELETE": "Slettet succesfuldt", + "UPDATE": "Opdateret succesfuldt", + "FAIL": "Fejl - aktion ikke fuldført", + "LOADFAIL": "Fejl - kunne ikke loade" + }, "SEARCH": { "ICON": "", "TYPE": "Type", @@ -87,8 +94,10 @@ "DESCRIPTION": "Applikationens beskrivelse", "ATTACHED-IOT": "Tilknyttede IoT enheder", "DATATARGET-SHOW": "Tilknyttede data targets", - "MULTICAST-SHOW": "Tilknyttede multicast grupper", + "MULTICAST-SHOW": "Tilknyttede multicast", + "MULTICAST-GROUPS": "Multicast-grupper", "IMPORT-CSV": "Bulk import af IoT enheder", + "IOT-DEVICES": "IoT-enheder", "BULK": { "TEMPLATE": { "GENERIC": "Generic HTTP sample", From 473c76346bf91bbf997652f42e761b0085032572 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Wed, 24 Nov 2021 09:11:33 +0100 Subject: [PATCH 05/18] minor typo fix --- src/app/applications/multicast/multicast.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/applications/multicast/multicast.service.ts b/src/app/applications/multicast/multicast.service.ts index 44ec3ebb..a07c6f7c 100644 --- a/src/app/applications/multicast/multicast.service.ts +++ b/src/app/applications/multicast/multicast.service.ts @@ -58,8 +58,8 @@ export class MulticastService { return this.restService.post(this.multicastURL, multicast).pipe( map( (response: MulticastResponse) => { - const datatarget = this.mapToMulticast(response); - return datatarget; + const multicast = this.mapToMulticast(response); + return multicast; } ) ); From 7fffca21bd2a9a11d978b7b5ea0f99bcc8f272f2 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Thu, 25 Nov 2021 16:11:45 +0100 Subject: [PATCH 06/18] Finalized CRUD in frontend. Removed list maps from datatarget and multicast because of change in requirements - now the multicast and datatarget is in a tab bar in the application detail page. --- .../datatarget-list.component.html | 13 --- .../datatarget-list.component.scss | 0 .../datatarget-list.component.spec.ts | 25 ------ .../datatarget-list.component.ts | 49 ----------- .../multicast-detail.component.html | 16 ++-- .../multicast-detail.component.ts | 11 +-- .../multicast-edit.component.html | 82 +++++++++---------- .../multicast-edit.component.ts | 38 ++++----- .../multicast-list.component.html | 19 ----- .../multicast-list.component.scss | 0 .../multicast-list.component.spec.ts | 25 ------ .../multicast-list.component.ts | 47 ----------- .../multicast/multicast-response.model.ts | 2 +- .../multicast-table.component.html | 10 +-- .../multicast-table.component.ts | 44 +++++----- .../applications/multicast/multicast.model.ts | 16 ++-- .../multicast/multicast.module.ts | 1 - .../multicast/multicast.service.ts | 71 ++++++++-------- src/app/shared/enums/multicast-type.ts | 2 +- 19 files changed, 139 insertions(+), 332 deletions(-) delete mode 100644 src/app/applications/datatarget/datatarget-list/datatarget-list.component.html delete mode 100644 src/app/applications/datatarget/datatarget-list/datatarget-list.component.scss delete mode 100644 src/app/applications/datatarget/datatarget-list/datatarget-list.component.spec.ts delete mode 100644 src/app/applications/datatarget/datatarget-list/datatarget-list.component.ts delete mode 100644 src/app/applications/multicast/multicast-list/multicast-list.component.html delete mode 100644 src/app/applications/multicast/multicast-list/multicast-list.component.scss delete mode 100644 src/app/applications/multicast/multicast-list/multicast-list.component.spec.ts delete mode 100644 src/app/applications/multicast/multicast-list/multicast-list.component.ts diff --git a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.html b/src/app/applications/datatarget/datatarget-list/datatarget-list.component.html deleted file mode 100644 index bad1cea6..00000000 --- a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.html +++ /dev/null @@ -1,13 +0,0 @@ - - -
-
-
-
- -
-
-
-
\ No newline at end of file diff --git a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.scss b/src/app/applications/datatarget/datatarget-list/datatarget-list.component.scss deleted file mode 100644 index e69de29b..00000000 diff --git a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.spec.ts b/src/app/applications/datatarget/datatarget-list/datatarget-list.component.spec.ts deleted file mode 100644 index a3455dce..00000000 --- a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -// import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -// import { DatatargetListComponent } from './datatarget-list.component'; - -// describe('DatatargetListComponent', () => { -// let component: DatatargetListComponent; -// let fixture: ComponentFixture; - -// beforeEach(async(() => { -// TestBed.configureTestingModule({ -// declarations: [ DatatargetListComponent ] -// }) -// .compileComponents(); -// })); - -// beforeEach(() => { -// fixture = TestBed.createComponent(DatatargetListComponent); -// component = fixture.componentInstance; -// fixture.detectChanges(); -// }); - -// it('should create', () => { -// expect(component).toBeTruthy(); -// }); -// }); diff --git a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.ts b/src/app/applications/datatarget/datatarget-list/datatarget-list.component.ts deleted file mode 100644 index cf6ce46d..00000000 --- a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.ts +++ /dev/null @@ -1,49 +0,0 @@ -// import { Component, OnInit, Input } from '@angular/core'; -// import { TranslateService } from '@ngx-translate/core'; -// import { ActivatedRoute } from '@angular/router'; -// import { Datatarget } from '../datatarget.model'; -// import { BackButton } from '@shared/models/back-button.model'; -// import { environment } from '@environments/environment'; -// import { Title } from '@angular/platform-browser'; - - -// @Component({ -// selector: 'a[app-datatarget-list]', -// templateUrl: './datatarget-list.component.html', -// styleUrls: ['./datatarget-list.component.scss'] -// }) -// export class DatatargetListComponent implements OnInit { - -// public pageLimit = environment.tablePageSize; -// public title: string; -// public backButton: BackButton = { label: '', routerLink: ''}; -// public datatarget: Datatarget; -// private applikationId: string; - -// constructor( -// public translate: TranslateService, -// private titleService: Title, -// private route: ActivatedRoute) { -// translate.use('da'); -// } - -// ngOnInit(): void { -// const applikationName: string = this.route.snapshot.paramMap.get('name'); -// this.applikationId = this.route.snapshot.paramMap.get('id'); -// this.translate.get(["NAV.DATATARGET", "NAV.APPLICATIONS", "TITLE.DATATARGET"]) -// .subscribe((translate) => { -// this.title = translate['NAV.DATATARGET'] + ' - ' + applikationName; -// this.backButton.label = translate['NAV.APPLICATIONS']; -// this.titleService.setTitle(translate['TITLE.DATATARGET']); -// }); -// this.setBackButton() -// } - -// setBackButton() { -// this.backButton.routerLink = ['applications', this.applikationId]; -// } - -// updatePageLimit(limit: any) { -// console.log(limit); -// } -// } diff --git a/src/app/applications/multicast/multicast-detail/multicast-detail.component.html b/src/app/applications/multicast/multicast-detail/multicast-detail.component.html index a8aede80..65c4a16a 100644 --- a/src/app/applications/multicast/multicast-detail/multicast-detail.component.html +++ b/src/app/applications/multicast/multicast-detail/multicast-detail.component.html @@ -1,6 +1,6 @@
- +
@@ -8,12 +8,12 @@

{{ 'MULTICAST.DETAILS' | translate }}

-

{{ 'MULTICAST.GROUPNAME' | translate }}{{multicast.groupName | translate }}

-

{{ 'MULTICAST.ADDRESS' | translate }}{{multicast.address | translate}}

-

{{ 'MULTICAST.NETWORK-KEY' | translate }}{{multicast.networkSessionKey | translate}}

-

{{ 'MULTICAST.APPLICATION-KEY' | translate }}{{multicast.applicationSessionKey | translate}}

-

{{ 'MULTICAST.FRAMECOUNTER' | translate }}{{multicast.frameCounter}}

-

{{ 'MULTICAST.DATARATE' | translate }}{{multicast.dataRate}}

+

{{ 'MULTICAST.GROUPNAME' | translate }}{{multicast.name | translate }}

+

{{ 'MULTICAST.ADDRESS' | translate }}{{multicast.mcAddr | translate}}

+

{{ 'MULTICAST.NETWORK-KEY' | translate }}{{multicast.mcNwkSKey | translate}}

+

{{ 'MULTICAST.APPLICATION-KEY' | translate }}{{multicast.mcAppSKey | translate}}

+

{{ 'MULTICAST.FRAMECOUNTER' | translate }}{{multicast.fCnt}}

+

{{ 'MULTICAST.DATARATE' | translate }}{{multicast.dr}}

{{ 'MULTICAST.FREQUENCY' | translate }}{{multicast.frequency}}

{{ 'MULTICAST.GROUPTYPE' | translate }}{{multicast.groupType}}

diff --git a/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts b/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts index 3676f02f..f074882f 100644 --- a/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts +++ b/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts @@ -16,12 +16,10 @@ import { SnackService } from '@shared/services/snack.service'; styleUrls: ['./multicast-detail.component.scss'], }) export class MulticastDetailComponent implements OnInit { - public multicastSubscription: Subscription; public multicast: Multicast; public backButton: BackButton = { label: '', routerLink: '/multicast-list' }; private deleteDialogSubscription: Subscription; public dropdownButton: DropdownButton; - private applicationName: string; private applicationId: number; constructor( @@ -34,8 +32,7 @@ export class MulticastDetailComponent implements OnInit { ) {} ngOnInit(): void { - const id: number = +this.route.snapshot.paramMap.get('multicastId'); - this.applicationName = this.route.snapshot.paramMap.get('name'); + const id: string = this.route.snapshot.paramMap.get('multicastId'); // the multicastId is a string, created by chirpstack. if (id) { this.getMulticast(id); this.dropdownButton = { @@ -54,7 +51,7 @@ export class MulticastDetailComponent implements OnInit { }); } - getMulticast(id: number) { + getMulticast(id: string) { this.multicastService.get(id).subscribe((multicast: Multicast) => { this.multicast = multicast; this.setBackButton(this.applicationId); @@ -75,13 +72,13 @@ export class MulticastDetailComponent implements OnInit { // } else return false; // } - onDeleteDatatarget() { + onDeleteMulticast() { this.deleteDialogSubscription = this.deleteDialogService .showSimpleDialog() .subscribe((response) => { if (response) { this.multicastService - .delete(this.multicast.id) + .delete(this.multicast.multicastId) .subscribe((response) => { if (response.status !== 0) { this.showDeletedSnack(); diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.html b/src/app/applications/multicast/multicast-edit/multicast-edit.component.html index 95dca867..168c3e48 100644 --- a/src/app/applications/multicast/multicast-edit/multicast-edit.component.html +++ b/src/app/applications/multicast/multicast-edit/multicast-edit.component.html @@ -11,28 +11,28 @@
-
-
-
-
-
-
diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts b/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts index 435f3e7a..bfa0e314 100644 --- a/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts +++ b/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts @@ -9,7 +9,6 @@ import { ScrollToTopService } from '@shared/services/scroll-to-top.service'; import { Subscription } from 'rxjs'; import { Multicast } from '../multicast.model'; import { MulticastService } from '../multicast.service'; -import { THIS_EXPR } from '@angular/compiler/src/output/output_ast'; @Component({ selector: 'app-multicast-edit', @@ -18,16 +17,14 @@ import { THIS_EXPR } from '@angular/compiler/src/output/output_ast'; }) export class MulticastEditComponent implements OnInit { public title: string; - public multicastId: number; + public multicastId: string; public errorMessages: any; private multicastSubscription: Subscription; public errorFields: string[]; @Input() submitButton: string; public backButtonTitle: string; public multicast: Multicast = new Multicast(); - private counter: number; private applicationId: number; - private applicationName: string; public formFailedSubmit: boolean = false; public multicastTypes: string[] = Object.values(MulticastType); public periodicities: number[] = [2, 4, 8, 16, 32, 64, 128]; @@ -51,8 +48,10 @@ export class MulticastEditComponent implements OnInit { 'NAV.MULTICAST', ]) .subscribe((translations) => { - const multicastId = +this.route.snapshot.paramMap.get('multicastId'); - if (multicastId !== 0) { + this.multicastId = this.route.snapshot.paramMap.get('multicastId'); // the multicastId is a string, created by chirpstack. Used when in edit when update. + this.applicationId = +this.route.snapshot.paramMap.get('id'); + + if (this.multicastId !== null) { this.title = translations['FORM.EDIT-MULTICAST']; } else { this.title = translations['FORM.CREATE-NEW-MULTICAST']; @@ -61,28 +60,23 @@ export class MulticastEditComponent implements OnInit { this.backButtonTitle = translations['NAV.MULTICAST']; }); - this.multicastId = +this.route.snapshot.paramMap.get('multicastId'); - this.applicationId = +this.route.snapshot.paramMap.get('id'); - this.applicationName = this.route.snapshot.paramMap.get('name'); - - if (this.multicastId !== 0) { + if (this.multicastId !== null) { // If edit is pressed, then get the specific multicast. this.getMulticast(this.multicastId); } } onSubmit(): void { - this.counter = 0; - if (this.multicastId) { + if (this.multicastId) { // if already created, only update this.updateMulticast(); - } else { + } else { // else create new this.createMulticast(); } } - getMulticast(id: number) { + getMulticast(id: string) { this.multicastSubscription = this.multicastService .get(id) .subscribe((response: Multicast) => { - this.multicast = response; + this.multicast = response; // gets the multicast and set's local multicast. Used when update. }); } @@ -95,9 +89,9 @@ export class MulticastEditComponent implements OnInit { updateMulticast(): void { this.resetErrors(); - this.multicast.applicationId = this.applicationId; + this.multicast.applicationID = this.applicationId; this.multicastService.update(this.multicast).subscribe( - (response) => { + () => { this.showUpdatedSnack(); this.routeBack(); }, @@ -109,9 +103,9 @@ export class MulticastEditComponent implements OnInit { } createMulticast(): void { this.resetErrors(); - this.multicast.applicationId = this.applicationId; + this.multicast.applicationID = this.applicationId; this.multicastService.create(this.multicast).subscribe( - (response) => { + () => { this.showSavedSnack(); this.routeBack(); }, @@ -130,10 +124,10 @@ export class MulticastEditComponent implements OnInit { showUpdatedSnack() { this.snackService.showUpdatedSnack(); } - keyPressAlphaNumeric(event) { + keyPressHexadecimal(event) { // make sure only hexadecimal can be typed in input with adresses. var inp = String.fromCharCode(event.keyCode); - if (/[a-zA-Z0-9]/.test(inp)) { + if (/[a-fA-F0-9]/.test(inp)) { return true; } else { event.preventDefault(); diff --git a/src/app/applications/multicast/multicast-list/multicast-list.component.html b/src/app/applications/multicast/multicast-list/multicast-list.component.html deleted file mode 100644 index 52e442c4..00000000 --- a/src/app/applications/multicast/multicast-list/multicast-list.component.html +++ /dev/null @@ -1,19 +0,0 @@ - - -
-
-
-
- -
-
-
-
diff --git a/src/app/applications/multicast/multicast-list/multicast-list.component.scss b/src/app/applications/multicast/multicast-list/multicast-list.component.scss deleted file mode 100644 index e69de29b..00000000 diff --git a/src/app/applications/multicast/multicast-list/multicast-list.component.spec.ts b/src/app/applications/multicast/multicast-list/multicast-list.component.spec.ts deleted file mode 100644 index ab2d625e..00000000 --- a/src/app/applications/multicast/multicast-list/multicast-list.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -// import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -// import { MulticastListComponent } from './multicast-list.component'; - -// describe('MulticastListComponent', () => { -// let component: MulticastListComponent; -// let fixture: ComponentFixture; - -// beforeEach(async(() => { -// TestBed.configureTestingModule({ -// declarations: [ MulticastListComponent ] -// }) -// .compileComponents(); -// })); - -// beforeEach(() => { -// fixture = TestBed.createComponent(MulticastListComponent); -// component = fixture.componentInstance; -// fixture.detectChanges(); -// }); - -// it('should create', () => { -// expect(component).toBeTruthy(); -// }); -// }); diff --git a/src/app/applications/multicast/multicast-list/multicast-list.component.ts b/src/app/applications/multicast/multicast-list/multicast-list.component.ts deleted file mode 100644 index b0b338b5..00000000 --- a/src/app/applications/multicast/multicast-list/multicast-list.component.ts +++ /dev/null @@ -1,47 +0,0 @@ -// import { Component, OnInit } from '@angular/core'; -// import { Title } from '@angular/platform-browser'; -// import { ActivatedRoute } from '@angular/router'; -// import { environment } from '@environments/environment'; -// import { TranslateService } from '@ngx-translate/core'; -// import { BackButton } from '@shared/models/back-button.model'; - -// @Component({ -// selector: 'app-multicast-list', -// templateUrl: './multicast-list.component.html', -// styleUrls: ['./multicast-list.component.scss'], -// }) -// export class MulticastListComponent implements OnInit { -// public pageLimit = environment.tablePageSize; -// public title: string; -// public backButton: BackButton = { label: '', routerLink: '' }; -// private applicationId: string; - -// constructor( -// public translate: TranslateService, -// private titleService: Title, -// private route: ActivatedRoute -// ) { -// translate.use('da'); -// } - -// ngOnInit(): void { -// const applicationName: string = this.route.snapshot.paramMap.get('name'); -// this.applicationId = this.route.snapshot.paramMap.get('id'); -// this.translate -// .get(['NAV.MULTICAST', 'NAV.APPLICATIONS', 'TITLE.MULTICAST']) -// .subscribe((translate) => { -// this.title = translate['NAV.MULTICAST'] + ' - ' + applicationName; -// this.backButton.label = translate['NAV.APPLICATIONS']; -// this.titleService.setTitle(translate['TITLE.MULTICAST']); -// }); -// this.setBackButton(); -// } - -// setBackButton() { -// this.backButton.routerLink = ['applications', this.applicationId]; -// } - -// updatePageLimit(limit: any) { -// console.log(limit); -// } -// } diff --git a/src/app/applications/multicast/multicast-response.model.ts b/src/app/applications/multicast/multicast-response.model.ts index 1b80fbd8..5a2b8aa3 100644 --- a/src/app/applications/multicast/multicast-response.model.ts +++ b/src/app/applications/multicast/multicast-response.model.ts @@ -2,7 +2,7 @@ import { Application } from '@applications/application.model'; import { MulticastType } from '@shared/enums/multicast-type'; export class MulticastResponse { - id: number; + multicastId: string; application: Application; groupName: string; address: string; diff --git a/src/app/applications/multicast/multicast-table/multicast-table.component.html b/src/app/applications/multicast/multicast-table/multicast-table.component.html index adfb5208..37169681 100644 --- a/src/app/applications/multicast/multicast-table/multicast-table.component.html +++ b/src/app/applications/multicast/multicast-table/multicast-table.component.html @@ -10,7 +10,7 @@ {{ 'MULTICAST-TABLE.NAME' | translate }} - {{element.groupName}} @@ -24,17 +24,17 @@ {{element.groupType | translate}} - + +
+ + +
+ + {{ + 'QUESTION.MULTICAST.SELECT-DEVICES' | translate + }} + + + + + + {{ + device.name + }} + + +
+
diff --git a/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts b/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts index 4a6651ff..bd5d3a2f 100644 --- a/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts +++ b/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service'; @@ -9,6 +9,13 @@ import { Multicast } from '../multicast.model'; import { Location } from '@angular/common'; import { MulticastService } from '../multicast.service'; import { SnackService } from '@shared/services/snack.service'; +import { Downlink } from '@applications/iot-devices/downlink.model'; +import { DownlinkService } from '@shared/services/downlink.service'; +import { HttpErrorResponse } from '@angular/common/http'; +import { ErrorMessageService } from '@shared/error-message.service'; +import { MatDialog } from '@angular/material/dialog'; +import { DownlinkDialogComponent } from '@applications/iot-devices/iot-device-detail/downlink/downlink-dialog/downlink-dialog.component'; +import { MatSnackBar } from '@angular/material/snack-bar'; @Component({ selector: 'app-multicast-detail', @@ -20,18 +27,27 @@ export class MulticastDetailComponent implements OnInit { public backButton: BackButton = { label: '', routerLink: '/multicast-list' }; private deleteDialogSubscription: Subscription; public dropdownButton: DropdownButton; + + public formFailedSubmit: boolean = false; private applicationId: number; + public downlink = new Downlink(); + @Input() errorMessages: string[]; constructor( private route: ActivatedRoute, + private snackBar: MatSnackBar, + public dialog: MatDialog, private deleteDialogService: DeleteDialogService, private location: Location, private multicastService: MulticastService, public translate: TranslateService, - public snackService: SnackService + public snackService: SnackService, + public downlinkService: DownlinkService, + private errorMessageService: ErrorMessageService ) {} ngOnInit(): void { + this.errorMessages = []; const id: number = +this.route.snapshot.paramMap.get('multicastId'); if (id) { this.getMulticast(id); @@ -97,6 +113,87 @@ export class MulticastDetailComponent implements OnInit { showFailSnack(): void { this.snackService.showFailSnack(); } + showQueueSnack(): void { + this.snackService.showInQueueSnack(); + } + keyPressHexadecimal(event) { + // make sure only hexadecimal can be typed in input with adresses. + var inp = String.fromCharCode(event.keyCode); + + if (/[a-fA-F0-9]/.test(inp)) { + return true; + } else { + event.preventDefault(); + return false; + } + } + private handleError(error: HttpErrorResponse) { + const errors = this.errorMessageService.handleErrorMessageWithFields(error); + this.errorMessages = errors.errorFields; + this.errorMessages = errors.errorMessages; + } + + clickDownlink() { + if (this.validateHex(this.downlink.data)) { + this.downlinkService.multicastGet(this.multicast.id).subscribe( + (response: any) => { + console.log(response) + if (response.totalCount > 0) { + this.openDownlinkDialog(); + } else { + this.startDownlink(); + } + }, + (error) => { + this.handleError(error); + console.log(error); + } + ); + } + } + openDownlinkDialog() { + const dialog = this.dialog.open(DownlinkDialogComponent, {}); + + dialog.afterClosed().subscribe((result) => { + if (result === true) { + this.startDownlink(); + console.log(`Dialog result: ${result}`); + } + }); + } + + private startDownlink() { + this.errorMessages = []; + this.downlinkService + .multicastPost(this.downlink, this.multicast.id) + .subscribe( + (response) => { + this.showQueueSnack(); + }, + (error) => { + this.handleError(error); + } + ); + } + + private validateHex(input: string): boolean { + const isHexinput = /^[a-fA-F\d]+$/.test(input); + let validator = false; + if (isHexinput) { + validator = true; + } else { + console.log('test'); + this.addToErrorMessage('MULTICAST.DOWNLINK.NO-PORT-OR-PAYLOAD'); + validator = false; + } + return validator; + } + + addToErrorMessage(text: string) { + this.translate.get([text]).subscribe((translations) => { + this.errorMessages.push(translations[text]); + }); + } ngOnDestroy(): void { if (this.deleteDialogSubscription) { diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts b/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts index 7dcdfac4..16e95613 100644 --- a/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts +++ b/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts @@ -30,7 +30,7 @@ export class MulticastEditComponent implements OnInit { private applicationId: number; public formFailedSubmit: boolean = false; public multicastTypes: string[] = Object.values(MulticastType); - public periodicities: number[] = [2, 4, 8, 16, 32, 64, 128]; + // public periodicities: number[] = [2, 4, 8, 16, 32, 64, 128]; // used for classB if it has to be used in the future constructor( public translate: TranslateService, @@ -152,7 +152,7 @@ export class MulticastEditComponent implements OnInit { showSavedSnack() { this.snackService.showSavedSnack(); } - showFailSnack(){ + showFailSnack() { this.snackService.showFailSnack(); } showUpdatedSnack() { diff --git a/src/app/applications/multicast/multicast.service.ts b/src/app/applications/multicast/multicast.service.ts index c2dc0c3a..33b1e316 100644 --- a/src/app/applications/multicast/multicast.service.ts +++ b/src/app/applications/multicast/multicast.service.ts @@ -88,6 +88,7 @@ export class MulticastService { updatedByName: this.userMinimalService.getUserNameFrom( multicastResponse.updatedBy ), + }; return model; } diff --git a/src/app/shared/services/downlink.service.ts b/src/app/shared/services/downlink.service.ts index 0715afbe..e39a3ca2 100644 --- a/src/app/shared/services/downlink.service.ts +++ b/src/app/shared/services/downlink.service.ts @@ -10,6 +10,8 @@ export class DownlinkService { private IOTDEVICEURL = 'iot-device/'; private DOWNLINKURL = 'downlink'; + private MULTICASTURL = 'multicast/'; + private DOWNLINKMULTICASTURL = 'downlink-multicast'; constructor(private restService: RestService) { } @@ -22,4 +24,14 @@ export class DownlinkService { const url = this.IOTDEVICEURL + deviceId + '/' + this.DOWNLINKURL; return this.restService.post(url, downlink, params); } + + + public multicastGet(multicastId: number, params = {}): Observable { + const url = this.MULTICASTURL + multicastId + '/' + this.DOWNLINKMULTICASTURL; + return this.restService.get(url, params); + } + public multicastPost(downlink: Downlink, multicastId: number, params = {}): Observable { + const url = this.MULTICASTURL + multicastId + '/' + this.DOWNLINKMULTICASTURL; + return this.restService.post(url, downlink, params); + } } diff --git a/src/app/shared/services/snack.service.ts b/src/app/shared/services/snack.service.ts index 6eb98829..d5831815 100644 --- a/src/app/shared/services/snack.service.ts +++ b/src/app/shared/services/snack.service.ts @@ -12,27 +12,32 @@ export class SnackService { ) {} public showSavedSnack() { - this.snackBar.open(this.translate.instant('SNACK.SAVE'), 'Luk', { + this.snackBar.open(this.translate.instant('SNACK.SAVE'), this.translate.instant('SNACK.CLOSE'), { duration: 10000, }); } public showDeletedSnack() { - this.snackBar.open(this.translate.instant('SNACK.DELETE'), 'Luk', { + this.snackBar.open(this.translate.instant('SNACK.DELETE'), this.translate.instant('SNACK.CLOSE'), { duration: 10000, }); } public showUpdatedSnack() { - this.snackBar.open(this.translate.instant('SNACK.UPDATE'), 'Luk', { + this.snackBar.open(this.translate.instant('SNACK.UPDATE'), this.translate.instant('SNACK.CLOSE'), { duration: 10000, }); } public showFailSnack() { - this.snackBar.open(this.translate.instant('SNACK.FAIL'), 'Luk', { + this.snackBar.open(this.translate.instant('SNACK.FAIL'), this.translate.instant('SNACK.CLOSE'), { duration: 10000, }); } public showLoadFailSnack() { - this.snackBar.open(this.translate.instant('SNACK.LOADFAIL'), 'Luk', { + this.snackBar.open(this.translate.instant('SNACK.LOADFAIL'), this.translate.instant('SNACK.CLOSE'), { + duration: 10000, + }); + } + public showInQueueSnack() { + this.snackBar.open(this.translate.instant('SNACK.QUEUE'), this.translate.instant('SNACK.CLOSE'), { duration: 10000, }); } diff --git a/src/assets/i18n/da.json b/src/assets/i18n/da.json index 3964842a..ced5514c 100644 --- a/src/assets/i18n/da.json +++ b/src/assets/i18n/da.json @@ -51,7 +51,9 @@ "DELETE": "Slettet succesfuldt", "UPDATE": "Opdateret succesfuldt", "FAIL": "Fejl - aktion ikke fuldført", - "LOADFAIL": "Fejl - kunne ikke loade" + "LOADFAIL": "Fejl - kunne ikke loade", + "QUEUE": "Element sat i kø", + "CLOSE": "Luk" }, "SEARCH": { "ICON": "", @@ -177,7 +179,12 @@ "FREQUENCY": "Frekvens (Hz)", "GROUPTYPE": "Gruppe type", "PERIODICITY": "Periodicitet", - "IOTDEVICE": "IoT enhed(er)" + "IOTDEVICE": "IoT enhed(er)", + "DOWNLINK": { + "PORT": "Angiv den ønskede port", + "PAYLOAD": "Angiv det ønskede payload", + "START": "Sæt downlink i kø" + } }, "OPENDATADK": { "QUESTION": { @@ -516,7 +523,8 @@ "MULTICAST": { "SELECT-DEVICES": "Vælg enheder", "SELECTALLDEVICES": "Vælg alle", - "DESELECTALLDEVICES": "Fravælg alle" + "DESELECTALLDEVICES": "Fravælg alle", + "NO-PORT-OR-PAYLOAD": "Angiv en port og en payload" }, "SIGFOX": { "TITLE": "Sigfox specifikke felter", From 5f88b689cca0a98764fe4b1efff29ede13e7c692 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Mon, 6 Dec 2021 12:03:48 +0100 Subject: [PATCH 13/18] Changed details page. Not splitted up in basic details, and lorawan details. --- .../multicast-detail/multicast-detail.component.html | 6 ++++-- .../multicast-detail/multicast-detail.component.scss | 3 +++ src/app/applications/multicast/multicast-response.model.ts | 2 +- src/assets/i18n/da.json | 7 +++++-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/app/applications/multicast/multicast-detail/multicast-detail.component.html b/src/app/applications/multicast/multicast-detail/multicast-detail.component.html index 388bac0e..919ff162 100644 --- a/src/app/applications/multicast/multicast-detail/multicast-detail.component.html +++ b/src/app/applications/multicast/multicast-detail/multicast-detail.component.html @@ -10,13 +10,15 @@
-

{{ 'MULTICAST.DETAILS' | translate }}

+

{{ 'MULTICAST.BASIC-DETAILS' | translate }}

-

{{ 'MULTICAST.GROUPNAME' | translate }}{{ multicast.name | translate }}

+ +

{{ 'MULTICAST.LORAWAN-DETAILS' | translate }}

+

{{ 'MULTICAST.ADDRESS' | translate }}{{ multicast.mcAddr | translate }} diff --git a/src/app/applications/multicast/multicast-detail/multicast-detail.component.scss b/src/app/applications/multicast/multicast-detail/multicast-detail.component.scss index e69de29b..ea3f31bc 100644 --- a/src/app/applications/multicast/multicast-detail/multicast-detail.component.scss +++ b/src/app/applications/multicast/multicast-detail/multicast-detail.component.scss @@ -0,0 +1,3 @@ +.loraDetails{ + margin-top: 15px; +} \ No newline at end of file diff --git a/src/app/applications/multicast/multicast-response.model.ts b/src/app/applications/multicast/multicast-response.model.ts index 1d09c4bb..72c8558c 100644 --- a/src/app/applications/multicast/multicast-response.model.ts +++ b/src/app/applications/multicast/multicast-response.model.ts @@ -25,5 +25,5 @@ export class LorawanMulticastDefinition { dataRate: number = 0; frequency: number = 0; groupType: MulticastType; - chirpstackGroupId: string; + chirpstackGroupId?: string; } diff --git a/src/assets/i18n/da.json b/src/assets/i18n/da.json index ced5514c..a824b1e8 100644 --- a/src/assets/i18n/da.json +++ b/src/assets/i18n/da.json @@ -169,7 +169,8 @@ }, "MULTICAST": { "SAVE": "Gem multicast", - "DETAILS": "Detaljer", + "BASIC-DETAILS": "Basale detaljer", + "LORAWAN-DETAILS": "LoRaWAN detailjer", "GROUPNAME": "Gruppe navn", "ADDRESS": "Adresse", "NETWORK-KEY": "Network session key", @@ -698,7 +699,9 @@ "DELETE-NOT-ALLOWED-HAS-SIGFOX-DEVICE": "Applikation kan ikke blive slettet, da den indeholder en eller flere Sigfox enheder.", "DELETE-NOT-ALLOWED-HAS-LORAWAN-DEVICE": "Service profilen kan ikke blive slettet, da den er i brug af en eller flere LoRaWAN enheder.", "OTAA-INFO-MISSING": "OTAA nøgle mangler eller er ikke gyldig.", - "ABP-INFO-MISSING": "ABP nøgle mangler eller er ikke gyldig." + "ABP-INFO-MISSING": "ABP nøgle mangler eller er ikke gyldig.", + "DIFFERENT-SERVICE-PROFILE": "Dine devices har forskellige service profiles. De skal have den samme service profile!", + "WRONG-SERVICE-PROFILE": "Dine devices har forkert service profile. Vælg devices som har samme service profile som din multicast." }, "PROFILES": { "NAME": "LoRaWAN profiler", From 5780eaea252fae2ab79633d80bf62f60f2e61ea2 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Tue, 14 Dec 2021 14:54:35 +0100 Subject: [PATCH 14/18] PR changes plus search function for devices in multicast --- .../iot-devices/downlink.model.ts | 7 +- .../multicast-detail.component.spec.ts | 25 ------ .../multicast-detail.component.ts | 54 ++++--------- .../multicast-edit.component.html | 18 ++++- .../multicast-edit.component.scss | 5 ++ .../multicast-edit.component.spec.ts | 25 ------ .../multicast-edit.component.ts | 80 +++++++++++++------ .../multicast/multicast-response.model.ts | 6 +- .../multicast-table.component.html | 2 +- .../multicast-table.component.spec.ts | 25 ------ .../multicast-table.component.ts | 54 +++++-------- .../multicast/multicast.module.ts | 3 +- .../multicast/multicast.service.spec.ts | 16 ---- .../multicast/multicast.service.ts | 51 ++++++------ src/app/shared/constants/regex-constants.ts | 10 +++ src/app/shared/enums/multicast-type.ts | 4 +- src/app/shared/pipes/filter-devices.pipe.ts | 26 ++++++ src/app/shared/pipes/pipes.module.ts | 41 +++++----- src/app/shared/services/downlink.service.ts | 23 ++---- src/assets/i18n/da.json | 6 +- 20 files changed, 215 insertions(+), 266 deletions(-) delete mode 100644 src/app/applications/multicast/multicast-detail/multicast-detail.component.spec.ts delete mode 100644 src/app/applications/multicast/multicast-edit/multicast-edit.component.spec.ts delete mode 100644 src/app/applications/multicast/multicast-table/multicast-table.component.spec.ts delete mode 100644 src/app/applications/multicast/multicast.service.spec.ts create mode 100644 src/app/shared/constants/regex-constants.ts create mode 100644 src/app/shared/pipes/filter-devices.pipe.ts diff --git a/src/app/applications/iot-devices/downlink.model.ts b/src/app/applications/iot-devices/downlink.model.ts index 7ff3acf3..b5ed5035 100644 --- a/src/app/applications/iot-devices/downlink.model.ts +++ b/src/app/applications/iot-devices/downlink.model.ts @@ -1,6 +1,5 @@ - export class Downlink { - data: string; - port: number = 0; - confirmedDownlink? = false; + data: string; + port = 0; + confirmedDownlink? = false; } diff --git a/src/app/applications/multicast/multicast-detail/multicast-detail.component.spec.ts b/src/app/applications/multicast/multicast-detail/multicast-detail.component.spec.ts deleted file mode 100644 index 20b2cf8e..00000000 --- a/src/app/applications/multicast/multicast-detail/multicast-detail.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { MulticastDetailComponent } from './multicast-detail.component'; - -describe('MulticastDetailComponent', () => { - let component: MulticastDetailComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ MulticastDetailComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(MulticastDetailComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts b/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts index bd5d3a2f..3bbcccd0 100644 --- a/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts +++ b/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts @@ -10,12 +10,11 @@ import { Location } from '@angular/common'; import { MulticastService } from '../multicast.service'; import { SnackService } from '@shared/services/snack.service'; import { Downlink } from '@applications/iot-devices/downlink.model'; -import { DownlinkService } from '@shared/services/downlink.service'; import { HttpErrorResponse } from '@angular/common/http'; import { ErrorMessageService } from '@shared/error-message.service'; import { MatDialog } from '@angular/material/dialog'; import { DownlinkDialogComponent } from '@applications/iot-devices/iot-device-detail/downlink/downlink-dialog/downlink-dialog.component'; -import { MatSnackBar } from '@angular/material/snack-bar'; +import { keyPressedHex } from '@shared/constants/regex-constants'; @Component({ selector: 'app-multicast-detail', @@ -27,7 +26,6 @@ export class MulticastDetailComponent implements OnInit { public backButton: BackButton = { label: '', routerLink: '/multicast-list' }; private deleteDialogSubscription: Subscription; public dropdownButton: DropdownButton; - public formFailedSubmit: boolean = false; private applicationId: number; public downlink = new Downlink(); @@ -35,14 +33,12 @@ export class MulticastDetailComponent implements OnInit { constructor( private route: ActivatedRoute, - private snackBar: MatSnackBar, - public dialog: MatDialog, + private dialog: MatDialog, private deleteDialogService: DeleteDialogService, private location: Location, private multicastService: MulticastService, - public translate: TranslateService, - public snackService: SnackService, - public downlinkService: DownlinkService, + private translate: TranslateService, + private snackService: SnackService, private errorMessageService: ErrorMessageService ) {} @@ -78,6 +74,7 @@ export class MulticastDetailComponent implements OnInit { this.backButton.routerLink = ['applications', applicationId.toString()]; } + // Class-B: //only if classB can be used // canShowPeriodicity(): boolean { // if (this.multicast.groupType === MulticastType.ClassB) { @@ -101,7 +98,6 @@ export class MulticastDetailComponent implements OnInit { } }); } else { - console.log(response); } }); } @@ -118,15 +114,9 @@ export class MulticastDetailComponent implements OnInit { } keyPressHexadecimal(event) { // make sure only hexadecimal can be typed in input with adresses. - var inp = String.fromCharCode(event.keyCode); - - if (/[a-fA-F0-9]/.test(inp)) { - return true; - } else { - event.preventDefault(); - return false; - } + keyPressedHex(event); } + private handleError(error: HttpErrorResponse) { const errors = this.errorMessageService.handleErrorMessageWithFields(error); this.errorMessages = errors.errorFields; @@ -135,20 +125,15 @@ export class MulticastDetailComponent implements OnInit { clickDownlink() { if (this.validateHex(this.downlink.data)) { - this.downlinkService.multicastGet(this.multicast.id).subscribe( - (response: any) => { - console.log(response) + this.multicastService + .multicastGet(this.multicast.id) + .subscribe((response: any) => { if (response.totalCount > 0) { this.openDownlinkDialog(); } else { this.startDownlink(); } - }, - (error) => { - this.handleError(error); - console.log(error); - } - ); + }); } } openDownlinkDialog() { @@ -157,17 +142,16 @@ export class MulticastDetailComponent implements OnInit { dialog.afterClosed().subscribe((result) => { if (result === true) { this.startDownlink(); - console.log(`Dialog result: ${result}`); } }); } private startDownlink() { this.errorMessages = []; - this.downlinkService + this.multicastService .multicastPost(this.downlink, this.multicast.id) .subscribe( - (response) => { + () => { this.showQueueSnack(); }, (error) => { @@ -178,15 +162,13 @@ export class MulticastDetailComponent implements OnInit { private validateHex(input: string): boolean { const isHexinput = /^[a-fA-F\d]+$/.test(input); - let validator = false; + if (isHexinput) { - validator = true; + return true; } else { - console.log('test'); this.addToErrorMessage('MULTICAST.DOWNLINK.NO-PORT-OR-PAYLOAD'); - validator = false; + return false; } - return validator; } addToErrorMessage(text: string) { @@ -196,8 +178,6 @@ export class MulticastDetailComponent implements OnInit { } ngOnDestroy(): void { - if (this.deleteDialogSubscription) { - this.deleteDialogSubscription.unsubscribe(); - } + this.deleteDialogSubscription?.unsubscribe(); } } diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.html b/src/app/applications/multicast/multicast-edit/multicast-edit.component.html index 91945156..42e456dc 100644 --- a/src/app/applications/multicast/multicast-edit/multicast-edit.component.html +++ b/src/app/applications/multicast/multicast-edit/multicast-edit.component.html @@ -196,7 +196,7 @@

-->
-
+
@@ -211,7 +211,12 @@ name="devices" [compareWith]="compare" [(ngModel)]="multicast.iotDevices" + panelClass="overflow-x-hidden" > + + + - {{ - device.name - }} + {{ device.name }}
diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.scss b/src/app/applications/multicast/multicast-edit/multicast-edit.component.scss index e69de29b..74d588da 100644 --- a/src/app/applications/multicast/multicast-edit/multicast-edit.component.scss +++ b/src/app/applications/multicast/multicast-edit/multicast-edit.component.scss @@ -0,0 +1,5 @@ +.onlyLorawan { + font-weight: bold; + font-size: 13px; + margin-left: 10px; +} diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.spec.ts b/src/app/applications/multicast/multicast-edit/multicast-edit.component.spec.ts deleted file mode 100644 index 84638528..00000000 --- a/src/app/applications/multicast/multicast-edit/multicast-edit.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { MulticastEditComponent } from './multicast-edit.component'; - -describe('MulticastEditComponent', () => { - let component: MulticastEditComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ MulticastEditComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(MulticastEditComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts b/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts index 16e95613..f0715c58 100644 --- a/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts +++ b/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts @@ -6,11 +6,14 @@ import { MulticastType } from '@shared/enums/multicast-type'; import { ErrorMessageService } from '@shared/error-message.service'; import { SnackService } from '@shared/services/snack.service'; import { ScrollToTopService } from '@shared/services/scroll-to-top.service'; -import { Subscription } from 'rxjs'; +import { ReplaySubject, Subject, Subscription } from 'rxjs'; import { Multicast } from '../multicast.model'; import { MulticastService } from '../multicast.service'; import { IotDevice } from '@applications/iot-devices/iot-device.model'; import { ApplicationService } from '@applications/application.service'; +import { keyPressedHex } from '@shared/constants/regex-constants'; +import { FormControl } from '@angular/forms'; +import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'app-multicast-edit', @@ -22,25 +25,30 @@ export class MulticastEditComponent implements OnInit { public multicastId: number; public errorMessages: any; private multicastSubscription: Subscription; + public searchDevices: FormControl = new FormControl(); public errorFields: string[]; - public iotDevices: IotDevice[]; + public iotDevices: IotDevice[] = []; @Input() submitButton: string; public backButtonTitle: string; public multicast: Multicast = new Multicast(); private applicationId: number; public formFailedSubmit: boolean = false; public multicastTypes: string[] = Object.values(MulticastType); - // public periodicities: number[] = [2, 4, 8, 16, 32, 64, 128]; // used for classB if it has to be used in the future + // Class-B: { public periodicities: number[] = [2, 4, 8, 16, 32, 64, 128]; // used for classB if it has to be used in the future } + public deviceFilterCtrl: FormControl = new FormControl(); + public filteredDevicesMulti: ReplaySubject = new ReplaySubject< + IotDevice[] + >(1); constructor( - public translate: TranslateService, + private translate: TranslateService, private route: ActivatedRoute, private router: Router, - public multicastService: MulticastService, - public errorMessageService: ErrorMessageService, - public scrollToTopService: ScrollToTopService, - public snackService: SnackService, - public applicationService: ApplicationService + private multicastService: MulticastService, + private errorMessageService: ErrorMessageService, + private scrollToTopService: ScrollToTopService, + private snackService: SnackService, + private applicationService: ApplicationService ) {} ngOnInit(): void { @@ -71,7 +79,32 @@ export class MulticastEditComponent implements OnInit { // If edit is pressed, then get the specific multicast. this.getMulticast(this.multicastId); } + + this.deviceFilterCtrl.valueChanges + .pipe(takeUntil(this._onDestroy)) + .subscribe(() => { + this.filterDevicesMulti(); + }); + } + + private filterDevicesMulti() { + if (!this.iotDevices) { + return; + } + // get the search keyword + let search = this.deviceFilterCtrl?.value?.trim(); + if (!search) { + this.filteredDevicesMulti.next(this.iotDevices.slice()); + return; + } else { + search = search.toLowerCase(); + } + const filtered = this.iotDevices.filter((device) => { + return device.name.toLocaleLowerCase().indexOf(search) > -1; + }); + this.filteredDevicesMulti.next(filtered); } + onSubmit(): void { if (this.multicastId) { // if already created, only update @@ -91,9 +124,10 @@ export class MulticastEditComponent implements OnInit { } getApplication(id: number) { - this.applicationService - .getApplication(id) - .subscribe((application) => (this.iotDevices = application.iotDevices)); + this.applicationService.getApplication(id).subscribe((application) => { + this.iotDevices = application.iotDevices; + this.filteredDevicesMulti.next(this.iotDevices.slice()); + }); } //only if classB can be used @@ -135,8 +169,11 @@ export class MulticastEditComponent implements OnInit { } ); } - public compare(o1: any, o2: any): boolean { - return o1 && o2 && o1.id == o2.id; + public compare( + o1: IotDevice | undefined, + o2: IotDevice | undefined + ): boolean { + return o1?.id === o2?.id; } selectAll() { @@ -159,15 +196,7 @@ export class MulticastEditComponent implements OnInit { this.snackService.showUpdatedSnack(); } keyPressHexadecimal(event) { - // make sure only hexadecimal can be typed in input with adresses. - var inp = String.fromCharCode(event.keyCode); - - if (/[a-fA-F0-9]/.test(inp)) { - return true; - } else { - event.preventDefault(); - return false; - } + keyPressedHex(event); } private resetErrors() { this.errorFields = []; @@ -181,8 +210,7 @@ export class MulticastEditComponent implements OnInit { this.scrollToTopService.scrollToTop(); } ngOnDestroy(): void { - if (this.multicastSubscription) { - this.multicastSubscription.unsubscribe(); - } + this.multicastSubscription?.unsubscribe(); } + private _onDestroy = new Subject(); } diff --git a/src/app/applications/multicast/multicast-response.model.ts b/src/app/applications/multicast/multicast-response.model.ts index 72c8558c..16d385f6 100644 --- a/src/app/applications/multicast/multicast-response.model.ts +++ b/src/app/applications/multicast/multicast-response.model.ts @@ -21,9 +21,9 @@ export class LorawanMulticastDefinition { address: string; networkSessionKey: string; applicationSessionKey: string; - frameCounter: number = 0; - dataRate: number = 0; - frequency: number = 0; + frameCounter = 0; + dataRate = 0; + frequency = 0; groupType: MulticastType; chirpstackGroupId?: string; } diff --git a/src/app/applications/multicast/multicast-table/multicast-table.component.html b/src/app/applications/multicast/multicast-table/multicast-table.component.html index f7f5892a..babb247a 100644 --- a/src/app/applications/multicast/multicast-table/multicast-table.component.html +++ b/src/app/applications/multicast/multicast-table/multicast-table.component.html @@ -21,7 +21,7 @@ {{ 'MULTICAST-TABLE.TYPE' | translate }} - {{element.lorawanMulticastDefinition.groupType | translate}} + {{element.lorawanMulticastDefinition.groupType}} diff --git a/src/app/applications/multicast/multicast-table/multicast-table.component.spec.ts b/src/app/applications/multicast/multicast-table/multicast-table.component.spec.ts deleted file mode 100644 index 4a46e62b..00000000 --- a/src/app/applications/multicast/multicast-table/multicast-table.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { MulticastTableComponent } from './multicast-table.component'; - -describe('MulticastTableComponent', () => { - let component: MulticastTableComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ MulticastTableComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(MulticastTableComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/applications/multicast/multicast-table/multicast-table.component.ts b/src/app/applications/multicast/multicast-table/multicast-table.component.ts index 908c2849..7fc714c2 100644 --- a/src/app/applications/multicast/multicast-table/multicast-table.component.ts +++ b/src/app/applications/multicast/multicast-table/multicast-table.component.ts @@ -32,7 +32,7 @@ export class MulticastTableComponent displayedColumns: string[] = ['groupName', 'groupType', 'menu']; dataSource = new MatTableDataSource(); multicasts: Multicast[]; - resultsLength = 0 + resultsLength = 0; public canEdit = false; @Input() isLoadingResults: boolean = true; public pageSize = environment.tablePageSize; @@ -57,7 +57,7 @@ export class MulticastTableComponent ngOnInit(): void { this.applicationId = +Number(this.route.parent.snapshot.paramMap.get('id')); - this.getMulticasts(); // loads the multicasts + this.getMulticasts(); this.canEdit = this.meService.canWriteInTargetOrganization(); } @@ -70,7 +70,6 @@ export class MulticastTableComponent if (this.applicationId) { this.multicastSubscription = this.multicastService .getMulticastsByApplicationId( - // gets multicasts from db by applicationId this.pageLimit, this.pageOffset * this.pageLimit, this.applicationId @@ -86,7 +85,8 @@ export class MulticastTableComponent this.pageTotal = Math.ceil(multicasts.count / this.pageLimit); } if (multicasts.ok === false) { - this.showLoadFailSnack(); // if not possible to load the multicasts, show error. + // ok is only defined when it's an error. + this.snackService.showLoadFailSnack(); } }); } @@ -96,39 +96,25 @@ export class MulticastTableComponent this.deleteDialogSubscription = this.deleteDialogService .showSimpleDialog() .subscribe((response) => { - if (response) { // if user presses "yes, delete", then delete the multicast. - this.multicastService - .delete(multicast.id) - .subscribe((response) => { - if (response.ok && response.body.affected > 0) { // if deleted succesfully, get the new array of multicasts and show a succesful snack. - this.getMulticasts(); - this.showDeletedSnack(); - } else { - this.showFailSnack(); - } - }); - } else { - console.log(response); + if (response) { + // if user presses "yes, delete", then delete the multicast. + this.multicastService.delete(multicast.id).subscribe((response) => { + if (response.ok && response.body.affected > 0) { + // if deleted succesfully, get the new array of multicasts and show a succesful snack. + this.getMulticasts(); + this.snackService.showDeletedSnack(); + } else { + this.snackService.showFailSnack(); + } + }); } }); } - - showLoadFailSnack() { - this.snackService.showLoadFailSnack(); - } - showFailSnack() { - this.snackService.showFailSnack(); - } - showDeletedSnack() { - this.snackService.showDeletedSnack(); - } - ngOnDestroy() { // inspired by datatarget + ngOnDestroy() { // prevent memory leak by unsubscribing - if (this.multicastSubscription) { - this.multicastSubscription.unsubscribe(); - } - if (this.deleteDialogSubscription) { - this.deleteDialogSubscription.unsubscribe(); - } + + this.multicastSubscription?.unsubscribe(); + + this.deleteDialogSubscription?.unsubscribe(); } } diff --git a/src/app/applications/multicast/multicast.module.ts b/src/app/applications/multicast/multicast.module.ts index cdc2b9d8..e56d5271 100644 --- a/src/app/applications/multicast/multicast.module.ts +++ b/src/app/applications/multicast/multicast.module.ts @@ -7,10 +7,10 @@ import { MulticastTableComponent } from './multicast-table/multicast-table.compo import { RouterModule } from '@angular/router'; import { TranslateModule } from '@ngx-translate/core'; import { NGMaterialModule } from '@shared/Modules/materiale.module'; -import { FormModule } from '@shared/components/forms/form.module'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { PipesModule } from '@shared/pipes/pipes.module'; +import { MatSelectSearchModule } from '@shared/components/mat-select-search/mat-select-search.module'; @NgModule({ declarations: [ @@ -28,6 +28,7 @@ import { PipesModule } from '@shared/pipes/pipes.module'; FormsModule, SharedModule, PipesModule, + MatSelectSearchModule, ], exports: [ MulticastDetailComponent, diff --git a/src/app/applications/multicast/multicast.service.spec.ts b/src/app/applications/multicast/multicast.service.spec.ts deleted file mode 100644 index c86a61c3..00000000 --- a/src/app/applications/multicast/multicast.service.spec.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TestBed } from '@angular/core/testing'; - -import { MulticastService } from './multicast.service'; - -describe('MulticastService', () => { - let service: MulticastService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(MulticastService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/applications/multicast/multicast.service.ts b/src/app/applications/multicast/multicast.service.ts index 33b1e316..f769e24a 100644 --- a/src/app/applications/multicast/multicast.service.ts +++ b/src/app/applications/multicast/multicast.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core'; import { UserMinimalService } from '@app/admin/users/user-minimal.service'; +import { Downlink } from '@applications/iot-devices/downlink.model'; import { RestService } from '@shared/services/rest.service'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; @@ -15,7 +16,10 @@ export class MulticastService { private userMinimalService: UserMinimalService ) {} - private multicastURL = 'multicast'; // api endpoint + private multicastURL = 'multicast'; + private multicastDownlinkURL = 'multicast/'; + private DOWNLINKMULTICASTURL = 'downlink-multicast'; + getMulticastsByApplicationId( limit: number, offset: number, @@ -26,42 +30,27 @@ export class MulticastService { offset, applicationId, }; - return this.restService.get(this.multicastURL, body); // get's the multicasts from specific application by the url and the body with applicationId. + return this.restService.get(this.multicastURL, body); } + get(id: number): Observable { - // Get's a single multicast by id. return this.restService.get(this.multicastURL, {}, id).pipe( + // bind "this" correctly by creating a new lambda function map((response: MulticastResponse) => { - const multicast = this.mapToMulticast(response); // maps the response from backend. + const multicast = this.mapToMulticast(response); return multicast; }) ); } + delete(id: number) { - // deletes a chosen multicast by id return this.restService.delete(this.multicastURL, id); } update(multicast: Multicast): Observable { - // updates the chosen multicast by id - return this.restService - .put(this.multicastURL, multicast, multicast.id) - .pipe - // map((response: MulticastResponse) => { - // const multicast = this.mapToMulticast(response); - // return multicast; - // }) - (); + return this.restService.put(this.multicastURL, multicast, multicast.id); } create(multicast: Multicast): Observable { - // creates a new multicast - return this.restService - .post(this.multicastURL, multicast) - .pipe - // map((response: MulticastResponse) => { - // const multicast = this.mapToMulticast(response); - // return multicast; - // }) - (); + return this.restService.post(this.multicastURL, multicast); } private mapToMulticast(multicastResponse: MulticastResponse): Multicast { @@ -88,8 +77,22 @@ export class MulticastService { updatedByName: this.userMinimalService.getUserNameFrom( multicastResponse.updatedBy ), - }; return model; } + + public multicastGet(multicastId: number, params = {}): Observable { + const url = + this.multicastDownlinkURL + multicastId + '/' + this.DOWNLINKMULTICASTURL; + return this.restService.get(url, params); + } + public multicastPost( + downlink: Downlink, + multicastId: number, + params = {} + ): Observable { + const url = + this.multicastDownlinkURL + multicastId + '/' + this.DOWNLINKMULTICASTURL; + return this.restService.post(url, downlink, params); + } } diff --git a/src/app/shared/constants/regex-constants.ts b/src/app/shared/constants/regex-constants.ts new file mode 100644 index 00000000..ef7a76a5 --- /dev/null +++ b/src/app/shared/constants/regex-constants.ts @@ -0,0 +1,10 @@ +export function keyPressedHex(event) { + var inp = String.fromCharCode(event.keyCode); + + if (/[a-fA-F0-9]/.test(inp)) { + return true; + } else { + event.preventDefault(); + return false; + } +} diff --git a/src/app/shared/enums/multicast-type.ts b/src/app/shared/enums/multicast-type.ts index f078b06c..acb0283d 100644 --- a/src/app/shared/enums/multicast-type.ts +++ b/src/app/shared/enums/multicast-type.ts @@ -1,4 +1,4 @@ export enum MulticastType { - // ClassB = 'Class-B', - ClassC = 'CLASS_C' + // Class-B: {ClassB = 'Class-B'}, + ClassC = 'CLASS_C', } diff --git a/src/app/shared/pipes/filter-devices.pipe.ts b/src/app/shared/pipes/filter-devices.pipe.ts new file mode 100644 index 00000000..47edb0bf --- /dev/null +++ b/src/app/shared/pipes/filter-devices.pipe.ts @@ -0,0 +1,26 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { IotDevice } from '@applications/iot-devices/iot-device.model'; +import { DeviceType } from '@shared/enums/device-type'; + +@Pipe({ + name: 'filterDevices', +}) +export class FilterDevicesPipe implements PipeTransform { + transform(value: IotDevice[] | undefined, ..._: unknown[]): IotDevice[] { + // Filter devices so only LoRaWAN devices will be shown. + const lorawanDevices: IotDevice[] = []; + + if (!value) { + return lorawanDevices; + } + value.forEach((device) => { + if (device.type === DeviceType.LORAWAN) { + lorawanDevices.push(device); + } + }); + + lorawanDevices.sort((a, b) => a.name.localeCompare(b.name)); + + return lorawanDevices; + } +} diff --git a/src/app/shared/pipes/pipes.module.ts b/src/app/shared/pipes/pipes.module.ts index a3e26445..c5aacc28 100644 --- a/src/app/shared/pipes/pipes.module.ts +++ b/src/app/shared/pipes/pipes.module.ts @@ -5,26 +5,27 @@ import { ActiveDeactivePipe } from './activeDeactive.pipe'; import { isGlobalAdminPipe } from './is-global-admin.pipe'; import { CreatedUpdatedByPipe } from './created-updated-by.pipe'; import { CustomDatePipe, CustomTableDatePipe } from './custom-date.pipe'; +import { FilterDevicesPipe } from './filter-devices.pipe'; @NgModule({ - declarations: [ - isGlobalAdminPipe, - ActiveDeactivePipe, - YesNoPipe, - CustomDatePipe, - CustomTableDatePipe, - CreatedUpdatedByPipe, - ], - imports: [ - CommonModule - ], - exports: [ - isGlobalAdminPipe, - ActiveDeactivePipe, - YesNoPipe, - CustomDatePipe, - CustomTableDatePipe, - CreatedUpdatedByPipe, - ] + declarations: [ + isGlobalAdminPipe, + ActiveDeactivePipe, + YesNoPipe, + CustomDatePipe, + CustomTableDatePipe, + CreatedUpdatedByPipe, + FilterDevicesPipe, + ], + imports: [CommonModule], + exports: [ + isGlobalAdminPipe, + ActiveDeactivePipe, + YesNoPipe, + CustomDatePipe, + CustomTableDatePipe, + CreatedUpdatedByPipe, + FilterDevicesPipe, + ], }) -export class PipesModule { } +export class PipesModule {} diff --git a/src/app/shared/services/downlink.service.ts b/src/app/shared/services/downlink.service.ts index e39a3ca2..b031e1bb 100644 --- a/src/app/shared/services/downlink.service.ts +++ b/src/app/shared/services/downlink.service.ts @@ -4,34 +4,25 @@ import { Observable } from 'rxjs'; import { Downlink } from '@applications/iot-devices/downlink.model'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class DownlinkService { - private IOTDEVICEURL = 'iot-device/'; private DOWNLINKURL = 'downlink'; - private MULTICASTURL = 'multicast/'; - private DOWNLINKMULTICASTURL = 'downlink-multicast'; - constructor(private restService: RestService) { } + constructor(private restService: RestService) {} public get(deviceId: number, params = {}): Observable { const url = this.IOTDEVICEURL + deviceId + '/' + this.DOWNLINKURL; return this.restService.get(url, params); } - public post(downlink: Downlink, deviceId: number, params = {}): Observable { + public post( + downlink: Downlink, + deviceId: number, + params = {} + ): Observable { const url = this.IOTDEVICEURL + deviceId + '/' + this.DOWNLINKURL; return this.restService.post(url, downlink, params); } - - - public multicastGet(multicastId: number, params = {}): Observable { - const url = this.MULTICASTURL + multicastId + '/' + this.DOWNLINKMULTICASTURL; - return this.restService.get(url, params); - } - public multicastPost(downlink: Downlink, multicastId: number, params = {}): Observable { - const url = this.MULTICASTURL + multicastId + '/' + this.DOWNLINKMULTICASTURL; - return this.restService.post(url, downlink, params); - } } diff --git a/src/assets/i18n/da.json b/src/assets/i18n/da.json index a824b1e8..2e6c0614 100644 --- a/src/assets/i18n/da.json +++ b/src/assets/i18n/da.json @@ -91,7 +91,6 @@ "SAVE": "Gem applikation", "DELETE": "Slet applikation", "DELETE-HAS-DEVICES-PROMPT": "Der er knyttet IoT-enheder til denne applikation. Disse vil også blive slettet. Slet alligevel?", - "DELETE-HAS-SIGFOX-DEVICES-PROMPT": "Applikationen kan ikke slettes, da der er knyttet Sigfox enheder til den", "NAME": "Applikationens navn", "DESCRIPTION": "Applikationens beskrivelse", "ATTACHED-IOT": "Tilknyttede IoT enheder", @@ -180,7 +179,7 @@ "FREQUENCY": "Frekvens (Hz)", "GROUPTYPE": "Gruppe type", "PERIODICITY": "Periodicitet", - "IOTDEVICE": "IoT enhed(er)", + "IOTDEVICE": "IoT enheder", "DOWNLINK": { "PORT": "Angiv den ønskede port", "PAYLOAD": "Angiv det ønskede payload", @@ -525,7 +524,8 @@ "SELECT-DEVICES": "Vælg enheder", "SELECTALLDEVICES": "Vælg alle", "DESELECTALLDEVICES": "Fravælg alle", - "NO-PORT-OR-PAYLOAD": "Angiv en port og en payload" + "NO-PORT-OR-PAYLOAD": "Angiv en port og en payload", + "ONLY-LORAWAN": "* På nuværende tidspunkt er det kun muligt at tilknytte LoRaWAN devices." }, "SIGFOX": { "TITLE": "Sigfox specifikke felter", From e859ab15acd91f44aeb114ede8f2221a8377dadd Mon Sep 17 00:00:00 2001 From: August Andersen Date: Wed, 15 Dec 2021 10:39:24 +0100 Subject: [PATCH 15/18] PR changes - fixed pagination for multicast --- .../application-detail.component.html | 5 +- .../application-detail.component.ts | 3 - .../iot-devices-table.component.ts | 1 - .../multicast-table.component.html | 2 +- .../multicast-table.component.ts | 80 +++++++++++-------- .../multicast/multicast.service.ts | 4 + 6 files changed, 54 insertions(+), 41 deletions(-) diff --git a/src/app/applications/application-detail/application-detail.component.html b/src/app/applications/application-detail/application-detail.component.html index d044ddea..ff4a356a 100644 --- a/src/app/applications/application-detail/application-detail.component.html +++ b/src/app/applications/application-detail/application-detail.component.html @@ -1,7 +1,6 @@
+ [addDetailDowndown]="true" [dropDownButton]="dropdownButton" (deleteSelectedInDropdown)="onDeleteApplication()">
@@ -54,7 +53,7 @@

Detaljer

- +
diff --git a/src/app/applications/application-detail/application-detail.component.ts b/src/app/applications/application-detail/application-detail.component.ts index 168f6ac8..75eafee4 100644 --- a/src/app/applications/application-detail/application-detail.component.ts +++ b/src/app/applications/application-detail/application-detail.component.ts @@ -103,7 +103,4 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy { this.deleteDialogSubscription.unsubscribe(); } } - updatePageLimit(limit: any) { - console.log(limit); - } } diff --git a/src/app/applications/iot-devices/iot-devices-table/iot-devices-table.component.ts b/src/app/applications/iot-devices/iot-devices-table/iot-devices-table.component.ts index ac550bb7..c2ece359 100644 --- a/src/app/applications/iot-devices/iot-devices-table/iot-devices-table.component.ts +++ b/src/app/applications/iot-devices/iot-devices-table/iot-devices-table.component.ts @@ -20,7 +20,6 @@ import { DeleteDialogComponent } from '@shared/components/delete-dialog/delete-d import { DeviceType } from '@shared/enums/device-type'; import { MatDialog } from '@angular/material/dialog'; import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service'; -import { ReceivedMessageMetadata } from '@shared/models/received-message-metadata.model'; import { environment } from '@environments/environment'; import { startWith, switchMap, map, catchError } from 'rxjs/operators'; import { MeService } from '@shared/services/me.service'; diff --git a/src/app/applications/multicast/multicast-table/multicast-table.component.html b/src/app/applications/multicast/multicast-table/multicast-table.component.html index babb247a..2b35a5f4 100644 --- a/src/app/applications/multicast/multicast-table/multicast-table.component.html +++ b/src/app/applications/multicast/multicast-table/multicast-table.component.html @@ -2,7 +2,7 @@
- +
diff --git a/src/app/applications/multicast/multicast-table/multicast-table.component.ts b/src/app/applications/multicast/multicast-table/multicast-table.component.ts index 7fc714c2..b3fd804d 100644 --- a/src/app/applications/multicast/multicast-table/multicast-table.component.ts +++ b/src/app/applications/multicast/multicast-table/multicast-table.component.ts @@ -8,15 +8,14 @@ import { } from '@angular/core'; import { MatPaginator } from '@angular/material/paginator'; import { MatSort } from '@angular/material/sort'; -import { MatTableDataSource } from '@angular/material/table'; import { ActivatedRoute } from '@angular/router'; import { environment } from '@environments/environment'; import { TranslateService } from '@ngx-translate/core'; import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service'; -import { tableSorter } from '@shared/helpers/table-sorting.helper'; import { MeService } from '@shared/services/me.service'; import { SnackService } from '@shared/services/snack.service'; -import { Subscription } from 'rxjs'; +import { merge, Observable, Subscription, of as observableOf } from 'rxjs'; +import { catchError, map, startWith, switchMap } from 'rxjs/operators'; import { Multicast, MulticastData } from '../multicast.model'; import { MulticastService } from '../multicast.service'; @@ -30,15 +29,12 @@ export class MulticastTableComponent @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; displayedColumns: string[] = ['groupName', 'groupType', 'menu']; - dataSource = new MatTableDataSource(); - multicasts: Multicast[]; + multicasts: Multicast[] = []; resultsLength = 0; public canEdit = false; @Input() isLoadingResults: boolean = true; public pageSize = environment.tablePageSize; - @Input() pageLimit: number; public pageOffset = 0; - public pageTotal: number; public applicationId: number; private multicastSubscription: Subscription; @@ -57,38 +53,52 @@ export class MulticastTableComponent ngOnInit(): void { this.applicationId = +Number(this.route.parent.snapshot.paramMap.get('id')); - this.getMulticasts(); this.canEdit = this.meService.canWriteInTargetOrganization(); } ngAfterViewInit() { - this.dataSource.paginator = this.paginator; - this.dataSource.sort = this.sort; + // If the user changes the sort order, reset back to the first page. + this.sort.sortChange.subscribe(() => (this.paginator.pageIndex = 0)); + + merge(this.sort.sortChange, this.paginator.page) + .pipe( + startWith({}), + switchMap(() => { + this.isLoadingResults = true; + const multicasts = this.getMulticasts( + this.sort.active, + this.sort.direction + ); + //TODO::: Snack here + return multicasts; + }), + map((data) => { + // Flip flag to show that loading has finished. + this.isLoadingResults = false; + this.resultsLength = data.count; + + return data.data; + }), + catchError(() => { + this.isLoadingResults = false; + return observableOf([]); + }) + ) + .subscribe((data) => (this.multicasts = data)); } - getMulticasts(): void { + getMulticasts( + orderByColumn: string, + orderByDirection: string + ): Observable { if (this.applicationId) { - this.multicastSubscription = this.multicastService - .getMulticastsByApplicationId( - this.pageLimit, - this.pageOffset * this.pageLimit, - this.applicationId - ) - .subscribe((multicasts: MulticastData) => { - this.multicasts = multicasts.data; - this.dataSource = new MatTableDataSource(this.multicasts); // these lines of code is inspired/taken from datatarget. - this.dataSource.paginator = this.paginator; - this.dataSource.sort = this.sort; - this.dataSource.sortingDataAccessor = tableSorter; - this.isLoadingResults = false; - if (this.pageLimit) { - this.pageTotal = Math.ceil(multicasts.count / this.pageLimit); - } - if (multicasts.ok === false) { - // ok is only defined when it's an error. - this.snackService.showLoadFailSnack(); - } - }); + return this.multicastService.getMulticastsByApplicationId( + this.paginator.pageSize, + this.paginator.pageIndex * this.paginator.pageSize, + orderByDirection, + orderByColumn, + this.applicationId + ); } } @@ -101,7 +111,11 @@ export class MulticastTableComponent this.multicastService.delete(multicast.id).subscribe((response) => { if (response.ok && response.body.affected > 0) { // if deleted succesfully, get the new array of multicasts and show a succesful snack. - this.getMulticasts(); + this.paginator.page.emit({ + pageIndex: this.paginator.pageIndex, + pageSize: this.paginator.pageSize, + length: this.resultsLength, + }); this.snackService.showDeletedSnack(); } else { this.snackService.showFailSnack(); diff --git a/src/app/applications/multicast/multicast.service.ts b/src/app/applications/multicast/multicast.service.ts index f769e24a..9a674d0c 100644 --- a/src/app/applications/multicast/multicast.service.ts +++ b/src/app/applications/multicast/multicast.service.ts @@ -23,11 +23,15 @@ export class MulticastService { getMulticastsByApplicationId( limit: number, offset: number, + sort: string, + orderOn: string, applicationId: number ): Observable { const body = { limit, offset, + sort, + orderOn, applicationId, }; return this.restService.get(this.multicastURL, body); From 144a650aacbac314c5e49ee382d36001e758d7ed Mon Sep 17 00:00:00 2001 From: August Andersen Date: Thu, 16 Dec 2021 13:39:06 +0100 Subject: [PATCH 16/18] Minor snack changes and check if devices is included before sending downlink --- .../multicast-detail.component.ts | 40 ++++++++----------- .../multicast-edit.component.ts | 17 ++------ .../multicast-table.component.ts | 4 +- src/app/shared/services/snack.service.ts | 5 +++ src/assets/i18n/da.json | 3 +- 5 files changed, 31 insertions(+), 38 deletions(-) diff --git a/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts b/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts index 3bbcccd0..9aeb3cc1 100644 --- a/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts +++ b/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts @@ -91,10 +91,10 @@ export class MulticastDetailComponent implements OnInit { .delete(this.multicast.id) .subscribe((response) => { if (response.status !== 0) { - this.showDeletedSnack(); + this.snackService.showDeletedSnack(); this.location.back(); } else { - this.showFailSnack(); + this.snackService.showFailSnack(); } }); } else { @@ -102,16 +102,6 @@ export class MulticastDetailComponent implements OnInit { }); } - showDeletedSnack(): void { - this.snackService.showDeletedSnack(); - } - - showFailSnack(): void { - this.snackService.showFailSnack(); - } - showQueueSnack(): void { - this.snackService.showInQueueSnack(); - } keyPressHexadecimal(event) { // make sure only hexadecimal can be typed in input with adresses. keyPressedHex(event); @@ -124,16 +114,20 @@ export class MulticastDetailComponent implements OnInit { } clickDownlink() { - if (this.validateHex(this.downlink.data)) { - this.multicastService - .multicastGet(this.multicast.id) - .subscribe((response: any) => { - if (response.totalCount > 0) { - this.openDownlinkDialog(); - } else { - this.startDownlink(); - } - }); + if (this.multicast.iotDevices.length > 0) { + if (this.validateHex(this.downlink.data)) { + this.multicastService + .multicastGet(this.multicast.id) + .subscribe((response: any) => { + if (response.totalCount > 0) { + this.openDownlinkDialog(); + } else { + this.startDownlink(); + } + }); + } + } else { + this.snackService.showSendDownlinkFailNoDevices(); } } openDownlinkDialog() { @@ -152,7 +146,7 @@ export class MulticastDetailComponent implements OnInit { .multicastPost(this.downlink, this.multicast.id) .subscribe( () => { - this.showQueueSnack(); + this.snackService.showInQueueSnack(); }, (error) => { this.handleError(error); diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts b/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts index f0715c58..56e5014f 100644 --- a/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts +++ b/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts @@ -143,11 +143,11 @@ export class MulticastEditComponent implements OnInit { this.multicastService.update(this.multicast).subscribe( () => { - this.showUpdatedSnack(); + this.snackService.showUpdatedSnack(); this.routeBack(); }, (error: HttpErrorResponse) => { - this.showFailSnack(); + this.snackService.showFailSnack(); this.handleError(error); this.formFailedSubmit = true; } @@ -159,11 +159,11 @@ export class MulticastEditComponent implements OnInit { this.multicastService.create(this.multicast).subscribe( () => { - this.showSavedSnack(); + this.snackService.showSavedSnack(); this.routeBack(); }, (error: HttpErrorResponse) => { - this.showFailSnack(); + this.snackService.showFailSnack(); this.handleError(error); this.formFailedSubmit = true; } @@ -186,15 +186,6 @@ export class MulticastEditComponent implements OnInit { routeBack(): void { this.router.navigate(['applications', this.applicationId.toString()]); } - showSavedSnack() { - this.snackService.showSavedSnack(); - } - showFailSnack() { - this.snackService.showFailSnack(); - } - showUpdatedSnack() { - this.snackService.showUpdatedSnack(); - } keyPressHexadecimal(event) { keyPressedHex(event); } diff --git a/src/app/applications/multicast/multicast-table/multicast-table.component.ts b/src/app/applications/multicast/multicast-table/multicast-table.component.ts index b3fd804d..1a685a65 100644 --- a/src/app/applications/multicast/multicast-table/multicast-table.component.ts +++ b/src/app/applications/multicast/multicast-table/multicast-table.component.ts @@ -69,11 +69,13 @@ export class MulticastTableComponent this.sort.active, this.sort.direction ); - //TODO::: Snack here return multicasts; }), map((data) => { // Flip flag to show that loading has finished. + if (data.ok === false) { + this.snackService.showLoadFailSnack(); + } this.isLoadingResults = false; this.resultsLength = data.count; diff --git a/src/app/shared/services/snack.service.ts b/src/app/shared/services/snack.service.ts index d5831815..16cd3b80 100644 --- a/src/app/shared/services/snack.service.ts +++ b/src/app/shared/services/snack.service.ts @@ -41,4 +41,9 @@ export class SnackService { duration: 10000, }); } + public showSendDownlinkFailNoDevices(){ + this.snackBar.open(this.translate.instant('SNACK.NODEVICES'), this.translate.instant('SNACK.CLOSE'), { + duration: 10000, + }); + } } diff --git a/src/assets/i18n/da.json b/src/assets/i18n/da.json index 2e6c0614..a13050c4 100644 --- a/src/assets/i18n/da.json +++ b/src/assets/i18n/da.json @@ -53,7 +53,8 @@ "FAIL": "Fejl - aktion ikke fuldført", "LOADFAIL": "Fejl - kunne ikke loade", "QUEUE": "Element sat i kø", - "CLOSE": "Luk" + "CLOSE": "Luk", + "NODEVICES": "Kan ikke sende downlink - der er ingen devices!" }, "SEARCH": { "ICON": "", From 44de7a5e0d819c851400bcdcbf4684024ccbfdf3 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Wed, 22 Dec 2021 15:16:54 +0100 Subject: [PATCH 17/18] PR Changes --- .../multicast-detail.component.ts | 14 ++++++++------ .../multicast-edit/multicast-edit.component.ts | 14 +++++++------- .../multicast-table.component.ts | 5 +---- .../applications/multicast/multicast.service.ts | 4 ++-- src/app/shared/services/downlink.service.ts | 17 ++++++++++++++++- src/app/shared/services/snack.service.ts | 5 ----- 6 files changed, 34 insertions(+), 25 deletions(-) diff --git a/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts b/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts index 9aeb3cc1..a2a43859 100644 --- a/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts +++ b/src/app/applications/multicast/multicast-detail/multicast-detail.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service'; @@ -15,18 +15,19 @@ import { ErrorMessageService } from '@shared/error-message.service'; import { MatDialog } from '@angular/material/dialog'; import { DownlinkDialogComponent } from '@applications/iot-devices/iot-device-detail/downlink/downlink-dialog/downlink-dialog.component'; import { keyPressedHex } from '@shared/constants/regex-constants'; +import { DownlinkService } from '@shared/services/downlink.service'; @Component({ selector: 'app-multicast-detail', templateUrl: './multicast-detail.component.html', styleUrls: ['./multicast-detail.component.scss'], }) -export class MulticastDetailComponent implements OnInit { +export class MulticastDetailComponent implements OnInit, OnDestroy { public multicast: Multicast; public backButton: BackButton = { label: '', routerLink: '/multicast-list' }; private deleteDialogSubscription: Subscription; public dropdownButton: DropdownButton; - public formFailedSubmit: boolean = false; + public formFailedSubmit = false; private applicationId: number; public downlink = new Downlink(); @Input() errorMessages: string[]; @@ -39,7 +40,8 @@ export class MulticastDetailComponent implements OnInit { private multicastService: MulticastService, private translate: TranslateService, private snackService: SnackService, - private errorMessageService: ErrorMessageService + private errorMessageService: ErrorMessageService, + private downlinkService: DownlinkService ) {} ngOnInit(): void { @@ -75,7 +77,7 @@ export class MulticastDetailComponent implements OnInit { } // Class-B: - //only if classB can be used + // only if classB can be used // canShowPeriodicity(): boolean { // if (this.multicast.groupType === MulticastType.ClassB) { // return true; @@ -127,7 +129,7 @@ export class MulticastDetailComponent implements OnInit { }); } } else { - this.snackService.showSendDownlinkFailNoDevices(); + this.downlinkService.showSendDownlinkFailNoDevices(); } } openDownlinkDialog() { diff --git a/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts b/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts index 56e5014f..4bdde2f0 100644 --- a/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts +++ b/src/app/applications/multicast/multicast-edit/multicast-edit.component.ts @@ -1,5 +1,5 @@ import { HttpErrorResponse } from '@angular/common/http'; -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { MulticastType } from '@shared/enums/multicast-type'; @@ -20,10 +20,10 @@ import { takeUntil } from 'rxjs/operators'; templateUrl: './multicast-edit.component.html', styleUrls: ['./multicast-edit.component.scss'], }) -export class MulticastEditComponent implements OnInit { +export class MulticastEditComponent implements OnInit, OnDestroy { public title: string; public multicastId: number; - public errorMessages: any; + public errorMessages: unknown; private multicastSubscription: Subscription; public searchDevices: FormControl = new FormControl(); public errorFields: string[]; @@ -32,7 +32,8 @@ export class MulticastEditComponent implements OnInit { public backButtonTitle: string; public multicast: Multicast = new Multicast(); private applicationId: number; - public formFailedSubmit: boolean = false; + private onDestroy = new Subject(); + public formFailedSubmit = false; public multicastTypes: string[] = Object.values(MulticastType); // Class-B: { public periodicities: number[] = [2, 4, 8, 16, 32, 64, 128]; // used for classB if it has to be used in the future } public deviceFilterCtrl: FormControl = new FormControl(); @@ -81,7 +82,7 @@ export class MulticastEditComponent implements OnInit { } this.deviceFilterCtrl.valueChanges - .pipe(takeUntil(this._onDestroy)) + .pipe(takeUntil(this.onDestroy)) .subscribe(() => { this.filterDevicesMulti(); }); @@ -130,7 +131,7 @@ export class MulticastEditComponent implements OnInit { }); } - //only if classB can be used + // only if classB can be used // showPeriodicity(): boolean { // if (this.multicast.groupType === MulticastType.ClassB) { // return true; @@ -203,5 +204,4 @@ export class MulticastEditComponent implements OnInit { ngOnDestroy(): void { this.multicastSubscription?.unsubscribe(); } - private _onDestroy = new Subject(); } diff --git a/src/app/applications/multicast/multicast-table/multicast-table.component.ts b/src/app/applications/multicast/multicast-table/multicast-table.component.ts index 1a685a65..54225d5c 100644 --- a/src/app/applications/multicast/multicast-table/multicast-table.component.ts +++ b/src/app/applications/multicast/multicast-table/multicast-table.component.ts @@ -32,7 +32,7 @@ export class MulticastTableComponent multicasts: Multicast[] = []; resultsLength = 0; public canEdit = false; - @Input() isLoadingResults: boolean = true; + @Input() isLoadingResults = true; public pageSize = environment.tablePageSize; public pageOffset = 0; public applicationId: number; @@ -127,10 +127,7 @@ export class MulticastTableComponent }); } ngOnDestroy() { - // prevent memory leak by unsubscribing - this.multicastSubscription?.unsubscribe(); - this.deleteDialogSubscription?.unsubscribe(); } } diff --git a/src/app/applications/multicast/multicast.service.ts b/src/app/applications/multicast/multicast.service.ts index 9a674d0c..8dd061de 100644 --- a/src/app/applications/multicast/multicast.service.ts +++ b/src/app/applications/multicast/multicast.service.ts @@ -85,7 +85,7 @@ export class MulticastService { return model; } - public multicastGet(multicastId: number, params = {}): Observable { + public multicastGet(multicastId: number, params = {}): Observable { const url = this.multicastDownlinkURL + multicastId + '/' + this.DOWNLINKMULTICASTURL; return this.restService.get(url, params); @@ -94,7 +94,7 @@ export class MulticastService { downlink: Downlink, multicastId: number, params = {} - ): Observable { + ): Observable { const url = this.multicastDownlinkURL + multicastId + '/' + this.DOWNLINKMULTICASTURL; return this.restService.post(url, downlink, params); diff --git a/src/app/shared/services/downlink.service.ts b/src/app/shared/services/downlink.service.ts index b031e1bb..edbf8cfe 100644 --- a/src/app/shared/services/downlink.service.ts +++ b/src/app/shared/services/downlink.service.ts @@ -2,6 +2,8 @@ import { Injectable } from '@angular/core'; import { RestService } from './rest.service'; import { Observable } from 'rxjs'; import { Downlink } from '@applications/iot-devices/downlink.model'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { TranslateService } from '@ngx-translate/core'; @Injectable({ providedIn: 'root', @@ -10,7 +12,11 @@ export class DownlinkService { private IOTDEVICEURL = 'iot-device/'; private DOWNLINKURL = 'downlink'; - constructor(private restService: RestService) {} + constructor( + private restService: RestService, + private snackBar: MatSnackBar, + public translate: TranslateService + ) {} public get(deviceId: number, params = {}): Observable { const url = this.IOTDEVICEURL + deviceId + '/' + this.DOWNLINKURL; @@ -25,4 +31,13 @@ export class DownlinkService { const url = this.IOTDEVICEURL + deviceId + '/' + this.DOWNLINKURL; return this.restService.post(url, downlink, params); } + public showSendDownlinkFailNoDevices() { + this.snackBar.open( + this.translate.instant('SNACK.NODEVICES'), + this.translate.instant('SNACK.CLOSE'), + { + duration: 10000, + } + ); + } } diff --git a/src/app/shared/services/snack.service.ts b/src/app/shared/services/snack.service.ts index 16cd3b80..d5831815 100644 --- a/src/app/shared/services/snack.service.ts +++ b/src/app/shared/services/snack.service.ts @@ -41,9 +41,4 @@ export class SnackService { duration: 10000, }); } - public showSendDownlinkFailNoDevices(){ - this.snackBar.open(this.translate.instant('SNACK.NODEVICES'), this.translate.instant('SNACK.CLOSE'), { - duration: 10000, - }); - } } From 7112f40489785ca7a8b6cd2dc696794e5f9a1e15 Mon Sep 17 00:00:00 2001 From: August Andersen Date: Thu, 6 Jan 2022 14:50:30 +0100 Subject: [PATCH 18/18] merge conflicting --- .../application-detail.component.ts | 173 ++++++++++-------- 1 file changed, 95 insertions(+), 78 deletions(-) diff --git a/src/app/applications/application-detail/application-detail.component.ts b/src/app/applications/application-detail/application-detail.component.ts index 75eafee4..d8121c56 100644 --- a/src/app/applications/application-detail/application-detail.component.ts +++ b/src/app/applications/application-detail/application-detail.component.ts @@ -1,4 +1,10 @@ -import { Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core'; +import { + Component, + EventEmitter, + OnDestroy, + OnInit, + Output, +} from '@angular/core'; import { Title } from '@angular/platform-browser'; import { ActivatedRoute, Router } from '@angular/router'; import { Application } from '@applications/application.model'; @@ -12,95 +18,106 @@ import { MeService } from '@shared/services/me.service'; import { Subscription } from 'rxjs'; @Component({ - selector: 'app-application', - templateUrl: './application-detail.component.html', - styleUrls: ['./application-detail.component.scss'], + selector: 'app-application', + templateUrl: './application-detail.component.html', + styleUrls: ['./application-detail.component.scss'], }) export class ApplicationDetailComponent implements OnInit, OnDestroy { - @Output() deleteApplication = new EventEmitter(); - public applicationsSubscription: Subscription; - private deleteDialogSubscription: Subscription; - public application: Application; - public backButton: BackButton = { label: '', routerLink: '/applications' }; - public id: number; - public pageLimit = environment.tablePageSize; - public dropdownButton: DropdownButton; - public errorMessage: string; - public canEdit = false; + @Output() deleteApplication = new EventEmitter(); + public applicationsSubscription: Subscription; + private deleteDialogSubscription: Subscription; + public application: Application; + public backButton: BackButton = { label: '', routerLink: '/applications' }; + public id: number; + public pageLimit = environment.tablePageSize; + public dropdownButton: DropdownButton; + public errorMessage: string; + public canEdit = false; - constructor( - private applicationService: ApplicationService, - private route: ActivatedRoute, - public translate: TranslateService, - public router: Router, - private meService: MeService, - private titleService: Title, - private deleteDialogService: DeleteDialogService - ) { } + constructor( + private applicationService: ApplicationService, + private route: ActivatedRoute, + public translate: TranslateService, + public router: Router, + private meService: MeService, + private titleService: Title, + private deleteDialogService: DeleteDialogService + ) {} - ngOnInit(): void { - this.id = +this.route.snapshot.paramMap.get('id'); - if (this.id) { - this.bindApplication(this.id); - this.dropdownButton = { - label: '', - editRouterLink: '../../edit-application/' + this.id, - isErasable: true, - }; + ngOnInit(): void { + this.id = +this.route.snapshot.paramMap.get('id'); + if (this.id) { + this.bindApplication(this.id); + this.dropdownButton = { + label: '', + editRouterLink: '../../edit-application/' + this.id, + isErasable: true, + }; - console.log(this.id); - } + console.log(this.id); + } - this.translate.get(['NAV.APPLICATIONS', 'APPLICATION-TABLE-ROW.SHOW-OPTIONS', 'TITLE.APPLICATION']) - .subscribe(translations => { - this.backButton.label = translations['NAV.APPLICATIONS']; - this.dropdownButton.label = translations['APPLICATION-TABLE-ROW.SHOW-OPTIONS']; - this.titleService.setTitle(translations['TITLE.APPLICATION']); - }); - this.canEdit = this.meService.canWriteInTargetOrganization(); + this.translate + .get([ + 'NAV.APPLICATIONS', + 'APPLICATION-TABLE-ROW.SHOW-OPTIONS', + 'TITLE.APPLICATION', + ]) + .subscribe((translations) => { + this.backButton.label = translations['NAV.APPLICATIONS']; + this.dropdownButton.label = + translations['APPLICATION-TABLE-ROW.SHOW-OPTIONS']; + this.titleService.setTitle(translations['TITLE.APPLICATION']); + }); + this.canEdit = this.meService.canWriteInTargetOrganization(); + } + + onDeleteApplication() { + let message: string; + if (this.applicationHasDevices()) { + message = this.translate.instant('APPLICATION.DELETE-HAS-DEVICES-PROMPT'); } - onDeleteApplication() { - let message: string; - if (this.applicationHasDevices()) { - message = this.translate.instant('APPLICATION.DELETE-HAS-DEVICES-PROMPT'); + this.deleteDialogSubscription = this.deleteDialogService + .showSimpleDialog(message) + .subscribe((response) => { + if (response) { + this.applicationService + .deleteApplication(this.application.id) + .subscribe((response) => { + if (response.ok && response.body.affected > 0) { + console.log( + 'delete application with id:' + this.application.id.toString() + ); + this.router.navigate(['applications']); + } else { + this.errorMessage = response?.error?.message; + } + }); + } else { + console.log(response); } + }); + } - this.deleteDialogSubscription = this.deleteDialogService.showSimpleDialog(message).subscribe( - (response) => { - if (response) { - this.applicationService.deleteApplication(this.application.id).subscribe((response) => { - if (response.ok && response.body.affected > 0) { - console.log('delete application with id:' + this.application.id.toString()); - this.router.navigate(['applications']); - } else { - this.errorMessage = response?.error?.message; - } - }); - } else { - console.log(response); - } - } - ); - } + applicationHasDevices(): boolean { + return this.application.iotDevices?.length > 0; + } - applicationHasDevices(): boolean { - return this.application.iotDevices?.length > 0; - } + bindApplication(id: number): void { + this.applicationsSubscription = this.applicationService + .getApplication(id) + .subscribe((application) => { + this.application = application; + }); + } - - bindApplication(id: number): void { - this.applicationsSubscription = this.applicationService.getApplication(id).subscribe((application) => { - this.application = application; - }); + ngOnDestroy() { + if (this.applicationsSubscription) { + this.applicationsSubscription.unsubscribe(); } - - ngOnDestroy() { - if (this.applicationsSubscription) { - this.applicationsSubscription.unsubscribe(); - } - if (this.deleteDialogSubscription) { - this.deleteDialogSubscription.unsubscribe(); - } + if (this.deleteDialogSubscription) { + this.deleteDialogSubscription.unsubscribe(); } + } }