From c0ceda85b78986a380c761c42e0f93c3a5b68372 Mon Sep 17 00:00:00 2001 From: MadsSvejstrup <61703068+MadsSvejstrup@users.noreply.github.com> Date: Thu, 4 Nov 2021 11:10:41 +0100 Subject: [PATCH 1/7] Make environment configurable using environment variables (#52) --- Dockerfile-prod | 14 ++++++++++++-- angular.json | 6 ------ src/assets/env.js | 7 +++++++ src/assets/env.template.js | 7 +++++++ src/environments/environment.prod.ts | 5 ----- src/environments/environment.ts | 11 ++++------- src/index.html | 1 + 7 files changed, 31 insertions(+), 20 deletions(-) create mode 100644 src/assets/env.js create mode 100644 src/assets/env.template.js delete mode 100644 src/environments/environment.prod.ts diff --git a/Dockerfile-prod b/Dockerfile-prod index 55877833..585d65c8 100644 --- a/Dockerfile-prod +++ b/Dockerfile-prod @@ -23,7 +23,7 @@ RUN npm install -g @angular/cli@7.3.9 COPY . /app # Build the project and copy the files -RUN npm run ng build -- --deploy-url=/ --prod +RUN npm run ng build -- --deploy-url=/ --c production FROM bitnami/nginx:latest @@ -37,7 +37,17 @@ COPY ./.nginx/nginx.conf /opt/bitnami/nginx/conf/server_blocks/frontend.conf # Copy from the stahg 1 COPY --from=builder /app/dist/OS2IoT-frontend /app +## Change user to perform privileged actions +USER 0 +# Install envsubst +RUN apt-get update && apt-get install -y gettext-base +# Make sure we have write access to the env.js file without using the root user +RUN chown 1001 /app/assets/env.js +# Revert to the original non-root user +USER 1001 + EXPOSE 8080 EXPOSE 8081 -ENTRYPOINT ["nginx", "-g", "daemon off;"] +# Substiture placeholders in env.template.js using environment variables overwrite env.js +CMD ["/bin/sh", "-c", "envsubst < /app/assets/env.template.js > /app/assets/env.js && exec nginx -g 'daemon off;'"] diff --git a/angular.json b/angular.json index 99376f87..29cdb90b 100644 --- a/angular.json +++ b/angular.json @@ -40,12 +40,6 @@ }, "configurations": { "production": { - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.prod.ts" - } - ], "optimization": true, "outputHashing": "all", "sourceMap": false, diff --git a/src/assets/env.js b/src/assets/env.js new file mode 100644 index 00000000..c95e28db --- /dev/null +++ b/src/assets/env.js @@ -0,0 +1,7 @@ +// This file will be overwritten when running in Docker using env.template.js and envsubst +(function (window) { + window["env"] = window["env"] || {}; + window["env"].PRODUCTION = false; + window["env"].BASE_URL = 'http://localhost:3000/api/v1/'; // For local testing + window["env"].TABLE_PAGE_SIZE = 20; // For local testing + })(this); \ No newline at end of file diff --git a/src/assets/env.template.js b/src/assets/env.template.js new file mode 100644 index 00000000..a49bcf61 --- /dev/null +++ b/src/assets/env.template.js @@ -0,0 +1,7 @@ +// Variables in this file will be substituted using envsubst +(function (window) { + window["env"] = window["env"] || {}; + window["env"].PRODUCTION = "${PRODUCTION}"; + window["env"].BASE_URL = "${BASE_URL}"; + window["env"].TABLE_PAGE_SIZE = "${TABLE_PAGE_SIZE}"; + })(this); \ No newline at end of file diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts deleted file mode 100644 index 65a621ed..00000000 --- a/src/environments/environment.prod.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const environment = { - production: true, - baseUrl: 'http://localhost:3000/api/v1/', - tablePageSize: 20, -}; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 380111d7..4747152c 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -1,11 +1,8 @@ -// This file can be replaced during build by using the `fileReplacements` array. -// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. -// The list of file replacements can be found in `angular.json`. - +// "env" is defined in env.js and facilitates dynamic configurations using environment variables export const environment = { - production: false, - baseUrl: 'http://localhost:3000/api/v1/', - tablePageSize: 20, + production: window["env"].PRODUCTION === "true", + baseUrl: window["env"].BASE_URL, + tablePageSize: parseInt(window["env"].TABLE_PAGE_SIZE) || 20 }; /* diff --git a/src/index.html b/src/index.html index a6529fcb..c984af8c 100644 --- a/src/index.html +++ b/src/index.html @@ -15,6 +15,7 @@ + From b5cd43c8e658b6727663a495beb6ebae20d63760 Mon Sep 17 00:00:00 2001 From: Nikolaj Gustafsson Date: Thu, 4 Nov 2021 11:29:13 +0100 Subject: [PATCH 2/7] =?UTF-8?q?Added=20message=20to=20prompt=20when=20atte?= =?UTF-8?q?mpting=20to=20delete=20application=20with=20ex=E2=80=A6=20(#54)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added message to prompt when attempting to delete application with existing devices. Cleaned code in a few files. * Removed debugging print lines and fixed indentation. --- .../organisation-detail.component.ts | 3 ++- .../admin/organisation/organisation.service.ts | 10 +++++----- .../application-detail.component.ts | 14 ++++++++++++-- src/app/applications/application.service.ts | 16 ++++++++-------- .../applications-table.component.ts | 16 ++++++++++++++-- .../gateway-table/gateway-table.component.html | 2 +- .../gateway-table/gateway-table.component.ts | 2 +- .../services/chirpstack-gateway.service.ts | 2 +- src/assets/i18n/da.json | 1 + 9 files changed, 45 insertions(+), 21 deletions(-) diff --git a/src/app/admin/organisation/organisation-detail/organisation-detail.component.ts b/src/app/admin/organisation/organisation-detail/organisation-detail.component.ts index a2a2f0ee..38cce3fb 100644 --- a/src/app/admin/organisation/organisation-detail/organisation-detail.component.ts +++ b/src/app/admin/organisation/organisation-detail/organisation-detail.component.ts @@ -65,7 +65,8 @@ export class OrganisationDetailComponent implements OnInit, OnChanges, OnDestroy label: '', editRouterLink: 'edit-organisation', isErasable: true, - } + }; + this.translate.get(['NAV.ORGANISATIONS', 'ORGANISATION.DROPDOWN', 'TITLE.ORGANIZATION']) .subscribe(translations => { this.backButton.label = translations['NAV.ORGANISATIONS']; diff --git a/src/app/admin/organisation/organisation.service.ts b/src/app/admin/organisation/organisation.service.ts index 39902ef4..c480205e 100644 --- a/src/app/admin/organisation/organisation.service.ts +++ b/src/app/admin/organisation/organisation.service.ts @@ -15,7 +15,7 @@ import { UserMinimalService } from '../users/user-minimal.service'; }) export class OrganisationService { URL = 'organization'; - URLMINIMAL ='organization/minimal' + URLMINIMAL = 'organization/minimal'; constructor( private restService: RestService, @@ -38,7 +38,7 @@ export class OrganisationService { (response: OrganisationResponse) => { response.createdByName = this.userMinimalService.getUserNameFrom(response.createdBy); response.updatedByName = this.userMinimalService.getUserNameFrom(response.updatedBy); - return response + return response; } ) ); @@ -48,15 +48,15 @@ export class OrganisationService { return this.restService.get(this.URLMINIMAL, {}).pipe(shareReplay(1)); } - getMultiple( + getMultiple( limit: number = 1000, offset: number = 0, orderByColumn?: string, orderByDirection?: string, ): Observable { return this.restService.get(this.URL, { - limit: limit, - offset: offset, + limit, + offset, orderOn: orderByColumn, sort: orderByDirection, }); diff --git a/src/app/applications/application-detail/application-detail.component.ts b/src/app/applications/application-detail/application-detail.component.ts index f006843b..009f3a63 100644 --- a/src/app/applications/application-detail/application-detail.component.ts +++ b/src/app/applications/application-detail/application-detail.component.ts @@ -44,7 +44,8 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy { label: '', editRouterLink: '../../edit-application/' + this.id, isErasable: true, - } + }; + console.log(this.id); } @@ -58,7 +59,12 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy { } onDeleteApplication() { - this.deleteDialogSubscription = this.deleteDialogService.showSimpleDialog().subscribe( + 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) => { @@ -76,6 +82,10 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy { ); } + applicationHasDevices(): boolean { + return this.application.iotDevices?.length > 0; + } + bindApplication(id: number): void { this.applicationsSubscription = this.applicationService.getApplication(id).subscribe((application) => { this.application = application; diff --git a/src/app/applications/application.service.ts b/src/app/applications/application.service.ts index c150e04f..4cfe2bdd 100644 --- a/src/app/applications/application.service.ts +++ b/src/app/applications/application.service.ts @@ -55,16 +55,16 @@ export class ApplicationService { permissionId?: number ): Observable { const body: GetApplicationParameters = { - limit: limit, - offset: offset, - sort: sort, - orderOn: orderOn, + limit, + offset, + sort, + orderOn, }; if (permissionId) { - body.permissionId = permissionId - return this.restService.get(`permission/${permissionId}/applications`, body) + body.permissionId = permissionId; + return this.restService.get(`permission/${permissionId}/applications`, body); } else if (organizationId) { - body.organizationId = organizationId + body.organizationId = organizationId; return this.restService.get('application', body); } return this.restService.get('application', body); @@ -72,7 +72,7 @@ export class ApplicationService { getApplicationsByOrganizationId(organizationId: number): Observable { const body = { - organizationId: organizationId + organizationId }; return this.restService.get('application', body); diff --git a/src/app/applications/applications-list/applications-table/applications-table.component.ts b/src/app/applications/applications-list/applications-table/applications-table.component.ts index 1dadcca6..4da38304 100644 --- a/src/app/applications/applications-list/applications-table/applications-table.component.ts +++ b/src/app/applications/applications-list/applications-table/applications-table.component.ts @@ -5,6 +5,7 @@ import { Router } from '@angular/router'; import { Application, ApplicationData } 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 { MeService } from '@shared/services/me.service'; import { merge, Observable, of as observableOf } from 'rxjs'; @@ -34,6 +35,7 @@ export class ApplicationsTableComponent implements AfterViewInit, OnInit { @ViewChild(MatSort) sort: MatSort; constructor( + public translate: TranslateService, private applicationService: ApplicationService, private router: Router, private meService: MeService, @@ -41,7 +43,7 @@ export class ApplicationsTableComponent implements AfterViewInit, OnInit { ) { } ngOnInit() { - this.canEdit = this.meService.canWriteInTargetOrganization() + this.canEdit = this.meService.canWriteInTargetOrganization(); } ngAfterViewInit() { @@ -85,7 +87,12 @@ export class ApplicationsTableComponent implements AfterViewInit, OnInit { } deleteApplication(id: number) { - this.deleteDialogService.showSimpleDialog().subscribe((response) => { + let message: string; + if (this.applicationHasDevices(id)) { + message = this.translate.instant('APPLICATION.DELETE-HAS-DEVICES-PROMPT'); + } + + this.deleteDialogService.showSimpleDialog(message).subscribe((response) => { if (response) { this.applicationService.deleteApplication(id).subscribe((response) => { if (response.ok && response.body.affected > 0) { @@ -102,6 +109,11 @@ export class ApplicationsTableComponent implements AfterViewInit, OnInit { }); } + applicationHasDevices(id: number): boolean { + const applicationToDelete = this.data?.find(app => app.id === id); + return applicationToDelete && applicationToDelete.iotDevices.length > 0; + } + navigateToEditPage(applicationId: string) { this.router.navigate(['applications', 'edit-application', applicationId]); } diff --git a/src/app/gateway/gateway-table/gateway-table.component.html b/src/app/gateway/gateway-table/gateway-table.component.html index 4f6086d0..9b50a0f9 100644 --- a/src/app/gateway/gateway-table/gateway-table.component.html +++ b/src/app/gateway/gateway-table/gateway-table.component.html @@ -24,7 +24,7 @@ - + {{ 'LORA-GATEWAY-TABLE.ORGANIZATION' | translate }} diff --git a/src/app/gateway/gateway-table/gateway-table.component.ts b/src/app/gateway/gateway-table/gateway-table.component.ts index fbe3b882..20211329 100644 --- a/src/app/gateway/gateway-table/gateway-table.component.ts +++ b/src/app/gateway/gateway-table/gateway-table.component.ts @@ -57,7 +57,7 @@ export class GatewayTableComponent implements AfterViewInit { ) { this.translate.use('da'); moment.locale('da'); - } +} ngAfterViewInit() { this.organisationChangeSubject.subscribe((x) => { diff --git a/src/app/shared/services/chirpstack-gateway.service.ts b/src/app/shared/services/chirpstack-gateway.service.ts index e06c46d7..fd7a13ae 100644 --- a/src/app/shared/services/chirpstack-gateway.service.ts +++ b/src/app/shared/services/chirpstack-gateway.service.ts @@ -28,7 +28,7 @@ export class ChirpstackGatewayService { (response: GatewayResponse) => { response.gateway.internalOrganizationName = this.sharedVariableService.getOrganizationInfo() .find(org => org.id === response.gateway.internalOrganizationId)?.name; - //move createdat and updatedat to next level ease the use. + // Move createdat and updatedat to next level ease the use. response.gateway.updatedAt = response.updatedAt; response.gateway.createdAt = response.createdAt; response.gateway.lastSeenAt = response.lastSeenAt; diff --git a/src/assets/i18n/da.json b/src/assets/i18n/da.json index 5c26a491..96c8b754 100644 --- a/src/assets/i18n/da.json +++ b/src/assets/i18n/da.json @@ -80,6 +80,7 @@ "CREATE": "Opret applikation", "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?", "NAME": "Applikationens navn", "DESCRIPTION": "Applikationens beskrivelse", "ATTACHED-IOT": "Tilknyttede IoT enheder", From a6a72235ada25bcdd9921f73da51c04103423d35 Mon Sep 17 00:00:00 2001 From: Mads Svejstrup Date: Fri, 5 Nov 2021 10:27:08 +0100 Subject: [PATCH 3/7] Updated default baseUrl to match docs --- src/environments/environment.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 4747152c..04ab0b80 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -1,7 +1,7 @@ // "env" is defined in env.js and facilitates dynamic configurations using environment variables export const environment = { production: window["env"].PRODUCTION === "true", - baseUrl: window["env"].BASE_URL, + baseUrl: window["env"].BASE_URL || "http://localhost:3000/api/v1/", tablePageSize: parseInt(window["env"].TABLE_PAGE_SIZE) || 20 }; From 9e1679df0b6710a2762664cc8229287d949dbafa Mon Sep 17 00:00:00 2001 From: AramAlsabti <92869496+AramAlsabti@users.noreply.github.com> Date: Fri, 12 Nov 2021 14:45:46 +0100 Subject: [PATCH 4/7] Active column now uses timestamp from latest message (#56) --- .../iot-devices-table.component.ts | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) 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 a13c723f..ac550bb7 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 @@ -1,4 +1,10 @@ -import { Component, Input, ViewChild, AfterViewInit, OnInit } from '@angular/core'; +import { + Component, + Input, + ViewChild, + AfterViewInit, + OnInit, +} from '@angular/core'; import { merge, Observable, of as observableOf } from 'rxjs'; import { TranslateService } from '@ngx-translate/core'; import { RestService } from 'src/app/shared/services/rest.service'; @@ -59,7 +65,7 @@ export class IotDevicesTableComponent implements AfterViewInit, OnInit { } ngOnInit() { - this.canEdit = this.meService.canWriteInTargetOrganization() + this.canEdit = this.meService.canWriteInTargetOrganization(); } ngAfterViewInit() { @@ -114,15 +120,9 @@ export class IotDevicesTableComponent implements AfterViewInit, OnInit { } public lastActive(device: IotDevice) { - const arr = device?.receivedMessagesMetadata; - if (!arr || arr.length === 0) { - return this.translate.instant('ACTIVITY.NEVER'); - } else { - const lastActive = Math.max( - ...arr.map((x: ReceivedMessageMetadata) => Date.parse(x.sentTime)) - ); - return moment(lastActive).fromNow(); - } + return device.latestReceivedMessage + ? moment(device.latestReceivedMessage.sentTime).fromNow() + : this.translate.instant('ACTIVITY.NEVER'); } clickDelete(element: any) { From 4184c59e2c366b3ed12271af88a2230582177a51 Mon Sep 17 00:00:00 2001 From: bkdkmd Date: Mon, 14 Feb 2022 23:27:12 +0100 Subject: [PATCH 5/7] Datatarget multi-types administration and new FIWARE Datatarget type --- src/app/app.module.ts | 2 + .../applications-routing.module.ts | 6 +- ...get-detail-type-selector.directive.spec.ts | 11 + ...tatarget-detail-type-selector.directive.ts | 9 + .../datatarget-detail.component.html | 75 +--- .../datatarget-detail.component.ts | 118 ++--- .../datatarget-detail/datatarget-detail.ts | 2 + ...arget-edit-type-selector.directive.spec.ts | 11 + ...datatarget-edit-type-selector.directive.ts | 10 + .../datatarget-edit.component.html | 142 +----- .../datatarget-edit.component.ts | 421 +++--------------- .../datatarget-edit/datatarget-edit.ts | 2 + .../datatarget-list.component.html | 2 +- .../datatarget-new.component.html | 34 ++ .../datatarget-new.component.scss | 44 ++ .../datatarget-new.component.spec.ts | 28 ++ .../datatarget-new.component.ts | 63 +++ .../datatarget/datatarget-response.model.ts | 2 + .../datatarget-table.component.html | 2 +- .../datatarget-table.component.ts | 3 +- .../datatarget-types-service.service.spec.ts | 16 + .../datatarget-types-service.service.ts | 83 ++++ .../datatarget/datatarget.model.ts | 12 + .../datatarget/datatarget.module.ts | 25 +- .../datatarget/datatarget.service.ts | 2 + .../fiware-detail.component.html | 76 ++++ .../fiware-detail.component.scss | 0 .../fiware-detail.component.spec.ts | 28 ++ .../fiware-detail/fiware-detail.component.ts | 99 ++++ .../fiware-edit/fiware-edit.component.html | 167 +++++++ .../fiware-edit/fiware-edit.component.scss | 4 + .../fiware-edit/fiware-edit.component.spec.ts | 28 ++ .../fiware-edit/fiware-edit.component.ts | 337 ++++++++++++++ .../httppush-detail.component.html | 74 +++ .../httppush-detail.component.scss | 3 + .../httppush-detail.component.spec.ts | 28 ++ .../httppush-detail.component.ts | 99 ++++ .../httppush-edit.component.html | 139 ++++++ .../httppush-edit.component.scss | 0 .../httppush-edit.component.spec.ts | 28 ++ .../httppush-edit/httppush-edit.component.ts | 398 +++++++++++++++++ .../snack-bar/snack-bar.component.html | 9 + .../snack-bar/snack-bar.component.scss | 21 + .../snack-bar/snack-bar.component.ts | 18 + src/app/shared/enums/datatarget-type.ts | 3 +- src/app/shared/services/snack.service.ts | 26 ++ src/assets/i18n/da.json | 26 +- src/assets/images/logo_FIWARE.png | Bin 0 -> 1338 bytes src/assets/images/logo_opendatadk.svg | 1 + src/styles.scss | 35 ++ 50 files changed, 2103 insertions(+), 669 deletions(-) create mode 100644 src/app/applications/datatarget/datatarget-detail/datatarget-detail-type-selector.directive.spec.ts create mode 100644 src/app/applications/datatarget/datatarget-detail/datatarget-detail-type-selector.directive.ts create mode 100644 src/app/applications/datatarget/datatarget-detail/datatarget-detail.ts create mode 100644 src/app/applications/datatarget/datatarget-edit/datatarget-edit-type-selector.directive.spec.ts create mode 100644 src/app/applications/datatarget/datatarget-edit/datatarget-edit-type-selector.directive.ts create mode 100644 src/app/applications/datatarget/datatarget-edit/datatarget-edit.ts create mode 100644 src/app/applications/datatarget/datatarget-new/datatarget-new.component.html create mode 100644 src/app/applications/datatarget/datatarget-new/datatarget-new.component.scss create mode 100644 src/app/applications/datatarget/datatarget-new/datatarget-new.component.spec.ts create mode 100644 src/app/applications/datatarget/datatarget-new/datatarget-new.component.ts create mode 100644 src/app/applications/datatarget/datatarget-types-service.service.spec.ts create mode 100644 src/app/applications/datatarget/datatarget-types-service.service.ts create mode 100644 src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.html create mode 100644 src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.scss create mode 100644 src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.spec.ts create mode 100644 src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.ts create mode 100644 src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.html create mode 100644 src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.scss create mode 100644 src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.spec.ts create mode 100644 src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.ts create mode 100644 src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.html create mode 100644 src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.scss create mode 100644 src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.spec.ts create mode 100644 src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.ts create mode 100644 src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.html create mode 100644 src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.scss create mode 100644 src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.spec.ts create mode 100644 src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.ts create mode 100644 src/app/shared/components/snack-bar/snack-bar.component.html create mode 100644 src/app/shared/components/snack-bar/snack-bar.component.scss create mode 100644 src/app/shared/components/snack-bar/snack-bar.component.ts create mode 100644 src/app/shared/services/snack.service.ts create mode 100644 src/assets/images/logo_FIWARE.png create mode 100644 src/assets/images/logo_opendatadk.svg diff --git a/src/app/app.module.ts b/src/app/app.module.ts index aab4ebc9..82d3163a 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -23,6 +23,7 @@ import { MonacoEditorModule } from 'ngx-monaco-editor'; import { MatInputModule } from '@angular/material/input'; import { MatPaginatorIntl } from '@angular/material/paginator'; import { MatPaginatorIntlDa } from '@shared/helpers/mat-paginator-intl-da'; +import { MatTooltipModule } from '@angular/material/tooltip'; export function HttpLoaderFactory(http: HttpClient) { return new TranslateHttpLoader(http, './assets/i18n/', '.json'); @@ -62,6 +63,7 @@ export function tokenGetter() { SearchModule, HttpClientModule, MatInputModule, + MatTooltipModule, JwtModule.forRoot({ config: { tokenGetter diff --git a/src/app/applications/applications-routing.module.ts b/src/app/applications/applications-routing.module.ts index f563dfab..88434c0a 100644 --- a/src/app/applications/applications-routing.module.ts +++ b/src/app/applications/applications-routing.module.ts @@ -10,6 +10,7 @@ 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 { DatatargetNewComponent } from './datatarget/datatarget-new/datatarget-new.component'; const applicationRoutes: Routes = [ @@ -31,9 +32,10 @@ const applicationRoutes: Routes = [ path: 'datatarget-list/:name', children: [ { path: '', component: DatatargetListComponent }, + { path: 'datatarget-new', component: DatatargetNewComponent }, { path: 'datatarget-edit', component: DatatargetEditComponent }, { path: 'datatarget-edit/:datatargetId', component: DatatargetEditComponent }, - { path: 'datatarget/:datatargetId', component: DatatargetDetailComponent } + { path: 'datatarget/:datatargetId', component: DatatargetDetailComponent } ] }, @@ -41,7 +43,7 @@ const applicationRoutes: Routes = [ ], }, - ], + ], }, ]; diff --git a/src/app/applications/datatarget/datatarget-detail/datatarget-detail-type-selector.directive.spec.ts b/src/app/applications/datatarget/datatarget-detail/datatarget-detail-type-selector.directive.spec.ts new file mode 100644 index 00000000..a5b47f5c --- /dev/null +++ b/src/app/applications/datatarget/datatarget-detail/datatarget-detail-type-selector.directive.spec.ts @@ -0,0 +1,11 @@ +/* tslint:disable:no-unused-variable */ + +import { TestBed, async } from '@angular/core/testing'; +import { DatatargetDetailTypeSelectorDirective } from './datatarget-detail-type-selector.directive'; + +describe('Directive: DatatargetDetailTypeSelector', () => { + it('should create an instance', () => { + //const directive = new DatatargetDetailTypeSelectorDirective(); + //expect(directive).toBeTruthy(); + }); +}); diff --git a/src/app/applications/datatarget/datatarget-detail/datatarget-detail-type-selector.directive.ts b/src/app/applications/datatarget/datatarget-detail/datatarget-detail-type-selector.directive.ts new file mode 100644 index 00000000..84a3f73a --- /dev/null +++ b/src/app/applications/datatarget/datatarget-detail/datatarget-detail-type-selector.directive.ts @@ -0,0 +1,9 @@ +import { Directive, ViewContainerRef } from '@angular/core'; + +@Directive({ + selector: '[detail-component]' +}) +export class DatatargetDetailTypeSelectorDirective { + + constructor(public viewContainerRef: ViewContainerRef) { } +} diff --git a/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.html b/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.html index cc9829db..1c0c268c 100644 --- a/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.html +++ b/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.html @@ -1,74 +1,3 @@ -
- -
-
-
-
-

{{ 'DATATARGET.DETAILS' | translate }}

- - -

{{ 'DATATARGET.URL' | translate }}{{datatarget.url}}

-

{{ 'DATATARGET.TIMEOUT' | translate }}{{datatarget.timeout}}

-

{{ 'DATATARGET.TYPE' | translate }}{{datatarget.type | translate}}

- -

{{ 'DATATARGET.AUTHORIZATIONHEADER' | translate }}

-
{{datatarget.authorizationHeader}}
- -

{{ 'DATATARGET.NO-AUTHORIZATIONHEADER' | translate }}

-
- -
-
-
-
-

{{ 'DATATARGET.OPENDATA-DK' | translate }}

-
- -
- -

{{ 'DATATARGET.NO-OPENDATA-DK' | translate }}

-
-
-
-
- -
-
-
-
-

{{ 'DATATARGET.RELATIONS' | translate }}

-
-

{{'DATATARGET.NO-RELATIONS' | translate}}

-
-
-
-
-
-

{{'DATATARGET.PAYLOADEDECODER' | translate}} - {{relation.payloadDecoder.name}} - - {{ 'DATATARGET.NO-PAYLOADDECODER' | translate}} -

-
-
- -
-
-

{{'DATATARGET.IOTDEVICE' | translate}} - - , {{device.name}} - -

-
- -
-
-
-
-
-
-
-
+
+
\ No newline at end of file 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..46f12408 100644 --- a/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.ts +++ b/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.ts @@ -1,17 +1,12 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; -import { Subscription } from 'rxjs'; +import { AfterViewInit, Component, ComponentFactoryResolver, OnDestroy, OnInit, QueryList, Type, ViewChild, ViewChildren} from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { TranslateService } from '@ngx-translate/core'; -import { PayloadDeviceDatatargetGetByDataTarget } from '@app/payload-decoder/payload-device-data.model'; -import { PayloadDeviceDatatargetService } from '@app/payload-decoder/payload-device-datatarget.service'; -import { BackButton } from '@shared/models/back-button.model'; -import { DatatargetService } from '../datatarget.service'; -import { Location } from '@angular/common'; -import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service'; +import { DataTargetType } from '@shared/enums/datatarget-type'; +import { DatatargetTypesServiceService } from '../datatarget-types-service.service'; import { Datatarget } from '../datatarget.model'; -import { DropdownButton } from '@shared/models/dropdown-button.model'; -import { faArrowsAltH } from '@fortawesome/free-solid-svg-icons'; -import { IotDevice } from '@applications/iot-devices/iot-device.model'; +import { DatatargetService } from '../datatarget.service'; +import { HttppushDetailComponent } from '../httppush/httppush-detail/httppush-detail.component'; +import { DatatargetDetail } from './datatarget-detail'; +import { DatatargetDetailTypeSelectorDirective } from './datatarget-detail-type-selector.directive'; @Component({ selector: 'app-datatarget-detail', @@ -20,79 +15,50 @@ import { IotDevice } from '@applications/iot-devices/iot-device.model'; }) export class DatatargetDetailComponent implements OnInit, OnDestroy { - public datatargetSubscription: Subscription; - public datatarget: Datatarget; - public backButton: BackButton = { label: '', routerLink: '/datatarget-list' }; - public dataTargetRelations: PayloadDeviceDatatargetGetByDataTarget[]; - private deleteDialogSubscription: Subscription; - public dropdownButton: DropdownButton; - arrowsAltH = faArrowsAltH; - private applicationName: string; + @ViewChild(DatatargetDetailTypeSelectorDirective, {static: true}) adHost!: DatatargetDetailTypeSelectorDirective; - constructor( - private route: ActivatedRoute, - private deleteDialogService: DeleteDialogService, - private location: Location, - private datatargetRelationServicer: PayloadDeviceDatatargetService, + private applicationName: string; + public datatarget: Datatarget; + private datatargetType: DataTargetType; + + constructor(private componentFactoryResolver: ComponentFactoryResolver, private datatargetService: DatatargetService, - public translate: TranslateService) { } + private route: ActivatedRoute, + private datatargetTypesService: DatatargetTypesServiceService + ) { } + - ngOnInit(): void { - const id: number = +this.route.snapshot.paramMap.get('datatargetId'); - this.applicationName = this.route.snapshot.paramMap.get('name'); - if (id) { - this.getDatatarget(id); - this.getDatatargetRelations(id); - this.dropdownButton = { - label: '', - editRouterLink: '../../datatarget-edit/' + id, - isErasable: true, - } - } - this.translate.get(['NAV.MY-DATATARGET', 'DATATARGET.SHOW-OPTIONS']) - .subscribe(translations => { - this.backButton.label = translations['NAV.MY-DATATARGET']; - this.dropdownButton.label = translations['DATATARGET.SHOW-OPTIONS'] - }); - } + loadComponent(componentType: Type) { + + const viewContainerRef = this.adHost.viewContainerRef; + + viewContainerRef.clear(); + const factory = this.componentFactoryResolver.resolveComponentFactory(componentType); + const componentRef = viewContainerRef.createComponent(factory) + - getDatatarget(id: number) { - this.datatargetService.get(id) - .subscribe((dataTarget: Datatarget) => { - this.datatarget = dataTarget; - this.setBackButton(this.datatarget.applicationId); - }); } - private setBackButton(applicationId: number) { - this.backButton.routerLink = ['applications', applicationId.toString(), 'datatarget-list', this.applicationName ] - } + ngOnInit(): void { - onDeleteDatatarget() { - this.deleteDialogSubscription = this.deleteDialogService.showSimpleDialog().subscribe( - (response) => { - if (response) { - this.datatargetService.delete(this.datatarget.id).subscribe((response) => { - }); - this.location.back(); - } else { - console.log(response); - } - } - ); - } + this.applicationName = this.route.snapshot.paramMap.get('name'); + const id: number = +this.route.snapshot.paramMap.get('datatargetId'); + + this.datatargetService.get(id) + .subscribe((dataTarget: Datatarget) => { + this.datatarget = dataTarget; + this.datatargetType = dataTarget.type; + + const component = this.datatargetTypesService.getDetailComponent(this.datatargetType); - getDatatargetRelations(id: number) { - this.datatargetRelationServicer.getByDataTarget(id) - .subscribe((response) => { - this.dataTargetRelations = response.data; - }); - } + this.loadComponent(component); + + }); - ngOnDestroy(): void { - if (this.deleteDialogSubscription) { - this.deleteDialogSubscription.unsubscribe(); - } + } + ngOnDestroy() { + + } } diff --git a/src/app/applications/datatarget/datatarget-detail/datatarget-detail.ts b/src/app/applications/datatarget/datatarget-detail/datatarget-detail.ts new file mode 100644 index 00000000..4d5f7bfb --- /dev/null +++ b/src/app/applications/datatarget/datatarget-detail/datatarget-detail.ts @@ -0,0 +1,2 @@ +export interface DatatargetDetail { +} diff --git a/src/app/applications/datatarget/datatarget-edit/datatarget-edit-type-selector.directive.spec.ts b/src/app/applications/datatarget/datatarget-edit/datatarget-edit-type-selector.directive.spec.ts new file mode 100644 index 00000000..a18997fa --- /dev/null +++ b/src/app/applications/datatarget/datatarget-edit/datatarget-edit-type-selector.directive.spec.ts @@ -0,0 +1,11 @@ +/* tslint:disable:no-unused-variable */ + +import { TestBed, async } from '@angular/core/testing'; +import { DatatargetEditTypeSelectorDirective } from './datatarget-edit-type-selector.directive'; + +describe('Directive: DatatargetEditTypeSelector', () => { + it('should create an instance', () => { + //const directive = new DatatargetEditTypeSelectorDirective(); + //expect(directive).toBeTruthy(); + }); +}); diff --git a/src/app/applications/datatarget/datatarget-edit/datatarget-edit-type-selector.directive.ts b/src/app/applications/datatarget/datatarget-edit/datatarget-edit-type-selector.directive.ts new file mode 100644 index 00000000..25511bc7 --- /dev/null +++ b/src/app/applications/datatarget/datatarget-edit/datatarget-edit-type-selector.directive.ts @@ -0,0 +1,10 @@ +import { Directive, ViewContainerRef } from '@angular/core'; + +@Directive({ + selector: '[edit-component]' +}) +export class DatatargetEditTypeSelectorDirective { + + constructor(public viewContainerRef: ViewContainerRef) { } + +} \ No newline at end of file diff --git a/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.html b/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.html index 4d4df069..bb9f14e1 100644 --- a/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.html +++ b/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.html @@ -1,139 +1,3 @@ - - - -
-
-
    -
  • - {{error | translate}} -
  • -
-
- - {{'DATATARGET.ADD-TO-OPENDATADK' | translate}} - -
-
- * - -
-
- -
-
- * - -
-
-
-
- * - -
-
-
-
- - -
-
- -
-
-
-
{{'QUESTION.DATATARGET.RELATIONS' | translate}}
-
-
- {{'QUESTION.ADD-RELATIONS' | translate}} - - - - - - - - - -
-
- - {{'QUESTION.DATATARGET.SELECT-DEVICES' | translate}} - - - - - - {{device.name}} - - -
-
-
- - {{'QUESTION.DATATARGET.SELECT-PAYLOADDECODER' | translate}} - - - {{'QUESTION.DATATARGET.NO-PAYLOAD-DECODER-SELECTED' | translate}} - - - {{payloadDecoder.name}} - - - -
-
- -
- -

{{'DATATARGET.DELETE' | translate}}

-
-
-
-
-
-
- - -
-
\ No newline at end of file +
+ +
\ No newline at end of file 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..50e92747 100644 --- a/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.ts +++ b/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.ts @@ -1,26 +1,11 @@ -import { Component, OnInit, Input, OnDestroy } from '@angular/core'; -import { TranslateService } from '@ngx-translate/core'; -import { ActivatedRoute, Router } from '@angular/router'; +import { AfterViewInit, Component, ComponentFactoryResolver, OnDestroy, OnInit, QueryList, Type, ViewChild, ViewChildren} from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { DataTargetType } from '@shared/enums/datatarget-type'; +import { DatatargetTypesServiceService } from '../datatarget-types-service.service'; import { Datatarget } from '../datatarget.model'; -import { Observable, Subscription } from 'rxjs'; -import { Application } from '@applications/application.model'; -import { IotDevice } from '@applications/iot-devices/iot-device.model'; -import { faTimesCircle } from '@fortawesome/free-solid-svg-icons'; -import { PayloadDeviceDatatarget, PayloadDeviceDatatargetGetByDataTargetResponse } from '@payload-decoder/payload-device-data.model'; 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 { MatDialog } from '@angular/material/dialog'; -import { HttpErrorResponse } from '@angular/common/http'; -import { PayloadDecoderMappedResponse } from '@payload-decoder/payload-decoder.model'; -import { DeleteDialogComponent } from '@shared/components/delete-dialog/delete-dialog.component'; -import { ErrorMessageService } from '@shared/error-message.service'; -import { OpendatadkDialogService } from '@shared/components/opendatadk-dialog/opendatadk-dialog.service'; -import { OpendatadkService } from '@shared/services/opendatadk.service'; -import { ScrollToTopService } from '@shared/services/scroll-to-top.service'; -import { OpenDataDkDataset } from '../opendatadk/opendatadk-dataset.model'; +import { DatatargetEdit } from './datatarget-edit'; +import { DatatargetEditTypeSelectorDirective } from './datatarget-edit-type-selector.directive'; @Component({ selector: 'app-datatarget-edit', @@ -28,363 +13,61 @@ import { OpenDataDkDataset } from '../opendatadk/opendatadk-dataset.model'; styleUrls: ['./datatarget-edit.component.scss'] }) export class DatatargetEditComponent implements OnInit, OnDestroy { - public multiPage = false; - public title = ''; - public sectionTitle = ''; - public backButtonTitle = ''; - @Input() submitButton: string; - public datatarget: Datatarget = new Datatarget(); - faTimesCircle = faTimesCircle; - public datatargetSubscription: Subscription; - public relationSubscription: Subscription; - public applicationSubscription: Subscription; - public payloadDecoderSubscription: Subscription; - public errorMessages: any; - public errorFields: string[]; - public formFailedSubmit = false; - public datatargetid: number; - private applicationId: number; - private applicationNane: string; - public application: Application; - public devices: IotDevice[]; - public payloadDecoders = []; - private counter: number; - private dataSetExcists = false; - private isMailDialogAlreadyShown = false; - payloadDeviceDatatarget: PayloadDeviceDatatarget[]; - newDynamic: any = {}; - - constructor( - public translate: TranslateService, - private route: ActivatedRoute, - private router: Router, - private datatargetService: DatatargetService, - private applicationService: ApplicationService, - private payloadDecoderService: PayloadDecoderService, - private payloadDeviceDataTargetService: PayloadDeviceDatatargetService, - private saveSnackService: SaveSnackService, - private dialog: MatDialog, - private errorMessageService: ErrorMessageService, - private opendatadkService: OpendatadkService, - private opendatadkDialogService: OpendatadkDialogService, - private scrollToTopService: ScrollToTopService, - ) { - translate.use('da'); - } - - ngOnInit() { - this.translate - .get([ - 'FORM.CREATE-NEW-DATATARGET', - 'FORM.EDIT-DATATARGET', - 'DATATARGET.SAVE', - 'NAV.DATATARGET', - ]) - .subscribe((translations) => { - const datatargetid = +this.route.snapshot.paramMap.get('datatargetId'); - if (datatargetid !== 0) { - this.title = translations['FORM.EDIT-DATATARGET']; - } else { - this.title = translations['FORM.CREATE-NEW-DATATARGET']; - } - this.submitButton = translations['DATATARGET.SAVE']; - this.backButtonTitle = translations['NAV.DATATARGET']; - }); - - this.datatargetid = +this.route.snapshot.paramMap.get('datatargetId'); - this.applicationId = +this.route.snapshot.paramMap.get('id'); - this.applicationNane = this.route.snapshot.paramMap.get('name'); - if (this.datatargetid !== 0) { - this.getDatatarget(this.datatargetid); - this.getPayloadDeviceDatatarget(this.datatargetid); - } - if (this.applicationId !== 0) { - this.getDevices(); - } - this.getPayloadDecoders(); - this.setDataSetExcists(); - } - - addRow() { - if (!this.payloadDeviceDatatarget) { - this.payloadDeviceDatatarget = []; - } - this.payloadDeviceDatatarget.push({ id: null, iotDeviceIds: [], payloadDecoderId: null, dataTargetId: this.datatargetid }); - } - - private deleteRow(index) { - if (this.payloadDeviceDatatarget.length === 0) { - } else if (this.payloadDeviceDatatarget[index]?.id === null) { - this.payloadDeviceDatatarget.splice(index, 1); - } else { - this.payloadDeviceDataTargetService.delete(this.payloadDeviceDatatarget[index].id) - .subscribe((response) => { - this.payloadDeviceDatatarget.splice(index, 1); - }); - } - } - - openDeleteDialog(index) { - const dialog = this.dialog.open(DeleteDialogComponent, { - data: { - showAccept: true, - showCancel: true, - message: 'Er du sikker på at du vil slette?' - } - }); - - dialog.afterClosed().subscribe((result) => { - if (result === true) { - this.deleteRow(index); - } - }); - } - - onSubmit(): void { - this.counter = 0; - if (this.datatargetid) { - this.updateDatatarget(); - this.addPayloadDeviceDatatarget(); - } else { - this.createDatatarget(); - } - } - - public compare(o1: any, o2: any): boolean { - return o1 === o2; - } - - updateDatatarget() { - this.resetErrors(); - this.counter = 1 + (this.payloadDeviceDatatarget?.length ? this.payloadDeviceDatatarget?.length : 0); - this.datatargetService.update(this.datatarget) - .subscribe( - (response: Datatarget) => { - this.datatarget = response; - if (this.datatarget.openDataDkDataset != null) { - this.datatarget.openDataDkDataset.acceptTerms = true; - } - this.shouldShowMailDialog().subscribe( - (response) => { - this.countToRedirect(); - } - ); - }, - (error: HttpErrorResponse) => { - this.checkDataTargetModelOpendatadkdatasaet(); - this.handleError(error); - this.formFailedSubmit = true; - } - ); - } - - addPayloadDeviceDatatarget() { - this.payloadDeviceDatatarget.map( - pdd => { - if (pdd.payloadDecoderId === 0) { - pdd.payloadDecoderId = null; - } - } - ); - this.payloadDeviceDatatarget.forEach((relation) => { - if (relation.id) { - this.payloadDeviceDataTargetService.put(relation).subscribe( - (response) => { - this.countToRedirect(); - }, - (error) => { - this.handleError(error); - } - ); - } else { - this.payloadDeviceDataTargetService.post(relation).subscribe( - (res: any) => { - this.countToRedirect(); - }, - (error) => { - this.handleError(error); - } - ); - } - }); - } - - countToRedirect() { - this.counter -= 1; - if (this.counter <= 0 && !this.formFailedSubmit) { - this.showSavedSnack(); - this.routeToDatatargets(); - } - } - - getPayloadDeviceDatatarget(id: number) { - this.relationSubscription = this.payloadDeviceDataTargetService - .getByDataTarget(id) - .subscribe((response: PayloadDeviceDatatargetGetByDataTargetResponse) => { - this.mapToDatatargetDevicePayload(response); - }); - } - - createDatatarget() { - this.resetErrors(); - this.datatarget.applicationId = this.applicationId; - this.datatargetService.create(this.datatarget) - .subscribe((response: Datatarget) => { - this.datatargetid = response.id; - this.datatarget = response; - if (this.datatarget.openDataDkDataset != null) { - this.datatarget.openDataDkDataset.acceptTerms = true; - } - this.showSavedSnack(); - }, - (error: HttpErrorResponse) => { - this.checkDataTargetModelOpendatadkdatasaet(); - this.handleError(error); - this.formFailedSubmit = true; + @ViewChild(DatatargetEditTypeSelectorDirective, {static: true}) adHost!: DatatargetEditTypeSelectorDirective; + + private applicationName: string; + public datatarget: Datatarget; + private datatargetType: DataTargetType; + + constructor(private componentFactoryResolver: ComponentFactoryResolver, + private datatargetService: DatatargetService, + private route: ActivatedRoute, + private datatargetTypesService: DatatargetTypesServiceService + ) { } + + + loadComponent(componentType: Type) { + const viewContainerRef = this.adHost.viewContainerRef; + viewContainerRef.clear(); + const factory = this.componentFactoryResolver.resolveComponentFactory(componentType); + const componentRef = viewContainerRef.createComponent(factory) + } + + ngOnInit(): void { + + this.applicationName = this.route.snapshot.paramMap.get('name'); + const id: number = +this.route.snapshot.paramMap.get('datatargetId'); + + if (id > 0) { + this.datatargetService.get(id) + .subscribe((dataTarget: Datatarget) => { + this.datatarget = dataTarget; + this.datatargetType = dataTarget.type; + const component = this.datatargetTypesService.getEditComponent(this.datatargetType); + this.loadComponent(component); }); - - } - - private resetErrors() { - this.errorFields = []; - this.errorMessages = undefined; - this.formFailedSubmit = false; - } - - checkDataTargetModelOpendatadkdatasaet() { - if (!this.datatarget.openDataDkDataset) { - this.datatarget.openDataDkDataset = new OpenDataDkDataset(); - } - } - - getDevices(): void { - this.applicationSubscription = this.applicationService.getApplication(this.applicationId) - .subscribe((application: Application) => { - this.devices = application.iotDevices; - }); - } - - public selectAllDevices(index: number) { - this.payloadDeviceDatatarget[index].iotDeviceIds = this.devices.map(device => device.id); - } - - public deSelectAllDevices(index: number) { - this.payloadDeviceDatatarget[index].iotDeviceIds = []; - } - - getPayloadDecoders() { - this.payloadDecoderSubscription = this.payloadDecoderService.getMultiple(1000, 0, 'id', 'ASC') - .subscribe((response: PayloadDecoderMappedResponse) => { - this.payloadDecoders = response.data; - }); - } - - handleError(error: HttpErrorResponse) { - const errors = this.errorMessageService.handleErrorMessageWithFields(error); - this.errorFields = errors.errorFields; - this.errorMessages = errors.errorMessages; - this.scrollToTopService.scrollToTop(); - } - - routeToDatatargets(): void { - this.router.navigate(['applications',this.applicationId.toString(),'datatarget-list', this.applicationNane]) - } - - onCoordinateKey(event: any) { - if (event.target.value.length > event.target.maxLength) { - event.target.value = event.target.value.slice( - 0, - event.target.maxLength - ); - } - } - - getDatatarget(id: number) { - this.datatargetSubscription = this.datatargetService - .get(id) - .subscribe((response: Datatarget) => { - this.datatarget = response; - }); - } - - showSavedSnack() { - this.saveSnackService.showSavedSnack(); - } - - private setDataSetExcists() { - this.opendatadkService.get().subscribe( - (response) => { - this.dataSetExcists = response.dataset.length === 0 ? false : true; } - ); - } - - private shouldShowMailDialog(): Observable { - return new Observable( - (observer) => { - if (!this.dataSetExcists && this.datatarget.setToOpendataDk && !this.isMailDialogAlreadyShown) { - this.isMailDialogAlreadyShown = true; - this.opendatadkDialogService.showDialog().subscribe( - response => { - if (response) { - this.showMailClient(); - } - observer.next(response); - } - ); - } else { - observer.next(true); + else + { + var datatargetTypeParam = this.route.snapshot.paramMap.get('datatargetType'); + this.datatargetType = this.enumFromStringValue(DataTargetType, datatargetTypeParam); + if (this.datatargetType) { + const component = this.datatargetTypesService.getEditComponent(this.datatargetType); + this.loadComponent(component); } } - ) - } - private showMailClient() { - if (!this.datatarget.openDataDkDataset.url) { - this.datatarget.openDataDkDataset.url = this.datatargetService.getOpendataSharingApiUrl() - } - window.location.href = 'mailto:FG2V@kk.dk?subject=Oprettelse%20af%20datas%C3%A6t%20i%20OpenDataDK&body=K%C3%A6re%20Frans%0D%0A%0D%0AHermed%20fremsendes%20linket%20til%20DCAT%20kataloget%20%2C%20du%20bedes%20registrere%20p%C3%A5%20Open%20Data%20DK%20platformen.%0D%0A%0D%0ALink%3A ' + this.datatarget.openDataDkDataset.url; + } - disableSaveButton(): boolean { - let disable = true; - if (!this.datatarget.setToOpendataDk) { - disable = false; - } else if (this.datatarget.openDataDkDataset?.acceptTerms) { - disable = false; - } else { - disable = true; - } - return disable; + enumFromStringValue (enm: { [s: string]: T}, value: string): T | undefined { + return (Object.values(enm) as unknown as string[]).includes(value) + ? value as unknown as T + : undefined; } - ngOnDestroy(): void { - if (this.relationSubscription) { - this.relationSubscription.unsubscribe(); - } - if (this.applicationSubscription) { - this.applicationSubscription.unsubscribe(); - } - if (this.datatargetSubscription) { - this.datatargetSubscription.unsubscribe(); - } - if (this.payloadDecoderSubscription) { - this.payloadDecoderSubscription.unsubscribe(); + ngOnDestroy() { + } - } - - private mapToDatatargetDevicePayload(dto: PayloadDeviceDatatargetGetByDataTargetResponse) { - this.payloadDeviceDatatarget = []; - dto.data.forEach( - (element) => { - this.payloadDeviceDatatarget.push({ - id: element.id, - iotDeviceIds: element.iotDevices.map((x) => x.id), - payloadDecoderId: element.payloadDecoder?.id === undefined ? 0 : element.payloadDecoder?.id, - dataTargetId: element.dataTarget.id - }); - } - ); - } } diff --git a/src/app/applications/datatarget/datatarget-edit/datatarget-edit.ts b/src/app/applications/datatarget/datatarget-edit/datatarget-edit.ts new file mode 100644 index 00000000..16def301 --- /dev/null +++ b/src/app/applications/datatarget/datatarget-edit/datatarget-edit.ts @@ -0,0 +1,2 @@ +export interface DatatargetEdit { +} diff --git a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.html b/src/app/applications/datatarget/datatarget-list/datatarget-list.component.html index bad1cea6..06414964 100644 --- a/src/app/applications/datatarget/datatarget-list/datatarget-list.component.html +++ b/src/app/applications/datatarget/datatarget-list/datatarget-list.component.html @@ -1,5 +1,5 @@
diff --git a/src/app/applications/datatarget/datatarget-new/datatarget-new.component.html b/src/app/applications/datatarget/datatarget-new/datatarget-new.component.html new file mode 100644 index 00000000..6d654898 --- /dev/null +++ b/src/app/applications/datatarget/datatarget-new/datatarget-new.component.html @@ -0,0 +1,34 @@ + + + +
+
+ + +
+
+ + + +
+ {{dataTargetType.name}} +
+ + {{dataTargetType.provider}} + +
+ + {{ dataTargetType.description }} + + + + + + + + +
+
+
diff --git a/src/app/applications/datatarget/datatarget-new/datatarget-new.component.scss b/src/app/applications/datatarget/datatarget-new/datatarget-new.component.scss new file mode 100644 index 00000000..71485bcb --- /dev/null +++ b/src/app/applications/datatarget/datatarget-new/datatarget-new.component.scss @@ -0,0 +1,44 @@ +.data-component { + display: flex; + flex-direction: row; + flex-wrap: wrap; + margin-left: 10px; +} + +.mat-card{ + display:flex; + flex-direction: column; + flex-wrap: wrap; + width: 300px; + min-width: 300px; + max-width: 400px; + height: 320px; + margin: 10px; +} + +.mat-card-header { + flex-shrink: 1; + +} + +.mat-card-content{ + flex-grow: 1; + overflow: auto; + margin-left: 10px; +} + + +mat-card img{ + object-fit: contain; /*this makes the image in src fit to the size specified below*/ + object-position: left; + width: 50%; /* Here you can use wherever you want to specify the width and also the height of the */ + height: 20px; + margin-left: 3px; + margin-top: 3px; + margin-bottom: 3px; +} + +.img-placeholder{ + height: 26px; + clear: both; +} diff --git a/src/app/applications/datatarget/datatarget-new/datatarget-new.component.spec.ts b/src/app/applications/datatarget/datatarget-new/datatarget-new.component.spec.ts new file mode 100644 index 00000000..4f1f6508 --- /dev/null +++ b/src/app/applications/datatarget/datatarget-new/datatarget-new.component.spec.ts @@ -0,0 +1,28 @@ +/* tslint:disable:no-unused-variable */ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { DatatargetNewComponent } from './datatarget-new.component'; + +describe('DatatargetNewComponent', () => { + let component: DatatargetNewComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ DatatargetNewComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DatatargetNewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/applications/datatarget/datatarget-new/datatarget-new.component.ts b/src/app/applications/datatarget/datatarget-new/datatarget-new.component.ts new file mode 100644 index 00000000..93619d0b --- /dev/null +++ b/src/app/applications/datatarget/datatarget-new/datatarget-new.component.ts @@ -0,0 +1,63 @@ +import { Component, OnInit } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { DatatargetTypeDescriptor } from '../datatarget.model'; +import { DatatargetTypesServiceService } from '../datatarget-types-service.service'; + + + +@Component({ + selector: 'app-datatarget-new', + templateUrl: './datatarget-new.component.html', + styleUrls: ['./datatarget-new.component.scss'] +}) +export class DatatargetNewComponent implements OnInit { + + public title = ''; + public sectionTitle = ''; + public backButtonTitle = ''; + public submitButton = ''; + public avaiableDataTargetTypes : DatatargetTypeDescriptor[]; + + constructor( + public translate: TranslateService, + private route: ActivatedRoute, + private router: Router, + private dataTargetTypesService: DatatargetTypesServiceService + ) { + translate.use('da'); + } + + ngOnInit() { + + this.translate + .get([ + 'FORM.CREATE-NEW-DATATARGET', + 'FORM.EDIT-DATATARGET', + 'DATATARGET.SAVE', + 'NAV.DATATARGET', + ]) + .subscribe((translations) => { + const datatargetid = +this.route.snapshot.paramMap.get('datatargetId'); + if (datatargetid !== 0) { + this.title = translations['FORM.EDIT-DATATARGET']; + } else { + this.title = translations['FORM.CREATE-NEW-DATATARGET']; + } + this.submitButton = translations['DATATARGET.SAVE']; + this.backButtonTitle = translations['NAV.DATATARGET']; + }); + + this.avaiableDataTargetTypes = this.dataTargetTypesService.getAvailableDataTargetTypes(); + + } + + public createNewOf(typeDescriptor: DatatargetTypeDescriptor) + { + this.router.navigate(['../datatarget-edit', {datatargetType: typeDescriptor.type}], {relativeTo:this. route}); + } + public showReadMe(typeDescriptor: DatatargetTypeDescriptor) + { + window.open(typeDescriptor.readMoreUrl, "_blank"); + } +} diff --git a/src/app/applications/datatarget/datatarget-response.model.ts b/src/app/applications/datatarget/datatarget-response.model.ts index 1d6b809d..fcb40286 100644 --- a/src/app/applications/datatarget/datatarget-response.model.ts +++ b/src/app/applications/datatarget/datatarget-response.model.ts @@ -9,6 +9,8 @@ export class DatatargetResponse { timeout: number; type: DataTargetType; url: string; + tenant: string; + context: string; authorizationHeader: string; openDataDkDataset: OpenDataDkDataset; createdAt: string; 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..cc6acbef 100644 --- a/src/app/applications/datatarget/datatarget-table/datatarget-table.component.html +++ b/src/app/applications/datatarget/datatarget-table/datatarget-table.component.html @@ -21,7 +21,7 @@ {{ 'DATATARGET-TABLE.TYPE' | translate }} - {{element.type | translate}} + {{'DATATARGET.' + element.type | translate}} 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..4db7b3ce 100644 --- a/src/app/applications/datatarget/datatarget-table/datatarget-table.component.ts +++ b/src/app/applications/datatarget/datatarget-table/datatarget-table.component.ts @@ -46,8 +46,7 @@ export class DatatargetTableComponent implements OnInit, AfterViewInit, OnDestro } ngOnInit(): void { - this.applicationId = +Number(this.route.parent.parent.snapshot.paramMap.get('id')); - console.log(this.applicationId); + this.applicationId = +Number(this.route.parent.parent.snapshot.paramMap.get('id')); this.getDatatarget(); this.canEdit = this.meService.canWriteInTargetOrganization() } diff --git a/src/app/applications/datatarget/datatarget-types-service.service.spec.ts b/src/app/applications/datatarget/datatarget-types-service.service.spec.ts new file mode 100644 index 00000000..1a93045b --- /dev/null +++ b/src/app/applications/datatarget/datatarget-types-service.service.spec.ts @@ -0,0 +1,16 @@ +/* tslint:disable:no-unused-variable */ + +import { TestBed, async, inject } from '@angular/core/testing'; +import { DatatargetTypesServiceService } from './datatarget-types-service.service'; + +describe('Service: DatatargetTypesService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [DatatargetTypesServiceService] + }); + }); + + it('should ...', inject([DatatargetTypesServiceService], (service: DatatargetTypesServiceService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/src/app/applications/datatarget/datatarget-types-service.service.ts b/src/app/applications/datatarget/datatarget-types-service.service.ts new file mode 100644 index 00000000..80644ace --- /dev/null +++ b/src/app/applications/datatarget/datatarget-types-service.service.ts @@ -0,0 +1,83 @@ +import { Injectable, Type } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { DataTargetType } from '@shared/enums/datatarget-type'; +import { DatatargetTypeDescriptor } from './datatarget.model'; +import { FiwareDetailComponent } from './fiware/fiware-detail/fiware-detail.component'; +import { FiwareEditComponent } from './fiware/fiware-edit/fiware-edit.component'; +import { HttppushDetailComponent } from './httppush/httppush-detail/httppush-detail.component'; +import { HttppushEditComponent } from './httppush/httppush-edit/httppush-edit.component'; + +@Injectable({ + providedIn: 'root' +}) +export class DatatargetTypesServiceService { + +constructor() { } + + getAvailableDataTargetTypes() : DatatargetTypeDescriptor[] + { + return [ + { name: "Generisk HTTP Push", + type: DataTargetType.HTTPPUSH, + icon: null, + description: "Send data med HTTP POST requests til et HTTP URL endpoint", + readMoreUrl: "", + provider: "OS2" + + }, + { name: "Open Data DK", + type: DataTargetType.OPENDATADK, + icon: "/assets/images/logo_opendatadk.svg", + description: "Offentliggør datasæt i Open Data DK's åbne dataportal.", + readMoreUrl: "https://www.opendata.dk/", + provider: "OS2" + + }, + { name: "FIWARE connection", + type: DataTargetType.FIWARE, + icon: "/assets/images/logo_FIWARE.png", + description: "En integration til FIWARE Context Broker" , + readMoreUrl: "https://www.kmd.dk", + provider: "KMD A/S" + } + ] + } + + getDetailComponent(dataTargetType: DataTargetType): Type + { + if (dataTargetType == DataTargetType.HTTPPUSH) + { + return HttppushDetailComponent; + } + + if (dataTargetType == DataTargetType.OPENDATADK) + { + return HttppushDetailComponent; + } + + if (dataTargetType == DataTargetType.FIWARE) + { + return FiwareDetailComponent; + } + } + + getEditComponent(dataTargetType: DataTargetType): Type + { + if (dataTargetType == DataTargetType.HTTPPUSH) + { + return HttppushEditComponent; + } + + if (dataTargetType == DataTargetType.OPENDATADK) + { + return HttppushEditComponent; + } + + if (dataTargetType == DataTargetType.FIWARE) + { + return FiwareEditComponent; + } + } + +} + diff --git a/src/app/applications/datatarget/datatarget.model.ts b/src/app/applications/datatarget/datatarget.model.ts index 03fba64b..12e846c9 100644 --- a/src/app/applications/datatarget/datatarget.model.ts +++ b/src/app/applications/datatarget/datatarget.model.ts @@ -7,6 +7,8 @@ export class Datatarget { applicationId: number; type: DataTargetType = DataTargetType.HTTPPUSH; url: string; + tenant: string; + context: string; //default 30 sec timeout: number = 30000; authorizationHeader: string; @@ -24,4 +26,14 @@ export class DatatargetData { data: Datatarget[]; ok?: boolean; count?: number; +} + +export class DatatargetTypeDescriptor +{ + name: string; + type: DataTargetType; + icon: string; + description: string; + readMoreUrl: string; + provider: string; } \ No newline at end of file diff --git a/src/app/applications/datatarget/datatarget.module.ts b/src/app/applications/datatarget/datatarget.module.ts index 58bd4078..cd997d7c 100644 --- a/src/app/applications/datatarget/datatarget.module.ts +++ b/src/app/applications/datatarget/datatarget.module.ts @@ -15,16 +15,30 @@ import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { SharedModule } from '@shared/shared.module'; import { PipesModule } from '@shared/pipes/pipes.module'; +import { DatatargetNewComponent } from './datatarget-new/datatarget-new.component'; +import { FiwareEditComponent } from './fiware/fiware-edit/fiware-edit.component'; +import { FiwareDetailComponent } from './fiware/fiware-detail/fiware-detail.component'; +import { HttppushDetailComponent } from './httppush/httppush-detail/httppush-detail.component'; +import { HttppushEditComponent } from './httppush/httppush-edit/httppush-edit.component'; +import { DatatargetDetailTypeSelectorDirective } from './datatarget-detail/datatarget-detail-type-selector.directive'; +import { DatatargetEditTypeSelectorDirective } from './datatarget-edit/datatarget-edit-type-selector.directive'; @NgModule({ - declarations: [ + declarations: [ DatatargetTableComponent, DatatargetListComponent, DatatargetEditComponent, + DatatargetNewComponent, DatatargetDetailComponent, + FiwareDetailComponent, + FiwareEditComponent, + HttppushDetailComponent, + HttppushEditComponent, OpendatadkComponent, OpendatadkEditComponent, - OpendatadkDetailComponent], + OpendatadkDetailComponent, + DatatargetDetailTypeSelectorDirective, + DatatargetEditTypeSelectorDirective], imports: [ CommonModule, RouterModule, @@ -41,7 +55,12 @@ import { PipesModule } from '@shared/pipes/pipes.module'; DatatargetTableComponent, DatatargetListComponent, DatatargetEditComponent, - DatatargetDetailComponent, + DatatargetNewComponent, + DatatargetDetailComponent, + FiwareDetailComponent, + FiwareEditComponent, + HttppushDetailComponent, + HttppushEditComponent, NGMaterialModule ] }) diff --git a/src/app/applications/datatarget/datatarget.service.ts b/src/app/applications/datatarget/datatarget.service.ts index 72abdb98..a34854c4 100644 --- a/src/app/applications/datatarget/datatarget.service.ts +++ b/src/app/applications/datatarget/datatarget.service.ts @@ -90,6 +90,8 @@ export class DatatargetService { timeout: dataTargetResponse.timeout, type: dataTargetResponse.type, url: dataTargetResponse.url, + tenant: dataTargetResponse.tenant, + context: dataTargetResponse.context, authorizationHeader: dataTargetResponse.authorizationHeader, applicationId: dataTargetResponse.application.id, setToOpendataDk: dataTargetResponse?.openDataDkDataset ? true : false, 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 new file mode 100644 index 00000000..8e895d9c --- /dev/null +++ b/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.html @@ -0,0 +1,76 @@ +
+ +
+
+
+
+

{{ 'DATATARGET.DETAILS' | translate }}

+ + +

Context Broker{{datatarget.url}}

+

{{ 'DATATARGET.TIMEOUT' | translate }}{{datatarget.timeout}}

+

{{ 'DATATARGET.TYPE' | translate }}{{'DATATARGET.' + datatarget.type | translate}}

+ + +

{{ 'DATATARGET.TENANT' | translate }}

+
{{datatarget.tenant}}
+ +

{{ 'DATATARGET.NO-TENANT' | translate }}

+
+ +

{{ 'DATATARGET.CONTEXT' | translate }}

+
{{datatarget.context}}
+ +

{{ 'DATATARGET.NO-CONTEXT' | translate }}

+
+ +

{{ 'DATATARGET.AUTHORIZATIONHEADER' | translate }}

+
{{datatarget.authorizationHeader}}
+ +

{{ 'DATATARGET.NO-AUTHORIZATIONHEADER' | translate }}

+
+ +
+
+ + +
+
+
+
+

{{ 'DATATARGET.RELATIONS' | translate }}

+
+

{{'DATATARGET.NO-RELATIONS' | translate}}

+
+
+
+
+
+

{{'DATATARGET.PAYLOADEDECODER' | translate}} + {{relation.payloadDecoder.name}} + + {{ 'DATATARGET.NO-PAYLOADDECODER' | translate}} +

+
+
+ +
+
+

{{'DATATARGET.IOTDEVICE' | translate}} + + , {{device.name}} + +

+
+ +
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.scss b/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.spec.ts b/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.spec.ts new file mode 100644 index 00000000..7f5198d9 --- /dev/null +++ b/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.spec.ts @@ -0,0 +1,28 @@ +/* tslint:disable:no-unused-variable */ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { FiwareDetailComponent } from './fiware-detail.component'; + +describe('FiwareDetailComponent', () => { + let component: FiwareDetailComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ FiwareDetailComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(FiwareDetailComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.ts b/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.ts new file mode 100644 index 00000000..5ebc3e22 --- /dev/null +++ b/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.ts @@ -0,0 +1,99 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subscription } from 'rxjs'; +import { ActivatedRoute } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { PayloadDeviceDatatargetGetByDataTarget } from '@app/payload-decoder/payload-device-data.model'; +import { PayloadDeviceDatatargetService } from '@app/payload-decoder/payload-device-datatarget.service'; +import { BackButton } from '@shared/models/back-button.model'; +import { DatatargetService } from '../../datatarget.service'; +import { Location } from '@angular/common'; +import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service'; +import { Datatarget } from '../../datatarget.model'; +import { DropdownButton } from '@shared/models/dropdown-button.model'; +import { faArrowsAltH } from '@fortawesome/free-solid-svg-icons'; +import { DatatargetDetail } from '@applications/datatarget/datatarget-detail/datatarget-detail'; + + +@Component({ + selector: 'app-fiware-detail', + templateUrl: './fiware-detail.component.html', + styleUrls: ['./fiware-detail.component.scss'] +}) +export class FiwareDetailComponent implements DatatargetDetail, OnInit, OnDestroy { + + public datatargetSubscription: Subscription; + public datatarget: Datatarget; + public backButton: BackButton = { label: '', routerLink: '/datatarget-list' }; + public dataTargetRelations: PayloadDeviceDatatargetGetByDataTarget[]; + private deleteDialogSubscription: Subscription; + public dropdownButton: DropdownButton; + arrowsAltH = faArrowsAltH; + private applicationName: string; + + constructor( + private route: ActivatedRoute, + private deleteDialogService: DeleteDialogService, + private location: Location, + private datatargetRelationServicer: PayloadDeviceDatatargetService, + private datatargetService: DatatargetService, + public translate: TranslateService) { } + + ngOnInit(): void { + const id: number = +this.route.snapshot.paramMap.get('datatargetId'); + this.applicationName = this.route.snapshot.paramMap.get('name'); + if (id) { + this.getDatatarget(id); + this.getDatatargetRelations(id); + this.dropdownButton = { + label: '', + editRouterLink: '../../datatarget-edit/' + id, + isErasable: true, + } + } + this.translate.get(['NAV.MY-DATATARGET', 'DATATARGET.SHOW-OPTIONS']) + .subscribe(translations => { + this.backButton.label = translations['NAV.MY-DATATARGET']; + this.dropdownButton.label = translations['DATATARGET.SHOW-OPTIONS'] + }); + } + + getDatatarget(id: number) { + this.datatargetService.get(id) + .subscribe((dataTarget: Datatarget) => { + this.datatarget = dataTarget; + this.setBackButton(this.datatarget.applicationId); + }); + } + + private setBackButton(applicationId: number) { + this.backButton.routerLink = ['applications', applicationId.toString(), 'datatarget-list', this.applicationName ] + } + + onDeleteDatatarget() { + this.deleteDialogSubscription = this.deleteDialogService.showSimpleDialog().subscribe( + (response) => { + if (response) { + this.datatargetService.delete(this.datatarget.id).subscribe((response) => { + }); + this.location.back(); + } else { + console.log(response); + } + } + ); + } + + getDatatargetRelations(id: number) { + this.datatargetRelationServicer.getByDataTarget(id) + .subscribe((response) => { + this.dataTargetRelations = response.data; + }); + } + + ngOnDestroy(): void { + if (this.deleteDialogSubscription) { + this.deleteDialogSubscription.unsubscribe(); + } + } + +} diff --git a/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.html b/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.html new file mode 100644 index 00000000..02ec7529 --- /dev/null +++ b/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.html @@ -0,0 +1,167 @@ + + + +
+ +
+
    +
  • + {{error | translate}} +
  • +
+
+ +
+
+ * + +
+
+ +
+
+ * + +
+
+ +
+
+ + + +
+
+ +
+
+ + + +
+
+ +
+
+ * + +
+
+ +
+
+ + +
+
+
{{'QUESTION.DATATARGET.RELATIONS' | translate}}
+
+
+ {{'QUESTION.ADD-RELATIONS' | translate}} + + + + + + + + + +
+
+ + {{'QUESTION.DATATARGET.SELECT-DEVICES' | translate}} + + + + + + {{device.name}} + + +
+
+
+ + {{'QUESTION.DATATARGET.SELECT-PAYLOADDECODER' | translate}} + + + {{'QUESTION.DATATARGET.NO-PAYLOAD-DECODER-SELECTED' | translate}} + + + {{payloadDecoder.name}} + + + +
+
+ +
+ +

{{'DATATARGET.DELETE' | translate}}

+
+
+
+
+
+ +
+ + +
+
+
diff --git a/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.scss b/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.scss new file mode 100644 index 00000000..bb96f657 --- /dev/null +++ b/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.scss @@ -0,0 +1,4 @@ +.form-info-icon { + margin-left: 5px; + cursor: pointer; +} \ No newline at end of file diff --git a/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.spec.ts b/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.spec.ts new file mode 100644 index 00000000..6a58e7f6 --- /dev/null +++ b/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.spec.ts @@ -0,0 +1,28 @@ +/* tslint:disable:no-unused-variable */ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { FiwareEditComponent } from './fiware-edit.component'; + +describe('FiwareEditComponent', () => { + let component: FiwareEditComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ FiwareEditComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(FiwareEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.ts b/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.ts new file mode 100644 index 00000000..f2e5fef4 --- /dev/null +++ b/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.ts @@ -0,0 +1,337 @@ +import { Component, OnInit, Input, OnDestroy } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Datatarget } from '../../datatarget.model'; +import { Observable, Subscription } from 'rxjs'; +import { Application } from '@applications/application.model'; +import { IotDevice } from '@applications/iot-devices/iot-device.model'; +import { faTimesCircle } from '@fortawesome/free-solid-svg-icons'; +import { PayloadDeviceDatatarget, PayloadDeviceDatatargetGetByDataTargetResponse } from '@payload-decoder/payload-device-data.model'; +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 { MatDialog } from '@angular/material/dialog'; +import { HttpErrorResponse } from '@angular/common/http'; +import { PayloadDecoderMappedResponse } from '@payload-decoder/payload-decoder.model'; +import { DeleteDialogComponent } from '@shared/components/delete-dialog/delete-dialog.component'; +import { ErrorMessageService } from '@shared/error-message.service'; +import { ScrollToTopService } from '@shared/services/scroll-to-top.service'; +import { DataTargetType } from '@shared/enums/datatarget-type'; +import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons'; + +@Component({ + selector: 'app-fiware-edit', + templateUrl: './fiware-edit.component.html', + styleUrls: ['./fiware-edit.component.scss'] +}) +export class FiwareEditComponent implements OnInit { + + + public multiPage = false; + public title = ''; + public sectionTitle = ''; + public backButtonTitle = ''; + @Input() submitButton: string; + public datatarget: Datatarget = new Datatarget(); + faTimesCircle = faTimesCircle; + public datatargetSubscription: Subscription; + public relationSubscription: Subscription; + public applicationSubscription: Subscription; + public payloadDecoderSubscription: Subscription; + public errorMessages: any; + public errorFields: string[]; + public formFailedSubmit = false; + public datatargetid: number; + private applicationId: number; + private applicationNane: string; + public application: Application; + public devices: IotDevice[]; + public payloadDecoders = []; + private counter: number; + payloadDeviceDatatarget: PayloadDeviceDatatarget[]; + newDynamic: any = {}; + faQuestionCircle = faQuestionCircle; + + + constructor( + public translate: TranslateService, + private route: ActivatedRoute, + private router: Router, + private datatargetService: DatatargetService, + private applicationService: ApplicationService, + private payloadDecoderService: PayloadDecoderService, + private payloadDeviceDataTargetService: PayloadDeviceDatatargetService, + private saveSnackService: SaveSnackService, + private dialog: MatDialog, + private errorMessageService: ErrorMessageService, + private scrollToTopService: ScrollToTopService, + ) { + translate.use('da'); + } + + + + ngOnInit() { + this.translate + .get([ + 'FORM.CREATE-NEW-DATATARGET', + 'FORM.EDIT-DATATARGET', + 'DATATARGET.SAVE', + 'NAV.DATATARGET', + ]) + .subscribe((translations) => { + const datatargetid = +this.route.snapshot.paramMap.get('datatargetId'); + if (datatargetid !== 0) { + this.title = translations['FORM.EDIT-DATATARGET']; + } else { + this.title = translations['FORM.CREATE-NEW-DATATARGET']; + } + this.submitButton = translations['DATATARGET.SAVE']; + this.backButtonTitle = translations['NAV.DATATARGET']; + }); + + 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.datatarget.type = DataTargetType.FIWARE; + + if (this.datatargetid !== 0) { + this.getDatatarget(this.datatargetid); + this.getPayloadDeviceDatatarget(this.datatargetid); + } + if (this.applicationId !== 0) { + this.getDevices(); + } + this.getPayloadDecoders(); + + } + + + addRow() { + if (!this.payloadDeviceDatatarget) { + this.payloadDeviceDatatarget = []; + } + this.payloadDeviceDatatarget.push({ id: null, iotDeviceIds: [], payloadDecoderId: null, dataTargetId: this.datatargetid }); + } + + private deleteRow(index) { + if (this.payloadDeviceDatatarget.length === 0) { + } else if (this.payloadDeviceDatatarget[index]?.id === null) { + this.payloadDeviceDatatarget.splice(index, 1); + } else { + this.payloadDeviceDataTargetService.delete(this.payloadDeviceDatatarget[index].id) + .subscribe((response) => { + this.payloadDeviceDatatarget.splice(index, 1); + }); + } + } + + openDeleteDialog(index) { + const dialog = this.dialog.open(DeleteDialogComponent, { + data: { + showAccept: true, + showCancel: true, + message: 'Er du sikker på at du vil slette?' + } + }); + + dialog.afterClosed().subscribe((result) => { + if (result === true) { + this.deleteRow(index); + } + }); + } + + onSubmit(): void { + this.counter = 0; + if (this.datatargetid) { + this.updateDatatarget(); + this.addPayloadDeviceDatatarget(); + } else { + this.createDatatarget(); + } + } + + public compare(o1: any, o2: any): boolean { + return o1 === o2; + } + + updateDatatarget() { + this.resetErrors(); + this.counter = 1 + (this.payloadDeviceDatatarget?.length ? this.payloadDeviceDatatarget?.length : 0); + this.datatargetService.update(this.datatarget) + .subscribe( + (response: Datatarget) => { + this.datatarget = response; + this.countToRedirect(); + }, + (error: HttpErrorResponse) => { + this.handleError(error); + this.formFailedSubmit = true; + } + ); + } + + addPayloadDeviceDatatarget() { + this.payloadDeviceDatatarget.map( + pdd => { + if (pdd.payloadDecoderId === 0) { + pdd.payloadDecoderId = null; + } + } + ); + this.payloadDeviceDatatarget.forEach((relation) => { + if (relation.id) { + this.payloadDeviceDataTargetService.put(relation).subscribe( + (response) => { + this.countToRedirect(); + }, + (error) => { + this.handleError(error); + } + ); + } else { + this.payloadDeviceDataTargetService.post(relation).subscribe( + (res: any) => { + this.countToRedirect(); + }, + (error) => { + this.handleError(error); + } + ); + } + }); + } + + countToRedirect() { + this.counter -= 1; + if (this.counter <= 0 && !this.formFailedSubmit) { + this.showSavedSnack(); + this.routeToDatatargets(); + } + } + + getPayloadDeviceDatatarget(id: number) { + this.relationSubscription = this.payloadDeviceDataTargetService + .getByDataTarget(id) + .subscribe((response: PayloadDeviceDatatargetGetByDataTargetResponse) => { + this.mapToDatatargetDevicePayload(response); + }); + } + + createDatatarget() { + this.resetErrors(); + this.datatarget.applicationId = this.applicationId; + this.datatargetService.create(this.datatarget) + .subscribe((response: Datatarget) => { + this.datatargetid = response.id; + this.datatarget = response; + this.showSavedSnack(); + }, + (error: HttpErrorResponse) => { + this.handleError(error); + this.formFailedSubmit = true; + }); + + } + + private resetErrors() { + this.errorFields = []; + this.errorMessages = undefined; + this.formFailedSubmit = false; + } + + + + getDevices(): void { + this.applicationSubscription = this.applicationService.getApplication(this.applicationId) + .subscribe((application: Application) => { + this.devices = application.iotDevices; + }); + } + + public selectAllDevices(index: number) { + this.payloadDeviceDatatarget[index].iotDeviceIds = this.devices.map(device => device.id); + } + + public deSelectAllDevices(index: number) { + this.payloadDeviceDatatarget[index].iotDeviceIds = []; + } + + getPayloadDecoders() { + this.payloadDecoderSubscription = this.payloadDecoderService.getMultiple(1000, 0, 'id', 'ASC') + .subscribe((response: PayloadDecoderMappedResponse) => { + this.payloadDecoders = response.data; + }); + } + + handleError(error: HttpErrorResponse) { + const errors = this.errorMessageService.handleErrorMessageWithFields(error); + this.errorFields = errors.errorFields; + this.errorMessages = errors.errorMessages; + this.scrollToTopService.scrollToTop(); + } + + routeToDatatargets(): void { + this.router.navigate(['applications',this.applicationId.toString(),'datatarget-list', this.applicationNane]) + } + + onCoordinateKey(event: any) { + if (event.target.value.length > event.target.maxLength) { + event.target.value = event.target.value.slice( + 0, + event.target.maxLength + ); + } + } + + getDatatarget(id: number) { + this.datatargetSubscription = this.datatargetService + .get(id) + .subscribe((response: Datatarget) => { + this.datatarget = response; + }); + } + + showSavedSnack() { + this.saveSnackService.showSavedSnack(); + } + + disableSaveButton(): boolean { + let disable = false; + + return disable; + } + + ngOnDestroy(): void { + if (this.relationSubscription) { + this.relationSubscription.unsubscribe(); + } + if (this.applicationSubscription) { + this.applicationSubscription.unsubscribe(); + } + if (this.datatargetSubscription) { + this.datatargetSubscription.unsubscribe(); + } + if (this.payloadDecoderSubscription) { + this.payloadDecoderSubscription.unsubscribe(); + } + } + + private mapToDatatargetDevicePayload(dto: PayloadDeviceDatatargetGetByDataTargetResponse) { + this.payloadDeviceDatatarget = []; + dto.data.forEach( + (element) => { + this.payloadDeviceDatatarget.push({ + id: element.id, + iotDeviceIds: element.iotDevices.map((x) => x.id), + payloadDecoderId: element.payloadDecoder?.id === undefined ? 0 : element.payloadDecoder?.id, + dataTargetId: element.dataTarget.id + }); + } + ); + } +} 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 new file mode 100644 index 00000000..42cf6d1f --- /dev/null +++ b/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.html @@ -0,0 +1,74 @@ +
+ +
+
+
+
+

{{ 'DATATARGET.DETAILS' | translate }}

+ + +

{{ 'DATATARGET.URL' | translate }}{{datatarget.url}}

+

{{ 'DATATARGET.TIMEOUT' | translate }}{{datatarget.timeout}}

+

{{ 'DATATARGET.TYPE' | translate }}{{'DATATARGET.' + datatarget.type | translate}}

+ +

{{ 'DATATARGET.AUTHORIZATIONHEADER' | translate }}

+
{{datatarget.authorizationHeader}}
+ +

{{ 'DATATARGET.NO-AUTHORIZATIONHEADER' | translate }}

+
+ +
+
+
+
+

{{ 'DATATARGET.OPENDATA-DK' | translate }}

+
+ +
+ +

{{ 'DATATARGET.NO-OPENDATA-DK' | translate }}

+
+
+
+
+ +
+
+
+
+

{{ 'DATATARGET.RELATIONS' | translate }}

+
+

{{'DATATARGET.NO-RELATIONS' | translate}}

+
+
+
+
+
+

{{'DATATARGET.PAYLOADEDECODER' | translate}} + {{relation.payloadDecoder.name}} + + {{ 'DATATARGET.NO-PAYLOADDECODER' | translate}} +

+
+
+ +
+
+

{{'DATATARGET.IOTDEVICE' | translate}} + + , {{device.name}} + +

+
+ +
+
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.scss b/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.scss new file mode 100644 index 00000000..e5e49dff --- /dev/null +++ b/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.scss @@ -0,0 +1,3 @@ +pre { + word-wrap: break-word; + } \ No newline at end of file diff --git a/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.spec.ts b/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.spec.ts new file mode 100644 index 00000000..a212025a --- /dev/null +++ b/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.spec.ts @@ -0,0 +1,28 @@ +/* tslint:disable:no-unused-variable */ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { HttppushDetailComponent } from './httppush-detail.component'; + +describe('HttppushDetailComponent', () => { + let component: HttppushDetailComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HttppushDetailComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HttppushDetailComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.ts b/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.ts new file mode 100644 index 00000000..6219b705 --- /dev/null +++ b/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.ts @@ -0,0 +1,99 @@ +import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Subscription } from 'rxjs'; +import { ActivatedRoute } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { PayloadDeviceDatatargetGetByDataTarget } from '@app/payload-decoder/payload-device-data.model'; +import { PayloadDeviceDatatargetService } from '@app/payload-decoder/payload-device-datatarget.service'; +import { BackButton } from '@shared/models/back-button.model'; +import { DatatargetService } from '../../datatarget.service'; +import { Location } from '@angular/common'; +import { DeleteDialogService } from '@shared/components/delete-dialog/delete-dialog.service'; +import { Datatarget } from '../../datatarget.model'; +import { DropdownButton } from '@shared/models/dropdown-button.model'; +import { faArrowsAltH } from '@fortawesome/free-solid-svg-icons'; +import { IotDevice } from '@applications/iot-devices/iot-device.model'; +import { DatatargetDetail } from '@applications/datatarget/datatarget-detail/datatarget-detail'; + +@Component({ + selector: 'app-httppush-detail', + templateUrl: './httppush-detail.component.html', + styleUrls: ['./httppush-detail.component.scss'] +}) +export class HttppushDetailComponent implements DatatargetDetail, OnInit, OnDestroy { + + public datatargetSubscription: Subscription; + public datatarget: Datatarget; + public backButton: BackButton = { label: '', routerLink: '/datatarget-list' }; + public dataTargetRelations: PayloadDeviceDatatargetGetByDataTarget[]; + private deleteDialogSubscription: Subscription; + public dropdownButton: DropdownButton; + arrowsAltH = faArrowsAltH; + private applicationName: string; + + constructor( + private route: ActivatedRoute, + private deleteDialogService: DeleteDialogService, + private location: Location, + private datatargetRelationServicer: PayloadDeviceDatatargetService, + private datatargetService: DatatargetService, + public translate: TranslateService) { } + + ngOnInit(): void { + const id: number = +this.route.snapshot.paramMap.get('datatargetId'); + this.applicationName = this.route.snapshot.paramMap.get('name'); + if (id) { + this.getDatatarget(id); + this.getDatatargetRelations(id); + this.dropdownButton = { + label: '', + editRouterLink: '../../datatarget-edit/' + id, + isErasable: true, + } + } + this.translate.get(['NAV.MY-DATATARGET', 'DATATARGET.SHOW-OPTIONS']) + .subscribe(translations => { + this.backButton.label = translations['NAV.MY-DATATARGET']; + this.dropdownButton.label = translations['DATATARGET.SHOW-OPTIONS'] + }); + } + + getDatatarget(id: number) { + this.datatargetService.get(id) + .subscribe((dataTarget: Datatarget) => { + this.datatarget = dataTarget; + this.setBackButton(this.datatarget.applicationId); + }); + } + + private setBackButton(applicationId: number) { + this.backButton.routerLink = ['applications', applicationId.toString(), 'datatarget-list', this.applicationName ] + } + + onDeleteDatatarget() { + this.deleteDialogSubscription = this.deleteDialogService.showSimpleDialog().subscribe( + (response) => { + if (response) { + this.datatargetService.delete(this.datatarget.id).subscribe((response) => { + }); + this.location.back(); + } else { + console.log(response); + } + } + ); + } + + getDatatargetRelations(id: number) { + this.datatargetRelationServicer.getByDataTarget(id) + .subscribe((response) => { + this.dataTargetRelations = response.data; + }); + } + + ngOnDestroy(): void { + if (this.deleteDialogSubscription) { + this.deleteDialogSubscription.unsubscribe(); + } + } + +} diff --git a/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.html b/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.html new file mode 100644 index 00000000..4d4df069 --- /dev/null +++ b/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.html @@ -0,0 +1,139 @@ + + + +
+
+
    +
  • + {{error | translate}} +
  • +
+
+ + {{'DATATARGET.ADD-TO-OPENDATADK' | translate}} + +
+
+ * + +
+
+ +
+
+ * + +
+
+
+
+ * + +
+
+
+
+ + +
+
+ +
+
+
+
{{'QUESTION.DATATARGET.RELATIONS' | translate}}
+
+
+ {{'QUESTION.ADD-RELATIONS' | translate}} + + + + + + + + + +
+
+ + {{'QUESTION.DATATARGET.SELECT-DEVICES' | translate}} + + + + + + {{device.name}} + + +
+
+
+ + {{'QUESTION.DATATARGET.SELECT-PAYLOADDECODER' | translate}} + + + {{'QUESTION.DATATARGET.NO-PAYLOAD-DECODER-SELECTED' | translate}} + + + {{payloadDecoder.name}} + + + +
+
+ +
+ +

{{'DATATARGET.DELETE' | translate}}

+
+
+
+
+
+
+ + +
+
\ No newline at end of file diff --git a/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.scss b/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.spec.ts b/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.spec.ts new file mode 100644 index 00000000..1ff864db --- /dev/null +++ b/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.spec.ts @@ -0,0 +1,28 @@ +/* tslint:disable:no-unused-variable */ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { DebugElement } from '@angular/core'; + +import { HttppushEditComponent } from './httppush-edit.component'; + +describe('HttppushEditComponent', () => { + let component: HttppushEditComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HttppushEditComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HttppushEditComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.ts b/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.ts new file mode 100644 index 00000000..cbf83c68 --- /dev/null +++ b/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.ts @@ -0,0 +1,398 @@ +import { Component, OnInit, Input, OnDestroy } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Datatarget } from '../../datatarget.model'; +import { Observable, Subscription } from 'rxjs'; +import { Application } from '@applications/application.model'; +import { IotDevice } from '@applications/iot-devices/iot-device.model'; +import { faTimesCircle } from '@fortawesome/free-solid-svg-icons'; +import { PayloadDeviceDatatarget, PayloadDeviceDatatargetGetByDataTargetResponse } from '@payload-decoder/payload-device-data.model'; +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 { MatDialog } from '@angular/material/dialog'; +import { HttpErrorResponse } from '@angular/common/http'; +import { PayloadDecoderMappedResponse } from '@payload-decoder/payload-decoder.model'; +import { DeleteDialogComponent } from '@shared/components/delete-dialog/delete-dialog.component'; +import { ErrorMessageService } from '@shared/error-message.service'; +import { OpendatadkDialogService } from '@shared/components/opendatadk-dialog/opendatadk-dialog.service'; +import { OpendatadkService } from '@shared/services/opendatadk.service'; +import { ScrollToTopService } from '@shared/services/scroll-to-top.service'; +import { OpenDataDkDataset } from '../../opendatadk/opendatadk-dataset.model'; +import { DataTargetType } from '@shared/enums/datatarget-type'; + +@Component({ + selector: 'app-httppush-edit', + templateUrl: './httppush-edit.component.html', + styleUrls: ['./httppush-edit.component.scss'] +}) +export class HttppushEditComponent implements OnInit, OnDestroy { + public multiPage = false; + public title = ''; + public sectionTitle = ''; + public backButtonTitle = ''; + @Input() submitButton: string; + public datatarget: Datatarget = new Datatarget(); + faTimesCircle = faTimesCircle; + public datatargetSubscription: Subscription; + public relationSubscription: Subscription; + public applicationSubscription: Subscription; + public payloadDecoderSubscription: Subscription; + public errorMessages: any; + public errorFields: string[]; + public formFailedSubmit = false; + public datatargetid: number; + private applicationId: number; + private applicationNane: string; + public application: Application; + public devices: IotDevice[]; + public payloadDecoders = []; + private counter: number; + private dataSetExcists = false; + private isMailDialogAlreadyShown = false; + private defaultOpenDataDKStatusForNewEntry = false; + payloadDeviceDatatarget: PayloadDeviceDatatarget[]; + newDynamic: any = {}; + + constructor( + public translate: TranslateService, + private route: ActivatedRoute, + private router: Router, + private datatargetService: DatatargetService, + private applicationService: ApplicationService, + private payloadDecoderService: PayloadDecoderService, + private payloadDeviceDataTargetService: PayloadDeviceDatatargetService, + private saveSnackService: SaveSnackService, + private dialog: MatDialog, + private errorMessageService: ErrorMessageService, + private opendatadkService: OpendatadkService, + private opendatadkDialogService: OpendatadkDialogService, + private scrollToTopService: ScrollToTopService, + ) { + translate.use('da'); + } + + ngOnInit() { + this.translate + .get([ + 'FORM.CREATE-NEW-DATATARGET', + 'FORM.EDIT-DATATARGET', + 'DATATARGET.SAVE', + 'NAV.DATATARGET', + ]) + .subscribe((translations) => { + const datatargetid = +this.route.snapshot.paramMap.get('datatargetId'); + if (datatargetid !== 0) { + this.title = translations['FORM.EDIT-DATATARGET']; + } else { + this.title = translations['FORM.CREATE-NEW-DATATARGET']; + } + this.submitButton = translations['DATATARGET.SAVE']; + this.backButtonTitle = translations['NAV.DATATARGET']; + }); + + this.datatargetid = +this.route.snapshot.paramMap.get('datatargetId'); + this.applicationId = +this.route.snapshot.paramMap.get('id'); + this.applicationNane = this.route.snapshot.paramMap.get('name'); + + var datatargetTypeParam = this.route.snapshot.paramMap.get('datatargetType'); + + this.defaultOpenDataDKStatusForNewEntry = (datatargetTypeParam == DataTargetType.OPENDATADK) + + this.datatarget.setToOpendataDk = this.defaultOpenDataDKStatusForNewEntry; + + if (this.datatargetid !== 0) { + this.getDatatarget(this.datatargetid); + this.getPayloadDeviceDatatarget(this.datatargetid); + } + if (this.applicationId !== 0) { + this.getDevices(); + } + this.getPayloadDecoders(); + this.setDataSetExcists(); + } + + addRow() { + if (!this.payloadDeviceDatatarget) { + this.payloadDeviceDatatarget = []; + } + this.payloadDeviceDatatarget.push({ id: null, iotDeviceIds: [], payloadDecoderId: null, dataTargetId: this.datatargetid }); + } + + private deleteRow(index) { + if (this.payloadDeviceDatatarget.length === 0) { + } else if (this.payloadDeviceDatatarget[index]?.id === null) { + this.payloadDeviceDatatarget.splice(index, 1); + } else { + this.payloadDeviceDataTargetService.delete(this.payloadDeviceDatatarget[index].id) + .subscribe((response) => { + this.payloadDeviceDatatarget.splice(index, 1); + }); + } + } + + openDeleteDialog(index) { + const dialog = this.dialog.open(DeleteDialogComponent, { + data: { + showAccept: true, + showCancel: true, + message: 'Er du sikker på at du vil slette?' + } + }); + + dialog.afterClosed().subscribe((result) => { + if (result === true) { + this.deleteRow(index); + } + }); + } + + onSubmit(): void { + this.counter = 0; + if (this.datatargetid) { + this.updateDatatarget(); + this.addPayloadDeviceDatatarget(); + } else { + this.createDatatarget(); + } + } + + public compare(o1: any, o2: any): boolean { + return o1 === o2; + } + + updateDatatarget() { + this.resetErrors(); + this.counter = 1 + (this.payloadDeviceDatatarget?.length ? this.payloadDeviceDatatarget?.length : 0); + this.datatargetService.update(this.datatarget) + .subscribe( + (response: Datatarget) => { + this.datatarget = response; + if (this.datatarget.openDataDkDataset != null) { + this.datatarget.openDataDkDataset.acceptTerms = true; + } + this.shouldShowMailDialog().subscribe( + (response) => { + this.countToRedirect(); + } + ); + }, + (error: HttpErrorResponse) => { + this.checkDataTargetModelOpendatadkdatasaet(); + this.handleError(error); + this.formFailedSubmit = true; + } + ); + } + + addPayloadDeviceDatatarget() { + this.payloadDeviceDatatarget.map( + pdd => { + if (pdd.payloadDecoderId === 0) { + pdd.payloadDecoderId = null; + } + } + ); + this.payloadDeviceDatatarget.forEach((relation) => { + if (relation.id) { + this.payloadDeviceDataTargetService.put(relation).subscribe( + (response) => { + this.countToRedirect(); + }, + (error) => { + this.handleError(error); + } + ); + } else { + this.payloadDeviceDataTargetService.post(relation).subscribe( + (res: any) => { + this.countToRedirect(); + }, + (error) => { + this.handleError(error); + } + ); + } + }); + } + + countToRedirect() { + this.counter -= 1; + if (this.counter <= 0 && !this.formFailedSubmit) { + this.showSavedSnack(); + this.routeToDatatargets(); + } + } + + getPayloadDeviceDatatarget(id: number) { + this.relationSubscription = this.payloadDeviceDataTargetService + .getByDataTarget(id) + .subscribe((response: PayloadDeviceDatatargetGetByDataTargetResponse) => { + this.mapToDatatargetDevicePayload(response); + }); + } + + createDatatarget() { + this.resetErrors(); + this.datatarget.applicationId = this.applicationId; + this.datatargetService.create(this.datatarget) + .subscribe((response: Datatarget) => { + this.datatargetid = response.id; + this.datatarget = response; + if (this.datatarget.openDataDkDataset != null) { + this.datatarget.openDataDkDataset.acceptTerms = true; + } + this.showSavedSnack(); + }, + (error: HttpErrorResponse) => { + this.checkDataTargetModelOpendatadkdatasaet(); + this.handleError(error); + this.formFailedSubmit = true; + }); + + } + + private resetErrors() { + this.errorFields = []; + this.errorMessages = undefined; + this.formFailedSubmit = false; + } + + checkDataTargetModelOpendatadkdatasaet() { + if (!this.datatarget.openDataDkDataset) { + this.datatarget.openDataDkDataset = new OpenDataDkDataset(); + } + } + + getDevices(): void { + this.applicationSubscription = this.applicationService.getApplication(this.applicationId) + .subscribe((application: Application) => { + this.devices = application.iotDevices; + }); + } + + public selectAllDevices(index: number) { + this.payloadDeviceDatatarget[index].iotDeviceIds = this.devices.map(device => device.id); + } + + public deSelectAllDevices(index: number) { + this.payloadDeviceDatatarget[index].iotDeviceIds = []; + } + + getPayloadDecoders() { + this.payloadDecoderSubscription = this.payloadDecoderService.getMultiple(1000, 0, 'id', 'ASC') + .subscribe((response: PayloadDecoderMappedResponse) => { + this.payloadDecoders = response.data; + }); + } + + handleError(error: HttpErrorResponse) { + const errors = this.errorMessageService.handleErrorMessageWithFields(error); + this.errorFields = errors.errorFields; + this.errorMessages = errors.errorMessages; + this.scrollToTopService.scrollToTop(); + } + + routeToDatatargets(): void { + this.router.navigate(['applications',this.applicationId.toString(),'datatarget-list', this.applicationNane]) + } + + onCoordinateKey(event: any) { + if (event.target.value.length > event.target.maxLength) { + event.target.value = event.target.value.slice( + 0, + event.target.maxLength + ); + } + } + + getDatatarget(id: number) { + this.datatargetSubscription = this.datatargetService + .get(id) + .subscribe((response: Datatarget) => { + this.datatarget = response; + }); + } + + showSavedSnack() { + this.saveSnackService.showSavedSnack(); + } + + private setDataSetExcists() { + this.opendatadkService.get().subscribe( + (response) => { + this.dataSetExcists = response.dataset.length === 0 ? false : true; + } + ); + } + + private shouldShowMailDialog(): Observable { + return new Observable( + (observer) => { + if (!this.dataSetExcists && this.datatarget.setToOpendataDk && !this.isMailDialogAlreadyShown) { + this.isMailDialogAlreadyShown = true; + this.opendatadkDialogService.showDialog().subscribe( + response => { + if (response) { + this.showMailClient(); + } + observer.next(response); + } + ); + } else { + observer.next(true); + } + } + ) + } + + private showMailClient() { + if (!this.datatarget.openDataDkDataset.url) { + this.datatarget.openDataDkDataset.url = this.datatargetService.getOpendataSharingApiUrl() + } + window.location.href = 'mailto:FG2V@kk.dk?subject=Oprettelse%20af%20datas%C3%A6t%20i%20OpenDataDK&body=K%C3%A6re%20Frans%0D%0A%0D%0AHermed%20fremsendes%20linket%20til%20DCAT%20kataloget%20%2C%20du%20bedes%20registrere%20p%C3%A5%20Open%20Data%20DK%20platformen.%0D%0A%0D%0ALink%3A ' + this.datatarget.openDataDkDataset.url; + } + + disableSaveButton(): boolean { + let disable = true; + if (!this.datatarget.setToOpendataDk) { + disable = false; + } else if (this.datatarget.openDataDkDataset?.acceptTerms) { + disable = false; + } else { + disable = true; + } + return disable; + } + + ngOnDestroy(): void { + if (this.relationSubscription) { + this.relationSubscription.unsubscribe(); + } + if (this.applicationSubscription) { + this.applicationSubscription.unsubscribe(); + } + if (this.datatargetSubscription) { + this.datatargetSubscription.unsubscribe(); + } + if (this.payloadDecoderSubscription) { + this.payloadDecoderSubscription.unsubscribe(); + } + } + + private mapToDatatargetDevicePayload(dto: PayloadDeviceDatatargetGetByDataTargetResponse) { + this.payloadDeviceDatatarget = []; + dto.data.forEach( + (element) => { + this.payloadDeviceDatatarget.push({ + id: element.id, + iotDeviceIds: element.iotDevices.map((x) => x.id), + payloadDecoderId: element.payloadDecoder?.id === undefined ? 0 : element.payloadDecoder?.id, + dataTargetId: element.dataTarget.id + }); + } + ); + } +} diff --git a/src/app/shared/components/snack-bar/snack-bar.component.html b/src/app/shared/components/snack-bar/snack-bar.component.html new file mode 100644 index 00000000..aa504cd5 --- /dev/null +++ b/src/app/shared/components/snack-bar/snack-bar.component.html @@ -0,0 +1,9 @@ +
+ {{data.title}} +
+
+ {{data.message}} +
+
+ +
\ No newline at end of file diff --git a/src/app/shared/components/snack-bar/snack-bar.component.scss b/src/app/shared/components/snack-bar/snack-bar.component.scss new file mode 100644 index 00000000..29916f9b --- /dev/null +++ b/src/app/shared/components/snack-bar/snack-bar.component.scss @@ -0,0 +1,21 @@ +.snackbar-title-style { + font-weight: 500; + letter-spacing: 0.5px; +} +.snackbar-content-style { + letter-spacing: 0.5px; + border: none; + padding: 0 10px; + margin-top: 10px; + margin-bottom: 10px; +} +.snackbar-button-div-style { + text-align: center; + + .button-style { + letter-spacing: 0.5px; + border: 1px solid #000; + border-radius: 5px; + padding: 5px 15px; + } +} diff --git a/src/app/shared/components/snack-bar/snack-bar.component.ts b/src/app/shared/components/snack-bar/snack-bar.component.ts new file mode 100644 index 00000000..2bf27e0b --- /dev/null +++ b/src/app/shared/components/snack-bar/snack-bar.component.ts @@ -0,0 +1,18 @@ +import { Component, OnInit, Inject } from "@angular/core"; +import { MAT_SNACK_BAR_DATA, MatSnackBarRef } from "@angular/material/snack-bar"; + + +@Component({ + selector: 'app-snackbar', + templateUrl: './snack-bar.component.html', + styleUrls: ['./snack-bar.component.scss'] +}) +export class SnackBarComponent implements OnInit { + + constructor( + @Inject(MAT_SNACK_BAR_DATA) public data: any, + public snackBarRef: MatSnackBarRef) {} + + ngOnInit(): void { + } +} diff --git a/src/app/shared/enums/datatarget-type.ts b/src/app/shared/enums/datatarget-type.ts index 5dea3827..795c317d 100644 --- a/src/app/shared/enums/datatarget-type.ts +++ b/src/app/shared/enums/datatarget-type.ts @@ -1,4 +1,5 @@ export enum DataTargetType { HTTPPUSH = 'HTTP_PUSH', - OPENDATADK = 'OPENDATADK' + OPENDATADK = 'OPENDATADK', + FIWARE = 'FIWARE' } diff --git a/src/app/shared/services/snack.service.ts b/src/app/shared/services/snack.service.ts new file mode 100644 index 00000000..a715c48a --- /dev/null +++ b/src/app/shared/services/snack.service.ts @@ -0,0 +1,26 @@ +import { Injectable } from '@angular/core'; +import { MatSnackBar } from '@angular/material/snack-bar'; +import { SnackBarComponent } from '@shared/components/snack-bar/snack-bar.component'; + + +@Injectable({ + providedIn: 'root', +}) +export class SnackService { + + constructor(private snackBar: MatSnackBar) {} + + public showSnackBar(title: string, displayMessage: string, buttonText: string) { + this.snackBar.openFromComponent(SnackBarComponent, { + data: { + title: title, + message: displayMessage, + buttonText: buttonText + }, + duration: 5000, + horizontalPosition: 'right', + verticalPosition: 'top', + panelClass: 'snackBar' + }); + } +} diff --git a/src/assets/i18n/da.json b/src/assets/i18n/da.json index 96c8b754..b017ea17 100644 --- a/src/assets/i18n/da.json +++ b/src/assets/i18n/da.json @@ -135,6 +135,8 @@ "DATATARGET": { "DETAILS": "Detaljer", "SAVE": "Gem datatarget", + "CREATE": "Opret", + "READMORE": "Læs mere", "DESCRIPTION": "Beskrivelse", "URL": "URL", "TIMEOUT": "Timeout", @@ -147,11 +149,17 @@ "NO-PAYLOADDECODER": "Ingen payload decoder", "IOTDEVICE": "IoT enhed(er)", "NO-RELATIONS": "ingen tilknyttede relationer", + "TENANT": "Tenant", + "NO-TENANT": "Ingen Tenant angivet", + "CONTEXT": "Context", + "NO-CONTEXT": "Ingen Context angivet", "AUTHORIZATIONHEADER": "Authorization header", "NO-AUTHORIZATIONHEADER": "Ingen Authorization header angivet", "ADD-TO-OPENDATADK": "Send data til OpenDataDK", "OPENDATA-DK": "OpenDataDK", - "NO-OPENDATA-DK": "Der er ikke oprettet nogen datadeling med Open Data DK endnu" + "NO-OPENDATA-DK": "Der er ikke oprettet nogen datadeling med Open Data DK endnu", + "HTTP_PUSH": "HTTP Push", + "FIWARE": "FIWARE" }, "OPENDATADK": { "QUESTION": { @@ -841,5 +849,19 @@ "Forbidden resource": "Du har ikke rettigheder til at foretage denne handling", "GENERIC_HTTP": "Generisk HTTP", "LORAWAN": "LoRaWAN", - "SIGFOX": "Sigfox" + "SIGFOX": "Sigfox", + + "FIWARE": { + "QUESTION": { + "GIVE-DATATARGET-CONTEXTBROKER-URL": "Angiv datatargets 'context broker' URL", + "GIVE-DATATARGET-CONTEXTBROKER-URL-PLACEHOLDER": "https://contextBroker.dk/", + "GIVE-DATATARGET-TENANT": "Angiv 'tenant'", + "GIVE-DATATARGET-TENANT-INFO": "hvis tom, vil default tenant blive brugt", + "GIVE-DATATARGET-TENANT-PLACEHOLDER": "Tenant's navn", + "GIVE-DATATARGET-CONTEXT": "Angiv 'context'", + "GIVE-DATATARGET-CONTEXT-INFO": "hvis tom, skal den angives i 'payload'", + "GIVE-DATATARGET-CONTEXT-PLACEHOLDER": "https://os2iot/context-file.json" + } + + } } diff --git a/src/assets/images/logo_FIWARE.png b/src/assets/images/logo_FIWARE.png new file mode 100644 index 0000000000000000000000000000000000000000..beb19973fe397cb52684f9fd57ca5a18582e6810 GIT binary patch literal 1338 zcmV-A1;zS_P)-}H%G`RLhz+}a9n$_{_ zizczb@&;Lu)tHw=%Z`G6CLB&fRBUPgQrRf%5x?fl|4XOY^Aae9U`-+tj{6~+ctpH1?rA;E4W zJDw*{7Gh&@bLtopmM07l;LR8SY5J{IhL<#5QxKbd=U7voR z!D(91y7<(ebuIClohD;)&{J9?QniLv#q>;-h}%(W?>6)cdyIvCVekp#)iS6f2wDLQ z;dw9R$*x&R`@DjT;YZsTG(-a)2YyH|1s&j752L;6#iO0^dyt?j$`-_!(qG^h5l;u{ zPxVM2kYnaT+mvLq3bYXhKRStzJM&+!yvI+vM7AKwBz>B`++t-ja$TKua;By#TAs_wN3m{J2(@R!*Na(WNC8@gp zCh+n9>ACg@40#c|RzPsdb#bPWKEj`8>wvVXfC9i6oiF{dLG_Yf^cxq)5_ z;=AXq8u*><9irb05d8&uy4Hh5LA6Bn6R#bfBZ6-$K=^$LRLj&a2Ibk`CIh0w5R~oqpf^%Ktd}{oVvb%@9VA5%Y`f0E zp1kgb*1yu@Ki8YFt39WfRWII^(BOq149c-|xL11e3B9@AE%mBNdb-w?Xuwoz2n&CG z)+6o^^I5%N3r}PGdNhyY7d9`0U}k@ui%k|~=o6LGQ^%N`hkrhe11g4Q*s2648UJhW z#;U?v6LTU2TH#u&A+3E6i%=81m6R&BY8on{Wv)Db9(ivUQ)bY z=~*Q4JAN)cjY__%=hu3CO>bX!4_peJ1mpm z#U1ytvd5m}vR=Xy3q5>@7xYkF=IjPp;r9*_u%WxIXZ)Th(8HjSxu7>ymx`(Ea6?&q zi6soiRXrq&7i*%m+r3#EjpYD?H}z0me81;%Vh=EV4R6g$vQyYy)x-47;F{OJ&f@BF zx~1n~hq}T-uGhGz7ya7qnjYF}K3~ #EIgCrdRx=~R@osPKP@=u`Pt@?g zQFk23LA6ZZKm{|- w6X*Vg-#W^vp)Yr=C+8$7goT$J+xzC^eOpen Data DK diff --git a/src/styles.scss b/src/styles.scss index 91b964e8..4455b654 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -53,3 +53,38 @@ font-family: 'roboto-bold'; src: url('./assets/fonts/Roboto-Bold.ttf') format('truetype'); } + +body { + // For Google Chrome + &::-webkit-scrollbar { + width: 5px; + height: 5px; + } + + &::-webkit-scrollbar-thumb { + background: rgba($color: #000000, $alpha: 0.5); + } + + &::-webkit-scrollbar-track { + background: rgba($color: #000000, $alpha: 0.4); + } + + // For FireFox + scrollbar-width: 5px; + + // For Internet Explorer + & { + scrollbar-face-color: rgba($color: #000000, $alpha: 0.5); + scrollbar-track-color: rgba($color: #000000, $alpha: 0.4); + } +} + +.snackBar.mat-snack-bar-container{ + background: #f4f4f4; + color: #000; +} + +.mat-tooltip { + font-size: 1rem !important; +} + From ac070b6d61a97e32ddc55cdc83b2bfd5c2112a19 Mon Sep 17 00:00:00 2001 From: bkdkmd Date: Wed, 16 Feb 2022 11:04:07 +0100 Subject: [PATCH 6/7] PR fixes --- .../application-detail.component.ts | 4 +- ...get-detail-type-selector.directive.spec.ts | 6 +- .../datatarget-detail.component.ts | 39 ++-- ...arget-edit-type-selector.directive.spec.ts | 8 +- ...datatarget-edit-type-selector.directive.ts | 4 +- .../datatarget-edit.component.ts | 44 ++--- .../datatarget-new.component.ts | 4 +- .../datatarget-table.component.ts | 3 +- ...ec.ts => datatarget-types.service.spec.ts} | 6 +- ...service.ts => datatarget-types.service.ts} | 31 ++- .../fiware-detail/fiware-detail.component.ts | 11 +- .../fiware-edit/fiware-edit.component.ts | 32 ++-- .../httppush-detail.component.ts | 6 +- .../httppush-edit/httppush-edit.component.ts | 181 ++++++++++-------- 14 files changed, 189 insertions(+), 190 deletions(-) rename src/app/applications/datatarget/{datatarget-types-service.service.spec.ts => datatarget-types.service.spec.ts} (53%) rename src/app/applications/datatarget/{datatarget-types-service.service.ts => datatarget-types.service.ts} (68%) diff --git a/src/app/applications/application-detail/application-detail.component.ts b/src/app/applications/application-detail/application-detail.component.ts index 288804b8..2b6dfdbe 100644 --- a/src/app/applications/application-detail/application-detail.component.ts +++ b/src/app/applications/application-detail/application-detail.component.ts @@ -52,9 +52,7 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy { label: '', editRouterLink: '../../edit-application/' + this.id, isErasable: true, - }; - - console.log(this.id); + }; } this.translate diff --git a/src/app/applications/datatarget/datatarget-detail/datatarget-detail-type-selector.directive.spec.ts b/src/app/applications/datatarget/datatarget-detail/datatarget-detail-type-selector.directive.spec.ts index 3b61cb6b..3a9402c7 100644 --- a/src/app/applications/datatarget/datatarget-detail/datatarget-detail-type-selector.directive.spec.ts +++ b/src/app/applications/datatarget/datatarget-detail/datatarget-detail-type-selector.directive.spec.ts @@ -1,9 +1,11 @@ /* tslint:disable:no-unused-variable */ -import { TestBed, async } from '@angular/core/testing'; +import { ViewContainerRef } from '@angular/core'; import { DatatargetDetailTypeSelectorDirective } from './datatarget-detail-type-selector.directive'; - +let viewContainerRef: ViewContainerRef; describe('Directive: DatatargetDetailTypeSelector', () => { it('should create an instance', () => { + const directive = new DatatargetDetailTypeSelectorDirective(viewContainerRef); + expect(directive).toBeTruthy(); }); }); 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 46f12408..17970ff3 100644 --- a/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.ts +++ b/src/app/applications/datatarget/datatarget-detail/datatarget-detail.component.ts @@ -1,10 +1,9 @@ -import { AfterViewInit, Component, ComponentFactoryResolver, OnDestroy, OnInit, QueryList, Type, ViewChild, ViewChildren} from '@angular/core'; +import { Component, ComponentFactoryResolver, OnDestroy, OnInit, Type, ViewChild } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { DataTargetType } from '@shared/enums/datatarget-type'; -import { DatatargetTypesServiceService } from '../datatarget-types-service.service'; +import { DatatargetTypesService } from '../datatarget-types.service'; import { Datatarget } from '../datatarget.model'; import { DatatargetService } from '../datatarget.service'; -import { HttppushDetailComponent } from '../httppush/httppush-detail/httppush-detail.component'; import { DatatargetDetail } from './datatarget-detail'; import { DatatargetDetailTypeSelectorDirective } from './datatarget-detail-type-selector.directive'; @@ -17,48 +16,44 @@ export class DatatargetDetailComponent implements OnInit, OnDestroy { @ViewChild(DatatargetDetailTypeSelectorDirective, {static: true}) adHost!: DatatargetDetailTypeSelectorDirective; - private applicationName: string; public datatarget: Datatarget; private datatargetType: DataTargetType; - - constructor(private componentFactoryResolver: ComponentFactoryResolver, - private datatargetService: DatatargetService, - private route: ActivatedRoute, - private datatargetTypesService: DatatargetTypesServiceService + + constructor(private componentFactoryResolver: ComponentFactoryResolver, + private datatargetService: DatatargetService, + private route: ActivatedRoute, + private datatargetTypesService: DatatargetTypesService ) { } - + loadComponent(componentType: Type) { - + const viewContainerRef = this.adHost.viewContainerRef; - + viewContainerRef.clear(); const factory = this.componentFactoryResolver.resolveComponentFactory(componentType); - const componentRef = viewContainerRef.createComponent(factory) - - + viewContainerRef.createComponent(factory); } ngOnInit(): void { - this.applicationName = this.route.snapshot.paramMap.get('name'); const id: number = +this.route.snapshot.paramMap.get('datatargetId'); - - this.datatargetService.get(id) + + this.datatargetService.get(id) .subscribe((dataTarget: Datatarget) => { this.datatarget = dataTarget; this.datatargetType = dataTarget.type; - + const component = this.datatargetTypesService.getDetailComponent(this.datatargetType); this.loadComponent(component); - + }); - + } ngOnDestroy() { - + } } diff --git a/src/app/applications/datatarget/datatarget-edit/datatarget-edit-type-selector.directive.spec.ts b/src/app/applications/datatarget/datatarget-edit/datatarget-edit-type-selector.directive.spec.ts index a18997fa..1c28242d 100644 --- a/src/app/applications/datatarget/datatarget-edit/datatarget-edit-type-selector.directive.spec.ts +++ b/src/app/applications/datatarget/datatarget-edit/datatarget-edit-type-selector.directive.spec.ts @@ -1,11 +1,11 @@ /* tslint:disable:no-unused-variable */ -import { TestBed, async } from '@angular/core/testing'; +import { ViewContainerRef } from '@angular/core'; import { DatatargetEditTypeSelectorDirective } from './datatarget-edit-type-selector.directive'; - +let viewContainerRef: ViewContainerRef; describe('Directive: DatatargetEditTypeSelector', () => { it('should create an instance', () => { - //const directive = new DatatargetEditTypeSelectorDirective(); - //expect(directive).toBeTruthy(); + const directive = new DatatargetEditTypeSelectorDirective(viewContainerRef); + expect(directive).toBeTruthy(); }); }); diff --git a/src/app/applications/datatarget/datatarget-edit/datatarget-edit-type-selector.directive.ts b/src/app/applications/datatarget/datatarget-edit/datatarget-edit-type-selector.directive.ts index 25511bc7..03b06ddb 100644 --- a/src/app/applications/datatarget/datatarget-edit/datatarget-edit-type-selector.directive.ts +++ b/src/app/applications/datatarget/datatarget-edit/datatarget-edit-type-selector.directive.ts @@ -6,5 +6,5 @@ import { Directive, ViewContainerRef } from '@angular/core'; export class DatatargetEditTypeSelectorDirective { constructor(public viewContainerRef: ViewContainerRef) { } - -} \ No newline at end of file + +} 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 50e92747..432a5e2b 100644 --- a/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.ts +++ b/src/app/applications/datatarget/datatarget-edit/datatarget-edit.component.ts @@ -1,7 +1,7 @@ -import { AfterViewInit, Component, ComponentFactoryResolver, OnDestroy, OnInit, QueryList, Type, ViewChild, ViewChildren} from '@angular/core'; +import { AfterViewInit, Component, ComponentFactoryResolver, OnDestroy, OnInit, QueryList, Type, ViewChild, ViewChildren } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { DataTargetType } from '@shared/enums/datatarget-type'; -import { DatatargetTypesServiceService } from '../datatarget-types-service.service'; +import { DatatargetTypesService } from '../datatarget-types.service'; import { Datatarget } from '../datatarget.model'; import { DatatargetService } from '../datatarget.service'; import { DatatargetEdit } from './datatarget-edit'; @@ -16,41 +16,37 @@ export class DatatargetEditComponent implements OnInit, OnDestroy { @ViewChild(DatatargetEditTypeSelectorDirective, {static: true}) adHost!: DatatargetEditTypeSelectorDirective; - private applicationName: string; public datatarget: Datatarget; private datatargetType: DataTargetType; - - constructor(private componentFactoryResolver: ComponentFactoryResolver, - private datatargetService: DatatargetService, - private route: ActivatedRoute, - private datatargetTypesService: DatatargetTypesServiceService + + constructor(private componentFactoryResolver: ComponentFactoryResolver, + private datatargetService: DatatargetService, + private route: ActivatedRoute, + private datatargetTypesService: DatatargetTypesService ) { } - - loadComponent(componentType: Type) { - const viewContainerRef = this.adHost.viewContainerRef; + + loadComponent(componentType: Type) { + const viewContainerRef = this.adHost.viewContainerRef; viewContainerRef.clear(); const factory = this.componentFactoryResolver.resolveComponentFactory(componentType); - const componentRef = viewContainerRef.createComponent(factory) + viewContainerRef.createComponent(factory); } ngOnInit(): void { - this.applicationName = this.route.snapshot.paramMap.get('name'); const id: number = +this.route.snapshot.paramMap.get('datatargetId'); - - if (id > 0) { + + if (id > 0) { this.datatargetService.get(id) .subscribe((dataTarget: Datatarget) => { this.datatarget = dataTarget; - this.datatargetType = dataTarget.type; + this.datatargetType = dataTarget.type; const component = this.datatargetTypesService.getEditComponent(this.datatargetType); - this.loadComponent(component); + this.loadComponent(component); }); - } - else - { - var datatargetTypeParam = this.route.snapshot.paramMap.get('datatargetType'); + } else { + let datatargetTypeParam = this.route.snapshot.paramMap.get('datatargetType'); this.datatargetType = this.enumFromStringValue(DataTargetType, datatargetTypeParam); if (this.datatargetType) { const component = this.datatargetTypesService.getEditComponent(this.datatargetType); @@ -58,16 +54,16 @@ export class DatatargetEditComponent implements OnInit, OnDestroy { } } - + } - enumFromStringValue (enm: { [s: string]: T}, value: string): T | undefined { + enumFromStringValue(enm: { [s: string]: T}, value: string): T | undefined { return (Object.values(enm) as unknown as string[]).includes(value) ? value as unknown as T : undefined; } ngOnDestroy() { - + } } diff --git a/src/app/applications/datatarget/datatarget-new/datatarget-new.component.ts b/src/app/applications/datatarget/datatarget-new/datatarget-new.component.ts index 93619d0b..d3f90b12 100644 --- a/src/app/applications/datatarget/datatarget-new/datatarget-new.component.ts +++ b/src/app/applications/datatarget/datatarget-new/datatarget-new.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { TranslateService } from '@ngx-translate/core'; import { ActivatedRoute, Router } from '@angular/router'; import { DatatargetTypeDescriptor } from '../datatarget.model'; -import { DatatargetTypesServiceService } from '../datatarget-types-service.service'; +import { DatatargetTypesService } from '../datatarget-types.service'; @@ -23,7 +23,7 @@ export class DatatargetNewComponent implements OnInit { public translate: TranslateService, private route: ActivatedRoute, private router: Router, - private dataTargetTypesService: DatatargetTypesServiceService + private dataTargetTypesService: DatatargetTypesService ) { translate.use('da'); } 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 fa4eb35d..65c04906 100644 --- a/src/app/applications/datatarget/datatarget-table/datatarget-table.component.ts +++ b/src/app/applications/datatarget/datatarget-table/datatarget-table.component.ts @@ -46,8 +46,7 @@ export class DatatargetTableComponent implements OnInit, AfterViewInit, OnDestro } ngOnInit(): void { - this.applicationId = +Number(this.route.parent.snapshot.paramMap.get('id')); - console.log(this.applicationId); + this.applicationId = +Number(this.route.parent.snapshot.paramMap.get('id')); this.getDatatarget(); this.canEdit = this.meService.canWriteInTargetOrganization() } diff --git a/src/app/applications/datatarget/datatarget-types-service.service.spec.ts b/src/app/applications/datatarget/datatarget-types.service.spec.ts similarity index 53% rename from src/app/applications/datatarget/datatarget-types-service.service.spec.ts rename to src/app/applications/datatarget/datatarget-types.service.spec.ts index 1a93045b..d5ef25d5 100644 --- a/src/app/applications/datatarget/datatarget-types-service.service.spec.ts +++ b/src/app/applications/datatarget/datatarget-types.service.spec.ts @@ -1,16 +1,16 @@ /* tslint:disable:no-unused-variable */ import { TestBed, async, inject } from '@angular/core/testing'; -import { DatatargetTypesServiceService } from './datatarget-types-service.service'; +import { DatatargetTypesService } from './datatarget-types.service'; describe('Service: DatatargetTypesService', () => { beforeEach(() => { TestBed.configureTestingModule({ - providers: [DatatargetTypesServiceService] + providers: [DatatargetTypesService] }); }); - it('should ...', inject([DatatargetTypesServiceService], (service: DatatargetTypesServiceService) => { + it('should ...', inject([DatatargetTypesService], (service: DatatargetTypesService) => { expect(service).toBeTruthy(); })); }); diff --git a/src/app/applications/datatarget/datatarget-types-service.service.ts b/src/app/applications/datatarget/datatarget-types.service.ts similarity index 68% rename from src/app/applications/datatarget/datatarget-types-service.service.ts rename to src/app/applications/datatarget/datatarget-types.service.ts index 80644ace..c0dd41ad 100644 --- a/src/app/applications/datatarget/datatarget-types-service.service.ts +++ b/src/app/applications/datatarget/datatarget-types.service.ts @@ -1,5 +1,4 @@ import { Injectable, Type } from '@angular/core'; -import { ActivatedRoute, Router } from '@angular/router'; import { DataTargetType } from '@shared/enums/datatarget-type'; import { DatatargetTypeDescriptor } from './datatarget.model'; import { FiwareDetailComponent } from './fiware/fiware-detail/fiware-detail.component'; @@ -10,35 +9,35 @@ import { HttppushEditComponent } from './httppush/httppush-edit/httppush-edit.co @Injectable({ providedIn: 'root' }) -export class DatatargetTypesServiceService { +export class DatatargetTypesService { constructor() { } getAvailableDataTargetTypes() : DatatargetTypeDescriptor[] { return [ - { name: "Generisk HTTP Push", + { name: 'Generisk HTTP Push', type: DataTargetType.HTTPPUSH, icon: null, - description: "Send data med HTTP POST requests til et HTTP URL endpoint", - readMoreUrl: "", - provider: "OS2" + description: 'Send data med HTTP POST requests til et HTTP URL endpoint', + readMoreUrl: '', + provider: 'OS2' }, - { name: "Open Data DK", + { name: 'Open Data DK', type: DataTargetType.OPENDATADK, - icon: "/assets/images/logo_opendatadk.svg", - description: "Offentliggør datasæt i Open Data DK's åbne dataportal.", - readMoreUrl: "https://www.opendata.dk/", - provider: "OS2" + icon: '/assets/images/logo_opendatadk.svg', + description: 'Offentliggør datasæt i Open Data DK\'s åbne dataportal.', + readMoreUrl: 'https://www.opendata.dk/', + provider: 'OS2' }, - { name: "FIWARE connection", + { name: 'FIWARE connection', type: DataTargetType.FIWARE, - icon: "/assets/images/logo_FIWARE.png", - description: "En integration til FIWARE Context Broker" , - readMoreUrl: "https://www.kmd.dk", - provider: "KMD A/S" + icon: '/assets/images/logo_FIWARE.png', + description: 'En integration til FIWARE Context Broker' , + readMoreUrl: 'https://www.kmd.dk', + provider: 'KMD A/S' } ] } diff --git a/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.ts b/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.ts index bdf93ff1..d56148e6 100644 --- a/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.ts +++ b/src/app/applications/datatarget/fiware/fiware-detail/fiware-detail.component.ts @@ -23,12 +23,11 @@ export class FiwareDetailComponent implements DatatargetDetail, OnInit, OnDestr public datatargetSubscription: Subscription; public datatarget: Datatarget; - public backButton: BackButton = { label: '', routerLink: '/datatarget-list' }; + public backButton: BackButton = { label: '', routerLink: '' }; public dataTargetRelations: PayloadDeviceDatatargetGetByDataTarget[]; private deleteDialogSubscription: Subscription; public dropdownButton: DropdownButton; arrowsAltH = faArrowsAltH; - private applicationName: string; constructor( private route: ActivatedRoute, @@ -40,7 +39,7 @@ export class FiwareDetailComponent implements DatatargetDetail, OnInit, OnDestr ngOnInit(): void { const id: number = +this.route.snapshot.paramMap.get('datatargetId'); - this.applicationName = this.route.snapshot.paramMap.get('name'); + if (id) { this.getDatatarget(id); this.getDatatargetRelations(id); @@ -48,12 +47,12 @@ export class FiwareDetailComponent implements DatatargetDetail, OnInit, OnDestr label: '', editRouterLink: '../../datatarget-edit/' + id, isErasable: true, - } + }; } this.translate.get(['NAV.MY-DATATARGET', 'DATATARGET.SHOW-OPTIONS']) .subscribe(translations => { this.backButton.label = translations['NAV.MY-DATATARGET']; - this.dropdownButton.label = translations['DATATARGET.SHOW-OPTIONS'] + this.dropdownButton.label = translations['DATATARGET.SHOW-OPTIONS']; }); } @@ -66,7 +65,7 @@ export class FiwareDetailComponent implements DatatargetDetail, OnInit, OnDestr } private setBackButton(applicationId: number) { - this.backButton.routerLink = ['applications', applicationId.toString() ] + this.backButton.routerLink = ['applications', applicationId.toString() ]; } onDeleteDatatarget() { diff --git a/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.ts b/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.ts index 06ca24bc..b52a823b 100644 --- a/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.ts +++ b/src/app/applications/datatarget/fiware/fiware-edit/fiware-edit.component.ts @@ -29,7 +29,7 @@ import { DatatargetEdit } from '@applications/datatarget/datatarget-edit/datatar }) export class FiwareEditComponent implements DatatargetEdit, OnInit, OnDestroy { - + public multiPage = false; public title = ''; public sectionTitle = ''; @@ -46,11 +46,10 @@ export class FiwareEditComponent implements DatatargetEdit, OnInit, OnDestroy { public formFailedSubmit = false; public datatargetid: number; private applicationId: number; - private applicationNane: string; public application: Application; public devices: IotDevice[]; public payloadDecoders = []; - private counter: number; + private counter: number; payloadDeviceDatatarget: PayloadDeviceDatatarget[]; newDynamic: any = {}; faQuestionCircle = faQuestionCircle; @@ -73,7 +72,7 @@ export class FiwareEditComponent implements DatatargetEdit, OnInit, OnDestroy { } - + ngOnInit() { this.translate .get([ @@ -95,10 +94,9 @@ export class FiwareEditComponent implements DatatargetEdit, 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.datatarget.type = DataTargetType.FIWARE; - + if (this.datatargetid !== 0) { this.getDatatarget(this.datatargetid); this.getPayloadDeviceDatatarget(this.datatargetid); @@ -110,7 +108,7 @@ export class FiwareEditComponent implements DatatargetEdit, OnInit, OnDestroy { } - + addRow() { if (!this.payloadDeviceDatatarget) { this.payloadDeviceDatatarget = []; @@ -166,10 +164,10 @@ export class FiwareEditComponent implements DatatargetEdit, OnInit, OnDestroy { this.datatargetService.update(this.datatarget) .subscribe( (response: Datatarget) => { - this.datatarget = response; - this.countToRedirect(); + this.datatarget = response; + this.countToRedirect(); }, - (error: HttpErrorResponse) => { + (error: HttpErrorResponse) => { this.handleError(error); this.formFailedSubmit = true; } @@ -229,10 +227,10 @@ export class FiwareEditComponent implements DatatargetEdit, OnInit, OnDestroy { this.datatargetService.create(this.datatarget) .subscribe((response: Datatarget) => { this.datatargetid = response.id; - this.datatarget = response; + this.datatarget = response; this.showSavedSnack(); }, - (error: HttpErrorResponse) => { + (error: HttpErrorResponse) => { this.handleError(error); this.formFailedSubmit = true; }); @@ -245,7 +243,7 @@ export class FiwareEditComponent implements DatatargetEdit, OnInit, OnDestroy { this.formFailedSubmit = false; } - + getDevices(): void { this.applicationSubscription = this.applicationService.getApplication(this.applicationId) @@ -277,7 +275,7 @@ export class FiwareEditComponent implements DatatargetEdit, OnInit, OnDestroy { } routeToDatatargets(): void { - this.router.navigate(['applications',this.applicationId.toString(),'datatarget-list']) + this.router.navigate(['applications', this.applicationId.toString()]); } onCoordinateKey(event: any) { @@ -299,11 +297,11 @@ export class FiwareEditComponent implements DatatargetEdit, OnInit, OnDestroy { showSavedSnack() { this.snackService.showSavedSnack(); - } + } disableSaveButton(): boolean { - let disable = false; - + const disable = false; + return disable; } diff --git a/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.ts b/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.ts index 7f2e7876..179aebcf 100644 --- a/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.ts +++ b/src/app/applications/datatarget/httppush/httppush-detail/httppush-detail.component.ts @@ -47,12 +47,12 @@ export class HttppushDetailComponent implements DatatargetDetail, OnInit, OnDes label: '', editRouterLink: '../../datatarget-edit/' + id, isErasable: true, - } + }; } this.translate.get(['NAV.MY-DATATARGET', 'DATATARGET.SHOW-OPTIONS']) .subscribe(translations => { this.backButton.label = translations['NAV.MY-DATATARGET']; - this.dropdownButton.label = translations['DATATARGET.SHOW-OPTIONS'] + this.dropdownButton.label = translations['DATATARGET.SHOW-OPTIONS']; }); } @@ -65,7 +65,7 @@ export class HttppushDetailComponent implements DatatargetDetail, OnInit, OnDes } private setBackButton(applicationId: number) { - this.backButton.routerLink = ['applications', applicationId.toString()] + this.backButton.routerLink = ['applications', applicationId.toString()]; } onDeleteDatatarget() { diff --git a/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.ts b/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.ts index 81e726e6..d192c2a6 100644 --- a/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.ts +++ b/src/app/applications/datatarget/httppush/httppush-edit/httppush-edit.component.ts @@ -6,7 +6,10 @@ import { Observable, Subscription } from 'rxjs'; import { Application } from '@applications/application.model'; import { IotDevice } from '@applications/iot-devices/iot-device.model'; import { faTimesCircle } from '@fortawesome/free-solid-svg-icons'; -import { PayloadDeviceDatatarget, PayloadDeviceDatatargetGetByDataTargetResponse } from '@payload-decoder/payload-device-data.model'; +import { + PayloadDeviceDatatarget, + PayloadDeviceDatatargetGetByDataTargetResponse, +} from '@payload-decoder/payload-device-data.model'; import { DatatargetService } from '../../datatarget.service'; import { ApplicationService } from '@applications/application.service'; import { PayloadDecoderService } from '@payload-decoder/payload-decoder.service'; @@ -27,9 +30,10 @@ import { DatatargetEdit } from '@applications/datatarget/datatarget-edit/datatar @Component({ selector: 'app-httppush-edit', templateUrl: './httppush-edit.component.html', - styleUrls: ['./httppush-edit.component.scss'] + styleUrls: ['./httppush-edit.component.scss'], }) -export class HttppushEditComponent implements DatatargetEdit, OnInit, OnDestroy { +export class HttppushEditComponent + implements DatatargetEdit, OnInit, OnDestroy { public multiPage = false; public title = ''; public sectionTitle = ''; @@ -70,7 +74,7 @@ export class HttppushEditComponent implements DatatargetEdit, OnInit, OnDestroy private errorMessageService: ErrorMessageService, private opendatadkService: OpendatadkService, private opendatadkDialogService: OpendatadkDialogService, - private scrollToTopService: ScrollToTopService, + private scrollToTopService: ScrollToTopService ) { translate.use('da'); } @@ -112,7 +116,12 @@ export class HttppushEditComponent implements DatatargetEdit, OnInit, OnDestroy if (!this.payloadDeviceDatatarget) { this.payloadDeviceDatatarget = []; } - this.payloadDeviceDatatarget.push({ id: null, iotDeviceIds: [], payloadDecoderId: null, dataTargetId: this.datatargetid }); + this.payloadDeviceDatatarget.push({ + id: null, + iotDeviceIds: [], + payloadDecoderId: null, + dataTargetId: this.datatargetid, + }); } private deleteRow(index) { @@ -120,7 +129,8 @@ export class HttppushEditComponent implements DatatargetEdit, OnInit, OnDestroy } else if (this.payloadDeviceDatatarget[index]?.id === null) { this.payloadDeviceDatatarget.splice(index, 1); } else { - this.payloadDeviceDataTargetService.delete(this.payloadDeviceDatatarget[index].id) + this.payloadDeviceDataTargetService + .delete(this.payloadDeviceDatatarget[index].id) .subscribe((response) => { this.payloadDeviceDatatarget.splice(index, 1); }); @@ -132,8 +142,8 @@ export class HttppushEditComponent implements DatatargetEdit, OnInit, OnDestroy data: { showAccept: true, showCancel: true, - message: 'Er du sikker på at du vil slette?' - } + message: 'Er du sikker på at du vil slette?', + }, }); dialog.afterClosed().subscribe((result) => { @@ -159,36 +169,35 @@ export class HttppushEditComponent implements DatatargetEdit, OnInit, OnDestroy updateDatatarget() { this.resetErrors(); - this.counter = 1 + (this.payloadDeviceDatatarget?.length ? this.payloadDeviceDatatarget?.length : 0); - this.datatargetService.update(this.datatarget) - .subscribe( - (response: Datatarget) => { - this.datatarget = response; - if (this.datatarget.openDataDkDataset != null) { - this.datatarget.openDataDkDataset.acceptTerms = true; - } - this.shouldShowMailDialog().subscribe( - (response) => { - this.countToRedirect(); - } - ); - }, - (error: HttpErrorResponse) => { - this.checkDataTargetModelOpendatadkdatasaet(); - this.handleError(error); - this.formFailedSubmit = true; + this.counter = + 1 + + (this.payloadDeviceDatatarget?.length + ? this.payloadDeviceDatatarget?.length + : 0); + this.datatargetService.update(this.datatarget).subscribe( + (response: Datatarget) => { + this.datatarget = response; + if (this.datatarget.openDataDkDataset != null) { + this.datatarget.openDataDkDataset.acceptTerms = true; } - ); + this.shouldShowMailDialog().subscribe((response) => { + this.countToRedirect(); + }); + }, + (error: HttpErrorResponse) => { + this.checkDataTargetModelOpendatadkdatasaet(); + this.handleError(error); + this.formFailedSubmit = true; + } + ); } addPayloadDeviceDatatarget() { - this.payloadDeviceDatatarget.map( - pdd => { - if (pdd.payloadDecoderId === 0) { - pdd.payloadDecoderId = null; - } + this.payloadDeviceDatatarget.map((pdd) => { + if (pdd.payloadDecoderId === 0) { + pdd.payloadDecoderId = null; } - ); + }); this.payloadDeviceDatatarget.forEach((relation) => { if (relation.id) { this.payloadDeviceDataTargetService.put(relation).subscribe( @@ -231,8 +240,8 @@ export class HttppushEditComponent implements DatatargetEdit, OnInit, OnDestroy createDatatarget() { this.resetErrors(); this.datatarget.applicationId = this.applicationId; - this.datatargetService.create(this.datatarget) - .subscribe((response: Datatarget) => { + this.datatargetService.create(this.datatarget).subscribe( + (response: Datatarget) => { this.datatargetid = response.id; this.datatarget = response; if (this.datatarget.openDataDkDataset != null) { @@ -241,12 +250,12 @@ export class HttppushEditComponent implements DatatargetEdit, OnInit, OnDestroy this.showSavedSnack(); this.routeToDatatargets(); }, - (error: HttpErrorResponse) => { - this.checkDataTargetModelOpendatadkdatasaet(); - this.handleError(error); - this.formFailedSubmit = true; - }); - + (error: HttpErrorResponse) => { + this.checkDataTargetModelOpendatadkdatasaet(); + this.handleError(error); + this.formFailedSubmit = true; + } + ); } private resetErrors() { @@ -262,14 +271,17 @@ export class HttppushEditComponent implements DatatargetEdit, OnInit, OnDestroy } getDevices(): void { - this.applicationSubscription = this.applicationService.getApplication(this.applicationId) + this.applicationSubscription = this.applicationService + .getApplication(this.applicationId) .subscribe((application: Application) => { this.devices = application.iotDevices; }); } public selectAllDevices(index: number) { - this.payloadDeviceDatatarget[index].iotDeviceIds = this.devices.map(device => device.id); + this.payloadDeviceDatatarget[index].iotDeviceIds = this.devices.map( + (device) => device.id + ); } public deSelectAllDevices(index: number) { @@ -277,7 +289,8 @@ export class HttppushEditComponent implements DatatargetEdit, OnInit, OnDestroy } getPayloadDecoders() { - this.payloadDecoderSubscription = this.payloadDecoderService.getMultiple(1000, 0, 'id', 'ASC') + this.payloadDecoderSubscription = this.payloadDecoderService + .getMultiple(1000, 0, 'id', 'ASC') .subscribe((response: PayloadDecoderMappedResponse) => { this.payloadDecoders = response.data; }); @@ -291,15 +304,12 @@ export class HttppushEditComponent implements DatatargetEdit, OnInit, OnDestroy } routeToDatatargets(): void { - this.router.navigate(['applications',this.applicationId.toString()]) + this.router.navigate(['applications', this.applicationId.toString()]); } onCoordinateKey(event: any) { if (event.target.value.length > event.target.maxLength) { - event.target.value = event.target.value.slice( - 0, - event.target.maxLength - ); + event.target.value = event.target.value.slice(0, event.target.maxLength); } } @@ -316,38 +326,38 @@ export class HttppushEditComponent implements DatatargetEdit, OnInit, OnDestroy } private setDataSetExcists() { - this.opendatadkService.get().subscribe( - (response) => { - this.dataSetExcists = response.dataset.length === 0 ? false : true; - } - ); + this.opendatadkService.get().subscribe((response) => { + this.dataSetExcists = response.dataset.length === 0 ? false : true; + }); } private shouldShowMailDialog(): Observable { - return new Observable( - (observer) => { - if (!this.dataSetExcists && this.datatarget.setToOpendataDk && !this.isMailDialogAlreadyShown) { - this.isMailDialogAlreadyShown = true; - this.opendatadkDialogService.showDialog().subscribe( - response => { - if (response) { - this.showMailClient(); - } - observer.next(response); - } - ); - } else { - observer.next(true); - } + return new Observable((observer) => { + if ( + !this.dataSetExcists && + this.datatarget.setToOpendataDk && + !this.isMailDialogAlreadyShown + ) { + this.isMailDialogAlreadyShown = true; + this.opendatadkDialogService.showDialog().subscribe((response) => { + if (response) { + this.showMailClient(); + } + observer.next(response); + }); + } else { + observer.next(true); } - ) + }); } private showMailClient() { if (!this.datatarget.openDataDkDataset.url) { - this.datatarget.openDataDkDataset.url = this.datatargetService.getOpendataSharingApiUrl() + this.datatarget.openDataDkDataset.url = this.datatargetService.getOpendataSharingApiUrl(); } - window.location.href = 'mailto:FG2V@kk.dk?subject=Oprettelse%20af%20datas%C3%A6t%20i%20OpenDataDK&body=K%C3%A6re%20Frans%0D%0A%0D%0AHermed%20fremsendes%20linket%20til%20DCAT%20kataloget%20%2C%20du%20bedes%20registrere%20p%C3%A5%20Open%20Data%20DK%20platformen.%0D%0A%0D%0ALink%3A ' + this.datatarget.openDataDkDataset.url; + window.location.href = + 'mailto:FG2V@kk.dk?subject=Oprettelse%20af%20datas%C3%A6t%20i%20OpenDataDK&body=K%C3%A6re%20Frans%0D%0A%0D%0AHermed%20fremsendes%20linket%20til%20DCAT%20kataloget%20%2C%20du%20bedes%20registrere%20p%C3%A5%20Open%20Data%20DK%20platformen.%0D%0A%0D%0ALink%3A ' + + this.datatarget.openDataDkDataset.url; } disableSaveButton(): boolean { @@ -377,17 +387,20 @@ export class HttppushEditComponent implements DatatargetEdit, OnInit, OnDestroy } } - private mapToDatatargetDevicePayload(dto: PayloadDeviceDatatargetGetByDataTargetResponse) { + private mapToDatatargetDevicePayload( + dto: PayloadDeviceDatatargetGetByDataTargetResponse + ) { this.payloadDeviceDatatarget = []; - dto.data.forEach( - (element) => { - this.payloadDeviceDatatarget.push({ - id: element.id, - iotDeviceIds: element.iotDevices.map((x) => x.id), - payloadDecoderId: element.payloadDecoder?.id === undefined ? 0 : element.payloadDecoder?.id, - dataTargetId: element.dataTarget.id - }); - } - ); + dto.data.forEach((element) => { + this.payloadDeviceDatatarget.push({ + id: element.id, + iotDeviceIds: element.iotDevices.map((x) => x.id), + payloadDecoderId: + element.payloadDecoder?.id === undefined + ? 0 + : element.payloadDecoder?.id, + dataTargetId: element.dataTarget.id, + }); + }); } -} \ No newline at end of file +} From dd1984f04a5077ffd1182e55a3eeae115766d155 Mon Sep 17 00:00:00 2001 From: bkdkmd Date: Wed, 16 Feb 2022 12:06:02 +0100 Subject: [PATCH 7/7] DatatargetTypesService pr fixes --- .../datatarget/datatarget-types.service.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/app/applications/datatarget/datatarget-types.service.ts b/src/app/applications/datatarget/datatarget-types.service.ts index c0dd41ad..581788cf 100644 --- a/src/app/applications/datatarget/datatarget-types.service.ts +++ b/src/app/applications/datatarget/datatarget-types.service.ts @@ -1,5 +1,7 @@ import { Injectable, Type } from '@angular/core'; import { DataTargetType } from '@shared/enums/datatarget-type'; +import { DatatargetDetail } from './datatarget-detail/datatarget-detail'; +import { DatatargetEdit } from './datatarget-edit/datatarget-edit'; import { DatatargetTypeDescriptor } from './datatarget.model'; import { FiwareDetailComponent } from './fiware/fiware-detail/fiware-detail.component'; import { FiwareEditComponent } from './fiware/fiware-edit/fiware-edit.component'; @@ -42,37 +44,37 @@ constructor() { } ] } - getDetailComponent(dataTargetType: DataTargetType): Type + getDetailComponent(dataTargetType: DataTargetType): Type { - if (dataTargetType == DataTargetType.HTTPPUSH) + if (dataTargetType === DataTargetType.HTTPPUSH) { return HttppushDetailComponent; } - if (dataTargetType == DataTargetType.OPENDATADK) + if (dataTargetType === DataTargetType.OPENDATADK) { return HttppushDetailComponent; } - if (dataTargetType == DataTargetType.FIWARE) + if (dataTargetType === DataTargetType.FIWARE) { return FiwareDetailComponent; } } - getEditComponent(dataTargetType: DataTargetType): Type + getEditComponent(dataTargetType: DataTargetType): Type { - if (dataTargetType == DataTargetType.HTTPPUSH) + if (dataTargetType === DataTargetType.HTTPPUSH) { return HttppushEditComponent; } - if (dataTargetType == DataTargetType.OPENDATADK) + if (dataTargetType === DataTargetType.OPENDATADK) { return HttppushEditComponent; } - if (dataTargetType == DataTargetType.FIWARE) + if (dataTargetType === DataTargetType.FIWARE) { return FiwareEditComponent; }