diff --git a/src/app/applications/application-detail/application-detail.component.html b/src/app/applications/application-detail/application-detail.component.html index 71fe09ff..78a8fec2 100644 --- a/src/app/applications/application-detail/application-detail.component.html +++ b/src/app/applications/application-detail/application-detail.component.html @@ -11,8 +11,8 @@
-
-
+
+
{{ errorMessage | translate }}
@@ -39,10 +39,24 @@

{{ "APPLICATION.DETAILS" | translate }}

>
-
-
+
+
- + +
+
+
+ IoTDeviceMarker +

: IoT-Enhed

+
+
+ InactiveGatewayMarker +

: Inaktiv gateway

+
+
+ ActiveGatewayMarker +

: Aktiv gateway

+
diff --git a/src/app/applications/application-detail/application-detail.component.scss b/src/app/applications/application-detail/application-detail.component.scss index 12afb2a5..ff72dad8 100644 --- a/src/app/applications/application-detail/application-detail.component.scss +++ b/src/app/applications/application-detail/application-detail.component.scss @@ -1,13 +1,22 @@ -@import 'src/assets/scss/setup/breakpoints'; -@import 'src/assets/scss/setup/variables'; +@import "src/assets/scss/setup/breakpoints"; +@import "src/assets/scss/setup/variables"; .application-component { - .bottom-separator { - min-height: 60px; - border-bottom: $grey-separator solid 1px; + .bottom-separator { + min-height: 60px; + border-bottom: $grey-separator solid 1px; - @include media-breakpoint-up(md) { - min-height: 150px; + @include media-breakpoint-up(md) { + min-height: 150px; + } } - } +} + +.marker { + height: 25px; + width: 20px; +} + +.markerDescriptionDiv { + margin-top: 10px; } diff --git a/src/app/applications/application-detail/application-detail.component.ts b/src/app/applications/application-detail/application-detail.component.ts index d2fd2f34..ff9ea829 100644 --- a/src/app/applications/application-detail/application-detail.component.ts +++ b/src/app/applications/application-detail/application-detail.component.ts @@ -54,6 +54,9 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy, AfterViewI private deviceSubscription: Subscription; private gatewaysSubscription: Subscription; public gateways: Gateway[]; + public redMarker = "/assets/images/red-marker.png"; + public greenMarker = "/assets/images/green-marker.png"; + public greyMarker = "/assets/images/grey-marker.png"; constructor( private applicationService: ApplicationService, @@ -149,29 +152,29 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy, AfterViewI } private mapGatewaysToCoordinateList() { - const tempcoordinateList = []; - this.gateways.map(gateway => - tempcoordinateList.push({ - longitude: gateway.location.longitude, - latitude: gateway.location.latitude, - draggable: false, - editEnabled: false, - useGeolocation: false, - markerInfo: { - name: gateway.name, - active: this.getGatewayStatus(gateway), - id: gateway.gatewayId, - internalOrganizationId: gateway.organizationId, - internalOrganizationName: gateway.organizationName, - }, - }) - ); - this.coordinateList.push.apply(this.coordinateList, tempcoordinateList); - } + const tempcoordinateList = []; + this.gateways.map(gateway => + tempcoordinateList.push({ + longitude: gateway.location.longitude, + latitude: gateway.location.latitude, + draggable: false, + editEnabled: false, + useGeolocation: false, + markerInfo: { + name: gateway.name, + active: this.getGatewayStatus(gateway), + id: gateway.gatewayId, + internalOrganizationId: gateway.organizationId, + internalOrganizationName: gateway.organizationName, + }, + }) + ); + this.coordinateList.push.apply(this.coordinateList, tempcoordinateList); + } - private getGatewayStatus(gateway: Gateway): boolean { - return this.chirpstackGatewayService.isGatewayActive(gateway); - } + private getGatewayStatus(gateway: Gateway): boolean { + return this.chirpstackGatewayService.isGatewayActive(gateway); + } onDeleteApplication() { this.deleteDialogService.showApplicationDialog(this.application).subscribe(response => { diff --git a/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.html b/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.html index f488cb60..f878370c 100644 --- a/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.html +++ b/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.html @@ -4,7 +4,7 @@
-
+

{{ 'DATATARGET.DETAILS' | translate }}

diff --git a/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.html b/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.html index 37b36bcf..72d69c57 100644 --- a/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.html +++ b/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.html @@ -4,7 +4,7 @@
-
+

{{ 'DATATARGET.DETAILS' | translate }}

diff --git a/src/app/applications/datatarget/mqtt-detail/mqtt-detail.component.html b/src/app/applications/datatarget/mqtt-detail/mqtt-detail.component.html index dd7f7058..e8b225e2 100644 --- a/src/app/applications/datatarget/mqtt-detail/mqtt-detail.component.html +++ b/src/app/applications/datatarget/mqtt-detail/mqtt-detail.component.html @@ -5,7 +5,7 @@
-
+

{{ 'DATATARGET.DETAILS' | translate }}

diff --git a/src/app/applications/iot-devices/iot-device-detail/iot-device-detail-generic/iot-device-detail-generic.component.html b/src/app/applications/iot-devices/iot-device-detail/iot-device-detail-generic/iot-device-detail-generic.component.html index b1972a6d..ec754230 100644 --- a/src/app/applications/iot-devices/iot-device-detail/iot-device-detail-generic/iot-device-detail-generic.component.html +++ b/src/app/applications/iot-devices/iot-device-detail/iot-device-detail-generic/iot-device-detail-generic.component.html @@ -1,6 +1,6 @@
-
+

{{ 'IOTDEVICE.DETAIL' | translate }}

{{ 'IOT-TABLE.APPLICATION' | translate }}{{device.application.name}}

@@ -62,17 +62,17 @@

{{ 'IOTDEVICE.DETAIL' | translate }}

-
+

{{ 'IOTDEVICE.LOCATION' | translate }}

-
+

{{ 'IOTDEVICE.LATITUDE' | translate }}{{latitude | number:'2.1-9'}}

-
+

{{ 'IOTDEVICE.LONGITUDE' | translate }}{{longitude | number:'2.1-9'}}

diff --git a/src/app/applications/iot-devices/iot-device-detail/iot-device-detail-generic/iot-device-detail-generic.component.scss b/src/app/applications/iot-devices/iot-device-detail/iot-device-detail-generic/iot-device-detail-generic.component.scss index 8e0bf6a9..2f7d4fa0 100644 --- a/src/app/applications/iot-devices/iot-device-detail/iot-device-detail-generic/iot-device-detail-generic.component.scss +++ b/src/app/applications/iot-devices/iot-device-detail/iot-device-detail-generic/iot-device-detail-generic.component.scss @@ -1,11 +1,19 @@ +@import 'src/assets/scss/setup/variables'; + .pre { - white-space: pre-wrap; - white-space: -moz-pre-wrap; - white-space: -o-pre-wrap; - font-family: monospace; + white-space: pre-wrap; + white-space: -moz-pre-wrap; + white-space: -o-pre-wrap; + font-family: monospace; +} + +.alarmText { + color: #ff0000; + font-size: 1em; } -.alarmText{ - color: #ff0000; - font-size: 1em; +.latLonWrapWidth { + @media (max-width: 1250px) { + width: 100%; + } } diff --git a/src/app/applications/iot-devices/iot-device-detail/iot-device-details-tab/iot-device-details-tab.component.html b/src/app/applications/iot-devices/iot-device-detail/iot-device-details-tab/iot-device-details-tab.component.html index a54cf9ff..1f4c4401 100644 --- a/src/app/applications/iot-devices/iot-device-detail/iot-device-details-tab/iot-device-details-tab.component.html +++ b/src/app/applications/iot-devices/iot-device-detail/iot-device-details-tab/iot-device-details-tab.component.html @@ -3,7 +3,7 @@
-
+
diff --git a/src/app/applications/iot-devices/iot-device-edit/iot-device-edit.component.ts b/src/app/applications/iot-devices/iot-device-edit/iot-device-edit.component.ts index c6f11b37..a4126d51 100644 --- a/src/app/applications/iot-devices/iot-device-edit/iot-device-edit.component.ts +++ b/src/app/applications/iot-devices/iot-device-edit/iot-device-edit.component.ts @@ -1,386 +1,350 @@ -import { Location } from '@angular/common'; -import { HttpErrorResponse } from '@angular/common/http'; -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { Title } from '@angular/platform-browser'; -import { ActivatedRoute, Router } from '@angular/router'; -import { Application } from '@app/applications/application.model'; -import { ApplicationService } from '@app/applications/application.service'; -import { DeviceModelService } from '@app/device-model/device-model.service'; -import { DeviceModel } from '@app/device-model/device.model'; -import { TranslateService } from '@ngx-translate/core'; -import { DeviceProfile } from '@profiles/device-profiles/device-profile.model'; -import { DeviceProfileService } from '@profiles/device-profiles/device-profile.service'; -import { ActivationType } from '@shared/enums/activation-type'; -import { DeviceType } from '@shared/enums/device-type'; -import { ErrorMessageService } from '@shared/error-message.service'; -import { jsonToList } from '@shared/helpers/json.helper'; -import { ErrorMessage } from '@shared/models/error-message.model'; -import { ScrollToTopService } from '@shared/services/scroll-to-top.service'; -import { SharedVariableService } from '@shared/shared-variable/shared-variable.service'; -import { Subscription } from 'rxjs'; -import { IotDevice } from '../iot-device.model'; -import { IoTDeviceService } from '../iot-device.service'; -import { MeService } from '@shared/services/me.service'; -import { OrganizationAccessScope } from '@shared/enums/access-scopes'; +import { Location } from "@angular/common"; +import { HttpErrorResponse } from "@angular/common/http"; +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { Title } from "@angular/platform-browser"; +import { ActivatedRoute, Router } from "@angular/router"; +import { Application } from "@app/applications/application.model"; +import { ApplicationService } from "@app/applications/application.service"; +import { DeviceModelService } from "@app/device-model/device-model.service"; +import { DeviceModel } from "@app/device-model/device.model"; +import { TranslateService } from "@ngx-translate/core"; +import { DeviceProfile } from "@profiles/device-profiles/device-profile.model"; +import { DeviceProfileService } from "@profiles/device-profiles/device-profile.service"; +import { ActivationType } from "@shared/enums/activation-type"; +import { DeviceType } from "@shared/enums/device-type"; +import { ErrorMessageService } from "@shared/error-message.service"; +import { jsonToList } from "@shared/helpers/json.helper"; +import { ErrorMessage } from "@shared/models/error-message.model"; +import { ScrollToTopService } from "@shared/services/scroll-to-top.service"; +import { SharedVariableService } from "@shared/shared-variable/shared-variable.service"; +import { Subscription } from "rxjs"; +import { IotDevice } from "../iot-device.model"; +import { IoTDeviceService } from "../iot-device.service"; +import { MeService } from "@shared/services/me.service"; +import { OrganizationAccessScope } from "@shared/enums/access-scopes"; @Component({ - selector: 'app-iot-device-edit', - templateUrl: './iot-device-edit.component.html', - styleUrls: ['./iot-device-edit.component.scss'], + selector: "app-iot-device-edit", + templateUrl: "./iot-device-edit.component.html", + styleUrls: ["./iot-device-edit.component.scss"], }) export class IotDeviceEditComponent implements OnInit, OnDestroy { - public errorMessages: any; - public errorFields: string[]; - public formFailedSubmit = false; - public application: Application; - private deviceId: number; - public disableChoseApplication = true; - public loraDevice = DeviceType.LORAWAN; - public sigfoxDevice = DeviceType.SIGFOX; - public deviceProfiles: DeviceProfile[]; - public deviceModels: DeviceModel[]; - iotDevice = new IotDevice(); - editmode = false; - public OTAA = true; - metadataTags: { key?: string; value?: string }[] = []; - errorMetadataFieldId: string | undefined; - public deviceSubscription: Subscription; - private applicationsSubscription: Subscription; - private deviceProfileSubscription: Subscription; - private devicesProfileSubscription: Subscription; - canEdit: boolean; - - constructor( - private route: ActivatedRoute, - public translate: TranslateService, - private router: Router, - private deviceProfileService: DeviceProfileService, - private applicationService: ApplicationService, - private iotDeviceService: IoTDeviceService, - private location: Location, - private shareVariable: SharedVariableService, - private deviceModelService: DeviceModelService, - private errorMessageService: ErrorMessageService, - private scrollToTopService: ScrollToTopService, - private titleService: Title, - private meService: MeService - ) {} - - ngOnInit(): void { - this.translate.use('da'); - this.iotDevice.applicationId = +this.route.snapshot.paramMap.get('id'); - this.deviceId = +this.route.snapshot.paramMap.get('deviceId'); - - if (this.iotDevice.applicationId && this.deviceId) { - this.editmode = true; - this.getDevice(this.deviceId); - this.disableChoseApplication = false; - } + public errorMessages: any; + public errorFields: string[]; + public formFailedSubmit = false; + public application: Application; + private deviceId: number; + public disableChoseApplication = true; + public loraDevice = DeviceType.LORAWAN; + public sigfoxDevice = DeviceType.SIGFOX; + public deviceProfiles: DeviceProfile[]; + public deviceModels: DeviceModel[]; + iotDevice = new IotDevice(); + editmode = false; + public OTAA = true; + metadataTags: { key?: string; value?: string }[] = []; + errorMetadataFieldId: string | undefined; + public deviceSubscription: Subscription; + private applicationsSubscription: Subscription; + private deviceProfileSubscription: Subscription; + private devicesProfileSubscription: Subscription; + canEdit: boolean; + + constructor( + private route: ActivatedRoute, + public translate: TranslateService, + private router: Router, + private deviceProfileService: DeviceProfileService, + private applicationService: ApplicationService, + private iotDeviceService: IoTDeviceService, + private location: Location, + private shareVariable: SharedVariableService, + private deviceModelService: DeviceModelService, + private errorMessageService: ErrorMessageService, + private scrollToTopService: ScrollToTopService, + private titleService: Title, + private meService: MeService + ) {} + + ngOnInit(): void { + this.translate.use("da"); + this.iotDevice.applicationId = +this.route.snapshot.paramMap.get("id"); + this.deviceId = +this.route.snapshot.paramMap.get("deviceId"); + + if (this.iotDevice.applicationId && this.deviceId) { + this.editmode = true; + this.getDevice(this.deviceId); + this.disableChoseApplication = false; + } - this.translate.get(['TITLE.IOTDEVICE']).subscribe((translations) => { - this.titleService.setTitle(translations['TITLE.IOTDEVICE']); - }); - - this.getApplication(); - this.getDeviceProfiles(); - this.getDeviceModels(); - this.canEdit = this.meService.hasAccessToTargetOrganization( - OrganizationAccessScope.ApplicationWrite, - undefined, - this.iotDevice.applicationId - ); - } - - public compare(o1: any, o2: any): boolean { - return o1 === o2; - } - - getDeviceModels() { - this.deviceModelService - .getMultiple( - 1000, - 0, - 'id', - 'ASC', - this.shareVariable.getSelectedOrganisationId() - ) - .subscribe((response) => { - this.deviceModels = response.data.sort((a, b) => - a.body.name.localeCompare(b.body.name, 'en', { numeric: true }) + this.translate.get(["TITLE.IOTDEVICE"]).subscribe(translations => { + this.titleService.setTitle(translations["TITLE.IOTDEVICE"]); + }); + + this.getApplication(); + this.getDeviceProfiles(); + this.getDeviceModels(); + this.canEdit = this.meService.hasAccessToTargetOrganization( + OrganizationAccessScope.ApplicationWrite, + undefined, + this.iotDevice.applicationId ); - }); - } - - getApplication(): void { - this.applicationsSubscription = this.applicationService - .getApplication(this.iotDevice.applicationId) - .subscribe((application: Application) => { - this.application = application; - }); - } - - isChecked(event) { - if (event.target.checked) { - this.iotDevice.type = event.target.name; - } else if ( - !event.target.checked && - this.iotDevice.type.toString().includes(event.target.name) - ) { - event.target.checked = true; } - } - - getDevice(id: number): void { - this.deviceSubscription = this.iotDeviceService - .getIoTDevice(id) - .subscribe((device: IotDevice) => { - this.iotDevice = device; - if (this.iotDevice?.application?.id) { - this.iotDevice.applicationId = device.application?.id; - } - if (device.location) { - this.iotDevice.longitude = device.location.coordinates[0]; - this.iotDevice.latitude = device.location.coordinates[1]; - } - this.OTAA = this.iotDevice.lorawanSettings?.OTAAapplicationKey - ? true - : false; - if (device.sigfoxSettings) { + + public compare(o1: any, o2: any): boolean { + return o1 === o2; + } + + getDeviceModels() { + this.deviceModelService + .getMultiple(1000, 0, "id", "ASC", this.shareVariable.getSelectedOrganisationId()) + .subscribe(response => { + this.deviceModels = response.data.sort((a, b) => + a.body.name.localeCompare(b.body.name, "en", { numeric: true }) + ); + }); + } + + getApplication(): void { + this.applicationsSubscription = this.applicationService + .getApplication(this.iotDevice.applicationId) + .subscribe((application: Application) => { + this.application = application; + }); + } + + isChecked(event) { + if (event.target.checked) { + this.iotDevice.type = event.target.name; + } else if (!event.target.checked && this.iotDevice.type.toString().includes(event.target.name)) { + event.target.checked = true; } - if (!device.deviceModelId || device.deviceModelId === null) { - this.iotDevice.deviceModelId = 0; + } + + getDevice(id: number): void { + this.deviceSubscription = this.iotDeviceService.getIoTDevice(id).subscribe((device: IotDevice) => { + this.iotDevice = device; + if (this.iotDevice?.application?.id) { + this.iotDevice.applicationId = device.application?.id; + } + if (device.location) { + this.iotDevice.longitude = device.location.coordinates[0]; + this.iotDevice.latitude = device.location.coordinates[1]; + } + this.OTAA = this.iotDevice.lorawanSettings?.OTAAapplicationKey ? true : false; + if (device.sigfoxSettings) { + } + if (!device.deviceModelId || device.deviceModelId === null) { + this.iotDevice.deviceModelId = 0; + } + if (device.metadata) { + this.metadataTags = jsonToList(device.metadata); + } + }); + } + + onChangeDeviceProfile(deviceProfileId: string) { + this.getDeviceProfile(deviceProfileId); + } + + getDeviceProfile(deviceProfileId: string) { + this.deviceProfileSubscription = this.deviceProfileService.getOne(deviceProfileId).subscribe(response => { + this.OTAA = response.deviceProfile.supportsJoin; + }); + } + + getDeviceProfiles() { + this.devicesProfileSubscription = this.deviceProfileService.getMultiple().subscribe(result => { + this.deviceProfiles = result.result.sort((a, b) => a.name.localeCompare(b.name, "en", { numeric: true })); + }); + } + + getCoordinates() { + return { + longitude: this.iotDevice.longitude, + latitude: this.iotDevice.latitude, + draggable: true, + editEnabled: false, + useGeolocation: !this.editmode, + }; + } + + updateCoordinates(event: any) { + this.iotDevice.longitude = event.longitude; + this.iotDevice.latitude = event.latitude; + } + + onSubmit(): void { + this.adjustModelBasedOnType(); + + if (this.metadataTags.length === 0) { + this.iotDevice.metadata = JSON.stringify({}); + } else if (this.isMetadataSet()) { + const invalidKey = this.validateMetadata(); + + if (!invalidKey) { + this.setMetadata(); + } else { + this.handleMetadataError(invalidKey); + return; + } } - if (device.metadata) { - this.metadataTags = jsonToList(device.metadata); + + if (this.deviceId !== 0) { + this.updateIoTDevice(this.deviceId); + } else { + this.postIoTDevice(); } - }); - } - - onChangeDeviceProfile(deviceProfileId: string) { - this.getDeviceProfile(deviceProfileId); - } - - getDeviceProfile(deviceProfileId: string) { - this.deviceProfileSubscription = this.deviceProfileService - .getOne(deviceProfileId) - .subscribe((response) => { - this.OTAA = response.deviceProfile.supportsJoin; - }); - } - - getDeviceProfiles() { - this.devicesProfileSubscription = this.deviceProfileService - .getMultiple() - .subscribe((result) => { - this.deviceProfiles = result.result.sort((a, b) => - a.name.localeCompare(b.name, 'en', { numeric: true }) - ); - }); - } - - getCoordinates() { - return { - longitude: this.iotDevice.longitude, - latitude: this.iotDevice.latitude, - draggable: true, - editEnabled: false, - useGeolocation: !this.editmode, - }; - } - - updateCoordinates(event: any) { - this.iotDevice.longitude = event.longitude; - this.iotDevice.latitude = event.latitude; - } - - onSubmit(): void { - this.adjustModelBasedOnType(); - - if (this.metadataTags.length === 0) { - this.iotDevice.metadata = JSON.stringify({}); - } else if (this.isMetadataSet()) { - const invalidKey = this.validateMetadata(); - - if (!invalidKey) { - this.setMetadata(); - } else { - this.handleMetadataError(invalidKey); - return; - } } - if (this.deviceId !== 0) { - this.updateIoTDevice(this.deviceId); - } else { - this.postIoTDevice(); - } - } - - private handleMetadataError(invalidKey: string) { - this.handleError({ - error: { - message: [ - { - field: 'metadata', - message: 'MESSAGE.DUPLICATE-METADATA-KEY', - }, - ], - }, - }); - this.errorMetadataFieldId = invalidKey; - this.formFailedSubmit = true; - } - - setActivationType() { - if (this.OTAA) { - this.iotDevice.lorawanSettings.activationType = ActivationType.OTAA; - } else { - this.iotDevice.lorawanSettings.activationType = ActivationType.ABP; + private handleMetadataError(invalidKey: string) { + this.handleError({ + error: { + message: [ + { + field: "metadata", + message: "MESSAGE.DUPLICATE-METADATA-KEY", + }, + ], + }, + }); + this.errorMetadataFieldId = invalidKey; + this.formFailedSubmit = true; } - } - private adjustModelBasedOnType() { - if (this.iotDevice.deviceModelId === 0) { - this.iotDevice.deviceModelId = null; + setActivationType() { + if (this.OTAA) { + this.iotDevice.lorawanSettings.activationType = ActivationType.OTAA; + } else { + this.iotDevice.lorawanSettings.activationType = ActivationType.ABP; + } } - switch (this.iotDevice.type) { - case DeviceType.GENERIC_HTTP: { - this.iotDevice.lorawanSettings = undefined; - this.iotDevice.sigfoxSettings = undefined; - break; - } - case DeviceType.LORAWAN: { - this.setActivationType(); - this.iotDevice.sigfoxSettings = undefined; - if (this.iotDevice.lorawanSettings.devEUI) { - this.iotDevice.lorawanSettings.devEUI = this.iotDevice.lorawanSettings.devEUI.toLowerCase(); + + private adjustModelBasedOnType() { + if (this.iotDevice.deviceModelId === 0) { + this.iotDevice.deviceModelId = null; } - break; - } - case DeviceType.SIGFOX: { - this.iotDevice.lorawanSettings = undefined; - if (this.iotDevice.sigfoxSettings.endProductCertificate) { - this.iotDevice.sigfoxSettings.prototype = false; + switch (this.iotDevice.type) { + case DeviceType.GENERIC_HTTP: { + this.iotDevice.lorawanSettings = undefined; + this.iotDevice.sigfoxSettings = undefined; + break; + } + case DeviceType.LORAWAN: { + this.setActivationType(); + this.iotDevice.sigfoxSettings = undefined; + if (this.iotDevice.lorawanSettings.devEUI) { + this.iotDevice.lorawanSettings.devEUI = this.iotDevice.lorawanSettings.devEUI.toLowerCase(); + } + break; + } + case DeviceType.SIGFOX: { + this.iotDevice.lorawanSettings = undefined; + if (this.iotDevice.sigfoxSettings.endProductCertificate) { + this.iotDevice.sigfoxSettings.prototype = false; + } + break; + } } - break; - } } - } - - private isMetadataSet(): boolean { - return ( - this.metadataTags.length && - this.metadataTags.some((tag) => tag.key && tag.value) - ); - } - - private validateMetadata(): string | undefined { - const seen = new Set(); - - for (const tag of this.metadataTags) { - if (seen.size === seen.add(tag.key).size) { - return tag.key; - } + + private isMetadataSet(): boolean { + return this.metadataTags.length && this.metadataTags.some(tag => tag.key && tag.value); } - } - - private setMetadata(): void { - if ( - this.metadataTags.length && - this.metadataTags.some((tag) => tag.key && tag.value) - ) { - const metadata: Record = {}; - this.metadataTags.forEach((tag) => { - if (!tag.key) { - return; + + private validateMetadata(): string | undefined { + const seen = new Set(); + + for (const tag of this.metadataTags) { + if (seen.size === seen.add(tag.key).size) { + return tag.key; + } } - metadata[tag.key] = tag.value; - }); - this.iotDevice.metadata = JSON.stringify(metadata); } - } - - postIoTDevice() { - // Sanitize devEUI for non-hex characters - if (this.iotDevice.type === DeviceType.LORAWAN) { - this.iotDevice.lorawanSettings.devEUI = this.iotDevice.lorawanSettings.devEUI.replace( - /[^0-9A-Fa-f]/g, - '' - ); + + private setMetadata(): void { + if (this.metadataTags.length && this.metadataTags.some(tag => tag.key && tag.value)) { + const metadata: Record = {}; + this.metadataTags.forEach(tag => { + if (!tag.key) { + return; + } + metadata[tag.key] = tag.value; + }); + this.iotDevice.metadata = JSON.stringify(metadata); + } } - this.iotDeviceService.createIoTDevice(this.iotDevice).subscribe( - (response: IotDevice) => { - this.router.navigate([ - 'applications/' + - this.iotDevice.applicationId + - '/iot-device/' + - response.id + - '/details', - ]); - }, - (error: HttpErrorResponse) => { - this.handleError(error); - this.formFailedSubmit = true; - } - ); - } - - updateIoTDevice(id: number) { - this.iotDevice.applicationId = Number(this.iotDevice.applicationId); - this.iotDeviceService.updateIoTDevice(this.iotDevice, id).subscribe( - () => { - this.routeBack(); - }, - (error: HttpErrorResponse) => { - this.handleError(error); - this.formFailedSubmit = true; - } - ); - } - - routeBack(): void { - this.location.back(); - } - - handleError(error: Pick) { - if (error?.error?.message === 'MESSAGE.OTAA-INFO-MISSING') { - this.errorFields = ['OTAAapplicationKey']; - this.errorMessages = [error?.error?.message]; - } else if ( - error?.error?.message === 'MESSAGE.ID-INVALID-OR-ALREADY-IN-USE' - ) { - this.errorFields = ['devEUI']; - this.errorMessages = [error?.error?.message]; - } else { - const errorMessage: ErrorMessage = this.errorMessageService.handleErrorMessageWithFields( - error - ); - this.errorFields = errorMessage.errorFields; - this.errorMessages = errorMessage.errorMessages; + postIoTDevice() { + // Sanitize devEUI for non-hex characters + if (this.iotDevice.type === DeviceType.LORAWAN && this.iotDevice.lorawanSettings.devEUI) { + this.iotDevice.lorawanSettings.devEUI = this.iotDevice.lorawanSettings.devEUI.replace(/[^0-9A-Fa-f]/g, ""); + } + + this.iotDeviceService.createIoTDevice(this.iotDevice).subscribe( + (response: IotDevice) => { + this.router.navigate([ + "applications/" + this.iotDevice.applicationId + "/iot-device/" + response.id + "/details", + ]); + }, + (error: HttpErrorResponse) => { + this.handleError(error); + this.formFailedSubmit = true; + } + ); } - this.scrollToTopService.scrollToTop(); - } - onCoordinateKey(event: any) { - if (event.target.value.length > event.target.maxLength) { - event.target.value = event.target.value.slice(0, event.target.maxLength); + updateIoTDevice(id: number) { + this.iotDevice.applicationId = Number(this.iotDevice.applicationId); + this.iotDeviceService.updateIoTDevice(this.iotDevice, id).subscribe( + () => { + this.routeBack(); + }, + (error: HttpErrorResponse) => { + this.handleError(error); + this.formFailedSubmit = true; + } + ); } - } - ngOnDestroy() { - // prevent memory leak by unsubscribing - if (this.applicationsSubscription) { - this.applicationsSubscription.unsubscribe(); + routeBack(): void { + this.location.back(); } - if (this.deviceSubscription) { - this.deviceSubscription.unsubscribe(); + + handleError(error: Pick) { + if (error?.error?.message === "MESSAGE.OTAA-INFO-MISSING") { + this.errorFields = ["OTAAapplicationKey"]; + this.errorMessages = [error?.error?.message]; + } else if (error?.error?.message === "MESSAGE.ID-INVALID-OR-ALREADY-IN-USE") { + this.errorFields = ["devEUI"]; + this.errorMessages = [error?.error?.message]; + } else { + const errorMessage: ErrorMessage = this.errorMessageService.handleErrorMessageWithFields(error); + this.errorFields = errorMessage.errorFields; + this.errorMessages = errorMessage.errorMessages; + } + this.scrollToTopService.scrollToTop(); } - if (this.deviceProfileSubscription) { - this.deviceProfileSubscription.unsubscribe(); + + onCoordinateKey(event: any) { + if (event.target.value.length > event.target.maxLength) { + event.target.value = event.target.value.slice(0, event.target.maxLength); + } } - if (this.devicesProfileSubscription) { - this.devicesProfileSubscription.unsubscribe(); + + ngOnDestroy() { + // prevent memory leak by unsubscribing + if (this.applicationsSubscription) { + this.applicationsSubscription.unsubscribe(); + } + if (this.deviceSubscription) { + this.deviceSubscription.unsubscribe(); + } + if (this.deviceProfileSubscription) { + this.deviceProfileSubscription.unsubscribe(); + } + if (this.devicesProfileSubscription) { + this.devicesProfileSubscription.unsubscribe(); + } } - } } 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 919ff162..3245567e 100644 --- a/src/app/applications/multicast/multicast-detail/multicast-detail.component.html +++ b/src/app/applications/multicast/multicast-detail/multicast-detail.component.html @@ -9,7 +9,7 @@ >
-
+

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

@@ -52,7 +52,7 @@

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

-
+

{{ 'APPLICATION.ATTACHED-IOT' | translate }}

diff --git a/src/app/auth/auth.component.ts b/src/app/auth/auth.component.ts index 0f355ed2..94372f72 100644 --- a/src/app/auth/auth.component.ts +++ b/src/app/auth/auth.component.ts @@ -69,7 +69,6 @@ export class AuthComponent implements OnInit { this.isLoading = true; this.authService.login(username, password).subscribe( (x: any) => { - console.log(x); if (x.accessToken) { this.success(); } else { diff --git a/src/app/gateway/gateway-detail/gateway-detail.component.html b/src/app/gateway/gateway-detail/gateway-detail.component.html index c0427fde..f0a57a57 100644 --- a/src/app/gateway/gateway-detail/gateway-detail.component.html +++ b/src/app/gateway/gateway-detail/gateway-detail.component.html @@ -4,7 +4,7 @@

-
+

{{ 'GATEWAY.DETAILS' | translate }}

{{ 'GATEWAY.ID' | translate }}{{gateway.gatewayId}}

{{ 'GATEWAY.ORGANIZATION' | translate }}{{gateway.organizationName}}

@@ -26,21 +26,21 @@

{{ 'GATEWAY.DETAILS' | translate }}

-
+

{{ 'GATEWAY.LOCATION' | translate }}

-
-

{{ 'GATEWAY.LONGITUDE' | translate }} - {{gateway.location?.longitude | number:'2.1-9'}}

-

{{ 'GATEWAY.LATITUDE' | translate }} {{gateway.location.latitude | number:'2.1-9'}}

+
+

{{ 'GATEWAY.LONGITUDE' | translate }} + {{gateway.location?.longitude | number:'2.1-9'}}

+

{{ 'GATEWAY.ALTITUDE' | translate }} {{gateway.location.altitude | number:'2.1-9'}}

diff --git a/src/app/gateway/gateway-detail/gateway-detail.component.ts b/src/app/gateway/gateway-detail/gateway-detail.component.ts index 3be60873..2c573761 100644 --- a/src/app/gateway/gateway-detail/gateway-detail.component.ts +++ b/src/app/gateway/gateway-detail/gateway-detail.component.ts @@ -33,7 +33,7 @@ export class GatewayDetailComponent implements OnInit, OnDestroy, AfterViewInit public gatewaySubscription: Subscription; public gateway: Gateway; - public backButton: BackButton = { label: "", routerLink: 0 as any }; + public backButton: BackButton = { label: "", routerLink: "/gateways/list" }; gatewayId: string; private deleteDialogSubscription: Subscription; @@ -85,6 +85,7 @@ export class GatewayDetailComponent implements OnInit, OnDestroy, AfterViewInit name: this.gateway.name, active: this.gatewayService.isGatewayActive(this.gateway), gatewayId: this.gateway.gatewayId, + id: this.gateway.gatewayId, internalOrganizationName: this.gateway.organizationName, }, }; diff --git a/src/app/gateway/gateway-edit/gateway-edit.component.html b/src/app/gateway/gateway-edit/gateway-edit.component.html index ceea42bc..3957f117 100644 --- a/src/app/gateway/gateway-edit/gateway-edit.component.html +++ b/src/app/gateway/gateway-edit/gateway-edit.component.html @@ -40,14 +40,6 @@

{{'DBLCLICKINFO' | translate}}

-
- - -
-
+
+ + +
+
{ - clusterGroup.addLayer( - this.addMarker(coord.latitude, coord.longitude, coord.draggable, coord.markerInfo) - ); + if (this.isFromApplication) { + if (!coord.markerInfo.isDevice) { + gatewayLayerGroup.push( + this.addMarker(coord.latitude, coord.longitude, coord.draggable, coord.markerInfo) + ); + this.markers = L.layerGroup(gatewayLayerGroup).addTo(this.map); + } else { + clusterGroup.addLayer( + this.addMarker(coord.latitude, coord.longitude, coord.draggable, coord.markerInfo) + ); + } + } else { + clusterGroup.addLayer( + this.addMarker(coord.latitude, coord.longitude, coord.draggable, coord.markerInfo) + ); + } }); this.markers = clusterGroup.addTo(this.map); @@ -182,10 +197,10 @@ export class MapComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy ' org.id === response.gateway.organizationId)?.name; + // We want to show helper text if tags is empty. To show empty text, the tagsString has to be undefined. + response.gateway.tagsString = + Object.keys(response.gateway.tags).length === 0 ? undefined : JSON.stringify(response.gateway.tags); + // Move createdat and updatedat to next level ease the use. - response.gateway.tagsString = JSON.stringify(response.gateway.tags); response.gateway.createdByName = this.userMinimalService.getUserNameFrom(response.gateway.createdBy); response.gateway.updatedByName = this.userMinimalService.getUserNameFrom(response.gateway.updatedBy); diff --git a/src/assets/i18n/da.json b/src/assets/i18n/da.json index ea1b4301..a00d41a4 100644 --- a/src/assets/i18n/da.json +++ b/src/assets/i18n/da.json @@ -384,7 +384,7 @@ "RESPONSIBLE-NAME": "Gateway-ansvarlig", "RESPONSIBLE-EMAIL": "Kontaktmail", "RESPONSIBLE-PHONE-NUMBER": "Kontakttelefon", - "OPERATIONAL-NAME": "Driftansvarlig", + "OPERATIONAL-NAME": "Driftsansvarlig", "OPERATIONAL-EMAIL": "Kontaktmail - drift", "TAGS": "Tags", "CREATED-AT": "Oprettelsesdato" @@ -828,7 +828,7 @@ "GATEWAYID": "Gateway id (EUI)", "GATEWAYID-PLACEHOLDER": "0000000000000000", "METADATA": "Gateway tags", - "METADATA-PLACEHOLDER": "Angiv JSON her", + "METADATA-PLACEHOLDER": "Angiv JSON her: {\"tagName\": \"tagValue\"}", "ALTITUDE": "Højde", "ALTITUDE-PLACEHOLDER": "00", "LONGITUDE": "Længdegrad", @@ -845,7 +845,7 @@ "GATEWAY-RESPONSIBLE-CONTACT-PLACEHOLDER": "Angiv mailadresse på gateway-ansvarlig", "GATEWAY-RESPONSIBLE-CONTACT-NUMBER": "Kontakttelefon", "GATEWAY-RESPONSIBLE-CONTACT-NUMBER-PLACEHOLDER": "Angiv telefonnummer på gateway-ansvarlig", - "OPERATION-RESPONSIBLE": "Driftansvarlig", + "OPERATION-RESPONSIBLE": "Driftsansvarlig", "OPERATION-RESPONSIBLE-PLACEHOLDER": "Angiv ansvarlig for den fysiske drift af gateway", "OPERATION-RESPONSIBLE-CONTACT": "Kontaktmail - drift", "OPERATION-RESPONSIBLE-CONTACT-PLACEHOLDER": "Angiv mailadresse på driftsansvarlig" diff --git a/src/styles.scss b/src/styles.scss index c5e12dd0..7680a06d 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -121,3 +121,7 @@ body { height: 400px; margin-right: 30px; } + +.width100percent { + width: 100%; +}